aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/53c700.c14
-rw-r--r--drivers/scsi/BusLogic.c9
-rw-r--r--drivers/scsi/BusLogic.h9
-rw-r--r--drivers/scsi/Kconfig62
-rw-r--r--drivers/scsi/Makefile4
-rw-r--r--drivers/scsi/NCR5380.c70
-rw-r--r--drivers/scsi/NCR5380.h2
-rw-r--r--drivers/scsi/a2091.c1
-rw-r--r--drivers/scsi/a3000.c1
-rw-r--r--drivers/scsi/a4000t.c1
-rw-r--r--drivers/scsi/aacraid/Makefile1
-rw-r--r--drivers/scsi/aacraid/aachba.c16
-rw-r--r--drivers/scsi/aacraid/aacraid.h16
-rw-r--r--drivers/scsi/aacraid/commctrl.c16
-rw-r--r--drivers/scsi/aacraid/comminit.c16
-rw-r--r--drivers/scsi/aacraid/commsup.c16
-rw-r--r--drivers/scsi/aacraid/dpcsup.c17
-rw-r--r--drivers/scsi/aacraid/linit.c15
-rw-r--r--drivers/scsi/aacraid/nark.c16
-rw-r--r--drivers/scsi/aacraid/rkt.c16
-rw-r--r--drivers/scsi/aacraid/rx.c16
-rw-r--r--drivers/scsi/aacraid/sa.c16
-rw-r--r--drivers/scsi/aacraid/src.c16
-rw-r--r--drivers/scsi/advansys.c8
-rw-r--r--drivers/scsi/aha152x.c59
-rw-r--r--drivers/scsi/aha1542.c1
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic79xx1
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic7xxx3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.reg2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c14
-rw-r--r--drivers/scsi/aic94xx/Kconfig20
-rw-r--r--drivers/scsi/aic94xx/Makefile18
-rw-r--r--drivers/scsi/aic94xx/aic94xx.h19
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c23
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.c20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.h20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg.c20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg.h20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg_def.h20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sas.h20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.c20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.h20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.h20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c20
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c20
-rw-r--r--drivers/scsi/am53c974.c1
-rw-r--r--drivers/scsi/arcmsr/Makefile1
-rw-r--r--drivers/scsi/arm/Kconfig1
-rw-r--r--drivers/scsi/arm/acornscsi-io.S5
-rw-r--r--drivers/scsi/arm/acornscsi.c5
-rw-r--r--drivers/scsi/arm/acornscsi.h5
-rw-r--r--drivers/scsi/arm/arxescsi.c1
-rw-r--r--drivers/scsi/arm/cumana_1.c1
-rw-r--r--drivers/scsi/arm/cumana_2.c5
-rw-r--r--drivers/scsi/arm/eesox.c5
-rw-r--r--drivers/scsi/arm/fas216.c5
-rw-r--r--drivers/scsi/arm/fas216.h5
-rw-r--r--drivers/scsi/arm/msgqueue.c5
-rw-r--r--drivers/scsi/arm/msgqueue.h5
-rw-r--r--drivers/scsi/arm/oak.c1
-rw-r--r--drivers/scsi/arm/powertec.c5
-rw-r--r--drivers/scsi/arm/queue.c5
-rw-r--r--drivers/scsi/arm/queue.h5
-rw-r--r--drivers/scsi/arm/scsi.h5
-rw-r--r--drivers/scsi/atp870u.c8
-rw-r--r--drivers/scsi/be2iscsi/Kconfig1
-rw-r--r--drivers/scsi/be2iscsi/Makefile1
-rw-r--r--drivers/scsi/be2iscsi/be.h7
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c9
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h7
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c7
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h7
-rw-r--r--drivers/scsi/be2iscsi/be_main.c1
-rw-r--r--drivers/scsi/be2iscsi/be_main.h7
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h7
-rw-r--r--drivers/scsi/bfa/bfa.h13
-rw-r--r--drivers/scsi/bfa/bfa_core.c10
-rw-r--r--drivers/scsi/bfa/bfa_cs.h10
-rw-r--r--drivers/scsi/bfa/bfa_defs.h10
-rw-r--r--drivers/scsi/bfa/bfa_defs_fcs.h10
-rw-r--r--drivers/scsi/bfa/bfa_defs_svc.h10
-rw-r--r--drivers/scsi/bfa/bfa_fc.h10
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.c10
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.h10
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c16
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.h10
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c10
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h10
-rw-r--r--drivers/scsi/bfa/bfa_fcs_fcpim.c10
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c10
-rw-r--r--drivers/scsi/bfa/bfa_fcs_rport.c10
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c12
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c12
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c10
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h10
-rw-r--r--drivers/scsi/bfa/bfa_ioc_cb.c10
-rw-r--r--drivers/scsi/bfa/bfa_ioc_ct.c10
-rw-r--r--drivers/scsi/bfa/bfa_modules.h10
-rw-r--r--drivers/scsi/bfa/bfa_plog.h10
-rw-r--r--drivers/scsi/bfa/bfa_port.c10
-rw-r--r--drivers/scsi/bfa/bfa_port.h10
-rw-r--r--drivers/scsi/bfa/bfa_svc.c10
-rw-r--r--drivers/scsi/bfa/bfa_svc.h10
-rw-r--r--drivers/scsi/bfa/bfad.c10
-rw-r--r--drivers/scsi/bfa/bfad_attr.c10
-rw-r--r--drivers/scsi/bfa/bfad_bsg.c10
-rw-r--r--drivers/scsi/bfa/bfad_bsg.h10
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c10
-rw-r--r--drivers/scsi/bfa/bfad_drv.h10
-rw-r--r--drivers/scsi/bfa/bfad_im.c10
-rw-r--r--drivers/scsi/bfa/bfad_im.h10
-rw-r--r--drivers/scsi/bfa/bfi.h10
-rw-r--r--drivers/scsi/bfa/bfi_ms.h10
-rw-r--r--drivers/scsi/bfa/bfi_reg.h10
-rw-r--r--drivers/scsi/bnx2fc/Kconfig1
-rw-r--r--drivers/scsi/bnx2fc/Makefile1
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h14
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_els.c60
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c3
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c4
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c119
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c10
-rw-r--r--drivers/scsi/bnx2i/Kconfig1
-rw-r--r--drivers/scsi/bnx2i/Makefile1
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c3
-rw-r--r--drivers/scsi/bvme6000_scsi.c1
-rw-r--r--drivers/scsi/ch.c1
-rw-r--r--drivers/scsi/csiostor/Kconfig1
-rw-r--r--drivers/scsi/csiostor/csio_isr.c28
-rw-r--r--drivers/scsi/csiostor/csio_wr.c1
-rw-r--r--drivers/scsi/cxgbi/Kconfig1
-rw-r--r--drivers/scsi/cxgbi/Makefile1
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/Kbuild1
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/Kconfig1
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c24
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/Kbuild1
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/Kconfig1
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c28
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c41
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.h9
-rw-r--r--drivers/scsi/cxlflash/Kconfig1
-rw-r--r--drivers/scsi/cxlflash/Makefile1
-rw-r--r--drivers/scsi/cxlflash/backend.h6
-rw-r--r--drivers/scsi/cxlflash/common.h6
-rw-r--r--drivers/scsi/cxlflash/cxl_hw.c6
-rw-r--r--drivers/scsi/cxlflash/lunmgt.c6
-rw-r--r--drivers/scsi/cxlflash/main.c6
-rw-r--r--drivers/scsi/cxlflash/main.h6
-rw-r--r--drivers/scsi/cxlflash/ocxl_hw.c6
-rw-r--r--drivers/scsi/cxlflash/ocxl_hw.h6
-rw-r--r--drivers/scsi/cxlflash/sislite.h6
-rw-r--r--drivers/scsi/cxlflash/superpipe.c6
-rw-r--r--drivers/scsi/cxlflash/superpipe.h6
-rw-r--r--drivers/scsi/cxlflash/vlun.c6
-rw-r--r--drivers/scsi/cxlflash/vlun.h6
-rw-r--r--drivers/scsi/device_handler/Kconfig1
-rw-r--r--drivers/scsi/device_handler/Makefile1
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c22
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c15
-rw-r--r--drivers/scsi/device_handler/scsi_dh_hp_sw.c15
-rw-r--r--drivers/scsi/dmx3191d.c14
-rw-r--r--drivers/scsi/dpt/dpti_i2o.h7
-rw-r--r--drivers/scsi/dpt/dpti_ioctl.h5
-rw-r--r--drivers/scsi/dpt_i2o.c17
-rw-r--r--drivers/scsi/dpti.h5
-rw-r--r--drivers/scsi/esas2r/Kconfig1
-rw-r--r--drivers/scsi/esas2r/Makefile1
-rw-r--r--drivers/scsi/esp_scsi.c23
-rw-r--r--drivers/scsi/esp_scsi.h2
-rw-r--r--drivers/scsi/fcoe/Makefile1
-rw-r--r--drivers/scsi/fcoe/fcoe.c14
-rw-r--r--drivers/scsi/fcoe/fcoe.h14
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c14
-rw-r--r--drivers/scsi/fcoe/fcoe_sysfs.c14
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c14
-rw-r--r--drivers/scsi/fdomain.c597
-rw-r--r--drivers/scsi/fdomain.h114
-rw-r--r--drivers/scsi/fdomain_isa.c222
-rw-r--r--drivers/scsi/fdomain_pci.c68
-rw-r--r--drivers/scsi/g_NCR5380.c1
-rw-r--r--drivers/scsi/gdth.c19
-rw-r--r--drivers/scsi/gvp11.c1
-rw-r--r--drivers/scsi/hisi_sas/Kconfig1
-rw-r--r--drivers/scsi/hisi_sas/Makefile1
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h18
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c127
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c28
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v2_hw.c106
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c506
-rw-r--r--drivers/scsi/hosts.c1
-rw-r--r--drivers/scsi/hpsa.c316
-rw-r--r--drivers/scsi/hpsa.h6
-rw-r--r--drivers/scsi/hpsa_cmd.h3
-rw-r--r--drivers/scsi/hptiop.c10
-rw-r--r--drivers/scsi/hptiop.h10
-rw-r--r--drivers/scsi/ibmvscsi/Makefile1
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c16
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h16
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c93
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h26
-rw-r--r--drivers/scsi/ibmvscsi_tgt/Makefile1
-rw-r--r--drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c11
-rw-r--r--drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h11
-rw-r--r--drivers/scsi/ibmvscsi_tgt/libsrp.c11
-rw-r--r--drivers/scsi/imm.c36
-rw-r--r--drivers/scsi/initio.c16
-rw-r--r--drivers/scsi/ipr.c45
-rw-r--r--drivers/scsi/ipr.h15
-rw-r--r--drivers/scsi/isci/remote_device.c4
-rw-r--r--drivers/scsi/isci/remote_device.h5
-rw-r--r--drivers/scsi/isci/request.c8
-rw-r--r--drivers/scsi/isci/task.c2
-rw-r--r--drivers/scsi/iscsi_boot_sysfs.c10
-rw-r--r--drivers/scsi/iscsi_tcp.c11
-rw-r--r--drivers/scsi/iscsi_tcp.h11
-rw-r--r--drivers/scsi/jazz_esp.c1
-rw-r--r--drivers/scsi/lasi700.c14
-rw-r--r--drivers/scsi/libfc/fc_disc.c14
-rw-r--r--drivers/scsi/libfc/fc_elsct.c14
-rw-r--r--drivers/scsi/libfc/fc_exch.c14
-rw-r--r--drivers/scsi/libfc/fc_fcp.c14
-rw-r--r--drivers/scsi/libfc/fc_frame.c14
-rw-r--r--drivers/scsi/libfc/fc_libfc.c14
-rw-r--r--drivers/scsi/libfc/fc_libfc.h14
-rw-r--r--drivers/scsi/libfc/fc_lport.c14
-rw-r--r--drivers/scsi/libfc/fc_npiv.c14
-rw-r--r--drivers/scsi/libfc/fc_rport.c14
-rw-r--r--drivers/scsi/libiscsi.c15
-rw-r--r--drivers/scsi/libiscsi_tcp.c13
-rw-r--r--drivers/scsi/libsas/Kconfig18
-rw-r--r--drivers/scsi/libsas/Makefile17
-rw-r--r--drivers/scsi/libsas/sas_ata.c18
-rw-r--r--drivers/scsi/libsas/sas_discover.c23
-rw-r--r--drivers/scsi/libsas/sas_event.c18
-rw-r--r--drivers/scsi/libsas/sas_expander.c154
-rw-r--r--drivers/scsi/libsas/sas_host_smp.c5
-rw-r--r--drivers/scsi/libsas/sas_init.c61
-rw-r--r--drivers/scsi/libsas/sas_internal.h19
-rw-r--r--drivers/scsi/libsas/sas_phy.c28
-rw-r--r--drivers/scsi/libsas/sas_port.c44
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c19
-rw-r--r--drivers/scsi/libsas/sas_task.c1
-rw-r--r--drivers/scsi/lpfc/lpfc.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c366
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c125
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h7
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c51
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c486
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c167
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c75
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h42
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c637
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_nvme.c89
-rw-r--r--drivers/scsi/lpfc/lpfc_nvmet.c414
-rw-r--r--drivers/scsi/lpfc/lpfc_nvmet.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c39
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c511
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h19
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h65
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h4
-rw-r--r--drivers/scsi/mac53c94.c1
-rw-r--r--drivers/scsi/mac_esp.c1
-rw-r--r--drivers/scsi/mac_scsi.c422
-rw-r--r--drivers/scsi/megaraid.c7
-rw-r--r--drivers/scsi/megaraid/Kconfig.megaraid2
-rw-r--r--drivers/scsi/megaraid/Makefile2
-rw-r--r--drivers/scsi/megaraid/mbox_defs.h7
-rw-r--r--drivers/scsi/megaraid/mega_common.h6
-rw-r--r--drivers/scsi/megaraid/megaraid_ioctl.h6
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c7
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h6
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c6
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.h6
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h115
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c731
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_debugfs.c179
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c96
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c568
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h47
-rw-r--r--drivers/scsi/mesh.c1
-rw-r--r--drivers/scsi/mpt3sas/Kconfig1
-rw-r--r--drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h2
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c666
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h53
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c73
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c234
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c52
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c8
-rw-r--r--drivers/scsi/mvme16x_scsi.c1
-rw-r--r--drivers/scsi/mvsas/Kconfig20
-rw-r--r--drivers/scsi/mvsas/Makefile17
-rw-r--r--drivers/scsi/mvsas/mv_64xx.c21
-rw-r--r--drivers/scsi/mvsas/mv_64xx.h18
-rw-r--r--drivers/scsi/mvsas/mv_94xx.c21
-rw-r--r--drivers/scsi/mvsas/mv_94xx.h18
-rw-r--r--drivers/scsi/mvsas/mv_chips.h18
-rw-r--r--drivers/scsi/mvsas/mv_defs.h18
-rw-r--r--drivers/scsi/mvsas/mv_init.c18
-rw-r--r--drivers/scsi/mvsas/mv_sas.c22
-rw-r--r--drivers/scsi/mvsas/mv_sas.h21
-rw-r--r--drivers/scsi/mvumi.c35
-rw-r--r--drivers/scsi/mvumi.h18
-rw-r--r--drivers/scsi/myrs.c2
-rw-r--r--drivers/scsi/ncr53c8xx.c14
-rw-r--r--drivers/scsi/ncr53c8xx.h14
-rw-r--r--drivers/scsi/nsp32.c12
-rw-r--r--drivers/scsi/nsp32.h11
-rw-r--r--drivers/scsi/osst.c6101
-rw-r--r--drivers/scsi/osst.h651
-rw-r--r--drivers/scsi/osst_detect.h7
-rw-r--r--drivers/scsi/osst_options.h107
-rw-r--r--drivers/scsi/pcmcia/Kconfig11
-rw-r--r--drivers/scsi/pcmcia/Makefile1
-rw-r--r--drivers/scsi/pcmcia/fdomain_cs.c95
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c4
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c11
-rw-r--r--drivers/scsi/pm8001/pm8001_ctl.c52
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c41
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c4
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c8
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h3
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c59
-rw-r--r--drivers/scsi/pmcraid.c31
-rw-r--r--drivers/scsi/pmcraid.h15
-rw-r--r--drivers/scsi/ppa.c3
-rw-r--r--drivers/scsi/ps3rom.c14
-rw-r--r--drivers/scsi/qedf/Kconfig1
-rw-r--r--drivers/scsi/qedf/Makefile1
-rw-r--r--drivers/scsi/qedf/drv_fcoe_fw_funcs.c5
-rw-r--r--drivers/scsi/qedf/drv_fcoe_fw_funcs.h5
-rw-r--r--drivers/scsi/qedf/drv_scsi_fw_funcs.c5
-rw-r--r--drivers/scsi/qedf/drv_scsi_fw_funcs.h5
-rw-r--r--drivers/scsi/qedf/qedf.h62
-rw-r--r--drivers/scsi/qedf/qedf_attr.c5
-rw-r--r--drivers/scsi/qedf/qedf_dbg.c37
-rw-r--r--drivers/scsi/qedf/qedf_dbg.h5
-rw-r--r--drivers/scsi/qedf/qedf_debugfs.c62
-rw-r--r--drivers/scsi/qedf/qedf_els.c87
-rw-r--r--drivers/scsi/qedf/qedf_fip.c100
-rw-r--r--drivers/scsi/qedf/qedf_hsi.h5
-rw-r--r--drivers/scsi/qedf/qedf_io.c758
-rw-r--r--drivers/scsi/qedf/qedf_main.c325
-rw-r--r--drivers/scsi/qedf/qedf_version.h11
-rw-r--r--drivers/scsi/qedi/Kconfig1
-rw-r--r--drivers/scsi/qedi/Makefile1
-rw-r--r--drivers/scsi/qedi/qedi.h5
-rw-r--r--drivers/scsi/qedi/qedi_dbg.c37
-rw-r--r--drivers/scsi/qedi/qedi_dbg.h5
-rw-r--r--drivers/scsi/qedi/qedi_debugfs.c5
-rw-r--r--drivers/scsi/qedi/qedi_fw.c10
-rw-r--r--drivers/scsi/qedi/qedi_fw_api.c5
-rw-r--r--drivers/scsi/qedi/qedi_fw_iscsi.h5
-rw-r--r--drivers/scsi/qedi/qedi_fw_scsi.h5
-rw-r--r--drivers/scsi/qedi/qedi_gbl.h5
-rw-r--r--drivers/scsi/qedi/qedi_hsi.h5
-rw-r--r--drivers/scsi/qedi/qedi_iscsi.c21
-rw-r--r--drivers/scsi/qedi/qedi_iscsi.h5
-rw-r--r--drivers/scsi/qedi/qedi_main.c42
-rw-r--r--drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h5
-rw-r--r--drivers/scsi/qedi/qedi_sysfs.c5
-rw-r--r--drivers/scsi/qedi/qedi_version.h11
-rw-r--r--drivers/scsi/qla1280.c26
-rw-r--r--drivers/scsi/qla1280.h11
-rw-r--r--drivers/scsi/qla2xxx/Kconfig1
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c329
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c84
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h11
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c192
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h10
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h272
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c9
-rw-r--r--drivers/scsi/qla2xxx/qla_dsd.h30
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h98
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h109
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c139
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c1491
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h69
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c360
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c144
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c336
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c9
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c111
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.h11
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.c307
-rw-r--r--drivers/scsi/qla2xxx/qla_nvme.h16
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c38
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.c13
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c829
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c973
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c228
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h44
-rw-r--r--drivers/scsi/qla2xxx/qla_tmpl.c447
-rw-r--r--drivers/scsi/qla2xxx/qla_tmpl.h76
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c68
-rw-r--r--drivers/scsi/qla4xxx/Kconfig1
-rw-r--r--drivers/scsi/qla4xxx/Makefile1
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c2
-rw-r--r--drivers/scsi/qlogicfas408.c4
-rw-r--r--drivers/scsi/qlogicpti.c1
-rw-r--r--drivers/scsi/raid_class.c3
-rw-r--r--drivers/scsi/script_asm.pl15
-rw-r--r--drivers/scsi/scsi.c13
-rw-r--r--drivers/scsi/scsi_debug.c7
-rw-r--r--drivers/scsi/scsi_debugfs.h1
-rw-r--r--drivers/scsi/scsi_dh.c15
-rw-r--r--drivers/scsi/scsi_error.c28
-rw-r--r--drivers/scsi/scsi_ioctl.c1
-rw-r--r--drivers/scsi/scsi_lib.c70
-rw-r--r--drivers/scsi/scsi_logging.c3
-rw-r--r--drivers/scsi/scsi_netlink.c16
-rw-r--r--drivers/scsi/scsi_pm.c7
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/scsi_proc.c2
-rw-r--r--drivers/scsi/scsi_scan.c7
-rw-r--r--drivers/scsi/scsi_sysctl.c2
-rw-r--r--drivers/scsi/scsi_sysfs.c8
-rw-r--r--drivers/scsi/scsi_trace.c14
-rw-r--r--drivers/scsi/scsi_transport_fc.c138
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c15
-rw-r--r--drivers/scsi/scsi_transport_sas.c2
-rw-r--r--drivers/scsi/scsi_transport_spi.c15
-rw-r--r--drivers/scsi/scsi_transport_srp.c16
-rw-r--r--drivers/scsi/sd.c146
-rw-r--r--drivers/scsi/sd_dif.c16
-rw-r--r--drivers/scsi/sd_zbc.c16
-rw-r--r--drivers/scsi/ses.c20
-rw-r--r--drivers/scsi/sg.c7
-rw-r--r--drivers/scsi/sim710.c15
-rw-r--r--drivers/scsi/smartpqi/Makefile1
-rw-r--r--drivers/scsi/smartpqi/smartpqi.h15
-rw-r--r--drivers/scsi/smartpqi/smartpqi_init.c82
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sas_transport.c15
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sis.c15
-rw-r--r--drivers/scsi/smartpqi/smartpqi_sis.h15
-rw-r--r--drivers/scsi/sni_53c710.c14
-rw-r--r--drivers/scsi/sr.c2
-rw-r--r--drivers/scsi/st.c10
-rw-r--r--drivers/scsi/stex.c7
-rw-r--r--drivers/scsi/storvsc_drv.c25
-rw-r--r--drivers/scsi/sun3_scsi.c1
-rw-r--r--drivers/scsi/sun3x_esp.c1
-rw-r--r--drivers/scsi/sun_esp.c1
-rw-r--r--drivers/scsi/sym53c8xx_2/Makefile1
-rw-r--r--drivers/scsi/sym53c8xx_2/sym53c8xx.h15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_defs.h15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw.c15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw.h15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw1.h15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw2.h15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.h15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.c17
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.h15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_malloc.c15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_misc.h15
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_nvram.c16
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_nvram.h15
-rw-r--r--drivers/scsi/ufs/Kconfig15
-rw-r--r--drivers/scsi/ufs/Makefile1
-rw-r--r--drivers/scsi/ufs/cdns-pltfrm.c74
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210-pci.c5
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210-pltfrm.c5
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210.c5
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210.h5
-rw-r--r--drivers/scsi/ufs/ufs-hisi.c117
-rw-r--r--drivers/scsi/ufs/ufs-hisi.h4
-rw-r--r--drivers/scsi/ufs/ufs-mediatek.c368
-rw-r--r--drivers/scsi/ufs/ufs-mediatek.h53
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c250
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h15
-rw-r--r--drivers/scsi/ufs/ufs-sysfs.c6
-rw-r--r--drivers/scsi/ufs/ufs.h1
-rw-r--r--drivers/scsi/ufs/ufs_bsg.c6
-rw-r--r--drivers/scsi/ufs/ufs_quirks.h11
-rw-r--r--drivers/scsi/ufs/ufshcd-dwc.c5
-rw-r--r--drivers/scsi/ufs/ufshcd-dwc.h5
-rw-r--r--drivers/scsi/ufs/ufshcd-pci.c2
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c123
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.h32
-rw-r--r--drivers/scsi/ufs/ufshcd.c79
-rw-r--r--drivers/scsi/ufs/ufshcd.h5
-rw-r--r--drivers/scsi/ufs/ufshci-dwc.h5
-rw-r--r--drivers/scsi/ufs/ufshci.h6
-rw-r--r--drivers/scsi/ufs/unipro.h8
-rw-r--r--drivers/scsi/virtio_scsi.c10
-rw-r--r--drivers/scsi/vmw_pvscsi.c8
-rw-r--r--drivers/scsi/wd33c93.c13
-rw-r--r--drivers/scsi/wd33c93.h12
-rw-r--r--drivers/scsi/wd719x.c43
-rw-r--r--drivers/scsi/zalon.c1
-rw-r--r--drivers/scsi/zorro7xx.c1
502 files changed, 13412 insertions, 16598 deletions
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 16957d7ac414..0068963bb933 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* -*- mode: c; c-basic-offset: 8 -*- */
/* NCR (or Symbios) 53c700 and 53c700-66 Driver
@@ -5,19 +6,6 @@
* Copyright (C) 2001 by James.Bottomley@HansenPartnership.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.
-**
-** 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., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index e41e51f1da71..c25e8a54e869 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
@@ -5,14 +6,6 @@
Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
- This program is free software; you may redistribute and/or modify it under
- the terms of the GNU General Public License 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 complete details.
The author respectfully requests that any modifications to this software be
sent directly to him for evaluation and testing.
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 8d47e2c88d24..6182cc8a0344 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -1,17 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
- This program is free software; you may redistribute and/or modify it under
- the terms of the GNU General Public License 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 complete details.
The author respectfully requests that any modifications to this software be
sent directly to him for evaluation and testing.
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index d528018e6fa8..75f66f8ad3ea 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
menu "SCSI device support"
config SCSI_MOD
@@ -98,28 +99,6 @@ config CHR_DEV_ST
To compile this driver as a module, choose M here and read
<file:Documentation/scsi/scsi.txt>. The module will be called st.
-config CHR_DEV_OSST
- tristate "SCSI OnStream SC-x0 tape support"
- depends on SCSI
- ---help---
- The OnStream SC-x0 SCSI tape drives cannot be driven by the
- standard st driver, but instead need this special osst driver and
- use the /dev/osstX char device nodes (major 206). Via usb-storage,
- you may be able to drive the USB-x0 and DI-x0 drives as well.
- Note that there is also a second generation of OnStream
- tape drives (ADR-x0) that supports the standard SCSI-2 commands for
- tapes (QIC-157) and can be driven by the standard driver st.
- For more information, you may have a look at the SCSI-HOWTO
- <http://www.tldp.org/docs.html#howto> and
- <file:Documentation/scsi/osst.txt> in the kernel source.
- More info on the OnStream driver may be found on
- <http://sourceforge.net/projects/osst/>
- Please also have a look at the standard st docu, as most of it
- applies to osst as well.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/scsi/scsi.txt>. The module will be called osst.
-
config BLK_DEV_SR
tristate "SCSI CDROM support"
depends on SCSI && BLK_DEV
@@ -182,7 +161,7 @@ config CHR_DEV_SCH
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/kbuild/modules.txt> and
+ say M here and read <file:Documentation/kbuild/modules.rst> and
<file:Documentation/scsi/scsi.txt>. The module will be called ch.o.
If unsure, say N.
@@ -663,6 +642,41 @@ config SCSI_DMX3191D
To compile this driver as a module, choose M here: the
module will be called dmx3191d.
+config SCSI_FDOMAIN
+ tristate
+ depends on SCSI
+
+config SCSI_FDOMAIN_PCI
+ tristate "Future Domain TMC-3260/AHA-2920A PCI SCSI support"
+ depends on PCI && SCSI
+ select SCSI_FDOMAIN
+ help
+ This is support for Future Domain's PCI SCSI host adapters (TMC-3260)
+ and other adapters with PCI bus based on the Future Domain chipsets
+ (Adaptec AHA-2920A).
+
+ NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip
+ and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI
+ controller support"). This Future Domain driver works with the older
+ Adaptec AHA-2920A boards with a Future Domain chip on them.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fdomain_pci.
+
+config SCSI_FDOMAIN_ISA
+ tristate "Future Domain 16xx ISA SCSI support"
+ depends on ISA && SCSI
+ select CHECK_SIGNATURE
+ select SCSI_FDOMAIN
+ help
+ This is support for Future Domain's 16-bit SCSI host adapters
+ (TMC-1660/1680, TMC-1650/1670, TMC-1610M/MER/MEX) and other adapters
+ with ISA bus based on the Future Domain chipsets (Quantum ISA-200S,
+ ISA-250MG; and at least one IBM board).
+
+ To compile this driver as a module, choose M here: the
+ module will be called fdomain_isa.
+
config SCSI_GDTH
tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
depends on PCI && SCSI
@@ -1473,7 +1487,7 @@ config ZFCP
This driver is also available as a module. This module will be
called zfcp. If you want to compile it as a module, say M here
- and read <file:Documentation/kbuild/modules.txt>.
+ and read <file:Documentation/kbuild/modules.rst>.
config SCSI_PMCRAID
tristate "PMC SIERRA Linux MaxRAID adapter support"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 8826111fdf4a..aeda53901064 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -76,6 +76,9 @@ obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_PM8001) += pm8001/
obj-$(CONFIG_SCSI_ISCI) += isci/
obj-$(CONFIG_SCSI_IPS) += ips.o
+obj-$(CONFIG_SCSI_FDOMAIN) += fdomain.o
+obj-$(CONFIG_SCSI_FDOMAIN_PCI) += fdomain_pci.o
+obj-$(CONFIG_SCSI_FDOMAIN_ISA) += fdomain_isa.o
obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
@@ -143,7 +146,6 @@ obj-$(CONFIG_SCSI_WD719X) += wd719x.o
obj-$(CONFIG_ARM) += arm/
obj-$(CONFIG_CHR_DEV_ST) += st.o
-obj-$(CONFIG_CHR_DEV_OSST) += osst.o
obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o
obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o
obj-$(CONFIG_CHR_DEV_SG) += sg.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 01c23d27f290..536426f25e86 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -149,12 +149,10 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
if (scsi_bufflen(cmd)) {
cmd->SCp.buffer = scsi_sglist(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;
} else {
cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
cmd->SCp.ptr = NULL;
cmd->SCp.this_residual = 0;
}
@@ -163,6 +161,17 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
cmd->SCp.Message = 0;
}
+static inline void advance_sg_buffer(struct scsi_cmnd *cmd)
+{
+ struct scatterlist *s = cmd->SCp.buffer;
+
+ if (!cmd->SCp.this_residual && s && !sg_is_last(s)) {
+ cmd->SCp.buffer = sg_next(s);
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ }
+}
+
/**
* NCR5380_poll_politely2 - wait for two chip register values
* @hostdata: host private data
@@ -272,9 +281,8 @@ mrs[] = {
static void NCR5380_print(struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
- unsigned char status, data, basr, mr, icr, i;
+ unsigned char status, basr, mr, icr, i;
- data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
mr = NCR5380_read(MODE_REG);
icr = NCR5380_read(INITIATOR_COMMAND_REG);
@@ -710,6 +718,8 @@ static void NCR5380_main(struct work_struct *work)
NCR5380_information_transfer(instance);
done = 0;
}
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
spin_unlock_irq(&hostdata->lock);
if (!done)
cond_resched();
@@ -1111,8 +1121,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_reselect(instance);
- if (!hostdata->connected)
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
goto out;
}
@@ -1120,7 +1128,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
if (err < 0) {
spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/* Can't touch cmd if it has been reclaimed by the scsi ML */
if (!hostdata->selecting)
@@ -1158,7 +1165,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
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) {
@@ -1673,12 +1679,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sun3_dma_setup_done != cmd) {
int count;
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- }
+ advance_sg_buffer(cmd);
count = sun3scsi_dma_xfer_len(hostdata, cmd);
@@ -1728,15 +1729,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
* scatter-gather list, move onto the next one.
*/
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
- cmd->SCp.this_residual,
- cmd->SCp.buffers_residual);
- }
+ advance_sg_buffer(cmd);
+ dsprintk(NDEBUG_INFORMATION, instance,
+ "this residual %d, sg ents %d\n",
+ cmd->SCp.this_residual,
+ sg_nents(cmd->SCp.buffer));
/*
* The preferred transfer method is going to be
@@ -1764,10 +1761,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
scmd_printk(KERN_INFO, cmd,
"switching to slow handshake\n");
cmd->device->borken = 1;
- sink = 1;
- do_abort(instance);
- cmd->result = DID_ERROR << 16;
- /* XXX - need to source or sink data here, as appropriate */
+ do_reset(instance);
+ bus_reset_cleanup(instance);
}
} else {
/* Transfer a small chunk so that the
@@ -1827,9 +1822,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
maybe_release_dma_irq(instance);
return;
case MESSAGE_REJECT:
@@ -1861,8 +1853,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
@@ -1933,13 +1923,13 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
if (!hostdata->connected)
return;
- /* Fall through to reject message */
-
+ /* Reject message */
+ /* Fall through */
+ default:
/*
* If we get something weird that we aren't expecting,
- * reject it.
+ * log it.
*/
- default:
if (tmp == EXTENDED_MESSAGE)
scmd_printk(KERN_INFO, cmd,
"rejecting unknown extended message code %02x, length %d\n",
@@ -1965,7 +1955,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
maybe_release_dma_irq(instance);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
}
msgout = NOP;
@@ -2137,12 +2126,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
if (sun3_dma_setup_done != tmp) {
int count;
- if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
- ++tmp->SCp.buffer;
- --tmp->SCp.buffers_residual;
- tmp->SCp.this_residual = tmp->SCp.buffer->length;
- tmp->SCp.ptr = sg_virt(tmp->SCp.buffer);
- }
+ advance_sg_buffer(tmp);
count = sun3scsi_dma_xfer_len(hostdata, tmp);
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index efca509b92b0..5935fd6d1a05 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -235,7 +235,7 @@ struct NCR5380_cmd {
#define NCR5380_PIO_CHUNK_SIZE 256
/* Time limit (ms) to poll registers when IRQs are disabled, e.g. during PDMA */
-#define NCR5380_REG_POLL_TIME 15
+#define NCR5380_REG_POLL_TIME 10
static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr)
{
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index c96bc7261a42..564b35473672 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <linux/types.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index dcf435f312dd..222c77c9621f 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/ioport.h>
diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c
index 66c573093901..5e575afce134 100644
--- a/drivers/scsi/a4000t.c
+++ b/drivers/scsi/a4000t.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
* Amiga Technologies A4000T SCSI controller.
diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile
index 3893b95b140b..8f0eec682bb6 100644
--- a/drivers/scsi/aacraid/Makefile
+++ b/drivers/scsi/aacraid/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
# Adaptec aacraid
obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 6085aa087a2f..0ed3f806ace5 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,25 +10,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* aachba.c
*
* Abstract: Contains Interfaces to manage IOs.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 11fb68d7e60d..3fa03230f6ba 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc. <alan@redhat.com>
@@ -9,25 +10,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* aacraid.h
*
* Abstract: Contains all routines for control of the aacraid driver
- *
*/
#ifndef _AACRAID_H_
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index f0ff40332753..ffe41bc111fc 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,25 +10,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* commctrl.c
*
* Abstract: Contains all routines for control of the AFA comm layer
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 0dc7b5a4fea2..d4fcfa1e54e0 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,26 +10,11 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* comminit.c
*
* Abstract: This supports the initialization of the host adapter commuication interface.
* This is a platform dependent module for the pci cyclone board.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 78430a7b294c..2142a649e865 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,26 +10,11 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* commsup.c
*
* Abstract: Contain all routines that are required for FSA host/adapter
* communication.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index 40a771dd1c0e..a557aa629827 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,26 +10,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* dpcsup.c
*
* Abstract: All DPC processing routines for the cyclone board occur here.
- *
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 8e28a505f7e8..644f7f5c61a2 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,20 +10,6 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* linit.c
*
diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c
index c59074e782d6..b5d6b24d6dbd 100644
--- a/drivers/scsi/aacraid/nark.c
+++ b/drivers/scsi/aacraid/nark.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
*
@@ -8,25 +9,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* nark.c
*
* Abstract: Hardware Device Interface for NEMER/ARK
- *
*/
#include <linux/pci.h>
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index a1bc5bbf7a34..5f2cede4d477 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,25 +10,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* rkt.c
*
* Abstract: Hardware miniport for Drawbridge specific hardware functions.
- *
*/
#include <linux/blkdev.h>
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index 576cdf9cc120..3dea348bd25d 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,25 +10,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* rx.c
*
* Abstract: Hardware miniport for Drawbridge specific hardware functions.
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index efa96c1c6aa3..aa5d7638cade 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,25 +10,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* sa.c
*
* Abstract: Drawbridge specific support functions
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index 97bb9e9d201c..3b66e06726c8 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Adaptec AAC series RAID controller driver
* (c) Copyright 2001 Red Hat Inc.
@@ -9,25 +10,10 @@
* 2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
* 2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
* Module Name:
* src.c
*
* Abstract: Hardware Device Interface for PMC SRC based controllers
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index d37584403c33..a242a62caaa1 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
*
@@ -6,11 +7,6 @@
* Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
* Copyright (c) 2014 Hannes Reinecke <hare@suse.de>
* All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
/*
@@ -7714,7 +7710,7 @@ adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp,
sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
return ADV_SUCCESS;
}
- slp++;
+ slp = sg_next(slp);
}
sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
prev_sg_block = sg_block;
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 97872838b983..eb466c2e1839 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -1,18 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* aha152x.c -- Adaptec AHA-152x driver
* Author: Jürgen E. Fischer, fischer@norbit.de
* Copyright 1993-2004 Jürgen E. Fischer
*
- * 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, 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.
- *
- *
* $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $
*
* $Log: aha152x.c,v $
@@ -228,7 +218,6 @@
* Revision 0.0 1993/08/14 19:54:25 root
* empty function bodies; detect() works.
*
- *
**************************************************************************
see Documentation/scsi/aha152x.txt for configuration details
@@ -948,7 +937,6 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
SCp.ptr : buffer pointer
SCp.this_residual : buffer length
SCp.buffer : next buffer
- SCp.buffers_residual : left buffers in list
SCp.phase : current state of the command */
if ((phase & resetting) || !scsi_sglist(SCpnt)) {
@@ -956,13 +944,11 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
SCpnt->SCp.this_residual = 0;
scsi_set_resid(SCpnt, 0);
SCpnt->SCp.buffer = NULL;
- SCpnt->SCp.buffers_residual = 0;
} else {
scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
SCpnt->SCp.buffer = scsi_sglist(SCpnt);
SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
- SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
}
DO_LOCK(flags);
@@ -2030,10 +2016,9 @@ static void datai_run(struct Scsi_Host *shpnt)
}
if (CURRENT_SC->SCp.this_residual == 0 &&
- CURRENT_SC->SCp.buffers_residual > 0) {
+ !sg_is_last(CURRENT_SC->SCp.buffer)) {
/* advance to next buffer */
- CURRENT_SC->SCp.buffers_residual--;
- CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer);
CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
}
@@ -2136,10 +2121,10 @@ static void datao_run(struct Scsi_Host *shpnt)
CMD_INC_RESID(CURRENT_SC, -2 * data_count);
}
- if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+ if (CURRENT_SC->SCp.this_residual == 0 &&
+ !sg_is_last(CURRENT_SC->SCp.buffer)) {
/* advance to next buffer */
- CURRENT_SC->SCp.buffers_residual--;
- CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer);
CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
}
@@ -2158,22 +2143,26 @@ static void datao_run(struct Scsi_Host *shpnt)
static void datao_end(struct Scsi_Host *shpnt)
{
if(TESTLO(DMASTAT, DFIFOEMP)) {
- int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) -
- GETSTCNT();
+ u32 datao_cnt = GETSTCNT();
+ int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC);
+ int done;
+ struct scatterlist *sg = scsi_sglist(CURRENT_SC);
- CMD_INC_RESID(CURRENT_SC, data_count);
+ CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt);
- data_count -= CURRENT_SC->SCp.ptr -
- SG_ADDRESS(CURRENT_SC->SCp.buffer);
- while(data_count>0) {
- CURRENT_SC->SCp.buffer--;
- CURRENT_SC->SCp.buffers_residual++;
- data_count -= CURRENT_SC->SCp.buffer->length;
+ done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC);
+ /* Locate the first SG entry not yet sent */
+ while (done > 0 && !sg_is_last(sg)) {
+ if (done < sg->length)
+ break;
+ done -= sg->length;
+ sg = sg_next(sg);
}
- CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) -
- data_count;
- CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length +
- data_count;
+
+ CURRENT_SC->SCp.buffer = sg;
+ CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done;
+ CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length -
+ done;
}
SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
@@ -2501,7 +2490,7 @@ static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
scsi_get_resid(ptr), ptr->SCp.this_residual,
- ptr->SCp.buffers_residual);
+ sg_nents(ptr->SCp.buffer) - 1);
if (ptr->SCp.phase & not_issued)
seq_puts(m, "not issued|");
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index ba7a5725be04..dc5667afeb27 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Adaptec AHA-1542 SCSI host adapters
*
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index 3b3d599103f8..16743fb9eead 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# AIC79XX 2.5.X Kernel configuration File.
# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#4 $
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index 55ac55ee6068..3546b8cc401f 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -1,9 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# AIC7XXX and AIC79XX 2.5.X Kernel configuration File.
# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#7 $
#
config SCSI_AIC7XXX
- tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)"
+ tristate "Adaptec AIC7xxx Fast -> U160 support"
depends on (PCI || EISA) && SCSI
select SCSI_SPI_ATTRS
---help---
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
index ba0b411d03e2..00fde2243e48 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.reg
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -1666,7 +1666,7 @@ scratch_ram {
size 6
/*
* These are reserved registers in the card's scratch ram on the 2742.
- * The EISA configuraiton chip is mapped here. On Rev E. of the
+ * The EISA configuration chip is mapped here. On Rev E. of the
* aic7770, the sequencer can use this area for scratch, but the
* host cannot directly access these registers. On later chips, this
* area can be read and written by both the host and the sequencer.
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index f3362f4ab16e..a9d40d3b90ef 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -1666,7 +1666,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
printk("\tCRC Value Mismatch\n");
if ((sstat2 & CRCENDERR) != 0)
printk("\tNo terminal CRC packet "
- "recevied\n");
+ "received\n");
if ((sstat2 & CRCREQERR) != 0)
printk("\tIllegal CRC packet "
"request\n");
@@ -4920,24 +4920,30 @@ ahc_fini_scbdata(struct ahc_softc *ahc)
}
ahc_dma_tag_destroy(ahc, scb_data->sg_dmat);
}
+ /* fall through */
case 6:
ahc_dmamap_unload(ahc, scb_data->sense_dmat,
scb_data->sense_dmamap);
+ /* fall through */
case 5:
ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense,
scb_data->sense_dmamap);
ahc_dmamap_destroy(ahc, scb_data->sense_dmat,
scb_data->sense_dmamap);
+ /* fall through */
case 4:
ahc_dma_tag_destroy(ahc, scb_data->sense_dmat);
+ /* fall through */
case 3:
ahc_dmamap_unload(ahc, scb_data->hscb_dmat,
scb_data->hscb_dmamap);
+ /* fall through */
case 2:
ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs,
scb_data->hscb_dmamap);
ahc_dmamap_destroy(ahc, scb_data->hscb_dmat,
scb_data->hscb_dmamap);
+ /* fall through */
case 1:
ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat);
break;
@@ -6002,8 +6008,8 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
if ((scb->flags & SCB_ACTIVE) == 0)
printk("Inactive SCB in Waiting List\n");
ahc_done(ahc, scb);
- /* FALLTHROUGH */
}
+ /* fall through */
case SEARCH_REMOVE:
next = ahc_rem_wscb(ahc, next, prev);
break;
@@ -7008,8 +7014,8 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
}
address -= address_offset;
fmt3_ins->address = address;
- /* FALLTHROUGH */
}
+ /* fall through */
case AIC_OP_OR:
case AIC_OP_AND:
case AIC_OP_XOR:
@@ -7035,7 +7041,7 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
fmt1_ins->opcode = AIC_OP_AND;
fmt1_ins->immediate = 0xff;
}
- /* FALLTHROUGH */
+ /* fall through */
case AIC_OP_ROL:
if ((ahc->features & AHC_ULTRA2) != 0) {
int i, count;
diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig
index c83fe751d0bb..71931c371b1c 100644
--- a/drivers/scsi/aic94xx/Kconfig
+++ b/drivers/scsi/aic94xx/Kconfig
@@ -1,28 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Kernel configuration file for aic94xx SAS/SATA driver.
#
# Copyright (c) 2005 Adaptec, Inc. All rights reserved.
# Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
#
-# This file is licensed under GPLv2.
-#
-# This file is part of the aic94xx driver.
-#
-# The aic94xx driver 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; version 2 of the
-# License.
-#
-# The aic94xx driver 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.
-#
-# You should have received a copy of the GNU General Public License
-# along with Aic94xx Driver; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#
config SCSI_AIC94XX
tristate "Adaptec AIC94xx SAS/SATA support"
diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile
index c0a15c754585..db9fbe3a8e4c 100644
--- a/drivers/scsi/aic94xx/Makefile
+++ b/drivers/scsi/aic94xx/Makefile
@@ -1,26 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for Adaptec aic94xx SAS/SATA driver.
#
# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
#
-# This file is licensed under GPLv2.
-#
-# This file is part of the aic94xx driver.
-#
-# The aic94xx driver 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; version 2 of the
-# License.
-#
-# The aic94xx driver 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.
-#
-# You should have received a copy of the GNU General Public License
-# along with the aic94xx driver; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
ccflags-$(CONFIG_AIC94XX_DEBUG) := -DASD_DEBUG -DASD_ENTER_EXIT
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
index 26d4ad9ede2e..c23bbb609126 100644
--- a/drivers/scsi/aic94xx/aic94xx.h
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -1,27 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Aic94xx SAS/SATA driver header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
* $Id: //depot/aic94xx/aic94xx.h#31 $
*/
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index 33072388ea16..604a5331f639 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -1,27 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA DDB management
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
* $Id: //depot/aic94xx/aic94xx_dev.c#21 $
*/
@@ -187,9 +170,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
}
} else {
flags |= CONCURRENT_CONN_SUPP;
- if (!dev->parent &&
- (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE))
+ if (!dev->parent && dev_is_expander(dev->dev_type))
asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
4);
else
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
index a16a77c8b9cf..7c4c53a54b78 100644
--- a/drivers/scsi/aic94xx/aic94xx_dump.c
+++ b/drivers/scsi/aic94xx/aic94xx_dump.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA driver dump interface.
*
@@ -5,28 +6,9 @@
* Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
* 2005/07/14/LT Complete overhaul of this file. Update pages, register
* locations, names, etc. Make use of macros. Print more information.
* Print all cseq and lseq mip and mdp.
- *
*/
#include <linux/pci.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.h b/drivers/scsi/aic94xx/aic94xx_dump.h
index 191a753d42a7..d8faa5db1998 100644
--- a/drivers/scsi/aic94xx/aic94xx_dump.h
+++ b/drivers/scsi/aic94xx/aic94xx_dump.h
@@ -1,27 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Aic94xx SAS/SATA driver dump header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifndef _AIC94XX_DUMP_H_
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
index 2bc7615193bd..c5a46c59d4f8 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -1,27 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA driver hardware interface.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/pci.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
index 8f147e720cfd..930e192b1cd4 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -1,27 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Aic94xx SAS/SATA driver hardware interface header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifndef _AIC94XX_HWI_H_
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index bbdae67774f0..261d8e495fed 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -1,27 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA driver initialization.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/module.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.c b/drivers/scsi/aic94xx/aic94xx_reg.c
index 56b17c22526e..392499e80821 100644
--- a/drivers/scsi/aic94xx/aic94xx_reg.c
+++ b/drivers/scsi/aic94xx/aic94xx_reg.c
@@ -1,27 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA driver register access.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/pci.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.h b/drivers/scsi/aic94xx/aic94xx_reg.h
index 2279307fd27e..d1c0975f8df3 100644
--- a/drivers/scsi/aic94xx/aic94xx_reg.h
+++ b/drivers/scsi/aic94xx/aic94xx_reg.h
@@ -1,27 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Aic94xx SAS/SATA driver hardware registers definitions.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifndef _AIC94XX_REG_H_
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
index dd6cc8008b16..b96cfc33bb8f 100644
--- a/drivers/scsi/aic94xx/aic94xx_reg_def.h
+++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Aic94xx SAS/SATA driver hardware registers definitions.
*
@@ -9,26 +10,7 @@
* agnostic register r/w functions. Some register corrections, sizes,
* etc.
*
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
* $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $
- *
*/
#ifndef _ADP94XX_REG_DEF_H_
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
index 101072cab70f..3fe34cb96bb1 100644
--- a/drivers/scsi/aic94xx/aic94xx_sas.h
+++ b/drivers/scsi/aic94xx/aic94xx_sas.h
@@ -1,27 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Aic94xx SAS/SATA driver SAS definitions and hardware interface header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifndef _AIC94XX_SAS_H_
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 91ea87dfb700..4a80ec08f0c9 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -1,27 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA driver SCB management.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/gfp.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
index c831e30411fa..3ddc8852bc32 100644
--- a/drivers/scsi/aic94xx/aic94xx_sds.c
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
@@ -1,28 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA driver access to shared data structures and memory
* maps.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/pci.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.h b/drivers/scsi/aic94xx/aic94xx_sds.h
index a06dc0114b8c..80f3c4782725 100644
--- a/drivers/scsi/aic94xx/aic94xx_sds.h
+++ b/drivers/scsi/aic94xx/aic94xx_sds.h
@@ -1,27 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Aic94xx SAS/SATA driver hardware interface header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Gilbert Wu <gilbert_wu@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifndef _AIC94XX_SDS_H_
#define _AIC94XX_SDS_H_
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index da1e0568510d..11853ec29d87 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA driver sequencer interface.
*
@@ -5,25 +6,6 @@
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* Parts of this code adapted from David Chaw's adp94xx_seq.c.
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/delay.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h
index ad787c55525f..5bf9b8ae6a87 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.h
+++ b/drivers/scsi/aic94xx/aic94xx_seq.h
@@ -1,27 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Aic94xx SAS/SATA driver sequencer interface header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#ifndef _AIC94XX_SEQ_H_
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index 7fea344531f6..f923ed019d4a 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -1,27 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx SAS/SATA Tasks
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/spinlock.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index 2a01702d5ba7..f814026f26fa 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -1,27 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Aic94xx Task Management Functions
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * This file is part of the aic94xx driver.
- *
- * The aic94xx driver 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; version 2 of the
- * License.
- *
- * The aic94xx driver 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with the aic94xx driver; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/spinlock.h>
diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c
index 27c0a4a937d9..b69edb473295 100644
--- a/drivers/scsi/am53c974.c
+++ b/drivers/scsi/am53c974.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD am53c974 driver.
* Copyright (c) 2014 Hannes Reinecke, SUSE Linux GmbH
diff --git a/drivers/scsi/arcmsr/Makefile b/drivers/scsi/arcmsr/Makefile
index 721aced39168..9051f66cae36 100644
--- a/drivers/scsi/arcmsr/Makefile
+++ b/drivers/scsi/arcmsr/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
# File: drivers/arcmsr/Makefile
# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver.
diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig
index cfd172a439c9..f34badc75196 100644
--- a/drivers/scsi/arm/Kconfig
+++ b/drivers/scsi/arm/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# SCSI driver configuration for Acorn
#
diff --git a/drivers/scsi/arm/acornscsi-io.S b/drivers/scsi/arm/acornscsi-io.S
index 22171b2110a8..fdd7237bb829 100644
--- a/drivers/scsi/arm/acornscsi-io.S
+++ b/drivers/scsi/arm/acornscsi-io.S
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/linkage.h>
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index d7509859dc00..d12dd89538df 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/acornscsi.c
*
* Acorn SCSI 3 driver
* By R.M.King.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Abandoned using the Select and Transfer command since there were
* some nasty races between our software and the target devices that
* were not easy to solve, and the device errata had a lot of entries
diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h
index 01bc715a3aec..376c76bc2aca 100644
--- a/drivers/scsi/arm/acornscsi.h
+++ b/drivers/scsi/arm/acornscsi.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/acornscsi.h
*
* Copyright (C) 1997 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Acorn SCSI driver
*/
#ifndef ACORNSCSI_H
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
index 5e9dd9f34821..591414120754 100644
--- a/drivers/scsi/arm/arxescsi.c
+++ b/drivers/scsi/arm/arxescsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/scsi/arm/arxescsi.c
*
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index e2d2a81d8e0b..3fd944374631 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic Generic NCR5380 driver
*
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index 40afcbd8de61..a1f3e9ee4e63 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/cumana_2.c
*
* Copyright (C) 1997-2005 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Changelog:
* 30-08-1997 RMK 0.0.0 Created, READONLY version.
* 22-01-1998 RMK 0.0.1 Updated to 2.1.80.
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index 8f64c370a8a7..134f040d58e2 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/eesox.c
*
* Copyright (C) 1997-2005 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* This driver is based on experimentation. Hence, it may have made
* assumptions about the particular card that I have available, and
* may not be reliable!
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 27bda2b05de6..aea4fd73c862 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/fas216.c
*
* Copyright (C) 1997-2003 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
* other sources, including:
* the AMD Am53CF94 data sheet
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index c57c16ef8193..847413ce14cf 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/fas216.h
*
* Copyright (C) 1997-2000 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* FAS216 generic driver
*/
#ifndef FAS216_H
diff --git a/drivers/scsi/arm/msgqueue.c b/drivers/scsi/arm/msgqueue.c
index 7c95c7582b29..58115831362f 100644
--- a/drivers/scsi/arm/msgqueue.c
+++ b/drivers/scsi/arm/msgqueue.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/msgqueue.c
*
* Copyright (C) 1997-1998 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* message queue handling
*/
#include <linux/module.h>
diff --git a/drivers/scsi/arm/msgqueue.h b/drivers/scsi/arm/msgqueue.h
index 41c7333df3e3..4bcc400f556b 100644
--- a/drivers/scsi/arm/msgqueue.h
+++ b/drivers/scsi/arm/msgqueue.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/msgqueue.h
*
* Copyright (C) 1997 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* message queue handling
*/
#ifndef MSGQUEUE_H
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index 8f2efaab8d46..7c9d361e91a9 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Oak Generic NCR5380 driver
*
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index 759f95ba993c..c795537a671c 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/powertec.c
*
* Copyright (C) 1997-2005 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c
index 996dfe903928..e5559f27669d 100644
--- a/drivers/scsi/arm/queue.c
+++ b/drivers/scsi/arm/queue.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/drivers/acorn/scsi/queue.c: queue handling primitives
*
* Copyright (C) 1997-2000 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Changelog:
* 15-Sep-1997 RMK Created.
* 11-Oct-1997 RMK Corrected problem with queue_remove_exclude
diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h
index 3c519c9237b2..cb51379dce94 100644
--- a/drivers/scsi/arm/queue.h
+++ b/drivers/scsi/arm/queue.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/queue.h: queue handling
*
* Copyright (C) 1997 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef QUEUE_H
#define QUEUE_H
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 138a521ba1a8..4d5ff7b4e864 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* linux/drivers/acorn/scsi/scsi.h
*
* Copyright (C) 2002 Russell King
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
* Commonly used scsi driver functions.
*/
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 1267200380f8..e41f0bbdc9fd 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 1997 Wu Ching Chen
* 2.1.x update (C) 1998 Krzysztof G. Baranowski
@@ -194,12 +195,11 @@ static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
((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;
+ if (dev->id[c][target_id].last_len != adrcnt) {
+ 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;
+ dev->id[c][target_id].last_len = adrcnt;
}
#ifdef ED_DBGP
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);
diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig
index bad5f32e1f67..958c9b46ec78 100644
--- a/drivers/scsi/be2iscsi/Kconfig
+++ b/drivers/scsi/be2iscsi/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config BE2ISCSI
tristate "Emulex 10Gbps iSCSI - BladeEngine 2"
depends on PCI && SCSI && NET
diff --git a/drivers/scsi/be2iscsi/Makefile b/drivers/scsi/be2iscsi/Makefile
index d0488eaafc25..910885343a75 100644
--- a/drivers/scsi/be2iscsi/Makefile
+++ b/drivers/scsi/be2iscsi/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile to build the iSCSI driver for Emulex OneConnect.
#
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index e035acf56652..4c58a02590c7 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -1,15 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2017 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation. The full GNU General
- * Public License is included in this distribution in the file called COPYING.
- *
* Contact Information:
* linux-drivers@broadcom.com
- *
*/
#ifndef BEISCSI_H
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index 0a6972ee94d7..69b1a80e3687 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2017 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation. The full GNU General
- * Public License is included in this distribution in the file called COPYING.
- *
* Contact Information:
* linux-drivers@broadcom.com
- *
*/
#include <scsi/iscsi_proto.h>
@@ -963,7 +958,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
* @ctrl: ptr to ctrl_info
* @cq: Completion Queue
* @dq: Default Queue
- * @lenght: ring size
+ * @length: ring size
* @entry_size: size of each entry in DEFQ
* @is_header: Header or Data DEFQ
* @ulp_num: Bind to which ULP
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index 6f05d1dfa10a..063dccc18f70 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -1,15 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2017 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation. The full GNU General
- * Public License is included in this distribution in the file called COPYING.
- *
* Contact Information:
* linux-drivers@broadcom.com
- *
*/
#ifndef BEISCSI_CMDS_H
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 96b96e2ab91a..2058d50d62e1 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* This file is part of the Emulex Linux Device Driver for Enterprise iSCSI
* Host Bus Adapters. Refer to the README file included with this package
@@ -6,13 +7,8 @@
* Copyright (c) 2018 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as published
- * by the Free Software Foundation.
- *
* Contact Information:
* linux-drivers@broadcom.com
- *
*/
#include <scsi/libiscsi.h>
@@ -679,6 +675,7 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
case ISCSI_PARAM_MAX_XMIT_DLENGTH:
if (conn->max_xmit_dlength > 65536)
conn->max_xmit_dlength = 65536;
+ /* fall through */
default:
return 0;
}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index f41dfda97e17..8c88657eed0d 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -1,15 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2017 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation. The full GNU General
- * Public License is included in this distribution in the file called COPYING.
- *
* Contact Information:
* linux-drivers@broadcom.com
- *
*/
#ifndef _BE_ISCSI_
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 76e49d902609..0760d0bd8a10 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -1532,6 +1532,7 @@ beiscsi_hdl_get_handle(struct beiscsi_conn *beiscsi_conn,
break;
case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
error = 1;
+ /* fall through */
case UNSOL_DATA_NOTIFY:
pasync_handle = pasync_ctx->async_entry[ci].data;
break;
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 42bb6bdb68bd..98977c0700f1 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -1,15 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2017 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation. The full GNU General
- * Public License is included in this distribution in the file called COPYING.
- *
* Contact Information:
* linux-drivers@broadcom.com
- *
*/
#ifndef _BEISCSI_MAIN_
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index 0b22c99a7a22..d10858828701 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -1,15 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2017 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation. The full GNU General
- * Public License is included in this distribution in the file called COPYING.
- *
* Contact Information:
* linux-drivers@broadcom.com
- *
*/
#ifndef _BEISCSI_MGMT_
diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h
index 0e119d838e1b..7bd2ba1ad4d1 100644
--- a/drivers/scsi/bfa/bfa.h
+++ b/drivers/scsi/bfa/bfa.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_H__
#define __BFA_H__
@@ -62,8 +54,7 @@ void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m);
((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \
writel((__bfa)->iocfc.req_cq_pi[__reqq], \
(__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq]); \
- mmiowb(); \
- } while (0)
+ } while (0)
#define bfa_rspq_pi(__bfa, __rspq) \
(*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva))
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index 10a63be92544..0f554ebb8f2c 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h
index 9685efc59b16..6b606bf589b4 100644
--- a/drivers/scsi/bfa/bfa_cs.h
+++ b/drivers/scsi/bfa/bfa_cs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h
index 5dc3782d615b..6abd9f42a3fc 100644
--- a/drivers/scsi/bfa/bfa_defs.h
+++ b/drivers/scsi/bfa/bfa_defs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_DEFS_H__
diff --git a/drivers/scsi/bfa/bfa_defs_fcs.h b/drivers/scsi/bfa/bfa_defs_fcs.h
index 5815a904574d..5e36620425ac 100644
--- a/drivers/scsi/bfa/bfa_defs_fcs.h
+++ b/drivers/scsi/bfa/bfa_defs_fcs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_DEFS_FCS_H__
diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h
index c19c26e0e405..8439951d95ac 100644
--- a/drivers/scsi/bfa/bfa_defs_svc.h
+++ b/drivers/scsi/bfa/bfa_defs_svc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_DEFS_SVC_H__
diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h
index 18b7304d6b0b..b00fb2409c50 100644
--- a/drivers/scsi/bfa/bfa_fc.h
+++ b/drivers/scsi/bfa/bfa_fc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_FC_H__
diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c
index 2de5d514e99c..df18d9d2af53 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.c
+++ b/drivers/scsi/bfa/bfa_fcbuild.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
/*
* fcbuild.c - FC link service frame building and parsing routines
diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h
index ac08d0b5b89a..49e0ee4a7334 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.h
+++ b/drivers/scsi/bfa/bfa_fcbuild.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
/*
* fcbuild.h - FC link service frame building and parsing routines
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index 2c85f5b1f9c1..284baa3b0c8e 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
@@ -2586,6 +2578,7 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
case FCP_IODIR_RW:
bfa_stats(itnim, input_reqs);
bfa_stats(itnim, output_reqs);
+ /* fall through */
default:
bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa));
}
@@ -2820,6 +2813,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
case BFI_IOIM_STS_TIMEDOUT:
bfa_stats(ioim->itnim, iocomp_timedout);
+ /* fall through */
case BFI_IOIM_STS_ABORTED:
rsp->io_status = BFI_IOIM_STS_ABORTED;
bfa_stats(ioim->itnim, iocomp_aborted);
@@ -3215,9 +3209,7 @@ bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
switch (event) {
case BFA_TSKIM_SM_DONE:
bfa_reqq_wcancel(&tskim->reqq_wait);
- /*
- * Fall through !!!
- */
+ /* fall through */
case BFA_TSKIM_SM_QRESUME:
bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
bfa_tskim_send_abort(tskim);
diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h
index ec8f863540ae..8bf09433549b 100644
--- a/drivers/scsi/bfa/bfa_fcpim.h
+++ b/drivers/scsi/bfa/bfa_fcpim.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_FCPIM_H__
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
index 932feb0ed4da..d2d396ca0e9a 100644
--- a/drivers/scsi/bfa/bfa_fcs.c
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h
index e60f72b766ea..3e117fed95c9 100644
--- a/drivers/scsi/bfa/bfa_fcs.h
+++ b/drivers/scsi/bfa/bfa_fcs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_FCS_H__
diff --git a/drivers/scsi/bfa/bfa_fcs_fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c
index 2e3b19e7e079..c7de62baeec9 100644
--- a/drivers/scsi/bfa/bfa_fcs_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index 646f09f66443..7c3eadc58b98 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c
index 1e400f2aaece..82801b366500 100644
--- a/drivers/scsi/bfa/bfa_fcs_rport.c
+++ b/drivers/scsi/bfa/bfa_fcs_rport.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
index c4a0c0eb88a5..6cc2f7290d7e 100644
--- a/drivers/scsi/bfa/bfa_hw_cb.c
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
@@ -61,7 +53,6 @@ bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq, u32 ci)
bfa_rspq_ci(bfa, rspq) = ci;
writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
- mmiowb();
}
void
@@ -72,7 +63,6 @@ bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
bfa_rspq_ci(bfa, rspq) = ci;
writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
- mmiowb();
}
void
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
index b0ff378dece2..4b1c0a568a22 100644
--- a/drivers/scsi/bfa/bfa_hw_ct.c
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
@@ -81,7 +73,6 @@ bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
bfa_rspq_ci(bfa, rspq) = ci;
writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
- mmiowb();
}
/*
@@ -94,7 +85,6 @@ bfa_hwct2_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
{
bfa_rspq_ci(bfa, rspq) = ci;
writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
- mmiowb();
}
void
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 79a55c3615be..93471d7c61d0 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index 0f9fab770339..933a1c3890ff 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_IOC_H__
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
index f1b80da298c8..2fc6215c2b2b 100644
--- a/drivers/scsi/bfa/bfa_ioc_cb.c
+++ b/drivers/scsi/bfa/bfa_ioc_cb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
index 651a8fb93037..18b58b2f304f 100644
--- a/drivers/scsi/bfa/bfa_ioc_ct.c
+++ b/drivers/scsi/bfa/bfa_ioc_ct.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h
index 1c2ab395e616..578e7678b056 100644
--- a/drivers/scsi/bfa/bfa_modules.h
+++ b/drivers/scsi/bfa/bfa_modules.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfa_plog.h b/drivers/scsi/bfa/bfa_plog.h
index da570c0b8275..0ed67339ed90 100644
--- a/drivers/scsi/bfa/bfa_plog.h
+++ b/drivers/scsi/bfa/bfa_plog.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_PORTLOG_H__
#define __BFA_PORTLOG_H__
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
index 079bc77f4102..4511ec865f06 100644
--- a/drivers/scsi/bfa/bfa_port.c
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
diff --git a/drivers/scsi/bfa/bfa_port.h b/drivers/scsi/bfa/bfa_port.h
index 0c3b200243ca..7e569d4b5214 100644
--- a/drivers/scsi/bfa/bfa_port.h
+++ b/drivers/scsi/bfa/bfa_port.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_PORT_H__
diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c
index 6fc34fb20f00..6d2131441f0a 100644
--- a/drivers/scsi/bfa/bfa_svc.c
+++ b/drivers/scsi/bfa/bfa_svc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include "bfad_drv.h"
diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h
index 7e8fb6231d49..9c83109574e9 100644
--- a/drivers/scsi/bfa/bfa_svc.h
+++ b/drivers/scsi/bfa/bfa_svc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFA_SVC_H__
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 88880a66a189..2f9213b257a4 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index 26b0fa4e90b5..29ab81df75c0 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c
index d8e6d7480f35..a76c968dbac5 100644
--- a/drivers/scsi/bfa/bfad_bsg.c
+++ b/drivers/scsi/bfa/bfad_bsg.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include <linux/uaccess.h>
diff --git a/drivers/scsi/bfa/bfad_bsg.h b/drivers/scsi/bfa/bfad_bsg.h
index 917e140dfbcc..e525339df4ae 100644
--- a/drivers/scsi/bfa/bfad_bsg.h
+++ b/drivers/scsi/bfa/bfad_bsg.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef BFAD_BSG_H
#define BFAD_BSG_H
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index bfcd87c0dc74..fd1b378a263a 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#include <linux/debugfs.h>
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 4fe980a6441f..eaee7c8bc2d2 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 394930cbaa13..b2014cb96f58 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
index bd4ac187fd8e..f16d4b219e44 100644
--- a/drivers/scsi/bfa/bfad_im.h
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFAD_IM_H__
diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h
index 5f698d038b21..41e6b4dac056 100644
--- a/drivers/scsi/bfa/bfi.h
+++ b/drivers/scsi/bfa/bfi.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFI_H__
diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h
index ccbd9e31a5de..b9dc0b9bb814 100644
--- a/drivers/scsi/bfa/bfi_ms.h
+++ b/drivers/scsi/bfa/bfi_ms.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*/
#ifndef __BFI_MS_H__
diff --git a/drivers/scsi/bfa/bfi_reg.h b/drivers/scsi/bfa/bfi_reg.h
index fd5b87616e8b..0803b710a26e 100644
--- a/drivers/scsi/bfa/bfi_reg.h
+++ b/drivers/scsi/bfa/bfi_reg.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
* Copyright (c) 2014- QLogic Corporation.
@@ -5,15 +6,6 @@
* www.qlogic.com
*
* 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
- * 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.
*/
/*
diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig
index d401a096dfc7..e0ccb48ec961 100644
--- a/drivers/scsi/bnx2fc/Kconfig
+++ b/drivers/scsi/bnx2fc/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_BNX2X_FCOE
tristate "QLogic FCoE offload support"
depends on PCI
diff --git a/drivers/scsi/bnx2fc/Makefile b/drivers/scsi/bnx2fc/Makefile
index 141149e8cdad..1d72e279a97d 100644
--- a/drivers/scsi/bnx2fc/Makefile
+++ b/drivers/scsi/bnx2fc/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SCSI_BNX2X_FCOE) += bnx2fc.o
bnx2fc-y := bnx2fc_els.o bnx2fc_fcoe.o bnx2fc_hwi.o bnx2fc_io.o bnx2fc_tgt.o \
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 901a31632493..3b84db8d13a9 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -66,7 +66,7 @@
#include "bnx2fc_constants.h"
#define BNX2FC_NAME "bnx2fc"
-#define BNX2FC_VERSION "2.11.8"
+#define BNX2FC_VERSION "2.12.10"
#define PFX "bnx2fc: "
@@ -75,8 +75,9 @@
#define BNX2X_DOORBELL_PCI_BAR 2
#define BNX2FC_MAX_BD_LEN 0xffff
-#define BNX2FC_BD_SPLIT_SZ 0x8000
-#define BNX2FC_MAX_BDS_PER_CMD 256
+#define BNX2FC_BD_SPLIT_SZ 0xffff
+#define BNX2FC_MAX_BDS_PER_CMD 255
+#define BNX2FC_FW_MAX_BDS_PER_CMD 255
#define BNX2FC_SQ_WQES_MAX 256
@@ -433,8 +434,10 @@ struct bnx2fc_cmd {
void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg);
struct bnx2fc_els_cb_arg *cb_arg;
struct delayed_work timeout_work; /* timer for ULP timeouts */
- struct completion tm_done;
- int wait_for_comp;
+ struct completion abts_done;
+ struct completion cleanup_done;
+ int wait_for_abts_comp;
+ int wait_for_cleanup_comp;
u16 xid;
struct fcoe_err_report_entry err_entry;
struct fcoe_task_ctx_entry *task;
@@ -455,6 +458,7 @@ struct bnx2fc_cmd {
#define BNX2FC_FLAG_ELS_TIMEOUT 0xb
#define BNX2FC_FLAG_CMD_LOST 0xc
#define BNX2FC_FLAG_SRR_SENT 0xd
+#define BNX2FC_FLAG_ISSUE_CLEANUP_REQ 0xe
u8 rec_retry;
u8 srr_retry;
u32 srr_offset;
diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c
index 76e65a32f38c..754f2e82d955 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_els.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_els.c
@@ -610,7 +610,6 @@ int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req)
rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec),
bnx2fc_rec_compl, cb_arg,
r_a_tov);
-rec_err:
if (rc) {
BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n");
spin_lock_bh(&tgt->tgt_lock);
@@ -618,6 +617,7 @@ rec_err:
spin_unlock_bh(&tgt->tgt_lock);
kfree(cb_arg);
}
+rec_err:
return rc;
}
@@ -654,7 +654,6 @@ int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl)
rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr),
bnx2fc_srr_compl, cb_arg,
r_a_tov);
-srr_err:
if (rc) {
BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n");
spin_lock_bh(&tgt->tgt_lock);
@@ -664,6 +663,7 @@ srr_err:
} else
set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags);
+srr_err:
return rc;
}
@@ -854,33 +854,57 @@ void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req,
kref_put(&els_req->refcount, bnx2fc_cmd_release);
}
+#define BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC 1
+#define BNX2FC_FCOE_MAC_METHOD_FCF_MAP 2
+#define BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC 3
static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
void *arg)
{
struct fcoe_ctlr *fip = arg;
struct fc_exch *exch = fc_seq_exch(seq);
struct fc_lport *lport = exch->lp;
- u8 *mac;
- u8 op;
+
+ struct fc_frame_header *fh;
+ u8 *granted_mac;
+ u8 fcoe_mac[6];
+ u8 fc_map[3];
+ int method;
if (IS_ERR(fp))
goto done;
- mac = fr_cb(fp)->granted_mac;
- if (is_zero_ether_addr(mac)) {
- op = fc_frame_payload_op(fp);
- if (lport->vport) {
- if (op == ELS_LS_RJT) {
- printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n");
- fc_vport_terminate(lport->vport);
- fc_frame_free(fp);
- return;
- }
- }
- fcoe_ctlr_recv_flogi(fip, lport, fp);
+ fh = fc_frame_header_get(fp);
+ granted_mac = fr_cb(fp)->granted_mac;
+
+ /*
+ * We set the source MAC for FCoE traffic based on the Granted MAC
+ * address from the switch.
+ *
+ * If granted_mac is non-zero, we use that.
+ * If the granted_mac is zeroed out, create the FCoE MAC based on
+ * the sel_fcf->fc_map and the d_id fo the FLOGI frame.
+ * If sel_fcf->fc_map is 0, then we use the default FCF-MAC plus the
+ * d_id of the FLOGI frame.
+ */
+ if (!is_zero_ether_addr(granted_mac)) {
+ ether_addr_copy(fcoe_mac, granted_mac);
+ method = BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC;
+ } else if (fip->sel_fcf && fip->sel_fcf->fc_map != 0) {
+ hton24(fc_map, fip->sel_fcf->fc_map);
+ fcoe_mac[0] = fc_map[0];
+ fcoe_mac[1] = fc_map[1];
+ fcoe_mac[2] = fc_map[2];
+ fcoe_mac[3] = fh->fh_d_id[0];
+ fcoe_mac[4] = fh->fh_d_id[1];
+ fcoe_mac[5] = fh->fh_d_id[2];
+ method = BNX2FC_FCOE_MAC_METHOD_FCF_MAP;
+ } else {
+ fc_fcoe_set_mac(fcoe_mac, fh->fh_d_id);
+ method = BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC;
}
- if (!is_zero_ether_addr(mac))
- fip->update_mac(lport, mac);
+
+ BNX2FC_HBA_DBG(lport, "fcoe_mac=%pM method=%d\n", fcoe_mac, method);
+ fip->update_mac(lport, fcoe_mac);
done:
fc_lport_flogi_resp(seq, fp, lport);
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index a75e74ad1698..7796799bf04a 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -2971,7 +2971,8 @@ static struct scsi_host_template bnx2fc_shost_template = {
.this_id = -1,
.cmd_per_lun = 3,
.sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
- .max_sectors = 1024,
+ .dma_boundary = 0x7fff,
+ .max_sectors = 0x3fbf,
.track_queue_depth = 1,
.slave_configure = bnx2fc_slave_configure,
.shost_attrs = bnx2fc_host_attrs,
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 039328d9ef13..747f019fb393 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -830,7 +830,7 @@ ret_err_rqe:
((u64)err_entry->data.err_warn_bitmap_hi << 32) |
(u64)err_entry->data.err_warn_bitmap_lo;
for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) {
- if (err_warn_bit_map & (u64) (1 << i)) {
+ if (err_warn_bit_map & ((u64)1 << i)) {
err_warn = i;
break;
}
@@ -991,7 +991,6 @@ void bnx2fc_arm_cq(struct bnx2fc_rport *tgt)
FCOE_CQE_TOGGLE_BIT_SHIFT);
msg = *((u32 *)rx_db);
writel(cpu_to_le32(msg), tgt->ctx_base);
- mmiowb();
}
@@ -1409,7 +1408,6 @@ void bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt)
(tgt->sq_curr_toggle_bit << 15);
msg = *((u32 *)sq_db);
writel(cpu_to_le32(msg), tgt->ctx_base);
- mmiowb();
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index bc9f2a2365f4..9e50e5b53763 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -70,7 +70,7 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
&io_req->req_flags)) {
/* Handle eh_abort timeout */
BNX2FC_IO_DBG(io_req, "eh_abort timed out\n");
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
} else if (test_bit(BNX2FC_FLAG_ISSUE_ABTS,
&io_req->req_flags)) {
/* Handle internally generated ABTS timeout */
@@ -775,31 +775,32 @@ retry_tmf:
io_req->on_tmf_queue = 1;
list_add_tail(&io_req->link, &tgt->active_tm_queue);
- init_completion(&io_req->tm_done);
- io_req->wait_for_comp = 1;
+ init_completion(&io_req->abts_done);
+ io_req->wait_for_abts_comp = 1;
/* Ring doorbell */
bnx2fc_ring_doorbell(tgt);
spin_unlock_bh(&tgt->tgt_lock);
- rc = wait_for_completion_timeout(&io_req->tm_done,
+ rc = wait_for_completion_timeout(&io_req->abts_done,
interface->tm_timeout * HZ);
spin_lock_bh(&tgt->tgt_lock);
- io_req->wait_for_comp = 0;
+ io_req->wait_for_abts_comp = 0;
if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) {
set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags);
if (io_req->on_tmf_queue) {
list_del_init(&io_req->link);
io_req->on_tmf_queue = 0;
}
- io_req->wait_for_comp = 1;
+ io_req->wait_for_cleanup_comp = 1;
+ init_completion(&io_req->cleanup_done);
bnx2fc_initiate_cleanup(io_req);
spin_unlock_bh(&tgt->tgt_lock);
- rc = wait_for_completion_timeout(&io_req->tm_done,
+ rc = wait_for_completion_timeout(&io_req->cleanup_done,
BNX2FC_FW_TIMEOUT);
spin_lock_bh(&tgt->tgt_lock);
- io_req->wait_for_comp = 0;
+ io_req->wait_for_cleanup_comp = 0;
if (!rc)
kref_put(&io_req->refcount, bnx2fc_cmd_release);
}
@@ -1047,6 +1048,9 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
/* Obtain free SQ entry */
bnx2fc_add_2_sq(tgt, xid);
+ /* Set flag that cleanup request is pending with the firmware */
+ set_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags);
+
/* Ring doorbell */
bnx2fc_ring_doorbell(tgt);
@@ -1083,10 +1087,10 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
{
struct bnx2fc_rport *tgt = io_req->tgt;
- int rc = SUCCESS;
unsigned int time_left;
- io_req->wait_for_comp = 1;
+ init_completion(&io_req->cleanup_done);
+ io_req->wait_for_cleanup_comp = 1;
bnx2fc_initiate_cleanup(io_req);
spin_unlock_bh(&tgt->tgt_lock);
@@ -1095,22 +1099,22 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
* Can't wait forever on cleanup response lest we let the SCSI error
* handler wait forever
*/
- time_left = wait_for_completion_timeout(&io_req->tm_done,
+ time_left = wait_for_completion_timeout(&io_req->cleanup_done,
BNX2FC_FW_TIMEOUT);
- io_req->wait_for_comp = 0;
- if (!time_left)
+ if (!time_left) {
BNX2FC_IO_DBG(io_req, "%s(): Wait for cleanup timed out.\n",
__func__);
- /*
- * Release reference held by SCSI command the cleanup completion
- * hits the BNX2FC_CLEANUP case in bnx2fc_process_cq_compl() and
- * thus the SCSI command is not returnedi by bnx2fc_scsi_done().
- */
- kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ /*
+ * Put the extra reference to the SCSI command since it would
+ * not have been returned in this case.
+ */
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+ }
spin_lock_bh(&tgt->tgt_lock);
- return rc;
+ io_req->wait_for_cleanup_comp = 0;
+ return SUCCESS;
}
/**
@@ -1198,7 +1202,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
/* Move IO req to retire queue */
list_add_tail(&io_req->link, &tgt->io_retire_queue);
- init_completion(&io_req->tm_done);
+ init_completion(&io_req->abts_done);
+ init_completion(&io_req->cleanup_done);
if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
@@ -1226,26 +1231,28 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
- io_req->wait_for_comp = 1;
+ io_req->wait_for_abts_comp = 1;
rc = bnx2fc_initiate_abts(io_req);
if (rc == FAILED) {
+ io_req->wait_for_cleanup_comp = 1;
bnx2fc_initiate_cleanup(io_req);
spin_unlock_bh(&tgt->tgt_lock);
- wait_for_completion(&io_req->tm_done);
+ wait_for_completion(&io_req->cleanup_done);
spin_lock_bh(&tgt->tgt_lock);
- io_req->wait_for_comp = 0;
+ io_req->wait_for_cleanup_comp = 0;
goto done;
}
spin_unlock_bh(&tgt->tgt_lock);
/* Wait 2 * RA_TOV + 1 to be sure timeout function hasn't fired */
- time_left = wait_for_completion_timeout(&io_req->tm_done,
- (2 * rp->r_a_tov + 1) * HZ);
+ time_left = wait_for_completion_timeout(&io_req->abts_done,
+ (2 * rp->r_a_tov + 1) * HZ);
if (time_left)
- BNX2FC_IO_DBG(io_req, "Timed out in eh_abort waiting for tm_done");
+ BNX2FC_IO_DBG(io_req,
+ "Timed out in eh_abort waiting for abts_done");
spin_lock_bh(&tgt->tgt_lock);
- io_req->wait_for_comp = 0;
+ io_req->wait_for_abts_comp = 0;
if (test_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags)) {
BNX2FC_IO_DBG(io_req, "IO completed in a different context\n");
rc = SUCCESS;
@@ -1320,10 +1327,29 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl "
"refcnt = %d, cmd_type = %d\n",
kref_read(&io_req->refcount), io_req->cmd_type);
+ /*
+ * Test whether there is a cleanup request pending. If not just
+ * exit.
+ */
+ if (!test_and_clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ,
+ &io_req->req_flags))
+ return;
+ /*
+ * If we receive a cleanup completion for this request then the
+ * firmware will not give us an abort completion for this request
+ * so clear any ABTS pending flags.
+ */
+ if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags) &&
+ !test_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) {
+ set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags);
+ if (io_req->wait_for_abts_comp)
+ complete(&io_req->abts_done);
+ }
+
bnx2fc_scsi_done(io_req, DID_ERROR);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
- if (io_req->wait_for_comp)
- complete(&io_req->tm_done);
+ if (io_req->wait_for_cleanup_comp)
+ complete(&io_req->cleanup_done);
}
void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
@@ -1347,6 +1373,16 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
return;
}
+ /*
+ * If we receive an ABTS completion here then we will not receive
+ * a cleanup completion so clear any cleanup pending flags.
+ */
+ if (test_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags)) {
+ clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags);
+ if (io_req->wait_for_cleanup_comp)
+ complete(&io_req->cleanup_done);
+ }
+
/* Do not issue RRQ as this IO is already cleanedup */
if (test_and_set_bit(BNX2FC_FLAG_IO_CLEANUP,
&io_req->req_flags))
@@ -1391,10 +1427,10 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req,
bnx2fc_cmd_timer_set(io_req, r_a_tov);
io_compl:
- if (io_req->wait_for_comp) {
+ if (io_req->wait_for_abts_comp) {
if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
&io_req->req_flags))
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
} else {
/*
* We end up here when ABTS is issued as
@@ -1578,9 +1614,9 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
sc_cmd->scsi_done(sc_cmd);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
- if (io_req->wait_for_comp) {
+ if (io_req->wait_for_abts_comp) {
BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n");
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
}
}
@@ -1624,6 +1660,7 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req)
u64 addr;
int i;
+ WARN_ON(scsi_sg_count(sc) > BNX2FC_MAX_BDS_PER_CMD);
/*
* Use dma_map_sg directly to ensure we're using the correct
* dev struct off of pcidev.
@@ -1671,6 +1708,16 @@ static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req)
}
io_req->bd_tbl->bd_valid = bd_count;
+ /*
+ * Return the command to ML if BD count exceeds the max number
+ * that can be handled by FW.
+ */
+ if (bd_count > BNX2FC_FW_MAX_BDS_PER_CMD) {
+ pr_err("bd_count = %d exceeded FW supported max BD(255), task_id = 0x%x\n",
+ bd_count, io_req->xid);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -1927,10 +1974,10 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
* between command abort and (late) completion.
*/
BNX2FC_IO_DBG(io_req, "xid not on active_cmd_queue\n");
- if (io_req->wait_for_comp)
+ if (io_req->wait_for_abts_comp)
if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
&io_req->req_flags))
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
}
bnx2fc_unmap_sg_list(io_req);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index d735e87e416a..50384b4a817c 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -187,7 +187,7 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
/* Handle eh_abort timeout */
BNX2FC_IO_DBG(io_req, "eh_abort for IO "
"cleaned up\n");
- complete(&io_req->tm_done);
+ complete(&io_req->abts_done);
}
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
@@ -210,8 +210,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
list_del_init(&io_req->link);
io_req->on_tmf_queue = 0;
BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n");
- if (io_req->wait_for_comp)
- complete(&io_req->tm_done);
+ if (io_req->wait_for_abts_comp)
+ complete(&io_req->abts_done);
}
list_for_each_entry_safe(io_req, tmp, &tgt->els_queue, link) {
@@ -251,8 +251,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
/* Handle eh_abort timeout */
BNX2FC_IO_DBG(io_req, "eh_abort for IO "
"in retire_q\n");
- if (io_req->wait_for_comp)
- complete(&io_req->tm_done);
+ if (io_req->wait_for_abts_comp)
+ complete(&io_req->abts_done);
}
kref_put(&io_req->refcount, bnx2fc_cmd_release);
}
diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig
index ba30ff86d581..702dc82c9501 100644
--- a/drivers/scsi/bnx2i/Kconfig
+++ b/drivers/scsi/bnx2i/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_BNX2_ISCSI
tristate "QLogic NetXtreme II iSCSI support"
depends on NET
diff --git a/drivers/scsi/bnx2i/Makefile b/drivers/scsi/bnx2i/Makefile
index b5802bd2e76a..25378671bb1e 100644
--- a/drivers/scsi/bnx2i/Makefile
+++ b/drivers/scsi/bnx2i/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
bnx2i-y := bnx2i_init.o bnx2i_hwi.o bnx2i_iscsi.o bnx2i_sysfs.o
obj-$(CONFIG_SCSI_BNX2_ISCSI) += bnx2i.o
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index fae6f71e677d..12666313b937 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -253,7 +253,6 @@ void bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count)
writew(ep->qp.rq_prod_idx,
ep->qp.ctx_base + CNIC_RECV_DOORBELL);
}
- mmiowb();
}
@@ -279,8 +278,6 @@ static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count)
bnx2i_ring_577xx_doorbell(bnx2i_conn);
} else
writew(count, ep->qp.ctx_base + CNIC_SEND_DOORBELL);
-
- mmiowb(); /* flush posted PCI writes */
}
diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c
index 0f846ae2f918..8d72b25535c5 100644
--- a/drivers/scsi/bvme6000_scsi.c
+++ b/drivers/scsi/bvme6000_scsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
*
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 1c5051b1c125..5f8153c37f77 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCSI Media Changer device driver for Linux 2.6
*
diff --git a/drivers/scsi/csiostor/Kconfig b/drivers/scsi/csiostor/Kconfig
index 7c7e5085968b..c6c03f9e3798 100644
--- a/drivers/scsi/csiostor/Kconfig
+++ b/drivers/scsi/csiostor/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_CHELSIO_FCOE
tristate "Chelsio Communications FCoE support"
depends on PCI && SCSI
diff --git a/drivers/scsi/csiostor/csio_isr.c b/drivers/scsi/csiostor/csio_isr.c
index 7c8814715711..b2540402fafc 100644
--- a/drivers/scsi/csiostor/csio_isr.c
+++ b/drivers/scsi/csiostor/csio_isr.c
@@ -474,13 +474,39 @@ csio_reduce_sqsets(struct csio_hw *hw, int cnt)
csio_dbg(hw, "Reduced sqsets to %d\n", hw->num_sqsets);
}
+static void csio_calc_sets(struct irq_affinity *affd, unsigned int nvecs)
+{
+ struct csio_hw *hw = affd->priv;
+ u8 i;
+
+ if (!nvecs)
+ return;
+
+ if (nvecs < hw->num_pports) {
+ affd->nr_sets = 1;
+ affd->set_size[0] = nvecs;
+ return;
+ }
+
+ affd->nr_sets = hw->num_pports;
+ for (i = 0; i < hw->num_pports; i++)
+ affd->set_size[i] = nvecs / hw->num_pports;
+}
+
static int
csio_enable_msix(struct csio_hw *hw)
{
int i, j, k, n, min, cnt;
int extra = CSIO_EXTRA_VECS;
struct csio_scsi_cpu_info *info;
- struct irq_affinity desc = { .pre_vectors = 2 };
+ struct irq_affinity desc = {
+ .pre_vectors = CSIO_EXTRA_VECS,
+ .calc_sets = csio_calc_sets,
+ .priv = hw,
+ };
+
+ if (hw->num_pports > IRQ_AFFINITY_MAX_SETS)
+ return -ENOSPC;
min = hw->num_pports + extra;
cnt = hw->num_sqsets + extra;
diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c
index 66bbd21819ae..03bd896cdbb9 100644
--- a/drivers/scsi/csiostor/csio_wr.c
+++ b/drivers/scsi/csiostor/csio_wr.c
@@ -808,6 +808,7 @@ csio_wr_destroy_queues(struct csio_hw *hw, bool cmd)
csio_q_eqid(hw, i) = CSIO_MAX_QID;
}
+ /* fall through */
case CSIO_INGRESS:
if (csio_q_iqid(hw, i) != CSIO_MAX_QID) {
csio_wr_cleanup_iq_ftr(hw, i);
diff --git a/drivers/scsi/cxgbi/Kconfig b/drivers/scsi/cxgbi/Kconfig
index 17eb5d522f42..75f9428a8a14 100644
--- a/drivers/scsi/cxgbi/Kconfig
+++ b/drivers/scsi/cxgbi/Kconfig
@@ -1,2 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
source "drivers/scsi/cxgbi/cxgb3i/Kconfig"
source "drivers/scsi/cxgbi/cxgb4i/Kconfig"
diff --git a/drivers/scsi/cxgbi/Makefile b/drivers/scsi/cxgbi/Makefile
index f78c9cc460a2..abfd38a26fec 100644
--- a/drivers/scsi/cxgbi/Makefile
+++ b/drivers/scsi/cxgbi/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
ccflags-y += -I $(srctree)/drivers/net/ethernet/chelsio/libcxgb
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libcxgbi.o cxgb3i/
diff --git a/drivers/scsi/cxgbi/cxgb3i/Kbuild b/drivers/scsi/cxgbi/cxgb3i/Kbuild
index 663c52e05d81..8d8a43f5ea80 100644
--- a/drivers/scsi/cxgbi/cxgb3i/Kbuild
+++ b/drivers/scsi/cxgbi/cxgb3i/Kbuild
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3
ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/libcxgb
diff --git a/drivers/scsi/cxgbi/cxgb3i/Kconfig b/drivers/scsi/cxgbi/cxgb3i/Kconfig
index f68c871b16ca..3e4b644249cb 100644
--- a/drivers/scsi/cxgbi/cxgb3i/Kconfig
+++ b/drivers/scsi/cxgbi/cxgb3i/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_CXGB3_ISCSI
tristate "Chelsio T3 iSCSI support"
depends on PCI && INET && (IPV6 || IPV6=n)
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index 75e1273a44b3..524cdbcd29aa 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -979,14 +979,17 @@ static int init_act_open(struct cxgbi_sock *csk)
csk->atid = cxgb3_alloc_atid(t3dev, &t3_client, csk);
if (csk->atid < 0) {
pr_err("NO atid available.\n");
- goto rel_resource;
+ return -EINVAL;
}
cxgbi_sock_set_flag(csk, CTPF_HAS_ATID);
cxgbi_sock_get(csk);
skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_KERNEL);
- if (!skb)
- goto rel_resource;
+ if (!skb) {
+ cxgb3_free_atid(t3dev, csk->atid);
+ cxgbi_sock_put(csk);
+ return -ENOMEM;
+ }
skb->sk = (struct sock *)csk;
set_arp_failure_handler(skb, act_open_arp_failure);
csk->snd_win = cxgb3i_snd_win;
@@ -1007,11 +1010,6 @@ static int init_act_open(struct cxgbi_sock *csk)
cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN);
send_act_open_req(csk, skb, csk->l2t);
return 0;
-
-rel_resource:
- if (skb)
- __kfree_skb(skb);
- return -EINVAL;
}
cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS] = {
@@ -1245,8 +1243,12 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev)
tformat.pgsz_order[i] = uinfo.pgsz_factor[i];
cxgbi_tagmask_check(tagmask, &tformat);
- cxgbi_ddp_ppm_setup(&tdev->ulp_iscsi, cdev, &tformat, ppmax,
- uinfo.llimit, uinfo.llimit, 0);
+ err = cxgbi_ddp_ppm_setup(&tdev->ulp_iscsi, cdev, &tformat,
+ (uinfo.ulimit - uinfo.llimit + 1),
+ uinfo.llimit, uinfo.llimit, 0, 0, 0);
+ if (err)
+ return err;
+
if (!(cdev->flags & CXGBI_FLAG_DDP_OFF)) {
uinfo.tagmask = tagmask;
uinfo.ulimit = uinfo.llimit + (ppmax << PPOD_SIZE_SHIFT);
@@ -1320,7 +1322,7 @@ static void cxgb3i_dev_open(struct t3cdev *t3dev)
err = cxgb3i_ddp_init(cdev);
if (err) {
- pr_info("0x%p ddp init failed\n", cdev);
+ pr_info("0x%p ddp init failed %d\n", cdev, err);
goto err_out;
}
diff --git a/drivers/scsi/cxgbi/cxgb4i/Kbuild b/drivers/scsi/cxgbi/cxgb4i/Kbuild
index 38e03c280417..fd3e0c964de6 100644
--- a/drivers/scsi/cxgbi/cxgb4i/Kbuild
+++ b/drivers/scsi/cxgbi/cxgb4i/Kbuild
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/libcxgb
diff --git a/drivers/scsi/cxgbi/cxgb4i/Kconfig b/drivers/scsi/cxgbi/cxgb4i/Kconfig
index f36b76e8e12c..d1f1baba3285 100644
--- a/drivers/scsi/cxgbi/cxgb4i/Kconfig
+++ b/drivers/scsi/cxgbi/cxgb4i/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_CXGB4_ISCSI
tristate "Chelsio T4 iSCSI support"
depends on PCI && INET && (IPV6 || IPV6=n)
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index d44914e5e415..da50e87921bc 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -60,7 +60,7 @@ MODULE_PARM_DESC(dbg_level, "Debug flag (default=0)");
#define CXGB4I_DEFAULT_10G_RCV_WIN (256 * 1024)
static int cxgb4i_rcv_win = -1;
module_param(cxgb4i_rcv_win, int, 0644);
-MODULE_PARM_DESC(cxgb4i_rcv_win, "TCP reveive window in bytes");
+MODULE_PARM_DESC(cxgb4i_rcv_win, "TCP receive window in bytes");
#define CXGB4I_DEFAULT_10G_SND_WIN (128 * 1024)
static int cxgb4i_snd_win = -1;
@@ -1665,8 +1665,12 @@ static u8 get_iscsi_dcb_priority(struct net_device *ndev)
return 0;
if (caps & DCB_CAP_DCBX_VER_IEEE) {
- iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
+ iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM;
rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
+ if (!rv) {
+ iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY;
+ rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app);
+ }
} else if (caps & DCB_CAP_DCBX_VER_CEE) {
iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM;
rv = dcb_getapp(ndev, &iscsi_dcb_app);
@@ -2070,7 +2074,7 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev)
struct net_device *ndev = cdev->ports[0];
struct cxgbi_tag_format tformat;
unsigned int ppmax;
- int i;
+ int i, err;
if (!lldi->vr->iscsi.size) {
pr_warn("%s, iscsi NOT enabled, check config!\n", ndev->name);
@@ -2086,8 +2090,17 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev)
& 0xF;
cxgbi_tagmask_check(lldi->iscsi_tagmask, &tformat);
- cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, ppmax,
- lldi->iscsi_llimit, lldi->vr->iscsi.start, 2);
+ pr_info("iscsi_edram.start 0x%x iscsi_edram.size 0x%x",
+ lldi->vr->ppod_edram.start, lldi->vr->ppod_edram.size);
+
+ err = cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat,
+ lldi->vr->iscsi.size, lldi->iscsi_llimit,
+ lldi->vr->iscsi.start, 2,
+ lldi->vr->ppod_edram.start,
+ lldi->vr->ppod_edram.size);
+
+ if (err < 0)
+ return err;
cdev->csk_ddp_setup_digest = ddp_setup_conn_digest;
cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx;
@@ -2141,7 +2154,7 @@ static void *t4_uld_add(const struct cxgb4_lld_info *lldi)
rc = cxgb4i_ddp_init(cdev);
if (rc) {
- pr_info("t4 0x%p ddp init failed.\n", cdev);
+ pr_info("t4 0x%p ddp init failed %d.\n", cdev, rc);
goto err_out;
}
rc = cxgb4i_ofld_init(cdev);
@@ -2251,7 +2264,8 @@ cxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val,
u8 priority;
if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) {
- if (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)
+ if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) &&
+ (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY))
return NOTIFY_DONE;
priority = iscsi_app->app.priority;
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 006372b3fba2..3e17af8aedeb 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -282,7 +282,6 @@ struct cxgbi_device *cxgbi_device_find_by_netdev_rcu(struct net_device *ndev,
}
EXPORT_SYMBOL_GPL(cxgbi_device_find_by_netdev_rcu);
-#if IS_ENABLED(CONFIG_IPV6)
static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev,
int *port)
{
@@ -315,7 +314,6 @@ static struct cxgbi_device *cxgbi_device_find_by_mac(struct net_device *ndev,
ndev, ndev->name);
return NULL;
}
-#endif
void cxgbi_hbas_remove(struct cxgbi_device *cdev)
{
@@ -641,6 +639,10 @@ cxgbi_check_route(struct sockaddr *dst_addr, int ifindex)
if (ndev->flags & IFF_LOOPBACK) {
ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr);
+ if (!ndev) {
+ err = -ENETUNREACH;
+ goto rel_neigh;
+ }
mtu = ndev->mtu;
pr_info("rt dev %s, loopback -> %s, mtu %u.\n",
n->dev->name, ndev->name, mtu);
@@ -653,6 +655,8 @@ cxgbi_check_route(struct sockaddr *dst_addr, int ifindex)
}
cdev = cxgbi_device_find_by_netdev(ndev, &port);
+ if (!cdev)
+ cdev = cxgbi_device_find_by_mac(ndev, &port);
if (!cdev) {
pr_info("dst %pI4, %s, NOT cxgbi device.\n",
&daddr->sin_addr.s_addr, ndev->name);
@@ -1281,14 +1285,15 @@ EXPORT_SYMBOL_GPL(cxgbi_ddp_set_one_ppod);
static unsigned char padding[4];
-void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev,
- struct cxgbi_tag_format *tformat, unsigned int ppmax,
- unsigned int llimit, unsigned int start,
- unsigned int rsvd_factor)
+int cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev,
+ struct cxgbi_tag_format *tformat,
+ unsigned int iscsi_size, unsigned int llimit,
+ unsigned int start, unsigned int rsvd_factor,
+ unsigned int edram_start, unsigned int edram_size)
{
int err = cxgbi_ppm_init(ppm_pp, cdev->ports[0], cdev->pdev,
- cdev->lldev, tformat, ppmax, llimit, start,
- rsvd_factor);
+ cdev->lldev, tformat, iscsi_size, llimit, start,
+ rsvd_factor, edram_start, edram_size);
if (err >= 0) {
struct cxgbi_ppm *ppm = (struct cxgbi_ppm *)(*ppm_pp);
@@ -1300,6 +1305,8 @@ void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev,
} else {
cdev->flags |= CXGBI_FLAG_DDP_OFF;
}
+
+ return err;
}
EXPORT_SYMBOL_GPL(cxgbi_ddp_ppm_setup);
@@ -2310,7 +2317,6 @@ int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param,
{
struct cxgbi_endpoint *cep = ep->dd_data;
struct cxgbi_sock *csk;
- int len;
log_debug(1 << CXGBI_DBG_ISCSI,
"cls_conn 0x%p, param %d.\n", ep, param);
@@ -2328,9 +2334,9 @@ int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param,
return iscsi_conn_get_addr_param((struct sockaddr_storage *)
&csk->daddr, param, buf);
default:
- return -ENOSYS;
+ break;
}
- return len;
+ return -ENOSYS;
}
EXPORT_SYMBOL_GPL(cxgbi_get_ep_param);
@@ -2563,13 +2569,9 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost,
pr_info("shost 0x%p, priv NULL.\n", shost);
goto err_out;
}
-
- rtnl_lock();
- if (!vlan_uses_dev(hba->ndev))
- ifindex = hba->ndev->ifindex;
- rtnl_unlock();
}
+check_route:
if (dst_addr->sa_family == AF_INET) {
csk = cxgbi_check_route(dst_addr, ifindex);
#if IS_ENABLED(CONFIG_IPV6)
@@ -2590,6 +2592,13 @@ struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost,
if (!hba)
hba = csk->cdev->hbas[csk->port_id];
else if (hba != csk->cdev->hbas[csk->port_id]) {
+ if (ifindex != hba->ndev->ifindex) {
+ cxgbi_sock_put(csk);
+ cxgbi_sock_closed(csk);
+ ifindex = hba->ndev->ifindex;
+ goto check_route;
+ }
+
pr_info("Could not connect through requested host %u"
"hba 0x%p != 0x%p (%u).\n",
shost->host_no, hba,
diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h
index 1917ff57651d..84b96af52655 100644
--- a/drivers/scsi/cxgbi/libcxgbi.h
+++ b/drivers/scsi/cxgbi/libcxgbi.h
@@ -617,8 +617,9 @@ void cxgbi_ddp_page_size_factor(int *);
void cxgbi_ddp_set_one_ppod(struct cxgbi_pagepod *,
struct cxgbi_task_tag_info *,
struct scatterlist **sg_pp, unsigned int *sg_off);
-void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *,
- struct cxgbi_tag_format *, unsigned int ppmax,
- unsigned int llimit, unsigned int start,
- unsigned int rsvd_factor);
+int cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev,
+ struct cxgbi_tag_format *tformat,
+ unsigned int iscsi_size, unsigned int llimit,
+ unsigned int start, unsigned int rsvd_factor,
+ unsigned int edram_start, unsigned int edram_size);
#endif /*__LIBCXGBI_H__*/
diff --git a/drivers/scsi/cxlflash/Kconfig b/drivers/scsi/cxlflash/Kconfig
index f1b17e3efb3f..5533bdcb0458 100644
--- a/drivers/scsi/cxlflash/Kconfig
+++ b/drivers/scsi/cxlflash/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# IBM CXL-attached Flash Accelerator SCSI Driver
#
diff --git a/drivers/scsi/cxlflash/Makefile b/drivers/scsi/cxlflash/Makefile
index 283377d8f6fb..fd2f0dd9daf9 100644
--- a/drivers/scsi/cxlflash/Makefile
+++ b/drivers/scsi/cxlflash/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_CXLFLASH) += cxlflash.o
cxlflash-y += main.o superpipe.o lunmgt.o vlun.o
cxlflash-$(CONFIG_CXL) += cxl_hw.o
diff --git a/drivers/scsi/cxlflash/backend.h b/drivers/scsi/cxlflash/backend.h
index 55638d19c2fd..181e0445ed42 100644
--- a/drivers/scsi/cxlflash/backend.h
+++ b/drivers/scsi/cxlflash/backend.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2018 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#ifndef _CXLFLASH_BACKEND_H
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index 4d90106fcb37..de6229e27b48 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#ifndef _CXLFLASH_COMMON_H
diff --git a/drivers/scsi/cxlflash/cxl_hw.c b/drivers/scsi/cxlflash/cxl_hw.c
index b42da88386bd..b814130f3f5c 100644
--- a/drivers/scsi/cxlflash/cxl_hw.c
+++ b/drivers/scsi/cxlflash/cxl_hw.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2018 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <misc/cxl.h>
diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c
index edea1255fdab..e0e15b44a2e6 100644
--- a/drivers/scsi/cxlflash/lunmgt.c
+++ b/drivers/scsi/cxlflash/lunmgt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <asm/unaligned.h>
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index 7096810fd222..b1f4724efde2 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/delay.h>
diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h
index a39be94d110c..0bfb98effce0 100644
--- a/drivers/scsi/cxlflash/main.h
+++ b/drivers/scsi/cxlflash/main.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#ifndef _CXLFLASH_MAIN_H
diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c
index 37b8dc60f5f6..96740c6fcd92 100644
--- a/drivers/scsi/cxlflash/ocxl_hw.c
+++ b/drivers/scsi/cxlflash/ocxl_hw.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2018 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/file.h>
diff --git a/drivers/scsi/cxlflash/ocxl_hw.h b/drivers/scsi/cxlflash/ocxl_hw.h
index 9270d35c4620..fc6ad4f985de 100644
--- a/drivers/scsi/cxlflash/ocxl_hw.h
+++ b/drivers/scsi/cxlflash/ocxl_hw.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Uma Krishnan <ukrishn@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2018 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#define OCXL_MAX_IRQS 4 /* Max interrupts per process */
diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h
index 874abce35ab4..ab315c59505b 100644
--- a/drivers/scsi/cxlflash/sislite.h
+++ b/drivers/scsi/cxlflash/sislite.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#ifndef _SISLITE_H
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index 1a94a469051e..593669ac3669 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/delay.h>
diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h
index 35c3cbf83fb5..0e3b45964066 100644
--- a/drivers/scsi/cxlflash/superpipe.h
+++ b/drivers/scsi/cxlflash/superpipe.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#ifndef _CXLFLASH_SUPERPIPE_H
diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c
index 2c904bf16b65..f1406ac77b0d 100644
--- a/drivers/scsi/cxlflash/vlun.c
+++ b/drivers/scsi/cxlflash/vlun.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#include <linux/interrupt.h>
diff --git a/drivers/scsi/cxlflash/vlun.h b/drivers/scsi/cxlflash/vlun.h
index 27a63a0155ce..68e3ea52fe80 100644
--- a/drivers/scsi/cxlflash/vlun.h
+++ b/drivers/scsi/cxlflash/vlun.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CXL Flash Device Driver
*
@@ -5,11 +6,6 @@
* Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) 2015 IBM 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*/
#ifndef _CXLFLASH_VLUN_H
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig
index 0b331c9c0a8f..368eb94c2456 100644
--- a/drivers/scsi/device_handler/Kconfig
+++ b/drivers/scsi/device_handler/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# SCSI Device Handler configuration
#
diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile
index 09866c50fbb4..0a603aefd2bb 100644
--- a/drivers/scsi/device_handler/Makefile
+++ b/drivers/scsi/device_handler/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# SCSI Device Handler
#
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index d7ac498ba35a..f0066f8a1786 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -1,23 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Generic SCSI-3 ALUA SCSI Device Handler
*
* Copyright (C) 2007-2010 Hannes Reinecke, SUSE Linux Products GmbH.
* All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * 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.
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
*/
#include <linux/slab.h>
#include <linux/delay.h>
@@ -1174,10 +1160,8 @@ 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;
- }
+ if (!kaluad_wq)
+ return -ENOMEM;
r = scsi_register_device_handler(&alua_dh);
if (r != 0) {
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index bea8e13febb6..caa685cfe3d4 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Target driver for EMC CLARiiON AX/CX-series hardware.
* Based on code from Lars Marowsky-Bree <lmb@suse.de>
@@ -5,20 +6,6 @@
*
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* Copyright (C) 2006 Mike Christie
- *
- * 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/slab.h>
#include <linux/module.h>
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 80129b033855..8acd4bb9fefb 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be
* upgraded.
@@ -5,20 +6,6 @@
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* Copyright (C) 2006 Mike Christie
* Copyright (C) 2008 Hannes Reinecke <hare@suse.de>
- *
- * 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/slab.h>
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 8db1cc552932..6df60b31ecb0 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
dmx3191d.c - driver for the Domex DMX3191D SCSI card.
Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it>
@@ -5,19 +6,6 @@
Based on the generic NCR5380 driver by Drew Eckhardt et al.
- 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.
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
index 16fc380b5512..bf0daeeb50a9 100644
--- a/drivers/scsi/dpt/dpti_i2o.h
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _SCSI_I2O_H
#define _SCSI_I2O_H
@@ -5,16 +6,10 @@
*
* (c) Copyright 1999, 2000 Red Hat Software
*
- * 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 header file defined the I2O APIs/structures for use by
* the I2O kernel modules.
- *
*/
#ifdef __KERNEL__ /* This file to be included by kernel only */
diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h
index f60236721e0d..6bc33f4f020d 100644
--- a/drivers/scsi/dpt/dpti_ioctl.h
+++ b/drivers/scsi/dpt/dpti_ioctl.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/***************************************************************************
dpti_ioctl.h - description
-------------------
@@ -10,10 +11,6 @@
/***************************************************************************
* *
- * 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. *
* *
***************************************************************************/
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index abdc34affdf6..abc74fd474dc 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/***************************************************************************
dpti.c - description
-------------------
@@ -13,10 +14,6 @@
/***************************************************************************
* *
- * 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. *
* *
***************************************************************************/
/***************************************************************************
@@ -835,8 +832,8 @@ static void adpt_i2o_sys_shutdown(void)
adpt_hba *pHba, *pNext;
struct adpt_i2o_post_wait_data *p1, *old;
- printk(KERN_INFO"Shutting down Adaptec I2O controllers.\n");
- printk(KERN_INFO" This could take a few minutes if there are many devices attached\n");
+ printk(KERN_INFO "Shutting down Adaptec I2O controllers.\n");
+ printk(KERN_INFO " This could take a few minutes if there are many devices attached\n");
/* Delete all IOPs from the controller chain */
/* They should have already been released by the
* scsi-core
@@ -859,7 +856,7 @@ static void adpt_i2o_sys_shutdown(void)
// spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
adpt_post_wait_queue = NULL;
- printk(KERN_INFO "Adaptec I2O controllers down.\n");
+ printk(KERN_INFO "Adaptec I2O controllers down.\n");
}
static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev)
@@ -3390,7 +3387,7 @@ static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
}
- return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */
+ return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */
}
@@ -3463,8 +3460,8 @@ static int adpt_i2o_enable_hba(adpt_hba* pHba)
static int adpt_i2o_systab_send(adpt_hba* pHba)
{
- u32 msg[12];
- int ret;
+ u32 msg[12];
+ int ret;
msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index dfc8d2eaa09e..42b1e28b5884 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/***************************************************************************
dpti.h - description
-------------------
@@ -10,10 +11,6 @@
/***************************************************************************
* *
- * 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. *
* *
***************************************************************************/
diff --git a/drivers/scsi/esas2r/Kconfig b/drivers/scsi/esas2r/Kconfig
index 78fdbfd9b4b7..19f6d3029658 100644
--- a/drivers/scsi/esas2r/Kconfig
+++ b/drivers/scsi/esas2r/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_ESAS2R
tristate "ATTO Technology's ExpressSAS RAID adapter driver"
depends on PCI && SCSI
diff --git a/drivers/scsi/esas2r/Makefile b/drivers/scsi/esas2r/Makefile
index c77160b8c8bd..279d9cb3ca69 100644
--- a/drivers/scsi/esas2r/Makefile
+++ b/drivers/scsi/esas2r/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SCSI_ESAS2R) += esas2r.o
esas2r-objs := esas2r_log.o esas2r_disc.o esas2r_flash.o esas2r_init.o \
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 465df475f753..bb88995a12c7 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* esp_scsi.c: ESP SCSI driver.
*
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
@@ -370,6 +371,7 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
struct scatterlist *sg = scsi_sglist(cmd);
int total = 0, i;
+ struct scatterlist *s;
if (cmd->sc_data_direction == DMA_NONE)
return;
@@ -380,16 +382,18 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
* a dma address, so perform an identity mapping.
*/
spriv->num_sg = scsi_sg_count(cmd);
- for (i = 0; i < spriv->num_sg; i++) {
- sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]);
- total += sg_dma_len(&sg[i]);
+
+ scsi_for_each_sg(cmd, s, spriv->num_sg, i) {
+ s->dma_address = (uintptr_t)sg_virt(s);
+ total += sg_dma_len(s);
}
} else {
spriv->num_sg = scsi_dma_map(cmd);
- for (i = 0; i < spriv->num_sg; i++)
- total += sg_dma_len(&sg[i]);
+ scsi_for_each_sg(cmd, s, spriv->num_sg, i)
+ total += sg_dma_len(s);
}
spriv->cur_residue = sg_dma_len(sg);
+ spriv->prv_sg = NULL;
spriv->cur_sg = sg;
spriv->tot_residue = total;
}
@@ -443,7 +447,8 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
p->tot_residue = 0;
}
if (!p->cur_residue && p->tot_residue) {
- p->cur_sg++;
+ p->prv_sg = p->cur_sg;
+ p->cur_sg = sg_next(p->cur_sg);
p->cur_residue = sg_dma_len(p->cur_sg);
}
}
@@ -464,6 +469,7 @@ static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
return;
}
ent->saved_cur_residue = spriv->cur_residue;
+ ent->saved_prv_sg = spriv->prv_sg;
ent->saved_cur_sg = spriv->cur_sg;
ent->saved_tot_residue = spriv->tot_residue;
}
@@ -478,6 +484,7 @@ static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent)
return;
}
spriv->cur_residue = ent->saved_cur_residue;
+ spriv->prv_sg = ent->saved_prv_sg;
spriv->cur_sg = ent->saved_cur_sg;
spriv->tot_residue = ent->saved_tot_residue;
}
@@ -1031,7 +1038,7 @@ static int esp_check_spur_intr(struct esp *esp)
static void esp_schedule_reset(struct esp *esp)
{
- esp_log_reset("esp_schedule_reset() from %pf\n",
+ esp_log_reset("esp_schedule_reset() from %ps\n",
__builtin_return_address(0));
esp->flags |= ESP_FLAG_RESETTING;
esp_event(esp, ESP_EVENT_RESET);
@@ -1646,7 +1653,7 @@ static int esp_msgin_process(struct esp *esp)
spriv = ESP_CMD_PRIV(ent->cmd);
if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) {
- spriv->cur_sg--;
+ spriv->cur_sg = spriv->prv_sg;
spriv->cur_residue = 1;
} else
spriv->cur_residue++;
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index aa87a6b72dcc..91b32f2a1a1b 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -251,6 +251,7 @@
struct esp_cmd_priv {
int num_sg;
int cur_residue;
+ struct scatterlist *prv_sg;
struct scatterlist *cur_sg;
int tot_residue;
};
@@ -273,6 +274,7 @@ struct esp_cmd_entry {
struct scsi_cmnd *cmd;
unsigned int saved_cur_residue;
+ struct scatterlist *saved_prv_sg;
struct scatterlist *saved_cur_sg;
unsigned int saved_tot_residue;
diff --git a/drivers/scsi/fcoe/Makefile b/drivers/scsi/fcoe/Makefile
index aed0f5db3668..1183e80a09e7 100644
--- a/drivers/scsi/fcoe/Makefile
+++ b/drivers/scsi/fcoe/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_FCOE) += fcoe.o
obj-$(CONFIG_LIBFCOE) += libfcoe.o
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 8ba8862d3292..00dd47bcbb1e 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h
index 6aa4820f6cc0..520c53512925 100644
--- a/drivers/scsi/fcoe/fcoe.h
+++ b/drivers/scsi/fcoe/fcoe.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2009 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 7dc4ffa24430..590ec8009f52 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2009 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c
index c3dcbdc3aa64..2cb7a8c93a15 100644
--- a/drivers/scsi/fcoe/fcoe_sysfs.c
+++ b/drivers/scsi/fcoe/fcoe_sysfs.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2011 - 2012 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 29fe3426f9f2..ba4603d76284 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
new file mode 100644
index 000000000000..b5e66971b6d9
--- /dev/null
+++ b/drivers/scsi/fdomain.c
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Future Domain TMC-16x0 and TMC-3260 SCSI host adapters
+ * Copyright 2019 Ondrej Zary
+ *
+ * Original driver by
+ * Rickard E. Faith, faith@cs.unc.edu
+ *
+ * Future Domain BIOS versions supported for autodetect:
+ * 2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61
+ * Chips supported:
+ * TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70
+ * Boards supported:
+ * Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX
+ * Future Domain TMC-3260 (PCI)
+ * Quantum ISA-200S, ISA-250MG
+ * Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead]
+ * IBM ?
+ *
+ * NOTE:
+ *
+ * The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it.
+ * Use the aic7xxx driver for this board.
+ *
+ * The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right
+ * driver for that card. Unfortunately, the boxes will probably just say
+ * "2920", so you'll have to look on the card for a Future Domain logo, or a
+ * letter after the 2920.
+ *
+ * If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
+ * your board.
+ *
+ * DESCRIPTION:
+ *
+ * This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
+ * TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a
+ * 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin
+ * high-density external connector. The 1670 and 1680 have floppy disk
+ * controllers built in. The TMC-3260 is a PCI bus card.
+ *
+ * Future Domain's older boards are based on the TMC-1800 chip, and this
+ * driver was originally written for a TMC-1680 board with the TMC-1800 chip.
+ * More recently, boards are being produced with the TMC-18C50 and TMC-18C30
+ * chips.
+ *
+ * Please note that the drive ordering that Future Domain implemented in BIOS
+ * versions 3.4 and 3.5 is the opposite of the order (currently) used by the
+ * rest of the SCSI industry.
+ *
+ *
+ * REFERENCES USED:
+ *
+ * "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation,
+ * 1990.
+ *
+ * "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain
+ * Corporation, January 1992.
+ *
+ * "LXT SCSI Products: Specifications and OEM Technical Manual (Revision
+ * B/September 1991)", Maxtor Corporation, 1991.
+ *
+ * "7213S product Manual (Revision P3)", Maxtor Corporation, 1992.
+ *
+ * "Draft Proposed American National Standard: Small Computer System
+ * Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109,
+ * revision 10h, October 17, 1991)
+ *
+ * Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
+ * Youngdale (ericy@cais.com), 1992.
+ *
+ * Private communication, Tuong Le (Future Domain Engineering department),
+ * 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
+ * TMC-18C30 detection.)
+ *
+ * Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page
+ * 60 (2.39: Disk Partition Table Layout).
+ *
+ * "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page
+ * 6-1.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+#include <scsi/scsicam.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include "fdomain.h"
+
+/*
+ * FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
+ * 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by
+ * the SCSI device, an interrupt will be raised. Therefore, this could be as
+ * low as 0, or as high as 16. Note, however, that values which are too high
+ * or too low seem to prevent any interrupts from occurring, and thereby lock
+ * up the machine.
+ */
+#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */
+#define PARITY_MASK ACTL_PAREN /* Parity enabled, 0 = disabled */
+
+enum chip_type {
+ unknown = 0x00,
+ tmc1800 = 0x01,
+ tmc18c50 = 0x02,
+ tmc18c30 = 0x03,
+};
+
+struct fdomain {
+ int base;
+ struct scsi_cmnd *cur_cmd;
+ enum chip_type chip;
+ struct work_struct work;
+};
+
+static inline void fdomain_make_bus_idle(struct fdomain *fd)
+{
+ outb(0, fd->base + REG_BCTL);
+ outb(0, fd->base + REG_MCTL);
+ if (fd->chip == tmc18c50 || fd->chip == tmc18c30)
+ /* Clear forced intr. */
+ outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK,
+ fd->base + REG_ACTL);
+ else
+ outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL);
+}
+
+static enum chip_type fdomain_identify(int port)
+{
+ u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8;
+
+ switch (id) {
+ case 0x6127:
+ return tmc1800;
+ case 0x60e9: /* 18c50 or 18c30 */
+ break;
+ default:
+ return unknown;
+ }
+
+ /* Try to toggle 32-bit mode. This only works on an 18c30 chip. */
+ outb(CFG2_32BIT, port + REG_CFG2);
+ if ((inb(port + REG_CFG2) & CFG2_32BIT)) {
+ outb(0, port + REG_CFG2);
+ if ((inb(port + REG_CFG2) & CFG2_32BIT) == 0)
+ return tmc18c30;
+ }
+ /* If that failed, we are an 18c50. */
+ return tmc18c50;
+}
+
+static int fdomain_test_loopback(int base)
+{
+ int i;
+
+ for (i = 0; i < 255; i++) {
+ outb(i, base + REG_LOOPBACK);
+ if (inb(base + REG_LOOPBACK) != i)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void fdomain_reset(int base)
+{
+ outb(1, base + REG_BCTL);
+ mdelay(20);
+ outb(0, base + REG_BCTL);
+ mdelay(1150);
+ outb(0, base + REG_MCTL);
+ outb(PARITY_MASK, base + REG_ACTL);
+}
+
+static int fdomain_select(struct Scsi_Host *sh, int target)
+{
+ int status;
+ unsigned long timeout;
+ struct fdomain *fd = shost_priv(sh);
+
+ outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
+ outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK);
+
+ /* Stop arbitration and enable parity */
+ outb(PARITY_MASK, fd->base + REG_ACTL);
+
+ timeout = 350; /* 350 msec */
+
+ do {
+ status = inb(fd->base + REG_BSTAT);
+ if (status & BSTAT_BSY) {
+ /* Enable SCSI Bus */
+ /* (on error, should make bus idle with 0) */
+ outb(BCTL_BUSEN, fd->base + REG_BCTL);
+ return 0;
+ }
+ mdelay(1);
+ } while (--timeout);
+ fdomain_make_bus_idle(fd);
+ return 1;
+}
+
+static void fdomain_finish_cmd(struct fdomain *fd, int result)
+{
+ outb(0, fd->base + REG_ICTL);
+ fdomain_make_bus_idle(fd);
+ fd->cur_cmd->result = result;
+ fd->cur_cmd->scsi_done(fd->cur_cmd);
+ fd->cur_cmd = NULL;
+}
+
+static void fdomain_read_data(struct scsi_cmnd *cmd)
+{
+ struct fdomain *fd = shost_priv(cmd->device->host);
+ unsigned char *virt, *ptr;
+ size_t offset, len;
+
+ while ((len = inw(fd->base + REG_FIFO_COUNT)) > 0) {
+ offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
+ virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
+ &offset, &len);
+ ptr = virt + offset;
+ if (len & 1)
+ *ptr++ = inb(fd->base + REG_FIFO);
+ if (len > 1)
+ insw(fd->base + REG_FIFO, ptr, len >> 1);
+ scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
+ scsi_kunmap_atomic_sg(virt);
+ }
+}
+
+static void fdomain_write_data(struct scsi_cmnd *cmd)
+{
+ struct fdomain *fd = shost_priv(cmd->device->host);
+ /* 8k FIFO for pre-tmc18c30 chips, 2k FIFO for tmc18c30 */
+ int FIFO_Size = fd->chip == tmc18c30 ? 0x800 : 0x2000;
+ unsigned char *virt, *ptr;
+ size_t offset, len;
+
+ while ((len = FIFO_Size - inw(fd->base + REG_FIFO_COUNT)) > 512) {
+ offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
+ if (len + offset > scsi_bufflen(cmd)) {
+ len = scsi_bufflen(cmd) - offset;
+ if (len == 0)
+ break;
+ }
+ virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
+ &offset, &len);
+ ptr = virt + offset;
+ if (len & 1)
+ outb(*ptr++, fd->base + REG_FIFO);
+ if (len > 1)
+ outsw(fd->base + REG_FIFO, ptr, len >> 1);
+ scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
+ scsi_kunmap_atomic_sg(virt);
+ }
+}
+
+static void fdomain_work(struct work_struct *work)
+{
+ struct fdomain *fd = container_of(work, struct fdomain, work);
+ struct Scsi_Host *sh = container_of((void *)fd, struct Scsi_Host,
+ hostdata);
+ struct scsi_cmnd *cmd = fd->cur_cmd;
+ unsigned long flags;
+ int status;
+ int done = 0;
+
+ spin_lock_irqsave(sh->host_lock, flags);
+
+ if (cmd->SCp.phase & in_arbitration) {
+ status = inb(fd->base + REG_ASTAT);
+ if (!(status & ASTAT_ARB)) {
+ fdomain_finish_cmd(fd, DID_BUS_BUSY << 16);
+ goto out;
+ }
+ cmd->SCp.phase = in_selection;
+
+ outb(ICTL_SEL | FIFO_COUNT, fd->base + REG_ICTL);
+ outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
+ outb(BIT(cmd->device->host->this_id) | BIT(scmd_id(cmd)),
+ fd->base + REG_SCSI_DATA_NOACK);
+ /* Stop arbitration and enable parity */
+ outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+ goto out;
+ } else if (cmd->SCp.phase & in_selection) {
+ status = inb(fd->base + REG_BSTAT);
+ if (!(status & BSTAT_BSY)) {
+ /* Try again, for slow devices */
+ if (fdomain_select(cmd->device->host, scmd_id(cmd))) {
+ fdomain_finish_cmd(fd, DID_NO_CONNECT << 16);
+ goto out;
+ }
+ /* Stop arbitration and enable parity */
+ outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+ }
+ cmd->SCp.phase = in_other;
+ outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, fd->base + REG_ICTL);
+ outb(BCTL_BUSEN, fd->base + REG_BCTL);
+ goto out;
+ }
+
+ /* cur_cmd->SCp.phase == in_other: this is the body of the routine */
+ status = inb(fd->base + REG_BSTAT);
+
+ if (status & BSTAT_REQ) {
+ switch (status & 0x0e) {
+ case BSTAT_CMD: /* COMMAND OUT */
+ outb(cmd->cmnd[cmd->SCp.sent_command++],
+ fd->base + REG_SCSI_DATA);
+ break;
+ case 0: /* DATA OUT -- tmc18c50/tmc18c30 only */
+ if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) {
+ cmd->SCp.have_data_in = -1;
+ outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
+ PARITY_MASK, fd->base + REG_ACTL);
+ }
+ break;
+ case BSTAT_IO: /* DATA IN -- tmc18c50/tmc18c30 only */
+ if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) {
+ cmd->SCp.have_data_in = 1;
+ outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
+ fd->base + REG_ACTL);
+ }
+ break;
+ case BSTAT_CMD | BSTAT_IO: /* STATUS IN */
+ cmd->SCp.Status = inb(fd->base + REG_SCSI_DATA);
+ break;
+ case BSTAT_MSG | BSTAT_CMD: /* MESSAGE OUT */
+ outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA);
+ break;
+ case BSTAT_MSG | BSTAT_IO | BSTAT_CMD: /* MESSAGE IN */
+ cmd->SCp.Message = inb(fd->base + REG_SCSI_DATA);
+ if (!cmd->SCp.Message)
+ ++done;
+ break;
+ }
+ }
+
+ if (fd->chip == tmc1800 && !cmd->SCp.have_data_in &&
+ cmd->SCp.sent_command >= cmd->cmd_len) {
+ if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+ cmd->SCp.have_data_in = -1;
+ outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
+ PARITY_MASK, fd->base + REG_ACTL);
+ } else {
+ cmd->SCp.have_data_in = 1;
+ outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
+ fd->base + REG_ACTL);
+ }
+ }
+
+ if (cmd->SCp.have_data_in == -1) /* DATA OUT */
+ fdomain_write_data(cmd);
+
+ if (cmd->SCp.have_data_in == 1) /* DATA IN */
+ fdomain_read_data(cmd);
+
+ if (done) {
+ fdomain_finish_cmd(fd, (cmd->SCp.Status & 0xff) |
+ ((cmd->SCp.Message & 0xff) << 8) |
+ (DID_OK << 16));
+ } else {
+ if (cmd->SCp.phase & disconnect) {
+ outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT,
+ fd->base + REG_ICTL);
+ outb(0, fd->base + REG_BCTL);
+ } else
+ outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT,
+ fd->base + REG_ICTL);
+ }
+out:
+ spin_unlock_irqrestore(sh->host_lock, flags);
+}
+
+static irqreturn_t fdomain_irq(int irq, void *dev_id)
+{
+ struct fdomain *fd = dev_id;
+
+ /* Is it our IRQ? */
+ if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0)
+ return IRQ_NONE;
+
+ outb(0, fd->base + REG_ICTL);
+
+ /* We usually have one spurious interrupt after each command. */
+ if (!fd->cur_cmd) /* Spurious interrupt */
+ return IRQ_NONE;
+
+ schedule_work(&fd->work);
+
+ return IRQ_HANDLED;
+}
+
+static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
+{
+ struct fdomain *fd = shost_priv(cmd->device->host);
+ unsigned long flags;
+
+ cmd->SCp.Status = 0;
+ cmd->SCp.Message = 0;
+ cmd->SCp.have_data_in = 0;
+ cmd->SCp.sent_command = 0;
+ cmd->SCp.phase = in_arbitration;
+ scsi_set_resid(cmd, scsi_bufflen(cmd));
+
+ spin_lock_irqsave(sh->host_lock, flags);
+
+ fd->cur_cmd = cmd;
+
+ fdomain_make_bus_idle(fd);
+
+ /* Start arbitration */
+ outb(0, fd->base + REG_ICTL);
+ outb(0, fd->base + REG_BCTL); /* Disable data drivers */
+ /* Set our id bit */
+ outb(BIT(cmd->device->host->this_id), fd->base + REG_SCSI_DATA_NOACK);
+ outb(ICTL_ARB, fd->base + REG_ICTL);
+ /* Start arbitration */
+ outb(ACTL_ARB | ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
+
+ spin_unlock_irqrestore(sh->host_lock, flags);
+
+ return 0;
+}
+
+static int fdomain_abort(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *sh = cmd->device->host;
+ struct fdomain *fd = shost_priv(sh);
+ unsigned long flags;
+
+ if (!fd->cur_cmd)
+ return FAILED;
+
+ spin_lock_irqsave(sh->host_lock, flags);
+
+ fdomain_make_bus_idle(fd);
+ fd->cur_cmd->SCp.phase |= aborted;
+ fd->cur_cmd->result = DID_ABORT << 16;
+
+ /* Aborts are not done well. . . */
+ fdomain_finish_cmd(fd, DID_ABORT << 16);
+ spin_unlock_irqrestore(sh->host_lock, flags);
+ return SUCCESS;
+}
+
+static int fdomain_host_reset(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *sh = cmd->device->host;
+ struct fdomain *fd = shost_priv(sh);
+ unsigned long flags;
+
+ spin_lock_irqsave(sh->host_lock, flags);
+ fdomain_reset(fd->base);
+ spin_unlock_irqrestore(sh->host_lock, flags);
+ return SUCCESS;
+}
+
+static int fdomain_biosparam(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity,
+ int geom[])
+{
+ unsigned char *p = scsi_bios_ptable(bdev);
+
+ if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
+ && p[4]) { /* Partition type */
+ geom[0] = p[5] + 1; /* heads */
+ geom[1] = p[6] & 0x3f; /* sectors */
+ } else {
+ if (capacity >= 0x7e0000) {
+ geom[0] = 255; /* heads */
+ geom[1] = 63; /* sectors */
+ } else if (capacity >= 0x200000) {
+ geom[0] = 128; /* heads */
+ geom[1] = 63; /* sectors */
+ } else {
+ geom[0] = 64; /* heads */
+ geom[1] = 32; /* sectors */
+ }
+ }
+ geom[2] = sector_div(capacity, geom[0] * geom[1]);
+ kfree(p);
+
+ return 0;
+}
+
+static struct scsi_host_template fdomain_template = {
+ .module = THIS_MODULE,
+ .name = "Future Domain TMC-16x0",
+ .proc_name = "fdomain",
+ .queuecommand = fdomain_queue,
+ .eh_abort_handler = fdomain_abort,
+ .eh_host_reset_handler = fdomain_host_reset,
+ .bios_param = fdomain_biosparam,
+ .can_queue = 1,
+ .this_id = 7,
+ .sg_tablesize = 64,
+ .dma_boundary = PAGE_SIZE - 1,
+};
+
+struct Scsi_Host *fdomain_create(int base, int irq, int this_id,
+ struct device *dev)
+{
+ struct Scsi_Host *sh;
+ struct fdomain *fd;
+ enum chip_type chip;
+ static const char * const chip_names[] = {
+ "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30"
+ };
+ unsigned long irq_flags = 0;
+
+ chip = fdomain_identify(base);
+ if (!chip)
+ return NULL;
+
+ fdomain_reset(base);
+
+ if (fdomain_test_loopback(base))
+ return NULL;
+
+ if (!irq) {
+ dev_err(dev, "card has no IRQ assigned");
+ return NULL;
+ }
+
+ sh = scsi_host_alloc(&fdomain_template, sizeof(struct fdomain));
+ if (!sh)
+ return NULL;
+
+ if (this_id)
+ sh->this_id = this_id & 0x07;
+
+ sh->irq = irq;
+ sh->io_port = base;
+ sh->n_io_port = FDOMAIN_REGION_SIZE;
+
+ fd = shost_priv(sh);
+ fd->base = base;
+ fd->chip = chip;
+ INIT_WORK(&fd->work, fdomain_work);
+
+ if (dev_is_pci(dev) || !strcmp(dev->bus->name, "pcmcia"))
+ irq_flags = IRQF_SHARED;
+
+ if (request_irq(irq, fdomain_irq, irq_flags, "fdomain", fd))
+ goto fail_put;
+
+ shost_printk(KERN_INFO, sh, "%s chip at 0x%x irq %d SCSI ID %d\n",
+ dev_is_pci(dev) ? "TMC-36C70 (PCI bus)" : chip_names[chip],
+ base, irq, sh->this_id);
+
+ if (scsi_add_host(sh, dev))
+ goto fail_free_irq;
+
+ scsi_scan_host(sh);
+
+ return sh;
+
+fail_free_irq:
+ free_irq(irq, fd);
+fail_put:
+ scsi_host_put(sh);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(fdomain_create);
+
+int fdomain_destroy(struct Scsi_Host *sh)
+{
+ struct fdomain *fd = shost_priv(sh);
+
+ cancel_work_sync(&fd->work);
+ scsi_remove_host(sh);
+ if (sh->irq)
+ free_irq(sh->irq, fd);
+ scsi_host_put(sh);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fdomain_destroy);
+
+#ifdef CONFIG_PM_SLEEP
+static int fdomain_resume(struct device *dev)
+{
+ struct fdomain *fd = shost_priv(dev_get_drvdata(dev));
+
+ fdomain_reset(fd->base);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(fdomain_pm_ops, NULL, fdomain_resume);
+#endif /* CONFIG_PM_SLEEP */
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-16x0/TMC-3260 SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h
new file mode 100644
index 000000000000..6f63fc6b0d12
--- /dev/null
+++ b/drivers/scsi/fdomain.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#define FDOMAIN_REGION_SIZE 0x10
+#define FDOMAIN_BIOS_SIZE 0x2000
+
+enum {
+ in_arbitration = 0x02,
+ in_selection = 0x04,
+ in_other = 0x08,
+ disconnect = 0x10,
+ aborted = 0x20,
+ sent_ident = 0x40,
+};
+
+/* (@) = not present on TMC1800, (#) = not present on TMC1800 and TMC18C50 */
+#define REG_SCSI_DATA 0 /* R/W: SCSI Data (with ACK) */
+#define REG_BSTAT 1 /* R: SCSI Bus Status */
+#define BSTAT_BSY BIT(0) /* Busy */
+#define BSTAT_MSG BIT(1) /* Message */
+#define BSTAT_IO BIT(2) /* Input/Output */
+#define BSTAT_CMD BIT(3) /* Command/Data */
+#define BSTAT_REQ BIT(4) /* Request and Not Ack */
+#define BSTAT_SEL BIT(5) /* Select */
+#define BSTAT_ACK BIT(6) /* Acknowledge and Request */
+#define BSTAT_ATN BIT(7) /* Attention */
+#define REG_BCTL 1 /* W: SCSI Bus Control */
+#define BCTL_RST BIT(0) /* Bus Reset */
+#define BCTL_SEL BIT(1) /* Select */
+#define BCTL_BSY BIT(2) /* Busy */
+#define BCTL_ATN BIT(3) /* Attention */
+#define BCTL_IO BIT(4) /* Input/Output */
+#define BCTL_CMD BIT(5) /* Command/Data */
+#define BCTL_MSG BIT(6) /* Message */
+#define BCTL_BUSEN BIT(7) /* Enable bus drivers */
+#define REG_ASTAT 2 /* R: Adapter Status 1 */
+#define ASTAT_IRQ BIT(0) /* Interrupt active */
+#define ASTAT_ARB BIT(1) /* Arbitration complete */
+#define ASTAT_PARERR BIT(2) /* Parity error */
+#define ASTAT_RST BIT(3) /* SCSI reset occurred */
+#define ASTAT_FIFODIR BIT(4) /* FIFO direction */
+#define ASTAT_FIFOEN BIT(5) /* FIFO enabled */
+#define ASTAT_PAREN BIT(6) /* Parity enabled */
+#define ASTAT_BUSEN BIT(7) /* Bus drivers enabled */
+#define REG_ICTL 2 /* W: Interrupt Control */
+#define ICTL_FIFO_MASK 0x0f /* FIFO threshold, 1/16 FIFO size */
+#define ICTL_FIFO BIT(4) /* Int. on FIFO count */
+#define ICTL_ARB BIT(5) /* Int. on Arbitration complete */
+#define ICTL_SEL BIT(6) /* Int. on SCSI Select */
+#define ICTL_REQ BIT(7) /* Int. on SCSI Request */
+#define REG_FSTAT 3 /* R: Adapter Status 2 (FIFO) - (@) */
+#define FSTAT_ONOTEMPTY BIT(0) /* Output FIFO not empty */
+#define FSTAT_INOTEMPTY BIT(1) /* Input FIFO not empty */
+#define FSTAT_NOTEMPTY BIT(2) /* Main FIFO not empty */
+#define FSTAT_NOTFULL BIT(3) /* Main FIFO not full */
+#define REG_MCTL 3 /* W: SCSI Data Mode Control */
+#define MCTL_ACK_MASK 0x0f /* Acknowledge period */
+#define MCTL_ACTDEASS BIT(4) /* Active deassert of REQ and ACK */
+#define MCTL_TARGET BIT(5) /* Enable target mode */
+#define MCTL_FASTSYNC BIT(6) /* Enable Fast Synchronous */
+#define MCTL_SYNC BIT(7) /* Enable Synchronous */
+#define REG_INTCOND 4 /* R: Interrupt Condition - (@) */
+#define IRQ_FIFO BIT(1) /* FIFO interrupt */
+#define IRQ_REQ BIT(2) /* SCSI Request interrupt */
+#define IRQ_SEL BIT(3) /* SCSI Select interrupt */
+#define IRQ_ARB BIT(4) /* SCSI Arbitration interrupt */
+#define IRQ_RST BIT(5) /* SCSI Reset interrupt */
+#define IRQ_FORCED BIT(6) /* Forced interrupt */
+#define IRQ_TIMEOUT BIT(7) /* Bus timeout */
+#define REG_ACTL 4 /* W: Adapter Control 1 */
+#define ACTL_RESET BIT(0) /* Reset FIFO, parity, reset int. */
+#define ACTL_FIRQ BIT(1) /* Set Forced interrupt */
+#define ACTL_ARB BIT(2) /* Initiate Bus Arbitration */
+#define ACTL_PAREN BIT(3) /* Enable SCSI Parity */
+#define ACTL_IRQEN BIT(4) /* Enable interrupts */
+#define ACTL_CLRFIRQ BIT(5) /* Clear Forced interrupt */
+#define ACTL_FIFOWR BIT(6) /* FIFO Direction (1=write) */
+#define ACTL_FIFOEN BIT(7) /* Enable FIFO */
+#define REG_ID_LSB 5 /* R: ID Code (LSB) */
+#define REG_ACTL2 5 /* Adapter Control 2 - (@) */
+#define ACTL2_RAMOVRLY BIT(0) /* Enable RAM overlay */
+#define ACTL2_SLEEP BIT(7) /* Sleep mode */
+#define REG_ID_MSB 6 /* R: ID Code (MSB) */
+#define REG_LOOPBACK 7 /* R/W: Loopback */
+#define REG_SCSI_DATA_NOACK 8 /* R/W: SCSI Data (no ACK) */
+#define REG_ASTAT3 9 /* R: Adapter Status 3 */
+#define ASTAT3_ACTDEASS BIT(0) /* Active deassert enabled */
+#define ASTAT3_RAMOVRLY BIT(1) /* RAM overlay enabled */
+#define ASTAT3_TARGERR BIT(2) /* Target error */
+#define ASTAT3_IRQEN BIT(3) /* Interrupts enabled */
+#define ASTAT3_IRQMASK 0xf0 /* Enabled interrupts mask */
+#define REG_CFG1 10 /* R: Configuration Register 1 */
+#define CFG1_BUS BIT(0) /* 0 = ISA */
+#define CFG1_IRQ_MASK 0x0e /* IRQ jumpers */
+#define CFG1_IO_MASK 0x30 /* I/O base jumpers */
+#define CFG1_BIOS_MASK 0xc0 /* BIOS base jumpers */
+#define REG_CFG2 11 /* R/W: Configuration Register 2 (@) */
+#define CFG2_ROMDIS BIT(0) /* ROM disabled */
+#define CFG2_RAMDIS BIT(1) /* RAM disabled */
+#define CFG2_IRQEDGE BIT(2) /* Edge-triggered interrupts */
+#define CFG2_NOWS BIT(3) /* No wait states */
+#define CFG2_32BIT BIT(7) /* 32-bit mode */
+#define REG_FIFO 12 /* R/W: FIFO */
+#define REG_FIFO_COUNT 14 /* R: FIFO Data Count */
+
+#ifdef CONFIG_PM_SLEEP
+static const struct dev_pm_ops fdomain_pm_ops;
+#define FDOMAIN_PM_OPS (&fdomain_pm_ops)
+#else
+#define FDOMAIN_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+struct Scsi_Host *fdomain_create(int base, int irq, int this_id,
+ struct device *dev);
+int fdomain_destroy(struct Scsi_Host *sh);
diff --git a/drivers/scsi/fdomain_isa.c b/drivers/scsi/fdomain_isa.c
new file mode 100644
index 000000000000..28639adf8219
--- /dev/null
+++ b/drivers/scsi/fdomain_isa.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/isa.h>
+#include <scsi/scsi_host.h>
+#include "fdomain.h"
+
+#define MAXBOARDS_PARAM 4
+static int io[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(io, int, ioport, NULL, 0);
+MODULE_PARM_DESC(io, "base I/O address of controller (0x140, 0x150, 0x160, 0x170)");
+
+static int irq[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(irq, int, irq, NULL, 0);
+MODULE_PARM_DESC(irq, "IRQ of controller (0=auto [default])");
+
+static int scsi_id[MAXBOARDS_PARAM] = { 0, 0, 0, 0 };
+module_param_hw_array(scsi_id, int, other, NULL, 0);
+MODULE_PARM_DESC(scsi_id, "SCSI ID of controller (default = 7)");
+
+static unsigned long addresses[] = {
+ 0xc8000,
+ 0xca000,
+ 0xce000,
+ 0xde000,
+};
+#define ADDRESS_COUNT ARRAY_SIZE(addresses)
+
+static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
+#define PORT_COUNT ARRAY_SIZE(ports)
+
+static unsigned short irqs[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
+
+/* This driver works *ONLY* for Future Domain cards using the TMC-1800,
+ * TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670,
+ * and 1680. These are all 16-bit cards.
+ * BIOS versions prior to 3.2 assigned SCSI ID 6 to SCSI adapter.
+ *
+ * The following BIOS signature signatures are for boards which do *NOT*
+ * work with this driver (these TMC-8xx and TMC-9xx boards may work with the
+ * Seagate driver):
+ *
+ * FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88
+ * FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89
+ * FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
+ * FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
+ * FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92
+ *
+ * (The cards which do *NOT* work are all 8-bit cards -- although some of
+ * them have a 16-bit form-factor, the upper 8-bits are used only for IRQs
+ * and are *NOT* used for data. You can tell the difference by following
+ * the tracings on the circuit board -- if only the IRQ lines are involved,
+ * you have a "8-bit" card, and should *NOT* use this driver.)
+ */
+
+static struct signature {
+ const char *signature;
+ int offset;
+ int length;
+ int this_id;
+ int base_offset;
+} signatures[] = {
+/* 1 2 3 4 5 6 */
+/* 123456789012345678901234567890123456789012345678901234567890 */
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 6, 0x1fcc },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 6, 0x1fcc },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 6, 0x1fa2 },
+{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 6, 0x1fa2 },
+{ "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 6, 0x1fa3 },
+{ "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 6, 0 },
+{ "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 7, 0 },
+{ "IBM F1 P2 BIOS v1.0011/09/92", 5, 28, 7, 0x1ff3 },
+{ "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 7, 0 },
+{ "Future Domain Corp. V1.0008/18/93", 5, 33, 7, 0 },
+{ "Future Domain Corp. V2.0108/18/93", 5, 33, 7, 0 },
+{ "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 7, 0 },
+{ "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 7, 0 },
+{ "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 7, 0 },
+{ "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 7, 0 },
+};
+#define SIGNATURE_COUNT ARRAY_SIZE(signatures)
+
+static int fdomain_isa_match(struct device *dev, unsigned int ndev)
+{
+ struct Scsi_Host *sh;
+ int i, base = 0, irq = 0;
+ unsigned long bios_base = 0;
+ struct signature *sig = NULL;
+ void __iomem *p;
+ static struct signature *saved_sig;
+ int this_id = 7;
+
+ if (ndev < ADDRESS_COUNT) { /* scan supported ISA BIOS addresses */
+ p = ioremap(addresses[ndev], FDOMAIN_BIOS_SIZE);
+ if (!p)
+ return 0;
+ for (i = 0; i < SIGNATURE_COUNT; i++)
+ if (check_signature(p + signatures[i].offset,
+ signatures[i].signature,
+ signatures[i].length))
+ break;
+ if (i == SIGNATURE_COUNT) /* no signature found */
+ goto fail_unmap;
+ sig = &signatures[i];
+ bios_base = addresses[ndev];
+ /* read I/O base from BIOS area */
+ if (sig->base_offset)
+ base = readb(p + sig->base_offset) +
+ (readb(p + sig->base_offset + 1) << 8);
+ iounmap(p);
+ if (base)
+ dev_info(dev, "BIOS at 0x%lx specifies I/O base 0x%x\n",
+ bios_base, base);
+ else
+ dev_info(dev, "BIOS at 0x%lx\n", bios_base);
+ if (!base) { /* no I/O base in BIOS area */
+ /* save BIOS signature for later use in port probing */
+ saved_sig = sig;
+ return 0;
+ }
+ } else /* scan supported I/O ports */
+ base = ports[ndev - ADDRESS_COUNT];
+
+ /* use saved BIOS signature if present */
+ if (!sig && saved_sig)
+ sig = saved_sig;
+
+ if (!request_region(base, FDOMAIN_REGION_SIZE, "fdomain_isa"))
+ return 0;
+
+ irq = irqs[(inb(base + REG_CFG1) & 0x0e) >> 1];
+
+
+ if (sig)
+ this_id = sig->this_id;
+
+ sh = fdomain_create(base, irq, this_id, dev);
+ if (!sh) {
+ release_region(base, FDOMAIN_REGION_SIZE);
+ return 0;
+ }
+
+ dev_set_drvdata(dev, sh);
+ return 1;
+fail_unmap:
+ iounmap(p);
+ return 0;
+}
+
+static int fdomain_isa_param_match(struct device *dev, unsigned int ndev)
+{
+ struct Scsi_Host *sh;
+ int irq_ = irq[ndev];
+
+ if (!io[ndev])
+ return 0;
+
+ if (!request_region(io[ndev], FDOMAIN_REGION_SIZE, "fdomain_isa")) {
+ dev_err(dev, "base 0x%x already in use", io[ndev]);
+ return 0;
+ }
+
+ if (irq_ <= 0)
+ irq_ = irqs[(inb(io[ndev] + REG_CFG1) & 0x0e) >> 1];
+
+ sh = fdomain_create(io[ndev], irq_, scsi_id[ndev], dev);
+ if (!sh) {
+ dev_err(dev, "controller not found at base 0x%x", io[ndev]);
+ release_region(io[ndev], FDOMAIN_REGION_SIZE);
+ return 0;
+ }
+
+ dev_set_drvdata(dev, sh);
+ return 1;
+}
+
+static int fdomain_isa_remove(struct device *dev, unsigned int ndev)
+{
+ struct Scsi_Host *sh = dev_get_drvdata(dev);
+ int base = sh->io_port;
+
+ fdomain_destroy(sh);
+ release_region(base, FDOMAIN_REGION_SIZE);
+ dev_set_drvdata(dev, NULL);
+ return 0;
+}
+
+static struct isa_driver fdomain_isa_driver = {
+ .match = fdomain_isa_match,
+ .remove = fdomain_isa_remove,
+ .driver = {
+ .name = "fdomain_isa",
+ .pm = FDOMAIN_PM_OPS,
+ },
+};
+
+static int __init fdomain_isa_init(void)
+{
+ int isa_probe_count = ADDRESS_COUNT + PORT_COUNT;
+
+ if (io[0]) { /* use module parameters if present */
+ fdomain_isa_driver.match = fdomain_isa_param_match;
+ isa_probe_count = MAXBOARDS_PARAM;
+ }
+
+ return isa_register_driver(&fdomain_isa_driver, isa_probe_count);
+}
+
+static void __exit fdomain_isa_exit(void)
+{
+ isa_unregister_driver(&fdomain_isa_driver);
+}
+
+module_init(fdomain_isa_init);
+module_exit(fdomain_isa_exit);
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-16x0 ISA SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fdomain_pci.c b/drivers/scsi/fdomain_pci.c
new file mode 100644
index 000000000000..3e05ce7b89e5
--- /dev/null
+++ b/drivers/scsi/fdomain_pci.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "fdomain.h"
+
+static int fdomain_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *d)
+{
+ int err;
+ struct Scsi_Host *sh;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ goto fail;
+
+ err = pci_request_regions(pdev, "fdomain_pci");
+ if (err)
+ goto disable_device;
+
+ err = -ENODEV;
+ if (pci_resource_len(pdev, 0) == 0)
+ goto release_region;
+
+ sh = fdomain_create(pci_resource_start(pdev, 0), pdev->irq, 7,
+ &pdev->dev);
+ if (!sh)
+ goto release_region;
+
+ pci_set_drvdata(pdev, sh);
+ return 0;
+
+release_region:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+fail:
+ return err;
+}
+
+static void fdomain_pci_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *sh = pci_get_drvdata(pdev);
+
+ fdomain_destroy(sh);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id fdomain_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, fdomain_pci_table);
+
+static struct pci_driver fdomain_pci_driver = {
+ .name = "fdomain_pci",
+ .id_table = fdomain_pci_table,
+ .probe = fdomain_pci_probe,
+ .remove = fdomain_pci_remove,
+ .driver.pm = FDOMAIN_PM_OPS,
+};
+
+module_pci_driver(fdomain_pci_driver);
+
+MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
+MODULE_DESCRIPTION("Future Domain TMC-3260 PCI SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 9cdca0625498..2ab774e62e40 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic Generic NCR5380 driver
*
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index e7f1dd4f3b66..fe03410268e6 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/************************************************************************
* Linux driver for *
* ICP vortex GmbH: GDT PCI Disk Array Controllers *
@@ -13,19 +14,6 @@
* Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com> *
* Johannes Dinner <johannes_dinner@adaptec.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. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this kernel; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Linux kernel 2.6.x supported *
* *
@@ -3697,8 +3685,9 @@ static int ioc_general(void __user *arg, char *cmnd)
rval = 0;
out_free_buf:
- dma_free_coherent(&ha->pdev->dev, gen.data_len + gen.sense_len, buf,
- paddr);
+ if (buf)
+ dma_free_coherent(&ha->pdev->dev, gen.data_len + gen.sense_len,
+ buf, paddr);
return rval;
}
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index d2acd0d826e2..11df0eca0293 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include <linux/types.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig
index 57183fce70fb..90a17452a50d 100644
--- a/drivers/scsi/hisi_sas/Kconfig
+++ b/drivers/scsi/hisi_sas/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_HISI_SAS
tristate "HiSilicon SAS"
depends on HAS_IOMEM
diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile
index 24623f228510..742e732cd51d 100644
--- a/drivers/scsi/hisi_sas/Makefile
+++ b/drivers/scsi/hisi_sas/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_main.o
obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_v1_hw.o hisi_sas_v2_hw.o
obj-$(CONFIG_SCSI_HISI_SAS_PCI) += hisi_sas_v3_hw.o
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 9bfa9f12d81e..42a02cc47a60 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -1,12 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* 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_
@@ -66,10 +61,6 @@
#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))
-
#define HISI_SAS_SATA_PROTOCOL_NONDATA 0x1
#define HISI_SAS_SATA_PROTOCOL_PIO 0x2
#define HISI_SAS_SATA_PROTOCOL_DMA 0x4
@@ -170,6 +161,7 @@ struct hisi_sas_phy {
u32 code_violation_err_count;
enum sas_linkrate minimum_linkrate;
enum sas_linkrate maximum_linkrate;
+ int enable;
};
struct hisi_sas_port {
@@ -483,12 +475,12 @@ struct hisi_sas_command_table_stp {
u8 atapi_cdb[ATAPI_CDB_LEN];
};
-#define HISI_SAS_SGE_PAGE_CNT SG_CHUNK_SIZE
+#define HISI_SAS_SGE_PAGE_CNT (124)
struct hisi_sas_sge_page {
struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
} __aligned(16);
-#define HISI_SAS_SGE_DIF_PAGE_CNT SG_CHUNK_SIZE
+#define HISI_SAS_SGE_DIF_PAGE_CNT HISI_SAS_SGE_PAGE_CNT
struct hisi_sas_sge_dif_page {
struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT];
} __aligned(16);
@@ -551,6 +543,8 @@ extern int hisi_sas_slave_configure(struct scsi_device *sdev);
extern int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time);
extern void hisi_sas_scan_start(struct Scsi_Host *shost);
extern int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type);
+extern void hisi_sas_phy_enable(struct hisi_hba *hisi_hba, int phy_no,
+ int enable);
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,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 14bac4966c87..cb746cfc2fa8 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1,16 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* 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"
-#include "../libsas/sas_internal.h"
#define DRV_NAME "hisi_sas"
#define DEV_IS_GONE(dev) \
@@ -171,7 +165,7 @@ void hisi_sas_stop_phys(struct hisi_hba *hisi_hba)
int phy_no;
for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++)
- hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 0);
}
EXPORT_SYMBOL_GPL(hisi_sas_stop_phys);
@@ -684,7 +678,7 @@ static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no)
id->initiator_bits = SAS_PROTOCOL_ALL;
id->target_bits = phy->identify.target_port_protocols;
} else if (phy->phy_type & PORT_TYPE_SATA) {
- /*Nothing*/
+ /* Nothing */
}
sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
@@ -755,7 +749,8 @@ static int hisi_sas_init_device(struct domain_device *device)
* STP target port
*/
local_phy = sas_get_local_phy(device);
- if (!scsi_is_sas_phy_local(local_phy)) {
+ if (!scsi_is_sas_phy_local(local_phy) &&
+ !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
unsigned long deadline = ata_deadline(jiffies, 20000);
struct sata_device *sata_dev = &device->sata_dev;
struct ata_host *ata_host = sata_dev->ata_host;
@@ -770,8 +765,7 @@ static int hisi_sas_init_device(struct domain_device *device)
}
sas_put_local_phy(local_phy);
if (rc) {
- dev_warn(dev, "SATA disk hardreset fail: 0x%x\n",
- rc);
+ dev_warn(dev, "SATA disk hardreset fail: %d\n", rc);
return rc;
}
@@ -809,7 +803,7 @@ static int hisi_sas_dev_found(struct domain_device *device)
device->lldd_dev = sas_dev;
hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ 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;
@@ -976,6 +970,30 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
timer_setup(&phy->timer, hisi_sas_wait_phyup_timedout, 0);
}
+/* Wrapper to ensure we track hisi_sas_phy.enable properly */
+void hisi_sas_phy_enable(struct hisi_hba *hisi_hba, int phy_no, int enable)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *aphy = &phy->sas_phy;
+ struct sas_phy *sphy = aphy->phy;
+ unsigned long flags;
+
+ spin_lock_irqsave(&phy->lock, flags);
+
+ if (enable) {
+ /* We may have been enabled already; if so, don't touch */
+ if (!phy->enable)
+ sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+ hisi_hba->hw->phy_start(hisi_hba, phy_no);
+ } else {
+ sphy->negotiated_linkrate = SAS_PHY_DISABLED;
+ hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+ }
+ phy->enable = enable;
+ spin_unlock_irqrestore(&phy->lock, flags);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_phy_enable);
+
static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
{
struct sas_ha_struct *sas_ha = sas_phy->ha;
@@ -1112,10 +1130,10 @@ static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no,
sas_phy->phy->maximum_linkrate = max;
sas_phy->phy->minimum_linkrate = min;
- hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 0);
msleep(100);
hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r);
- hisi_hba->hw->phy_start(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 1);
return 0;
}
@@ -1133,13 +1151,13 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
break;
case PHY_FUNC_LINK_RESET:
- hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 0);
msleep(100);
- hisi_hba->hw->phy_start(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 1);
break;
case PHY_FUNC_DISABLE:
- hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 0);
break;
case PHY_FUNC_SET_LINK_RATE:
@@ -1264,8 +1282,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
/* 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",
+ 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);
@@ -1280,10 +1297,16 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
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);
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_OPEN_REJECT) {
+ dev_warn(dev, "abort tmf: open reject failed\n");
+ res = -EIO;
+ } else {
+ 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;
}
@@ -1423,13 +1446,13 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state,
_sas_port = sas_port;
- if (DEV_IS_EXPANDER(dev->dev_type))
+ if (dev_is_expander(dev->dev_type))
sas_ha->notify_port_event(sas_phy,
PORTE_BROADCAST_RCVD);
}
- } else if (old_state & (1 << phy_no))
- /* PHY down but was up before */
+ } else {
hisi_sas_phy_down(hisi_hba, phy_no, 0);
+ }
}
}
@@ -1510,7 +1533,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba)
struct domain_device *port_dev = sas_port->port_dev;
struct domain_device *device;
- if (!port_dev || !DEV_IS_EXPANDER(port_dev->dev_type))
+ if (!port_dev || !dev_is_expander(port_dev->dev_type))
continue;
/* Try to find a SATA device */
@@ -1711,7 +1734,7 @@ static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct device *dev = hisi_hba->dev;
struct hisi_sas_tmf_task tmf_task;
- int rc = TMF_RESP_FUNC_FAILED;
+ int rc;
rc = hisi_sas_internal_task_abort(hisi_hba, device,
HISI_SAS_INT_ABT_DEV, 0);
@@ -1803,7 +1826,7 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
if (dev_is_sata(device)) {
rc = hisi_sas_softreset_ata_disk(device);
- if (rc)
+ if (rc == TMF_RESP_FUNC_FAILED)
return TMF_RESP_FUNC_FAILED;
}
@@ -1880,7 +1903,7 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
struct domain_device *device = sas_dev->sas_device;
if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device ||
- DEV_IS_EXPANDER(device->dev_type))
+ dev_is_expander(device->dev_type))
continue;
rc = hisi_sas_debug_I_T_nexus_reset(device);
@@ -2100,10 +2123,8 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
}
exit:
- dev_dbg(dev, "internal task abort: task to dev %016llx task=%p "
- "resp: 0x%x sts 0x%x\n",
- SAS_ADDR(device->sas_addr),
- task,
+ dev_dbg(dev, "internal task abort: task to dev %016llx task=%p resp: 0x%x sts 0x%x\n",
+ SAS_ADDR(device->sas_addr), task,
task->task_status.resp, /* 0 is complete, -1 is undelivered */
task->task_status.stat);
sas_free_task(task);
@@ -2172,16 +2193,18 @@ static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
{
struct asd_sas_phy *sas_phy = &phy->sas_phy;
struct sas_phy *sphy = sas_phy->phy;
- struct sas_phy_data *d = sphy->hostdata;
+ unsigned long flags;
phy->phy_attached = 0;
phy->phy_type = 0;
phy->port = NULL;
- if (d->enable)
+ spin_lock_irqsave(&phy->lock, flags);
+ if (phy->enable)
sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
else
sphy->negotiated_linkrate = SAS_PHY_DISABLED;
+ spin_unlock_irqrestore(&phy->lock, flags);
}
void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
@@ -2234,6 +2257,19 @@ void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba)
}
EXPORT_SYMBOL_GPL(hisi_sas_kill_tasklets);
+int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type)
+{
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+
+ if (reset_type != SCSI_ADAPTER_RESET)
+ return -EOPNOTSUPP;
+
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_host_reset);
+
struct scsi_transport_template *hisi_sas_stt;
EXPORT_SYMBOL_GPL(hisi_sas_stt);
@@ -2439,6 +2475,14 @@ EXPORT_SYMBOL_GPL(hisi_sas_alloc);
void hisi_sas_free(struct hisi_hba *hisi_hba)
{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+
+ del_timer_sync(&phy->timer);
+ }
+
if (hisi_hba->wq)
destroy_workqueue(hisi_hba->wq);
}
@@ -2491,22 +2535,19 @@ int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba)
if (device_property_read_u32(dev, "ctrl-reset-reg",
&hisi_hba->ctrl_reset_reg)) {
- dev_err(dev,
- "could not get property ctrl-reset-reg\n");
+ dev_err(dev, "could not get property ctrl-reset-reg\n");
return -ENOENT;
}
if (device_property_read_u32(dev, "ctrl-reset-sts-reg",
&hisi_hba->ctrl_reset_sts_reg)) {
- dev_err(dev,
- "could not get property ctrl-reset-sts-reg\n");
+ dev_err(dev, "could not get property ctrl-reset-sts-reg\n");
return -ENOENT;
}
if (device_property_read_u32(dev, "ctrl-clock-ena-reg",
&hisi_hba->ctrl_clock_ena_reg)) {
- dev_err(dev,
- "could not get property ctrl-clock-ena-reg\n");
+ dev_err(dev, "could not get property ctrl-clock-ena-reg\n");
return -ENOENT;
}
}
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 293807443480..3912216e8a4f 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1,12 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* 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"
@@ -798,16 +793,11 @@ static void start_phy_v1_hw(struct hisi_hba *hisi_hba, int 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);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 0);
msleep(100);
- start_phy_v1_hw(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 1);
}
static void start_phys_v1_hw(struct timer_list *t)
@@ -817,7 +807,7 @@ static void start_phys_v1_hw(struct timer_list *t)
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);
+ hisi_sas_phy_enable(hisi_hba, i, 1);
}
}
@@ -1695,8 +1685,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
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",
+ dev_err(dev, "irq init: fail map phy interrupt %d\n",
idx);
return -ENOENT;
}
@@ -1704,8 +1693,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
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",
+ dev_err(dev, "irq init: could not request phy interrupt %d, rc=%d\n",
irq, rc);
return -ENOENT;
}
@@ -1742,8 +1730,7 @@ static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
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",
+ dev_err(dev, "irq init: could not request fatal interrupt %d, rc=%d\n",
irq, rc);
return -ENOENT;
}
@@ -1823,6 +1810,7 @@ static struct scsi_host_template sht_v1_hw = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = host_attrs_v1_hw,
+ .host_reset = hisi_sas_host_reset,
};
static const struct hisi_sas_hw hisi_sas_v1_hw = {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 89160ab3efb0..e9b15d45f98f 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -1,12 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* 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"
@@ -427,70 +422,70 @@ static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
.msk = HGC_DQE_ECC_1B_ADDR_MSK,
.shift = HGC_DQE_ECC_1B_ADDR_OFF,
- .msg = "hgc_dqe_acc1b_intr found: Ram address is 0x%08X\n",
+ .msg = "hgc_dqe_ecc1b_intr",
.reg = HGC_DQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF),
.msk = HGC_IOST_ECC_1B_ADDR_MSK,
.shift = HGC_IOST_ECC_1B_ADDR_OFF,
- .msg = "hgc_iost_acc1b_intr found: Ram address is 0x%08X\n",
+ .msg = "hgc_iost_ecc1b_intr",
.reg = HGC_IOST_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF),
.msk = HGC_ITCT_ECC_1B_ADDR_MSK,
.shift = HGC_ITCT_ECC_1B_ADDR_OFF,
- .msg = "hgc_itct_acc1b_intr found: am address is 0x%08X\n",
+ .msg = "hgc_itct_ecc1b_intr",
.reg = HGC_ITCT_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF),
.msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
- .msg = "hgc_iostl_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "hgc_iostl_ecc1b_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF),
.msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
- .msg = "hgc_itctl_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "hgc_itctl_ecc1b_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF),
.msk = HGC_CQE_ECC_1B_ADDR_MSK,
.shift = HGC_CQE_ECC_1B_ADDR_OFF,
- .msg = "hgc_cqe_acc1b_intr found: Ram address is 0x%08X\n",
+ .msg = "hgc_cqe_ecc1b_intr",
.reg = HGC_CQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
- .msg = "rxm_mem0_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "rxm_mem0_ecc1b_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
- .msg = "rxm_mem1_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "rxm_mem1_ecc1b_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
- .msg = "rxm_mem2_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "rxm_mem2_ecc1b_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF),
.msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
.shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
- .msg = "rxm_mem3_acc1b_intr found: memory address is 0x%08X\n",
+ .msg = "rxm_mem3_ecc1b_intr",
.reg = HGC_RXM_DFX_STATUS15,
},
};
@@ -500,70 +495,70 @@ static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
.msk = HGC_DQE_ECC_MB_ADDR_MSK,
.shift = HGC_DQE_ECC_MB_ADDR_OFF,
- .msg = "hgc_dqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+ .msg = "hgc_dqe_eccbad_intr",
.reg = HGC_DQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
.msk = HGC_IOST_ECC_MB_ADDR_MSK,
.shift = HGC_IOST_ECC_MB_ADDR_OFF,
- .msg = "hgc_iost_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+ .msg = "hgc_iost_eccbad_intr",
.reg = HGC_IOST_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
.msk = HGC_ITCT_ECC_MB_ADDR_MSK,
.shift = HGC_ITCT_ECC_MB_ADDR_OFF,
- .msg = "hgc_itct_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+ .msg = "hgc_itct_eccbad_intr",
.reg = HGC_ITCT_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
.msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
- .msg = "hgc_iostl_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "hgc_iostl_eccbad_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
.msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
.shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
- .msg = "hgc_itctl_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "hgc_itctl_eccbad_intr",
.reg = HGC_LM_DFX_STATUS2,
},
{
.irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
.msk = HGC_CQE_ECC_MB_ADDR_MSK,
.shift = HGC_CQE_ECC_MB_ADDR_OFF,
- .msg = "hgc_cqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n",
+ .msg = "hgc_cqe_eccbad_intr",
.reg = HGC_CQE_ECC_ADDR,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
- .msg = "rxm_mem0_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "rxm_mem0_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
- .msg = "rxm_mem1_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "rxm_mem1_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
.shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
- .msg = "rxm_mem2_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "rxm_mem2_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS14,
},
{
.irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
.msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
.shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
- .msg = "rxm_mem3_accbad_intr (0x%x) found: memory address is 0x%08X\n",
+ .msg = "rxm_mem3_eccbad_intr",
.reg = HGC_RXM_DFX_STATUS15,
},
};
@@ -949,7 +944,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
break;
case SAS_SATA_DEV:
case SAS_SATA_PENDING:
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ 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;
@@ -1546,14 +1541,14 @@ static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
u32 txid_auto;
- disable_phy_v2_hw(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 0);
if (phy->identify.device_type == SAS_END_DEVICE) {
txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
txid_auto | TX_HARDRST_MSK);
}
msleep(100);
- start_phy_v2_hw(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 1);
}
static void phy_get_events_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -1586,7 +1581,7 @@ static void phys_init_v2_hw(struct hisi_hba *hisi_hba)
if (!sas_phy->phy->enabled)
continue;
- start_phy_v2_hw(hisi_hba, i);
+ hisi_sas_phy_enable(hisi_hba, i, 1);
}
}
@@ -2423,14 +2418,12 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
slot_err_v2_hw(hisi_hba, task, slot, 2);
if (ts->stat != SAS_DATA_UNDERRUN)
- dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d "
- "CQ hdr: 0x%x 0x%x 0x%x 0x%x "
- "Error info: 0x%x 0x%x 0x%x 0x%x\n",
- slot->idx, task, sas_dev->device_id,
- complete_hdr->dw0, complete_hdr->dw1,
- complete_hdr->act, complete_hdr->dw3,
- error_info[0], error_info[1],
- error_info[2], error_info[3]);
+ dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n",
+ slot->idx, task, sas_dev->device_id,
+ complete_hdr->dw0, complete_hdr->dw1,
+ complete_hdr->act, complete_hdr->dw3,
+ error_info[0], error_info[1],
+ error_info[2], error_info[3]);
if (unlikely(slot->abort))
return ts->stat;
@@ -2502,7 +2495,7 @@ out:
spin_lock_irqsave(&device->done_lock, flags);
if (test_bit(SAS_HA_FROZEN, &ha->state)) {
spin_unlock_irqrestore(&device->done_lock, flags);
- dev_info(dev, "slot complete: task(%p) ignored\n ",
+ dev_info(dev, "slot complete: task(%p) ignored\n",
task);
return sts;
}
@@ -2533,7 +2526,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
/* create header */
/* dw0 */
dw0 = port->id << CMD_HDR_PORT_OFF;
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
dw0 |= 3 << CMD_HDR_CMD_OFF;
else
dw0 |= 4 << CMD_HDR_CMD_OFF;
@@ -2935,7 +2928,7 @@ static irqreturn_t int_chnl_int_v2_hw(int irq_no, void *p)
if (irq_value2 & BIT(CHL_INT2_SL_IDAF_TOUT_CONF_OFF)) {
dev_warn(dev, "phy%d identify timeout\n",
- phy_no);
+ phy_no);
hisi_sas_notify_phy_event(phy,
HISI_PHYE_LINK_RESET);
}
@@ -2980,7 +2973,8 @@ one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value)
val = hisi_sas_read32(hisi_hba, ecc_error->reg);
val &= ecc_error->msk;
val >>= ecc_error->shift;
- dev_warn(dev, ecc_error->msg, val);
+ dev_warn(dev, "%s found: mem addr is 0x%08X\n",
+ ecc_error->msg, val);
}
}
}
@@ -2999,7 +2993,8 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba,
val = hisi_sas_read32(hisi_hba, ecc_error->reg);
val &= ecc_error->msk;
val >>= ecc_error->shift;
- dev_err(dev, ecc_error->msg, irq_value, val);
+ dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n",
+ ecc_error->msg, irq_value, val);
queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
}
@@ -3036,7 +3031,7 @@ static const struct hisi_sas_hw_error axi_error[] = {
{ .msk = BIT(5), .msg = "SATA_AXI_R_ERR" },
{ .msk = BIT(6), .msg = "DQE_AXI_R_ERR" },
{ .msk = BIT(7), .msg = "CQE_AXI_W_ERR" },
- {},
+ {}
};
static const struct hisi_sas_hw_error fifo_error[] = {
@@ -3045,7 +3040,7 @@ static const struct hisi_sas_hw_error fifo_error[] = {
{ .msk = BIT(10), .msg = "GETDQE_FIFO" },
{ .msk = BIT(11), .msg = "CMDP_FIFO" },
{ .msk = BIT(12), .msg = "AWTCTRL_FIFO" },
- {},
+ {}
};
static const struct hisi_sas_hw_error fatal_axi_errors[] = {
@@ -3109,12 +3104,12 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
if (!(err_value & sub->msk))
continue;
dev_err(dev, "%s (0x%x) found!\n",
- sub->msg, irq_value);
+ sub->msg, irq_value);
queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
} else {
dev_err(dev, "%s (0x%x) found!\n",
- axi_error->msg, irq_value);
+ axi_error->msg, irq_value);
queue_work(hisi_hba->wq, &hisi_hba->rst_work);
}
}
@@ -3258,7 +3253,7 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
/* check ERR bit of Status Register */
if (fis->status & ATA_ERR) {
dev_warn(dev, "sata int: phy%d FIS status: 0x%x\n", phy_no,
- fis->status);
+ fis->status);
hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
res = IRQ_NONE;
goto end;
@@ -3349,8 +3344,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
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",
+ dev_err(dev, "irq init: could not request phy interrupt %d, rc=%d\n",
irq, rc);
rc = -ENOENT;
goto free_phy_int_irqs;
@@ -3364,8 +3358,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
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",
+ dev_err(dev, "irq init: could not request sata interrupt %d, rc=%d\n",
irq, rc);
rc = -ENOENT;
goto free_sata_int_irqs;
@@ -3377,8 +3370,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
rc = devm_request_irq(dev, irq, fatal_interrupts[fatal_no], 0,
DRV_NAME " fatal", hisi_hba);
if (rc) {
- dev_err(dev,
- "irq init: could not request fatal interrupt %d, rc=%d\n",
+ dev_err(dev, "irq init: could not request fatal interrupt %d, rc=%d\n",
irq, rc);
rc = -ENOENT;
goto free_fatal_int_irqs;
@@ -3393,8 +3385,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
DRV_NAME " cq", cq);
if (rc) {
- dev_err(dev,
- "irq init: could not request cq interrupt %d, rc=%d\n",
+ dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
irq, rc);
rc = -ENOENT;
goto free_cq_int_irqs;
@@ -3546,7 +3537,7 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type,
break;
default:
dev_err(dev, "write gpio: unsupported or bad reg type %d\n",
- reg_type);
+ reg_type);
return -EINVAL;
}
@@ -3599,6 +3590,7 @@ static struct scsi_host_template sht_v2_hw = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = host_attrs_v2_hw,
+ .host_reset = hisi_sas_host_reset,
};
static const struct hisi_sas_hw hisi_sas_v2_hw = {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 086695a4099f..5f0f6df11adf 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -1,11 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2017 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"
@@ -28,6 +23,7 @@
#define ITCT_CLR_EN_MSK (0x1 << ITCT_CLR_EN_OFF)
#define ITCT_DEV_OFF 0
#define ITCT_DEV_MSK (0x7ff << ITCT_DEV_OFF)
+#define SAS_AXI_USER3 0x50
#define IO_SATA_BROKEN_MSG_ADDR_LO 0x58
#define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c
#define SATA_INITI_D2H_STORE_ADDR_LO 0x60
@@ -52,7 +48,36 @@
#define CFG_ABT_SET_IPTT_DONE 0xd8
#define CFG_ABT_SET_IPTT_DONE_OFF 0
#define HGC_IOMB_PROC1_STATUS 0x104
+#define HGC_LM_DFX_STATUS2 0x128
+#define HGC_LM_DFX_STATUS2_IOSTLIST_OFF 0
+#define HGC_LM_DFX_STATUS2_IOSTLIST_MSK (0xfff << \
+ HGC_LM_DFX_STATUS2_IOSTLIST_OFF)
+#define HGC_LM_DFX_STATUS2_ITCTLIST_OFF 12
+#define HGC_LM_DFX_STATUS2_ITCTLIST_MSK (0x7ff << \
+ HGC_LM_DFX_STATUS2_ITCTLIST_OFF)
+#define HGC_CQE_ECC_ADDR 0x13c
+#define HGC_CQE_ECC_1B_ADDR_OFF 0
+#define HGC_CQE_ECC_1B_ADDR_MSK (0x3f << HGC_CQE_ECC_1B_ADDR_OFF)
+#define HGC_CQE_ECC_MB_ADDR_OFF 8
+#define HGC_CQE_ECC_MB_ADDR_MSK (0x3f << HGC_CQE_ECC_MB_ADDR_OFF)
+#define HGC_IOST_ECC_ADDR 0x140
+#define HGC_IOST_ECC_1B_ADDR_OFF 0
+#define HGC_IOST_ECC_1B_ADDR_MSK (0x3ff << HGC_IOST_ECC_1B_ADDR_OFF)
+#define HGC_IOST_ECC_MB_ADDR_OFF 16
+#define HGC_IOST_ECC_MB_ADDR_MSK (0x3ff << HGC_IOST_ECC_MB_ADDR_OFF)
+#define HGC_DQE_ECC_ADDR 0x144
+#define HGC_DQE_ECC_1B_ADDR_OFF 0
+#define HGC_DQE_ECC_1B_ADDR_MSK (0xfff << HGC_DQE_ECC_1B_ADDR_OFF)
+#define HGC_DQE_ECC_MB_ADDR_OFF 16
+#define HGC_DQE_ECC_MB_ADDR_MSK (0xfff << HGC_DQE_ECC_MB_ADDR_OFF)
#define CHNL_INT_STATUS 0x148
+#define HGC_ITCT_ECC_ADDR 0x150
+#define HGC_ITCT_ECC_1B_ADDR_OFF 0
+#define HGC_ITCT_ECC_1B_ADDR_MSK (0x3ff << \
+ HGC_ITCT_ECC_1B_ADDR_OFF)
+#define HGC_ITCT_ECC_MB_ADDR_OFF 16
+#define HGC_ITCT_ECC_MB_ADDR_MSK (0x3ff << \
+ HGC_ITCT_ECC_MB_ADDR_OFF)
#define HGC_AXI_FIFO_ERR_INFO 0x154
#define AXI_ERR_INFO_OFF 0
#define AXI_ERR_INFO_MSK (0xff << AXI_ERR_INFO_OFF)
@@ -81,6 +106,10 @@
#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_SRC3_ABT_OFF 16
+#define ENT_INT_SRC3_DQE_POISON_OFF 18
+#define ENT_INT_SRC3_IOST_POISON_OFF 19
+#define ENT_INT_SRC3_ITCT_POISON_OFF 20
+#define ENT_INT_SRC3_ITCT_NCQ_POISON_OFF 21
#define ENT_INT_SRC_MSK1 0x1c4
#define ENT_INT_SRC_MSK2 0x1c8
#define ENT_INT_SRC_MSK3 0x1cc
@@ -90,6 +119,28 @@
#define HGC_COM_INT_MSK 0x1d8
#define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF)
#define SAS_ECC_INTR 0x1e8
+#define SAS_ECC_INTR_DQE_ECC_1B_OFF 0
+#define SAS_ECC_INTR_DQE_ECC_MB_OFF 1
+#define SAS_ECC_INTR_IOST_ECC_1B_OFF 2
+#define SAS_ECC_INTR_IOST_ECC_MB_OFF 3
+#define SAS_ECC_INTR_ITCT_ECC_1B_OFF 4
+#define SAS_ECC_INTR_ITCT_ECC_MB_OFF 5
+#define SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF 6
+#define SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF 7
+#define SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF 8
+#define SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF 9
+#define SAS_ECC_INTR_CQE_ECC_1B_OFF 10
+#define SAS_ECC_INTR_CQE_ECC_MB_OFF 11
+#define SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF 12
+#define SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF 13
+#define SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF 14
+#define SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF 15
+#define SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF 16
+#define SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF 17
+#define SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF 18
+#define SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF 19
+#define SAS_ECC_INTR_OOO_RAM_ECC_1B_OFF 20
+#define SAS_ECC_INTR_OOO_RAM_ECC_MB_OFF 21
#define SAS_ECC_INTR_MSK 0x1ec
#define HGC_ERR_STAT_EN 0x238
#define CQE_SEND_CNT 0x248
@@ -105,6 +156,20 @@
#define COMPL_Q_0_DEPTH 0x4e8
#define COMPL_Q_0_WR_PTR 0x4ec
#define COMPL_Q_0_RD_PTR 0x4f0
+#define HGC_RXM_DFX_STATUS14 0xae8
+#define HGC_RXM_DFX_STATUS14_MEM0_OFF 0
+#define HGC_RXM_DFX_STATUS14_MEM0_MSK (0x1ff << \
+ HGC_RXM_DFX_STATUS14_MEM0_OFF)
+#define HGC_RXM_DFX_STATUS14_MEM1_OFF 9
+#define HGC_RXM_DFX_STATUS14_MEM1_MSK (0x1ff << \
+ HGC_RXM_DFX_STATUS14_MEM1_OFF)
+#define HGC_RXM_DFX_STATUS14_MEM2_OFF 18
+#define HGC_RXM_DFX_STATUS14_MEM2_MSK (0x1ff << \
+ HGC_RXM_DFX_STATUS14_MEM2_OFF)
+#define HGC_RXM_DFX_STATUS15 0xaec
+#define HGC_RXM_DFX_STATUS15_MEM3_OFF 0
+#define HGC_RXM_DFX_STATUS15_MEM3_MSK (0x1ff << \
+ HGC_RXM_DFX_STATUS15_MEM3_OFF)
#define AWQOS_AWCACHE_CFG 0xc84
#define ARQOS_ARCACHE_CFG 0xc88
#define HILINK_ERR_DFX 0xe04
@@ -172,14 +237,18 @@
#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_INT1_DMAC_TX_ECC_MB_ERR_OFF 15
+#define CHL_INT1_DMAC_TX_ECC_1B_ERR_OFF 16
+#define CHL_INT1_DMAC_RX_ECC_MB_ERR_OFF 17
+#define CHL_INT1_DMAC_RX_ECC_1B_ERR_OFF 18
#define CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF 19
#define CHL_INT1_DMAC_TX_AXI_RD_ERR_OFF 20
#define CHL_INT1_DMAC_RX_AXI_WR_ERR_OFF 21
#define CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF 22
+#define CHL_INT1_DMAC_TX_FIFO_ERR_OFF 23
+#define CHL_INT1_DMAC_RX_FIFO_ERR_OFF 24
+#define CHL_INT1_DMAC_TX_AXI_RUSER_ERR_OFF 26
+#define CHL_INT1_DMAC_RX_AXI_RUSER_ERR_OFF 27
#define CHL_INT2 (PORT_BASE + 0x1bc)
#define CHL_INT2_SL_IDAF_TOUT_CONF_OFF 0
#define CHL_INT2_RX_DISP_ERR_OFF 28
@@ -227,10 +296,8 @@
#define AM_CFG_SINGLE_PORT_MAX_TRANS (0x5014)
#define AXI_CFG (0x5100)
#define AM_ROB_ECC_ERR_ADDR (0x510c)
-#define AM_ROB_ECC_ONEBIT_ERR_ADDR_OFF 0
-#define AM_ROB_ECC_ONEBIT_ERR_ADDR_MSK (0xff << AM_ROB_ECC_ONEBIT_ERR_ADDR_OFF)
-#define AM_ROB_ECC_MULBIT_ERR_ADDR_OFF 8
-#define AM_ROB_ECC_MULBIT_ERR_ADDR_MSK (0xff << AM_ROB_ECC_MULBIT_ERR_ADDR_OFF)
+#define AM_ROB_ECC_ERR_ADDR_OFF 0
+#define AM_ROB_ECC_ERR_ADDR_MSK 0xffffffff
/* RAS registers need init */
#define RAS_BASE (0x6000)
@@ -408,6 +475,10 @@ struct hisi_sas_err_record_v3 {
#define BASE_VECTORS_V3_HW 16
#define MIN_AFFINE_VECTORS_V3_HW (BASE_VECTORS_V3_HW + 1)
+enum {
+ DSM_FUNC_ERR_HANDLE_MSI = 0,
+};
+
static bool hisi_sas_intr_conv;
MODULE_PARM_DESC(intr_conv, "interrupt converge enable (0-1)");
@@ -474,12 +545,12 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
{
- struct pci_dev *pdev = hisi_hba->pci_dev;
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, SAS_AXI_USER3, 0);
hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400);
hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
@@ -494,14 +565,11 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
hisi_sas_write32(hisi_hba, ENT_INT_SRC3, 0xffffffff);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0xfefefefe);
hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0xfefefefe);
- if (pdev->revision >= 0x21)
- hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffff7aff);
- else
- hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xfffe20ff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK3, 0xffc220ff);
hisi_sas_write32(hisi_hba, CHNL_PHYUPDOWN_INT_MSK, 0x0);
hisi_sas_write32(hisi_hba, CHNL_ENT_INT_MSK, 0x0);
hisi_sas_write32(hisi_hba, HGC_COM_INT_MSK, 0x0);
- hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0x0);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0x155555);
hisi_sas_write32(hisi_hba, AWQOS_AWCACHE_CFG, 0xf0f0);
hisi_sas_write32(hisi_hba, ARQOS_ARCACHE_CFG, 0xf0f0);
for (i = 0; i < hisi_hba->queue_count; i++)
@@ -532,12 +600,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
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);
- if (pdev->revision >= 0x21)
- hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK,
- 0xffffffff);
- else
- hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK,
- 0xff87ffff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0xf2057fff);
hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0xffffbfe);
hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0);
hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_NOT_RDY_MSK, 0x0);
@@ -691,7 +754,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
break;
case SAS_SATA_DEV:
case SAS_SATA_PENDING:
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ 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;
@@ -804,6 +867,8 @@ static int reset_hw_v3_hw(struct hisi_hba *hisi_hba)
static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
{
struct device *dev = hisi_hba->dev;
+ union acpi_object *obj;
+ guid_t guid;
int rc;
rc = reset_hw_v3_hw(hisi_hba);
@@ -815,6 +880,19 @@ static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
msleep(100);
init_reg_v3_hw(hisi_hba);
+ if (guid_parse("D5918B4B-37AE-4E10-A99F-E5E8A6EF4C1F", &guid)) {
+ dev_err(dev, "Parse GUID failed\n");
+ return -EINVAL;
+ }
+
+ /* Switch over to MSI handling , from PCI AER default */
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &guid, 0,
+ DSM_FUNC_ERR_HANDLE_MSI, NULL);
+ if (!obj)
+ dev_warn(dev, "Switch over to MSI handling failed\n");
+ else
+ ACPI_FREE(obj);
+
return 0;
}
@@ -830,8 +908,14 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
{
u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+ u32 irq_msk = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2_MSK);
+ static const u32 msk = BIT(CHL_INT2_RX_DISP_ERR_OFF) |
+ BIT(CHL_INT2_RX_CODE_ERR_OFF) |
+ BIT(CHL_INT2_RX_INVLD_DW_OFF);
u32 state;
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, msk | irq_msk);
+
cfg &= ~PHY_CFG_ENA_MSK;
hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
@@ -842,6 +926,15 @@ static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
cfg |= PHY_CFG_PHY_RST_MSK;
hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
}
+
+ udelay(1);
+
+ hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_INVLD_DW);
+ hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_DISP_ERR);
+ hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_CODE_ERR);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, msk);
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, irq_msk);
}
static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -856,14 +949,14 @@ static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
u32 txid_auto;
- disable_phy_v3_hw(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 0);
if (phy->identify.device_type == SAS_END_DEVICE) {
txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
txid_auto | TX_HARDRST_MSK);
}
msleep(100);
- start_phy_v3_hw(hisi_hba, phy_no);
+ hisi_sas_phy_enable(hisi_hba, phy_no, 1);
}
static enum sas_linkrate phy_get_max_linkrate_v3_hw(void)
@@ -882,7 +975,7 @@ static void phys_init_v3_hw(struct hisi_hba *hisi_hba)
if (!sas_phy->phy->enabled)
continue;
- start_phy_v3_hw(hisi_hba, i);
+ hisi_sas_phy_enable(hisi_hba, i, 1);
}
}
@@ -929,7 +1022,7 @@ get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
DLVRY_Q_0_RD_PTR + (queue * 0x14));
if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
dev_warn(dev, "full queue=%d r=%d w=%d\n",
- queue, r, w);
+ queue, r, w);
return -EAGAIN;
}
@@ -1260,10 +1353,10 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
u32 dw1 = 0, dw2 = 0;
hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ 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);
+ hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF);
switch (task->data_dir) {
case DMA_TO_DEVICE:
@@ -1331,7 +1424,7 @@ static void prep_abort_v3_hw(struct hisi_hba *hisi_hba,
struct hisi_sas_port *port = slot->port;
/* dw0 */
- hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
+ hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /*abort*/
(port->id << CMD_HDR_PORT_OFF) |
(dev_is_sata(dev)
<< CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
@@ -1380,6 +1473,7 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
struct hisi_sas_initial_fis *initial_fis;
struct dev_to_host_fis *fis;
u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
+ struct Scsi_Host *shost = hisi_hba->shost;
dev_info(dev, "phyup: phy%d link_rate=%d(sata)\n", phy_no, link_rate);
initial_fis = &hisi_hba->initial_fis[phy_no];
@@ -1396,6 +1490,7 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
sas_phy->oob_mode = SATA_OOB_MODE;
attached_sas_addr[0] = 0x50;
+ attached_sas_addr[6] = shost->host_no;
attached_sas_addr[7] = phy_no;
memcpy(sas_phy->attached_sas_addr,
attached_sas_addr,
@@ -1540,6 +1635,14 @@ static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p)
static const struct hisi_sas_hw_error port_axi_error[] = {
{
+ .irq_msk = BIT(CHL_INT1_DMAC_TX_ECC_MB_ERR_OFF),
+ .msg = "dmac_tx_ecc_bad_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_RX_ECC_MB_ERR_OFF),
+ .msg = "dmac_rx_ecc_bad_err",
+ },
+ {
.irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_WR_ERR_OFF),
.msg = "dma_tx_axi_wr_err",
},
@@ -1555,6 +1658,22 @@ static const struct hisi_sas_hw_error port_axi_error[] = {
.irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RD_ERR_OFF),
.msg = "dma_rx_axi_rd_err",
},
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_TX_FIFO_ERR_OFF),
+ .msg = "dma_tx_fifo_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_RX_FIFO_ERR_OFF),
+ .msg = "dma_rx_fifo_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_TX_AXI_RUSER_ERR_OFF),
+ .msg = "dma_tx_axi_ruser_err",
+ },
+ {
+ .irq_msk = BIT(CHL_INT1_DMAC_RX_AXI_RUSER_ERR_OFF),
+ .msg = "dma_rx_axi_ruser_err",
+ },
};
static void handle_chl_int1_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -1719,6 +1838,122 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
return IRQ_HANDLED;
}
+static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = {
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF),
+ .msk = HGC_DQE_ECC_MB_ADDR_MSK,
+ .shift = HGC_DQE_ECC_MB_ADDR_OFF,
+ .msg = "hgc_dqe_eccbad_intr",
+ .reg = HGC_DQE_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF),
+ .msk = HGC_IOST_ECC_MB_ADDR_MSK,
+ .shift = HGC_IOST_ECC_MB_ADDR_OFF,
+ .msg = "hgc_iost_eccbad_intr",
+ .reg = HGC_IOST_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF),
+ .msk = HGC_ITCT_ECC_MB_ADDR_MSK,
+ .shift = HGC_ITCT_ECC_MB_ADDR_OFF,
+ .msg = "hgc_itct_eccbad_intr",
+ .reg = HGC_ITCT_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF),
+ .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK,
+ .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF,
+ .msg = "hgc_iostl_eccbad_intr",
+ .reg = HGC_LM_DFX_STATUS2,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF),
+ .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK,
+ .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF,
+ .msg = "hgc_itctl_eccbad_intr",
+ .reg = HGC_LM_DFX_STATUS2,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF),
+ .msk = HGC_CQE_ECC_MB_ADDR_MSK,
+ .shift = HGC_CQE_ECC_MB_ADDR_OFF,
+ .msg = "hgc_cqe_eccbad_intr",
+ .reg = HGC_CQE_ECC_ADDR,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF,
+ .msg = "rxm_mem0_eccbad_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF,
+ .msg = "rxm_mem1_eccbad_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF),
+ .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK,
+ .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF,
+ .msg = "rxm_mem2_eccbad_intr",
+ .reg = HGC_RXM_DFX_STATUS14,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF),
+ .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK,
+ .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF,
+ .msg = "rxm_mem3_eccbad_intr",
+ .reg = HGC_RXM_DFX_STATUS15,
+ },
+ {
+ .irq_msk = BIT(SAS_ECC_INTR_OOO_RAM_ECC_MB_OFF),
+ .msk = AM_ROB_ECC_ERR_ADDR_MSK,
+ .shift = AM_ROB_ECC_ERR_ADDR_OFF,
+ .msg = "ooo_ram_eccbad_intr",
+ .reg = AM_ROB_ECC_ERR_ADDR,
+ },
+};
+
+static void multi_bit_ecc_error_process_v3_hw(struct hisi_hba *hisi_hba,
+ u32 irq_value)
+{
+ struct device *dev = hisi_hba->dev;
+ const struct hisi_sas_hw_error *ecc_error;
+ u32 val;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(multi_bit_ecc_errors); i++) {
+ ecc_error = &multi_bit_ecc_errors[i];
+ if (irq_value & ecc_error->irq_msk) {
+ val = hisi_sas_read32(hisi_hba, ecc_error->reg);
+ val &= ecc_error->msk;
+ val >>= ecc_error->shift;
+ dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n",
+ ecc_error->msg, irq_value, val);
+ queue_work(hisi_hba->wq, &hisi_hba->rst_work);
+ }
+ }
+}
+
+static void fatal_ecc_int_v3_hw(struct hisi_hba *hisi_hba)
+{
+ u32 irq_value, irq_msk;
+
+ irq_msk = hisi_sas_read32(hisi_hba, SAS_ECC_INTR_MSK);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, irq_msk | 0xffffffff);
+
+ irq_value = hisi_sas_read32(hisi_hba, SAS_ECC_INTR);
+ if (irq_value)
+ multi_bit_ecc_error_process_v3_hw(hisi_hba, irq_value);
+
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR, irq_value);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, irq_msk);
+}
+
static const struct hisi_sas_hw_error axi_error[] = {
{ .msk = BIT(0), .msg = "IOST_AXI_W_ERR" },
{ .msk = BIT(1), .msg = "IOST_AXI_R_ERR" },
@@ -1728,7 +1963,7 @@ static const struct hisi_sas_hw_error axi_error[] = {
{ .msk = BIT(5), .msg = "SATA_AXI_R_ERR" },
{ .msk = BIT(6), .msg = "DQE_AXI_R_ERR" },
{ .msk = BIT(7), .msg = "CQE_AXI_W_ERR" },
- {},
+ {}
};
static const struct hisi_sas_hw_error fifo_error[] = {
@@ -1737,7 +1972,7 @@ static const struct hisi_sas_hw_error fifo_error[] = {
{ .msk = BIT(10), .msg = "GETDQE_FIFO" },
{ .msk = BIT(11), .msg = "CMDP_FIFO" },
{ .msk = BIT(12), .msg = "AWTCTRL_FIFO" },
- {},
+ {}
};
static const struct hisi_sas_hw_error fatal_axi_error[] = {
@@ -1771,6 +2006,23 @@ static const struct hisi_sas_hw_error fatal_axi_error[] = {
.irq_msk = BIT(ENT_INT_SRC3_ABT_OFF),
.msg = "SAS_HGC_ABT fetch LM list",
},
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_DQE_POISON_OFF),
+ .msg = "read dqe poison",
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_IOST_POISON_OFF),
+ .msg = "read iost poison",
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_ITCT_POISON_OFF),
+ .msg = "read itct poison",
+ },
+ {
+ .irq_msk = BIT(ENT_INT_SRC3_ITCT_NCQ_POISON_OFF),
+ .msg = "read itct ncq poison",
+ },
+
};
static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
@@ -1823,6 +2075,8 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p)
}
}
+ fatal_ecc_int_v3_hw(hisi_hba);
+
if (irq_value & BIT(ENT_INT_SRC3_ITC_INT_OFF)) {
u32 reg_val = hisi_sas_read32(hisi_hba, ITCT_CLR);
u32 dev_id = reg_val & ITCT_DEV_MSK;
@@ -1966,13 +2220,11 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
slot_err_v3_hw(hisi_hba, task, slot);
if (ts->stat != SAS_DATA_UNDERRUN)
- dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d "
- "CQ hdr: 0x%x 0x%x 0x%x 0x%x "
- "Error info: 0x%x 0x%x 0x%x 0x%x\n",
- slot->idx, task, sas_dev->device_id,
- dw0, dw1, complete_hdr->act, dw3,
- error_info[0], error_info[1],
- error_info[2], error_info[3]);
+ dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n",
+ slot->idx, task, sas_dev->device_id,
+ dw0, dw1, complete_hdr->act, dw3,
+ error_info[0], error_info[1],
+ error_info[2], error_info[3]);
if (unlikely(slot->abort))
return ts->stat;
goto out;
@@ -2205,8 +2457,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
cq_interrupt_v3_hw, irqflags,
DRV_NAME " cq", cq);
if (rc) {
- dev_err(dev,
- "could not request cq%d interrupt, rc=%d\n",
+ dev_err(dev, "could not request cq%d interrupt, rc=%d\n",
i, rc);
rc = -ENOENT;
goto free_cq_irqs;
@@ -2362,7 +2613,7 @@ static int write_gpio_v3_hw(struct hisi_hba *hisi_hba, u8 reg_type,
break;
default:
dev_err(dev, "write gpio: unsupported or bad reg type %d\n",
- reg_type);
+ reg_type);
return -EINVAL;
}
@@ -2678,6 +2929,7 @@ static struct scsi_host_template sht_v3_hw = {
.ioctl = sas_ioctl,
.shost_attrs = host_attrs_v3_hw,
.tag_alloc_policy = BLK_TAG_ALLOC_RR,
+ .host_reset = hisi_sas_host_reset,
};
static const struct hisi_sas_hw hisi_sas_v3_hw = {
@@ -2800,7 +3052,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hisi_hba->regs = pcim_iomap(pdev, 5, 0);
if (!hisi_hba->regs) {
- dev_err(dev, "cannot map register.\n");
+ dev_err(dev, "cannot map register\n");
rc = -ENOMEM;
goto err_out_ha;
}
@@ -2921,161 +3173,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
scsi_host_put(shost);
}
-static const struct hisi_sas_hw_error sas_ras_intr0_nfe[] = {
- { .irq_msk = BIT(19), .msg = "HILINK_INT" },
- { .irq_msk = BIT(20), .msg = "HILINK_PLL0_OUT_OF_LOCK" },
- { .irq_msk = BIT(21), .msg = "HILINK_PLL1_OUT_OF_LOCK" },
- { .irq_msk = BIT(22), .msg = "HILINK_LOSS_OF_REFCLK0" },
- { .irq_msk = BIT(23), .msg = "HILINK_LOSS_OF_REFCLK1" },
- { .irq_msk = BIT(24), .msg = "DMAC0_TX_POISON" },
- { .irq_msk = BIT(25), .msg = "DMAC1_TX_POISON" },
- { .irq_msk = BIT(26), .msg = "DMAC2_TX_POISON" },
- { .irq_msk = BIT(27), .msg = "DMAC3_TX_POISON" },
- { .irq_msk = BIT(28), .msg = "DMAC4_TX_POISON" },
- { .irq_msk = BIT(29), .msg = "DMAC5_TX_POISON" },
- { .irq_msk = BIT(30), .msg = "DMAC6_TX_POISON" },
- { .irq_msk = BIT(31), .msg = "DMAC7_TX_POISON" },
-};
-
-static const struct hisi_sas_hw_error sas_ras_intr1_nfe[] = {
- { .irq_msk = BIT(0), .msg = "RXM_CFG_MEM3_ECC2B_INTR" },
- { .irq_msk = BIT(1), .msg = "RXM_CFG_MEM2_ECC2B_INTR" },
- { .irq_msk = BIT(2), .msg = "RXM_CFG_MEM1_ECC2B_INTR" },
- { .irq_msk = BIT(3), .msg = "RXM_CFG_MEM0_ECC2B_INTR" },
- { .irq_msk = BIT(4), .msg = "HGC_CQE_ECC2B_INTR" },
- { .irq_msk = BIT(5), .msg = "LM_CFG_IOSTL_ECC2B_INTR" },
- { .irq_msk = BIT(6), .msg = "LM_CFG_ITCTL_ECC2B_INTR" },
- { .irq_msk = BIT(7), .msg = "HGC_ITCT_ECC2B_INTR" },
- { .irq_msk = BIT(8), .msg = "HGC_IOST_ECC2B_INTR" },
- { .irq_msk = BIT(9), .msg = "HGC_DQE_ECC2B_INTR" },
- { .irq_msk = BIT(10), .msg = "DMAC0_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(11), .msg = "DMAC1_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(12), .msg = "DMAC2_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(13), .msg = "DMAC3_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(14), .msg = "DMAC4_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(15), .msg = "DMAC5_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(16), .msg = "DMAC6_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(17), .msg = "DMAC7_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(18), .msg = "OOO_RAM_ECC2B_INTR" },
- { .irq_msk = BIT(20), .msg = "HGC_DQE_POISON_INTR" },
- { .irq_msk = BIT(21), .msg = "HGC_IOST_POISON_INTR" },
- { .irq_msk = BIT(22), .msg = "HGC_ITCT_POISON_INTR" },
- { .irq_msk = BIT(23), .msg = "HGC_ITCT_NCQ_POISON_INTR" },
- { .irq_msk = BIT(24), .msg = "DMAC0_RX_POISON" },
- { .irq_msk = BIT(25), .msg = "DMAC1_RX_POISON" },
- { .irq_msk = BIT(26), .msg = "DMAC2_RX_POISON" },
- { .irq_msk = BIT(27), .msg = "DMAC3_RX_POISON" },
- { .irq_msk = BIT(28), .msg = "DMAC4_RX_POISON" },
- { .irq_msk = BIT(29), .msg = "DMAC5_RX_POISON" },
- { .irq_msk = BIT(30), .msg = "DMAC6_RX_POISON" },
- { .irq_msk = BIT(31), .msg = "DMAC7_RX_POISON" },
-};
-
-static const struct hisi_sas_hw_error sas_ras_intr2_nfe[] = {
- { .irq_msk = BIT(0), .msg = "DMAC0_AXI_BUS_ERR" },
- { .irq_msk = BIT(1), .msg = "DMAC1_AXI_BUS_ERR" },
- { .irq_msk = BIT(2), .msg = "DMAC2_AXI_BUS_ERR" },
- { .irq_msk = BIT(3), .msg = "DMAC3_AXI_BUS_ERR" },
- { .irq_msk = BIT(4), .msg = "DMAC4_AXI_BUS_ERR" },
- { .irq_msk = BIT(5), .msg = "DMAC5_AXI_BUS_ERR" },
- { .irq_msk = BIT(6), .msg = "DMAC6_AXI_BUS_ERR" },
- { .irq_msk = BIT(7), .msg = "DMAC7_AXI_BUS_ERR" },
- { .irq_msk = BIT(8), .msg = "DMAC0_FIFO_OMIT_ERR" },
- { .irq_msk = BIT(9), .msg = "DMAC1_FIFO_OMIT_ERR" },
- { .irq_msk = BIT(10), .msg = "DMAC2_FIFO_OMIT_ERR" },
- { .irq_msk = BIT(11), .msg = "DMAC3_FIFO_OMIT_ERR" },
- { .irq_msk = BIT(12), .msg = "DMAC4_FIFO_OMIT_ERR" },
- { .irq_msk = BIT(13), .msg = "DMAC5_FIFO_OMIT_ERR" },
- { .irq_msk = BIT(14), .msg = "DMAC6_FIFO_OMIT_ERR" },
- { .irq_msk = BIT(15), .msg = "DMAC7_FIFO_OMIT_ERR" },
- { .irq_msk = BIT(16), .msg = "HGC_RLSE_SLOT_UNMATCH" },
- { .irq_msk = BIT(17), .msg = "HGC_LM_ADD_FCH_LIST_ERR" },
- { .irq_msk = BIT(18), .msg = "HGC_AXI_BUS_ERR" },
- { .irq_msk = BIT(19), .msg = "HGC_FIFO_OMIT_ERR" },
-};
-
-static bool process_non_fatal_error_v3_hw(struct hisi_hba *hisi_hba)
-{
- struct device *dev = hisi_hba->dev;
- const struct hisi_sas_hw_error *ras_error;
- bool need_reset = false;
- u32 irq_value;
- int i;
-
- irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR0);
- for (i = 0; i < ARRAY_SIZE(sas_ras_intr0_nfe); i++) {
- ras_error = &sas_ras_intr0_nfe[i];
- if (ras_error->irq_msk & irq_value) {
- dev_warn(dev, "SAS_RAS_INTR0: %s(irq_value=0x%x) found.\n",
- ras_error->msg, irq_value);
- need_reset = true;
- }
- }
- hisi_sas_write32(hisi_hba, SAS_RAS_INTR0, irq_value);
-
- irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR1);
- for (i = 0; i < ARRAY_SIZE(sas_ras_intr1_nfe); i++) {
- ras_error = &sas_ras_intr1_nfe[i];
- if (ras_error->irq_msk & irq_value) {
- dev_warn(dev, "SAS_RAS_INTR1: %s(irq_value=0x%x) found.\n",
- ras_error->msg, irq_value);
- need_reset = true;
- }
- }
- hisi_sas_write32(hisi_hba, SAS_RAS_INTR1, irq_value);
-
- irq_value = hisi_sas_read32(hisi_hba, SAS_RAS_INTR2);
- for (i = 0; i < ARRAY_SIZE(sas_ras_intr2_nfe); i++) {
- ras_error = &sas_ras_intr2_nfe[i];
- if (ras_error->irq_msk & irq_value) {
- dev_warn(dev, "SAS_RAS_INTR2: %s(irq_value=0x%x) found.\n",
- ras_error->msg, irq_value);
- need_reset = true;
- }
- }
- hisi_sas_write32(hisi_hba, SAS_RAS_INTR2, irq_value);
-
- return need_reset;
-}
-
-static pci_ers_result_t hisi_sas_error_detected_v3_hw(struct pci_dev *pdev,
- pci_channel_state_t state)
-{
- struct sas_ha_struct *sha = pci_get_drvdata(pdev);
- struct hisi_hba *hisi_hba = sha->lldd_ha;
- struct device *dev = hisi_hba->dev;
-
- dev_info(dev, "PCI error: detected callback, state(%d)!!\n", state);
- if (state == pci_channel_io_perm_failure)
- return PCI_ERS_RESULT_DISCONNECT;
-
- if (process_non_fatal_error_v3_hw(hisi_hba))
- return PCI_ERS_RESULT_NEED_RESET;
-
- return PCI_ERS_RESULT_CAN_RECOVER;
-}
-
-static pci_ers_result_t hisi_sas_mmio_enabled_v3_hw(struct pci_dev *pdev)
-{
- return PCI_ERS_RESULT_RECOVERED;
-}
-
-static pci_ers_result_t hisi_sas_slot_reset_v3_hw(struct pci_dev *pdev)
-{
- struct sas_ha_struct *sha = pci_get_drvdata(pdev);
- struct hisi_hba *hisi_hba = sha->lldd_ha;
- struct device *dev = hisi_hba->dev;
- HISI_SAS_DECLARE_RST_WORK_ON_STACK(r);
-
- dev_info(dev, "PCI error: slot reset callback!!\n");
- queue_work(hisi_hba->wq, &r.work);
- wait_for_completion(r.completion);
- if (r.done)
- return PCI_ERS_RESULT_RECOVERED;
-
- return PCI_ERS_RESULT_DISCONNECT;
-}
-
static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev)
{
struct sas_ha_struct *sha = pci_get_drvdata(pdev);
@@ -3171,7 +3268,7 @@ static int hisi_sas_v3_resume(struct pci_dev *pdev)
pci_power_t device_state = pdev->current_state;
dev_warn(dev, "resuming from operating state [D%d]\n",
- device_state);
+ device_state);
pci_set_power_state(pdev, PCI_D0);
pci_enable_wake(pdev, PCI_D0, 0);
pci_restore_state(pdev);
@@ -3199,9 +3296,6 @@ static const struct pci_device_id sas_v3_pci_table[] = {
MODULE_DEVICE_TABLE(pci, sas_v3_pci_table);
static const struct pci_error_handlers hisi_sas_err_handler = {
- .error_detected = hisi_sas_error_detected_v3_hw,
- .mmio_enabled = hisi_sas_mmio_enabled_v3_hw,
- .slot_reset = hisi_sas_slot_reset_v3_hw,
.reset_prepare = hisi_sas_reset_prepare_v3_hw,
.reset_done = hisi_sas_reset_done_v3_hw,
};
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index eaf329db3973..ff0d8c6a8d0c 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* hosts.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995 Eric Youngdale
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index f044e7d10d63..43a6b5350775 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -60,7 +60,7 @@
* 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.20-125"
+#define HPSA_DRIVER_VERSION "3.4.20-170"
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
#define HPSA "hpsa"
@@ -73,6 +73,8 @@
/*define how many times we will try a command because of bus resets */
#define MAX_CMD_RETRIES 3
+/* How long to wait before giving up on a command */
+#define HPSA_EH_PTRAID_TIMEOUT (240 * HZ)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Hewlett-Packard Company");
@@ -344,11 +346,6 @@ static inline bool hpsa_is_cmd_idle(struct CommandList *c)
return c->scsi_cmd == SCSI_CMD_IDLE;
}
-static inline bool hpsa_is_pending_event(struct CommandList *c)
-{
- return c->reset_pending;
-}
-
/* extract sense key, asc, and ascq from sense data. -1 means invalid. */
static void decode_sense_data(const u8 *sense_data, int sense_data_len,
u8 *sense_key, u8 *asc, u8 *ascq)
@@ -1144,6 +1141,8 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
{
dial_down_lockup_detection_during_fw_flash(h, c);
atomic_inc(&h->commands_outstanding);
+ if (c->device)
+ atomic_inc(&c->device->commands_outstanding);
reply_queue = h->reply_map[raw_smp_processor_id()];
switch (c->cmd_type) {
@@ -1167,9 +1166,6 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c)
{
- if (unlikely(hpsa_is_pending_event(c)))
- return finish_cmd(c);
-
__enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE);
}
@@ -1842,25 +1838,33 @@ static int hpsa_find_outstanding_commands_for_dev(struct ctlr_info *h,
return count;
}
+#define NUM_WAIT 20
static void hpsa_wait_for_outstanding_commands_for_dev(struct ctlr_info *h,
struct hpsa_scsi_dev_t *device)
{
int cmds = 0;
int waits = 0;
+ int num_wait = NUM_WAIT;
+
+ if (device->external)
+ num_wait = HPSA_EH_PTRAID_TIMEOUT;
while (1) {
cmds = hpsa_find_outstanding_commands_for_dev(h, device);
if (cmds == 0)
break;
- if (++waits > 20)
+ if (++waits > num_wait)
break;
msleep(1000);
}
- if (waits > 20)
+ if (waits > num_wait) {
dev_warn(&h->pdev->dev,
- "%s: removing device with %d outstanding commands!\n",
- __func__, cmds);
+ "%s: removing device [%d:%d:%d:%d] with %d outstanding commands!\n",
+ __func__,
+ h->scsi_host->host_no,
+ device->bus, device->target, device->lun, cmds);
+ }
}
static void hpsa_remove_device(struct ctlr_info *h,
@@ -2131,11 +2135,16 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
sdev->no_uld_attach = !sd || !sd->expose_device;
if (sd) {
- if (sd->external)
+ sd->was_removed = 0;
+ if (sd->external) {
queue_depth = EXTERNAL_QD;
- else
+ sdev->eh_timeout = HPSA_EH_PTRAID_TIMEOUT;
+ blk_queue_rq_timeout(sdev->request_queue,
+ HPSA_EH_PTRAID_TIMEOUT);
+ } else {
queue_depth = sd->queue_depth != 0 ?
sd->queue_depth : sdev->host->can_queue;
+ }
} else
queue_depth = sdev->host->can_queue;
@@ -2146,7 +2155,12 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
static void hpsa_slave_destroy(struct scsi_device *sdev)
{
- /* nothing to do. */
+ struct hpsa_scsi_dev_t *hdev = NULL;
+
+ hdev = sdev->hostdata;
+
+ if (hdev)
+ hdev->was_removed = 1;
}
static void hpsa_free_ioaccel2_sg_chain_blocks(struct ctlr_info *h)
@@ -2414,13 +2428,16 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h,
break;
}
+ if (dev->in_reset)
+ retry = 0;
+
return retry; /* retry on raid path? */
}
static void hpsa_cmd_resolve_events(struct ctlr_info *h,
struct CommandList *c)
{
- bool do_wake = false;
+ struct hpsa_scsi_dev_t *dev = c->device;
/*
* Reset c->scsi_cmd here so that the reset handler will know
@@ -2429,25 +2446,12 @@ static void hpsa_cmd_resolve_events(struct ctlr_info *h,
*/
c->scsi_cmd = SCSI_CMD_IDLE;
mb(); /* Declare command idle before checking for pending events. */
- if (c->reset_pending) {
- unsigned long flags;
- struct hpsa_scsi_dev_t *dev;
-
- /*
- * There appears to be a reset pending; lock the lock and
- * reconfirm. If so, then decrement the count of outstanding
- * commands and wake the reset command if this is the last one.
- */
- spin_lock_irqsave(&h->lock, flags);
- dev = c->reset_pending; /* Re-fetch under the lock. */
- if (dev && atomic_dec_and_test(&dev->reset_cmds_out))
- do_wake = true;
- c->reset_pending = NULL;
- spin_unlock_irqrestore(&h->lock, flags);
+ if (dev) {
+ atomic_dec(&dev->commands_outstanding);
+ if (dev->in_reset &&
+ atomic_read(&dev->commands_outstanding) <= 0)
+ wake_up_all(&h->event_sync_wait_queue);
}
-
- if (do_wake)
- wake_up_all(&h->event_sync_wait_queue);
}
static void hpsa_cmd_resolve_and_free(struct ctlr_info *h,
@@ -2496,6 +2500,11 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
dev->offload_to_be_enabled = 0;
}
+ if (dev->in_reset) {
+ cmd->result = DID_RESET << 16;
+ return hpsa_cmd_free_and_done(h, c, cmd);
+ }
+
return hpsa_retry_cmd(h, c);
}
@@ -2574,6 +2583,12 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+ /* SCSI command has already been cleaned up in SML */
+ if (dev->was_removed) {
+ hpsa_cmd_resolve_and_free(h, cp);
+ return;
+ }
+
if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) {
if (dev->physical_device && dev->expose_device &&
dev->removed) {
@@ -2595,10 +2610,6 @@ static void complete_scsi_command(struct CommandList *cp)
return hpsa_cmd_free_and_done(h, cp, cmd);
}
- if ((unlikely(hpsa_is_pending_event(cp))))
- if (cp->reset_pending)
- return hpsa_cmd_free_and_done(h, cp, cmd);
-
if (cp->cmd_type == CMD_IOACCEL2)
return process_ioaccel2_completion(h, cp, cmd, dev);
@@ -2647,9 +2658,20 @@ static void complete_scsi_command(struct CommandList *cp)
decode_sense_data(ei->SenseInfo, sense_data_size,
&sense_key, &asc, &ascq);
if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) {
- if (sense_key == ABORTED_COMMAND) {
+ switch (sense_key) {
+ case ABORTED_COMMAND:
cmd->result |= DID_SOFT_ERROR << 16;
break;
+ case UNIT_ATTENTION:
+ if (asc == 0x3F && ascq == 0x0E)
+ h->drv_req_rescan = 1;
+ break;
+ case ILLEGAL_REQUEST:
+ if (asc == 0x25 && ascq == 0x00) {
+ dev->removed = 1;
+ cmd->result = DID_NO_CONNECT << 16;
+ }
+ break;
}
break;
}
@@ -3037,7 +3059,7 @@ out:
return rc;
}
-static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
+static int hpsa_send_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
u8 reset_type, int reply_queue)
{
int rc = IO_OK;
@@ -3045,11 +3067,10 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
struct ErrorInfo *ei;
c = cmd_alloc(h);
-
+ c->device = dev;
/* fill_cmd can't fail here, no data buffer to map. */
- (void) fill_cmd(c, reset_type, h, NULL, 0, 0,
- scsi3addr, TYPE_MSG);
+ (void) fill_cmd(c, reset_type, h, NULL, 0, 0, dev->scsi3addr, TYPE_MSG);
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");
@@ -3127,9 +3148,8 @@ static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
}
static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
- unsigned char *scsi3addr, u8 reset_type, int reply_queue)
+ u8 reset_type, int reply_queue)
{
- int i;
int rc = 0;
/* We can really only handle one reset at a time */
@@ -3138,38 +3158,14 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
return -EINTR;
}
- BUG_ON(atomic_read(&dev->reset_cmds_out) != 0);
-
- for (i = 0; i < h->nr_cmds; i++) {
- struct CommandList *c = h->cmd_pool + i;
- int refcount = atomic_inc_return(&c->refcount);
-
- if (refcount > 1 && hpsa_cmd_dev_match(h, c, dev, scsi3addr)) {
- unsigned long flags;
-
- /*
- * Mark the target command as having a reset pending,
- * then lock a lock so that the command cannot complete
- * while we're considering it. If the command is not
- * idle then count it; otherwise revoke the event.
- */
- c->reset_pending = dev;
- spin_lock_irqsave(&h->lock, flags); /* Implied MB */
- if (!hpsa_is_cmd_idle(c))
- atomic_inc(&dev->reset_cmds_out);
- else
- c->reset_pending = NULL;
- spin_unlock_irqrestore(&h->lock, flags);
- }
-
- cmd_free(h, c);
- }
-
- rc = hpsa_send_reset(h, scsi3addr, reset_type, reply_queue);
- if (!rc)
+ rc = hpsa_send_reset(h, dev, reset_type, reply_queue);
+ if (!rc) {
+ /* incremented by sending the reset request */
+ atomic_dec(&dev->commands_outstanding);
wait_event(h->event_sync_wait_queue,
- atomic_read(&dev->reset_cmds_out) == 0 ||
+ atomic_read(&dev->commands_outstanding) <= 0 ||
lockup_detected(h));
+ }
if (unlikely(lockup_detected(h))) {
dev_warn(&h->pdev->dev,
@@ -3177,10 +3173,8 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
rc = -ENODEV;
}
- if (unlikely(rc))
- atomic_set(&dev->reset_cmds_out, 0);
- else
- rc = wait_for_device_to_become_ready(h, scsi3addr, 0);
+ if (!rc)
+ rc = wait_for_device_to_become_ready(h, dev->scsi3addr, 0);
mutex_unlock(&h->reset_mutex);
return rc;
@@ -3956,14 +3950,18 @@ static int hpsa_update_device_info(struct ctlr_info *h,
memset(this_device->device_id, 0,
sizeof(this_device->device_id));
if (hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
- sizeof(this_device->device_id)) < 0)
+ sizeof(this_device->device_id)) < 0) {
dev_err(&h->pdev->dev,
- "hpsa%d: %s: can't get device id for host %d:C0:T%d:L%d\t%s\t%.16s\n",
+ "hpsa%d: %s: can't get device id for [%d:%d:%d:%d]\t%s\t%.16s\n",
h->ctlr, __func__,
h->scsi_host->host_no,
- this_device->target, this_device->lun,
+ this_device->bus, this_device->target,
+ this_device->lun,
scsi_device_type(this_device->devtype),
this_device->model);
+ rc = HPSA_LV_FAILED;
+ goto bail_out;
+ }
if ((this_device->devtype == TYPE_DISK ||
this_device->devtype == TYPE_ZBC) &&
@@ -4805,6 +4803,9 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
c->phys_disk = dev;
+ if (dev->in_reset)
+ return -1;
+
return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev);
}
@@ -4925,7 +4926,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
curr_sg->reserved[0] = 0;
curr_sg->reserved[1] = 0;
curr_sg->reserved[2] = 0;
- curr_sg->chain_indicator = 0x80;
+ curr_sg->chain_indicator = IOACCEL2_CHAIN;
curr_sg = h->ioaccel2_cmd_sg_list[c->cmdindex];
}
@@ -4942,6 +4943,11 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
curr_sg++;
}
+ /*
+ * Set the last s/g element bit
+ */
+ (curr_sg - 1)->chain_indicator = IOACCEL2_LAST_SG;
+
switch (cmd->sc_data_direction) {
case DMA_TO_DEVICE:
cp->direction &= ~IOACCEL2_DIRECTION_MASK;
@@ -4990,6 +4996,11 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
} else
cp->sg_count = (u8) use_sg;
+ if (phys_disk->in_reset) {
+ cmd->result = DID_RESET << 16;
+ return -1;
+ }
+
enqueue_cmd_and_start_io(h, c);
return 0;
}
@@ -5007,6 +5018,9 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
if (!c->scsi_cmd->device->hostdata)
return -1;
+ if (phys_disk->in_reset)
+ return -1;
+
/* Try to honor the device's queue depth */
if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) >
phys_disk->queue_depth) {
@@ -5090,6 +5104,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
if (!dev)
return -1;
+ if (dev->in_reset)
+ return -1;
+
/* check for valid opcode, get LBA and block count */
switch (cmd->cmnd[0]) {
case WRITE_6:
@@ -5394,13 +5411,13 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
*/
static int hpsa_ciss_submit(struct ctlr_info *h,
struct CommandList *c, struct scsi_cmnd *cmd,
- unsigned char scsi3addr[])
+ struct hpsa_scsi_dev_t *dev)
{
cmd->host_scribble = (unsigned char *) c;
c->cmd_type = CMD_SCSI;
c->scsi_cmd = cmd;
c->Header.ReplyQueue = 0; /* unused in simple mode */
- memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
+ memcpy(&c->Header.LUN.LunAddrBytes[0], &dev->scsi3addr[0], 8);
c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT));
/* Fill in the request block... */
@@ -5451,6 +5468,12 @@ static int hpsa_ciss_submit(struct ctlr_info *h,
hpsa_cmd_resolve_and_free(h, c);
return SCSI_MLQUEUE_HOST_BUSY;
}
+
+ if (dev->in_reset) {
+ hpsa_cmd_resolve_and_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
enqueue_cmd_and_start_io(h, c);
/* the cmd'll come back via intr handler in complete_scsi_command() */
return 0;
@@ -5502,8 +5525,7 @@ static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index,
}
static int hpsa_ioaccel_submit(struct ctlr_info *h,
- struct CommandList *c, struct scsi_cmnd *cmd,
- unsigned char *scsi3addr)
+ struct CommandList *c, struct scsi_cmnd *cmd)
{
struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
int rc = IO_ACCEL_INELIGIBLE;
@@ -5511,6 +5533,12 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h,
if (!dev)
return SCSI_MLQUEUE_HOST_BUSY;
+ if (dev->in_reset)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ if (hpsa_simple_mode)
+ return IO_ACCEL_INELIGIBLE;
+
cmd->host_scribble = (unsigned char *) c;
if (dev->offload_enabled) {
@@ -5543,8 +5571,12 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
cmd->result = DID_NO_CONNECT << 16;
return hpsa_cmd_free_and_done(c->h, c, cmd);
}
- if (c->reset_pending)
+
+ if (dev->in_reset) {
+ cmd->result = DID_RESET << 16;
return hpsa_cmd_free_and_done(c->h, c, cmd);
+ }
+
if (c->cmd_type == CMD_IOACCEL2) {
struct ctlr_info *h = c->h;
struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
@@ -5552,7 +5584,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
if (c2->error_data.serv_response ==
IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) {
- rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr);
+ rc = hpsa_ioaccel_submit(h, c, cmd);
if (rc == 0)
return;
if (rc == SCSI_MLQUEUE_HOST_BUSY) {
@@ -5568,7 +5600,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
}
}
hpsa_cmd_partial_init(c->h, c->cmdindex, c);
- if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) {
+ if (hpsa_ciss_submit(c->h, c, cmd, dev)) {
/*
* If we get here, it means dma mapping failed. Try
* again via scsi mid layer, which will then get
@@ -5587,7 +5619,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
{
struct ctlr_info *h;
struct hpsa_scsi_dev_t *dev;
- unsigned char scsi3addr[8];
struct CommandList *c;
int rc = 0;
@@ -5609,14 +5640,18 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
return 0;
}
- memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
-
if (unlikely(lockup_detected(h))) {
cmd->result = DID_NO_CONNECT << 16;
cmd->scsi_done(cmd);
return 0;
}
+
+ if (dev->in_reset)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+
c = cmd_tagged_alloc(h, cmd);
+ if (c == NULL)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
/*
* Call alternate submit routine for I/O accelerated commands.
@@ -5625,7 +5660,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
if (likely(cmd->retries == 0 &&
!blk_rq_is_passthrough(cmd->request) &&
h->acciopath_status)) {
- rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr);
+ rc = hpsa_ioaccel_submit(h, c, cmd);
if (rc == 0)
return 0;
if (rc == SCSI_MLQUEUE_HOST_BUSY) {
@@ -5633,7 +5668,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
return SCSI_MLQUEUE_HOST_BUSY;
}
}
- return hpsa_ciss_submit(h, c, cmd, scsi3addr);
+ return hpsa_ciss_submit(h, c, cmd, dev);
}
static void hpsa_scan_complete(struct ctlr_info *h)
@@ -5809,7 +5844,7 @@ static int hpsa_send_test_unit_ready(struct ctlr_info *h,
/* Send the Test Unit Ready, fill_cmd can't fail, no mapping */
(void) fill_cmd(c, TEST_UNIT_READY, h,
NULL, 0, 0, lunaddr, TYPE_CMD);
- rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, DEFAULT_TIMEOUT);
+ rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT);
if (rc)
return rc;
/* no unmap needed here because no data xfer. */
@@ -5915,8 +5950,9 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
{
int rc = SUCCESS;
+ int i;
struct ctlr_info *h;
- struct hpsa_scsi_dev_t *dev;
+ struct hpsa_scsi_dev_t *dev = NULL;
u8 reset_type;
char msg[48];
unsigned long flags;
@@ -5982,9 +6018,19 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ");
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
+ /*
+ * wait to see if any commands will complete before sending reset
+ */
+ dev->in_reset = true; /* block any new cmds from OS for this device */
+ for (i = 0; i < 10; i++) {
+ if (atomic_read(&dev->commands_outstanding) > 0)
+ msleep(1000);
+ else
+ break;
+ }
+
/* send a reset to the SCSI LUN which the command was sent to */
- rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type,
- DEFAULT_REPLY_QUEUE);
+ rc = hpsa_do_reset(h, dev, reset_type, DEFAULT_REPLY_QUEUE);
if (rc == 0)
rc = SUCCESS;
else
@@ -5998,6 +6044,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
return_reset_status:
spin_lock_irqsave(&h->reset_lock, flags);
h->reset_in_progress = 0;
+ if (dev)
+ dev->in_reset = false;
spin_unlock_irqrestore(&h->reset_lock, flags);
return rc;
}
@@ -6023,7 +6071,6 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
BUG();
}
- atomic_inc(&c->refcount);
if (unlikely(!hpsa_is_cmd_idle(c))) {
/*
* We expect that the SCSI layer will hand us a unique tag
@@ -6031,14 +6078,20 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
* two requests...because if the selected command isn't idle
* then someone is going to be very disappointed.
*/
- dev_err(&h->pdev->dev,
- "tag collision (tag=%d) in cmd_tagged_alloc().\n",
- idx);
- if (c->scsi_cmd != NULL)
- scsi_print_command(c->scsi_cmd);
- scsi_print_command(scmd);
+ if (idx != h->last_collision_tag) { /* Print once per tag */
+ dev_warn(&h->pdev->dev,
+ "%s: tag collision (tag=%d)\n", __func__, idx);
+ if (c->scsi_cmd != NULL)
+ scsi_print_command(c->scsi_cmd);
+ if (scmd)
+ scsi_print_command(scmd);
+ h->last_collision_tag = idx;
+ }
+ return NULL;
}
+ atomic_inc(&c->refcount);
+
hpsa_cmd_partial_init(h, idx, c);
return c;
}
@@ -6106,6 +6159,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
break; /* it's ours now. */
}
hpsa_cmd_partial_init(h, i, c);
+ c->device = NULL;
return c;
}
@@ -6559,8 +6613,7 @@ static int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd,
}
}
-static void hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
- u8 reset_type)
+static void hpsa_send_host_reset(struct ctlr_info *h, u8 reset_type)
{
struct CommandList *c;
@@ -7745,7 +7798,7 @@ static void hpsa_free_pci_init(struct ctlr_info *h)
hpsa_disable_interrupt_mode(h); /* pci_init 2 */
/*
* call pci_disable_device before pci_release_regions per
- * Documentation/PCI/pci.txt
+ * Documentation/PCI/pci.rst
*/
pci_disable_device(h->pdev); /* pci_init 1 */
pci_release_regions(h->pdev); /* pci_init 2 */
@@ -7828,7 +7881,7 @@ clean2: /* intmode+region, pci */
clean1:
/*
* call pci_disable_device before pci_release_regions per
- * Documentation/PCI/pci.txt
+ * Documentation/PCI/pci.rst
*/
pci_disable_device(h->pdev);
pci_release_regions(h->pdev);
@@ -7963,10 +8016,15 @@ clean_up:
static void hpsa_free_irqs(struct ctlr_info *h)
{
int i;
+ int irq_vector = 0;
+
+ if (hpsa_simple_mode)
+ irq_vector = h->intr_mode;
if (!h->msix_vectors || h->intr_mode != PERF_MODE_INT) {
/* Single reply queue, only one irq to free */
- free_irq(pci_irq_vector(h->pdev, 0), &h->q[h->intr_mode]);
+ free_irq(pci_irq_vector(h->pdev, irq_vector),
+ &h->q[h->intr_mode]);
h->q[h->intr_mode] = 0;
return;
}
@@ -7985,6 +8043,10 @@ static int hpsa_request_irqs(struct ctlr_info *h,
irqreturn_t (*intxhandler)(int, void *))
{
int rc, i;
+ int irq_vector = 0;
+
+ if (hpsa_simple_mode)
+ irq_vector = h->intr_mode;
/*
* initialize h->q[x] = x so that interrupt handlers know which
@@ -8020,14 +8082,14 @@ static int hpsa_request_irqs(struct ctlr_info *h,
if (h->msix_vectors > 0 || h->pdev->msi_enabled) {
sprintf(h->intrname[0], "%s-msi%s", h->devname,
h->msix_vectors ? "x" : "");
- rc = request_irq(pci_irq_vector(h->pdev, 0),
+ rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
msixhandler, 0,
h->intrname[0],
&h->q[h->intr_mode]);
} else {
sprintf(h->intrname[h->intr_mode],
"%s-intx", h->devname);
- rc = request_irq(pci_irq_vector(h->pdev, 0),
+ rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
intxhandler, IRQF_SHARED,
h->intrname[0],
&h->q[h->intr_mode]);
@@ -8035,7 +8097,7 @@ static int hpsa_request_irqs(struct ctlr_info *h,
}
if (rc) {
dev_err(&h->pdev->dev, "failed to get irq %d for %s\n",
- pci_irq_vector(h->pdev, 0), h->devname);
+ pci_irq_vector(h->pdev, irq_vector), h->devname);
hpsa_free_irqs(h);
return -ENODEV;
}
@@ -8045,7 +8107,7 @@ static int hpsa_request_irqs(struct ctlr_info *h,
static int hpsa_kdump_soft_reset(struct ctlr_info *h)
{
int rc;
- hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER);
+ hpsa_send_host_reset(h, HPSA_RESET_TYPE_CONTROLLER);
dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY);
@@ -8101,6 +8163,11 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
destroy_workqueue(h->rescan_ctlr_wq);
h->rescan_ctlr_wq = NULL;
}
+ if (h->monitor_ctlr_wq) {
+ destroy_workqueue(h->monitor_ctlr_wq);
+ h->monitor_ctlr_wq = NULL;
+ }
+
kfree(h); /* init_one 1 */
}
@@ -8436,8 +8503,8 @@ static void hpsa_event_monitor_worker(struct work_struct *work)
spin_lock_irqsave(&h->lock, flags);
if (!h->remove_in_progress)
- schedule_delayed_work(&h->event_monitor_work,
- HPSA_EVENT_MONITOR_INTERVAL);
+ queue_delayed_work(h->monitor_ctlr_wq, &h->event_monitor_work,
+ HPSA_EVENT_MONITOR_INTERVAL);
spin_unlock_irqrestore(&h->lock, flags);
}
@@ -8482,7 +8549,7 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work)
spin_lock_irqsave(&h->lock, flags);
if (!h->remove_in_progress)
- schedule_delayed_work(&h->monitor_ctlr_work,
+ queue_delayed_work(h->monitor_ctlr_wq, &h->monitor_ctlr_work,
h->heartbeat_sample_interval);
spin_unlock_irqrestore(&h->lock, flags);
}
@@ -8650,6 +8717,12 @@ reinit_after_soft_reset:
goto clean7; /* aer/h */
}
+ h->monitor_ctlr_wq = hpsa_create_controller_wq(h, "monitor");
+ if (!h->monitor_ctlr_wq) {
+ rc = -ENOMEM;
+ goto clean7;
+ }
+
/*
* At this point, the controller is ready to take commands.
* Now, if reset_devices and the hard reset didn't work, try
@@ -8779,6 +8852,10 @@ clean1: /* wq/aer/h */
destroy_workqueue(h->rescan_ctlr_wq);
h->rescan_ctlr_wq = NULL;
}
+ if (h->monitor_ctlr_wq) {
+ destroy_workqueue(h->monitor_ctlr_wq);
+ h->monitor_ctlr_wq = NULL;
+ }
kfree(h);
return rc;
}
@@ -8926,6 +9003,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
cancel_delayed_work_sync(&h->event_monitor_work);
destroy_workqueue(h->rescan_ctlr_wq);
destroy_workqueue(h->resubmit_wq);
+ destroy_workqueue(h->monitor_ctlr_wq);
hpsa_delete_sas_host(h);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 59e023696fff..f8c88fc7b80a 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -65,6 +65,7 @@ struct hpsa_scsi_dev_t {
u8 physical_device : 1;
u8 expose_device;
u8 removed : 1; /* device is marked for death */
+ u8 was_removed : 1; /* device actually removed */
#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0"
unsigned char device_id[16]; /* from inquiry pg. 0x83 */
u64 sas_address;
@@ -75,11 +76,12 @@ struct hpsa_scsi_dev_t {
unsigned char raid_level; /* from inquiry page 0xC1 */
unsigned char volume_offline; /* discovered via TUR or VPD */
u16 queue_depth; /* max queue_depth for this device */
- atomic_t reset_cmds_out; /* Count of commands to-be affected */
+ atomic_t commands_outstanding; /* track commands sent to device */
atomic_t ioaccel_cmds_out; /* Only used for physical devices
* counts commands sent to physical
* device via "ioaccel" path.
*/
+ bool in_reset;
u32 ioaccel_handle;
u8 active_path_index;
u8 path_map;
@@ -174,6 +176,7 @@ struct ctlr_info {
struct CfgTable __iomem *cfgtable;
int interrupts_enabled;
int max_commands;
+ int last_collision_tag; /* tags are global */
atomic_t commands_outstanding;
# define PERF_MODE_INT 0
# define DOORBELL_INT 1
@@ -300,6 +303,7 @@ struct ctlr_info {
int needs_abort_tags_swizzled;
struct workqueue_struct *resubmit_wq;
struct workqueue_struct *rescan_ctlr_wq;
+ struct workqueue_struct *monitor_ctlr_wq;
atomic_t abort_cmds_available;
wait_queue_head_t event_sync_wait_queue;
struct mutex reset_mutex;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 21a726e2eec6..7825cbfea4dc 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -448,7 +448,7 @@ struct CommandList {
struct hpsa_scsi_dev_t *phys_disk;
int abort_pending;
- struct hpsa_scsi_dev_t *reset_pending;
+ struct hpsa_scsi_dev_t *device;
atomic_t refcount; /* Must be last to avoid memset in hpsa_cmd_init() */
} __aligned(COMMANDLIST_ALIGNMENT);
@@ -517,6 +517,7 @@ struct ioaccel2_sg_element {
u8 reserved[3];
u8 chain_indicator;
#define IOACCEL2_CHAIN 0x80
+#define IOACCEL2_LAST_SG 0x40
};
/*
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 251c084a6ff0..6a2561f26e38 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HighPoint RR3xxx/4xxx controller driver for Linux
* Copyright (C) 2006-2015 HighPoint Technologies, Inc. All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * 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.
- *
* Please report bugs/comments/suggestions to linux@highpoint-tech.com
*
* For more information, visit http://www.highpoint-tech.com
diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
index 4d1c51153b70..35184c2008af 100644
--- a/drivers/scsi/hptiop.h
+++ b/drivers/scsi/hptiop.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* HighPoint RR3xxx/4xxx controller driver for Linux
* Copyright (C) 2006-2015 HighPoint Technologies, Inc. All Rights Reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * 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.
- *
* Please report bugs/comments/suggestions to linux@highpoint-tech.com
*
* For more information, visit http://www.highpoint-tech.com
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index 3840c64f2966..5eb1cb1a0028 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,2 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi.o
obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 3ad997ac3510..acd16e0d52cf 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ibmvfc.c -- driver for IBM Power Virtual Fibre Channel Adapter
*
* Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) IBM Corporation, 2008
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/module.h>
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 459cc288ba1d..7da89f4d26b2 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -1,24 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ibmvfc.h -- driver for IBM Power Virtual Fibre Channel Adapter
*
* Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation
*
* Copyright (C) IBM Corporation, 2008
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#ifndef _IBMVFC_H
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 8cec5230fe31..7f66a7783209 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* ------------------------------------------------------------
* ibmvscsi.c
* (C) Copyright IBM Corporation 1994, 2004
@@ -5,21 +6,6 @@
* Santiago Leon (santil@us.ibm.com)
* Dave Boutcher (sleddog@us.ibm.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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
* ------------------------------------------------------------
* Emulation of a SCSI host adapter for Virtual I/O devices
*
@@ -828,7 +814,7 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
atomic_set(&hostdata->request_limit, 0);
purge_requests(hostdata, DID_ERROR);
- hostdata->reset_crq = 1;
+ hostdata->action = IBMVSCSI_HOST_ACTION_RESET;
wake_up(&hostdata->work_wait_q);
}
@@ -1179,7 +1165,8 @@ static void login_rsp(struct srp_event_struct *evt_struct)
be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta));
/* If we had any pending I/Os, kick them */
- scsi_unblock_requests(hostdata->host);
+ hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK;
+ wake_up(&hostdata->work_wait_q);
}
/**
@@ -1797,7 +1784,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
/* We need to re-setup the interpartition connection */
dev_info(hostdata->dev, "Re-enabling adapter!\n");
hostdata->client_migrated = 1;
- hostdata->reenable_crq = 1;
+ hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE;
purge_requests(hostdata, DID_REQUEUE);
wake_up(&hostdata->work_wait_q);
} else {
@@ -2050,6 +2037,16 @@ static struct device_attribute ibmvscsi_host_config = {
.show = show_host_config,
};
+static int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type)
+{
+ struct ibmvscsi_host_data *hostdata = shost_priv(shost);
+
+ dev_info(hostdata->dev, "Initiating adapter reset!\n");
+ ibmvscsi_reset_host(hostdata);
+
+ return 0;
+}
+
static struct device_attribute *ibmvscsi_attrs[] = {
&ibmvscsi_host_vhost_loc,
&ibmvscsi_host_vhost_name,
@@ -2076,6 +2073,7 @@ static struct scsi_host_template driver_template = {
.eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
.slave_configure = ibmvscsi_slave_configure,
.change_queue_depth = ibmvscsi_change_queue_depth,
+ .host_reset = ibmvscsi_host_reset,
.cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
.this_id = -1,
@@ -2105,48 +2103,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
{
+ unsigned long flags;
int rc;
char *action = "reset";
- if (hostdata->reset_crq) {
- smp_rmb();
- hostdata->reset_crq = 0;
-
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ switch (hostdata->action) {
+ case IBMVSCSI_HOST_ACTION_UNBLOCK:
+ rc = 0;
+ break;
+ case IBMVSCSI_HOST_ACTION_RESET:
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
if (!rc)
rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
vio_enable_interrupts(to_vio_dev(hostdata->dev));
- } else if (hostdata->reenable_crq) {
- smp_rmb();
+ break;
+ case IBMVSCSI_HOST_ACTION_REENABLE:
action = "enable";
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata);
- hostdata->reenable_crq = 0;
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
if (!rc)
rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
- } else
+ break;
+ case IBMVSCSI_HOST_ACTION_NONE:
+ default:
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
return;
+ }
+
+ hostdata->action = IBMVSCSI_HOST_ACTION_NONE;
if (rc) {
atomic_set(&hostdata->request_limit, -1);
dev_err(hostdata->dev, "error after %s\n", action);
}
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
scsi_unblock_requests(hostdata->host);
}
-static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+static int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
{
if (kthread_should_stop())
return 1;
- else if (hostdata->reset_crq) {
- smp_rmb();
- return 1;
- } else if (hostdata->reenable_crq) {
- smp_rmb();
- return 1;
+ switch (hostdata->action) {
+ case IBMVSCSI_HOST_ACTION_NONE:
+ return 0;
+ case IBMVSCSI_HOST_ACTION_RESET:
+ case IBMVSCSI_HOST_ACTION_REENABLE:
+ case IBMVSCSI_HOST_ACTION_UNBLOCK:
+ default:
+ break;
}
- return 0;
+ return 1;
+}
+
+static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ rc = __ibmvscsi_work_to_do(hostdata);
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
+ return rc;
}
static int ibmvscsi_work(void *data)
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 3a7875575616..e60916ef7a49 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* ------------------------------------------------------------
* ibmvscsi.h
* (C) Copyright IBM Corporation 1994, 2003
@@ -5,21 +6,6 @@
* Santiago Leon (santil@us.ibm.com)
* Dave Boutcher (sleddog@us.ibm.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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
* ------------------------------------------------------------
* Emulation of a SCSI host adapter for Virtual I/O devices
*
@@ -88,13 +74,19 @@ struct event_pool {
dma_addr_t iu_token;
};
+enum ibmvscsi_host_action {
+ IBMVSCSI_HOST_ACTION_NONE = 0,
+ IBMVSCSI_HOST_ACTION_RESET,
+ IBMVSCSI_HOST_ACTION_REENABLE,
+ IBMVSCSI_HOST_ACTION_UNBLOCK,
+};
+
/* all driver data associated with a host adapter */
struct ibmvscsi_host_data {
struct list_head host_list;
atomic_t request_limit;
int client_migrated;
- int reset_crq;
- int reenable_crq;
+ enum ibmvscsi_host_action action;
struct device *dev;
struct event_pool pool;
struct crq_queue queue;
diff --git a/drivers/scsi/ibmvscsi_tgt/Makefile b/drivers/scsi/ibmvscsi_tgt/Makefile
index 0c060ce64cb0..cc7a8256dcf8 100644
--- a/drivers/scsi/ibmvscsi_tgt/Makefile
+++ b/drivers/scsi/ibmvscsi_tgt/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsis.o
ibmvscsis-y := libsrp.o ibmvscsi_tgt.o
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index 7ca277e28d63..7f9535392a93 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
* IBM Virtual SCSI Target Driver
* Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
@@ -10,16 +11,6 @@
* Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
* Authors: Michael Cyr <mikecyr@linux.vnet.ibm.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.
- *
****************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
index cc96c2731134..7ae074e5d7a1 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*******************************************************************************
* IBM Virtual SCSI Target Driver
* Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
@@ -11,16 +12,6 @@
* Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
* Authors: Michael Cyr <mikecyr@linux.vnet.ibm.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.
- *
****************************************************************************/
#ifndef __H_IBMVSCSI_TGT
diff --git a/drivers/scsi/ibmvscsi_tgt/libsrp.c b/drivers/scsi/ibmvscsi_tgt/libsrp.c
index 5a4cc28ca5ff..8a0e28aec928 100644
--- a/drivers/scsi/ibmvscsi_tgt/libsrp.c
+++ b/drivers/scsi/ibmvscsi_tgt/libsrp.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
* SCSI RDMA Protocol lib functions
*
* Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
* Copyright (C) 2016 Bryant G. Ly <bryantly@linux.vnet.ibm.com> IBM Corp.
*
- * 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.
- *
***********************************************************************/
#define pr_fmt(fmt) "libsrp: " fmt
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index cea7f502e8ca..2519fb7aee51 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* imm.c -- low level driver for the IOMEGA MatchMaker
* parallel port SCSI host adapter.
*
@@ -686,7 +687,7 @@ static int imm_completion(struct scsi_cmnd *cmd)
if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
/* if scatter/gather, advance to the next segment */
if (cmd->SCp.buffers_residual--) {
- cmd->SCp.buffer++;
+ cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
cmd->SCp.this_residual =
cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
@@ -796,21 +797,21 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
return 0;
}
return 1; /* wait until imm_wakeup claims parport */
- /* Phase 1 - Connected */
- case 1:
+
+ case 1: /* Phase 1 - Connected */
imm_connect(dev, CONNECT_EPP_MAYBE);
cmd->SCp.phase++;
+ /* fall through */
- /* Phase 2 - We are now talking to the scsi bus */
- case 2:
+ case 2: /* Phase 2 - We are now talking to the scsi bus */
if (!imm_select(dev, scmd_id(cmd))) {
imm_fail(dev, DID_NO_CONNECT);
return 0;
}
cmd->SCp.phase++;
+ /* fall through */
- /* Phase 3 - Ready to accept a command */
- case 3:
+ case 3: /* Phase 3 - Ready to accept a command */
w_ctr(ppb, 0x0c);
if (!(r_str(ppb) & 0x80))
return 1;
@@ -818,9 +819,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
if (!imm_send_command(cmd))
return 0;
cmd->SCp.phase++;
+ /* fall through */
- /* Phase 4 - Setup scatter/gather buffers */
- case 4:
+ case 4: /* Phase 4 - Setup scatter/gather buffers */
if (scsi_bufflen(cmd)) {
cmd->SCp.buffer = scsi_sglist(cmd);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
@@ -834,8 +835,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
cmd->SCp.phase++;
if (cmd->SCp.this_residual & 0x01)
cmd->SCp.this_residual++;
- /* Phase 5 - Pre-Data transfer stage */
- case 5:
+ /* fall through */
+
+ case 5: /* Phase 5 - Pre-Data transfer stage */
/* Spin lock for BUSY */
w_ctr(ppb, 0x0c);
if (!(r_str(ppb) & 0x80))
@@ -850,9 +852,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
if (imm_negotiate(dev))
return 0;
cmd->SCp.phase++;
+ /* fall through */
- /* Phase 6 - Data transfer stage */
- case 6:
+ case 6: /* Phase 6 - Data transfer stage */
/* Spin lock for BUSY */
w_ctr(ppb, 0x0c);
if (!(r_str(ppb) & 0x80))
@@ -866,9 +868,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
return 1;
}
cmd->SCp.phase++;
+ /* fall through */
- /* Phase 7 - Post data transfer stage */
- case 7:
+ case 7: /* Phase 7 - Post data transfer stage */
if ((dev->dp) && (dev->rd)) {
if ((dev->mode == IMM_NIBBLE) || (dev->mode == IMM_PS2)) {
w_ctr(ppb, 0x4);
@@ -878,9 +880,9 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
}
}
cmd->SCp.phase++;
+ /* fall through */
- /* Phase 8 - Read status/message */
- case 8:
+ case 8: /* Phase 8 - Read status/message */
/* Check for data overrun */
if (imm_wait(dev) != (unsigned char) 0xb8) {
imm_fail(dev, DID_ERROR);
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index eb2778b5c81b..41fd64c9c8e9 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/**************************************************************************
* Initio 9100 device driver for Linux.
*
@@ -6,21 +7,6 @@
* Copyright (c) 2004 Christoph Hellwig <hch@lst.de>
* Copyright (c) 2007 Red Hat
*
- * 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, 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
*************************************************************************
*
* DESCRIPTION:
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 6d053e220153..079c04bc448a 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ipr.c -- driver for IBM Power Linux RAID adapters
*
* Written By: Brian King <brking@us.ibm.com>, IBM Corporation
*
* Copyright (C) 2003, 2004 IBM 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
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
/*
@@ -3915,22 +3901,23 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
u8 *buffer, u32 len)
{
int bsize_elem, i, result = 0;
- struct scatterlist *scatterlist;
+ struct scatterlist *sg;
void *kaddr;
/* Determine the actual number of bytes per element */
bsize_elem = PAGE_SIZE * (1 << sglist->order);
- scatterlist = sglist->scatterlist;
+ sg = sglist->scatterlist;
- for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
- struct page *page = sg_page(&scatterlist[i]);
+ for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg),
+ buffer += bsize_elem) {
+ struct page *page = sg_page(sg);
kaddr = kmap(page);
memcpy(kaddr, buffer, bsize_elem);
kunmap(page);
- scatterlist[i].length = bsize_elem;
+ sg->length = bsize_elem;
if (result != 0) {
ipr_trace;
@@ -3939,13 +3926,13 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
}
if (len % bsize_elem) {
- struct page *page = sg_page(&scatterlist[i]);
+ struct page *page = sg_page(sg);
kaddr = kmap(page);
memcpy(kaddr, buffer, len % bsize_elem);
kunmap(page);
- scatterlist[i].length = len % bsize_elem;
+ sg->length = len % bsize_elem;
}
sglist->buffer_len = len;
@@ -3966,6 +3953,7 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd,
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64;
struct scatterlist *scatterlist = sglist->scatterlist;
+ struct scatterlist *sg;
int i;
ipr_cmd->dma_use_sg = sglist->num_dma_sg;
@@ -3974,10 +3962,10 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd,
ioarcb->ioadl_len =
cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg);
- for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+ for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) {
ioadl64[i].flags = cpu_to_be32(IPR_IOADL_FLAGS_WRITE);
- ioadl64[i].data_len = cpu_to_be32(sg_dma_len(&scatterlist[i]));
- ioadl64[i].address = cpu_to_be64(sg_dma_address(&scatterlist[i]));
+ ioadl64[i].data_len = cpu_to_be32(sg_dma_len(sg));
+ ioadl64[i].address = cpu_to_be64(sg_dma_address(sg));
}
ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
@@ -3997,6 +3985,7 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl;
struct scatterlist *scatterlist = sglist->scatterlist;
+ struct scatterlist *sg;
int i;
ipr_cmd->dma_use_sg = sglist->num_dma_sg;
@@ -4006,11 +3995,11 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd,
ioarcb->ioadl_len =
cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
- for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+ for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) {
ioadl[i].flags_and_data_len =
- cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i]));
+ cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(sg));
ioadl[i].address =
- cpu_to_be32(sg_dma_address(&scatterlist[i]));
+ cpu_to_be32(sg_dma_address(sg));
}
ioadl[i-1].flags_and_data_len |=
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index f6baa2351313..a67baeb36d1f 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ipr.h -- driver for IBM Power Linux RAID adapters
*
@@ -5,20 +6,6 @@
*
* Copyright (C) 2003, 2004 IBM 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
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
* Alan Cox <alan@lxorguk.ukuu.org.uk> - Removed several careless u32/dma_addr_t errors
* that broke 64bit platforms.
*/
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 9d29edb9f590..49aa4e657c44 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1087,7 +1087,7 @@ static void sci_remote_device_ready_state_enter(struct sci_base_state_machine *s
if (dev->dev_type == SAS_SATA_DEV || (dev->tproto & SAS_PROTOCOL_SATA)) {
sci_change_state(&idev->sm, SCI_STP_DEV_IDLE);
- } else if (dev_is_expander(dev)) {
+ } else if (dev_is_expander(dev->dev_type)) {
sci_change_state(&idev->sm, SCI_SMP_DEV_IDLE);
} else
isci_remote_device_ready(ihost, idev);
@@ -1478,7 +1478,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport,
struct domain_device *dev = idev->domain_dev;
enum sci_status status;
- if (dev->parent && dev_is_expander(dev->parent))
+ if (dev->parent && dev_is_expander(dev->parent->dev_type))
status = sci_remote_device_ea_construct(iport, idev);
else
status = sci_remote_device_da_construct(iport, idev);
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 47a013fffae7..3ad681c4c20a 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -295,11 +295,6 @@ static inline struct isci_remote_device *rnc_to_dev(struct sci_remote_node_conte
return idev;
}
-static inline bool dev_is_expander(struct domain_device *dev)
-{
- return dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE;
-}
-
static inline void sci_remote_device_decrement_request_count(struct isci_remote_device *idev)
{
/* XXX delete this voodoo when converting to the top-level device
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 1b18cf55167e..343d24c7e788 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -224,7 +224,7 @@ static void scu_ssp_request_construct_task_context(
idev = ireq->target_device;
iport = idev->owning_port;
- /* Fill in the TC with the its required data */
+ /* Fill in the TC with its required data */
task_context->abort = 0;
task_context->priority = 0;
task_context->initiator_request = 1;
@@ -506,7 +506,7 @@ static void scu_sata_request_construct_task_context(
idev = ireq->target_device;
iport = idev->owning_port;
- /* Fill in the TC with the its required data */
+ /* Fill in the TC with its required data */
task_context->abort = 0;
task_context->priority = SCU_TASK_PRIORITY_NORMAL;
task_context->initiator_request = 1;
@@ -3101,7 +3101,7 @@ sci_io_request_construct(struct isci_host *ihost,
/* pass */;
else if (dev_is_sata(dev))
memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd));
- else if (dev_is_expander(dev))
+ else if (dev_is_expander(dev->dev_type))
/* pass */;
else
return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
@@ -3235,7 +3235,7 @@ sci_io_request_construct_smp(struct device *dev,
iport = idev->owning_port;
/*
- * Fill in the TC with the its required data
+ * Fill in the TC with its required data
* 00h
*/
task_context->priority = 0;
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index fb6eba331ac6..26fa1a4d1e6b 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -511,7 +511,7 @@ int isci_task_abort_task(struct sas_task *task)
"%s: dev = %p (%s%s), task = %p, old_request == %p\n",
__func__, idev,
(dev_is_sata(task->dev) ? "STP/SATA"
- : ((dev_is_expander(task->dev))
+ : ((dev_is_expander(task->dev->dev_type))
? "SMP"
: "SSP")),
((idev) ? ((test_bit(IDEV_GONE, &idev->flags))
diff --git a/drivers/scsi/iscsi_boot_sysfs.c b/drivers/scsi/iscsi_boot_sysfs.c
index d453667612f8..e4857b728033 100644
--- a/drivers/scsi/iscsi_boot_sysfs.c
+++ b/drivers/scsi/iscsi_boot_sysfs.c
@@ -1,17 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Export the iSCSI boot info to userland via sysfs.
*
* Copyright (C) 2010 Red Hat, Inc. All rights reserved.
* Copyright (C) 2010 Mike Christie
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2.0 as published by
- * the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index ed3debce2819..7bedbe877704 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* iSCSI Initiator over TCP/IP Data-Path
*
@@ -7,16 +8,6 @@
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.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.
- *
* See the file COPYING included with this distribution for more details.
*
* Credits:
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 06d42d00a323..791453195099 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* iSCSI Initiator TCP Transport
* Copyright (C) 2004 Dmitry Yusupov
@@ -6,16 +7,6 @@
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.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.
- *
* See the file COPYING included with this distribution for more details.
*/
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index 1ad28262b00a..7f683e42c798 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* jazz_esp.c: ESP front-end for MIPS JAZZ systems.
*
* Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende)
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index dc839279bbd9..abac2f350aee 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* -*- mode: c; c-basic-offset: 8 -*- */
/* PARISC LASI driver for the 53c700 chip
@@ -5,19 +6,6 @@
* Copyright (C) 2001 by James.Bottomley@HansenPartnership.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.
-**
-** 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., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index f969a71348ef..9c5f7c9178c6 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c
index 6384a98048af..13a2e7c33cb1 100644
--- a/drivers/scsi/libfc/fc_elsct.c
+++ b/drivers/scsi/libfc/fc_elsct.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2008 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 42bcf7f3a0f9..8e1053bdd843 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2007 Intel Corporation. All rights reserved.
* Copyright(c) 2008 Red Hat, Inc. All rights reserved.
* Copyright(c) 2008 Mike Christie
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index b1bd283be51c..bf2cc9656e19 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2007 Intel Corporation. All rights reserved.
* Copyright(c) 2008 Red Hat, Inc. All rights reserved.
* Copyright(c) 2008 Mike Christie
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c
index 0382ac06906e..f3aefb2deca9 100644
--- a/drivers/scsi/libfc/fc_frame.c
+++ b/drivers/scsi/libfc/fc_frame.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2007 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
index dbadbc81b24b..19c4ab4e0f4d 100644
--- a/drivers/scsi/libfc/fc_libfc.c
+++ b/drivers/scsi/libfc/fc_libfc.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2009 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
index b74189d89322..685e3bdd033a 100644
--- a/drivers/scsi/libfc/fc_libfc.h
+++ b/drivers/scsi/libfc/fc_libfc.h
@@ -1,19 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2009 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index ff943f477d6f..684c5e361a28 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2007 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c
index c168321b560e..c045898b84df 100644
--- a/drivers/scsi/libfc/fc_npiv.c
+++ b/drivers/scsi/libfc/fc_npiv.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2009 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 5bf61431434b..e0f3852fdad1 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
* Maintained at www.Open-FCoE.org
*/
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e893949a3d11..ebd47c0cf9e9 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* iSCSI lib functions
*
@@ -6,20 +7,6 @@
* Copyright (C) 2004 - 2005 Dmitry Yusupov
* Copyright (C) 2004 - 2005 Alex Aizman
* maintained by open-iscsi@googlegroups.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.
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/types.h>
#include <linux/kfifo.h>
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index c3fe3f3a78f5..6ef93c7af954 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* iSCSI over TCP/IP Data-Path lib
*
@@ -7,18 +8,6 @@
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* maintained by open-iscsi@googlegroups.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.
- *
- * See the file COPYING included with this distribution for more details.
- *
* Credits:
* Christoph Hellwig
* FUJITA Tomonori
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index 13739bfacc67..5c6a5eff2f8e 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -1,26 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Kernel configuration file for the SAS Class
#
# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
#
-# This file is licensed under GPLv2.
-#
-# 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; version 2 of the
-# License.
-#
-# 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.
-#
-# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-# USA
-#
config SCSI_SAS_LIBSAS
tristate "SAS Domain Transport Attributes"
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
index 5d51520c6f23..e63a54f5ab8c 100644
--- a/drivers/scsi/libsas/Makefile
+++ b/drivers/scsi/libsas/Makefile
@@ -1,25 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Kernel Makefile for the libsas helpers
#
# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
#
-# This file is licensed under GPLv2.
-#
-# 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; version 2 of the
-# License.
-#
-# 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.
-#
-# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-# USA
obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas.o
libsas-y += sas_init.o \
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 6f93fee2b21b..e9e00740f7ca 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -1,24 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Support for SATA devices on Serial Attached SCSI (SAS) controllers
*
* Copyright (C) 2006 IBM Corporation
*
* Written by: Darrick J. Wong <djwong@us.ibm.com>, IBM 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 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include <linux/scatterlist.h>
@@ -281,7 +267,7 @@ int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
res = sas_get_report_phy_sata(dev->parent, phy->phy_id,
&dev->sata_dev.rps_resp);
if (res) {
- pr_debug("report phy sata to %016llx:0x%x returned 0x%x\n",
+ pr_debug("report phy sata to %016llx:%02d returned 0x%x\n",
SAS_ADDR(dev->parent->sas_addr),
phy->phy_id, res);
return res;
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 726ada9b8c79..abcad097ff2f 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Discover process
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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.
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/scatterlist.h>
@@ -309,7 +293,7 @@ void sas_free_device(struct kref *kref)
dev->phy = NULL;
/* remove the phys and ports, everything else should be gone */
- if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+ if (dev_is_expander(dev->dev_type))
kfree(dev->ex_dev.ex_phy);
if (dev_is_sata(dev) && dev->sata_dev.ap) {
@@ -519,8 +503,7 @@ static void sas_revalidate_domain(struct work_struct *work)
pr_debug("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
task_pid_nr(current));
- if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
- ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE))
+ if (ddev && dev_is_expander(ddev->dev_type))
res = sas_ex_revalidate_domain(ddev);
pr_debug("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index b1e0f7d2b396..a1852f6c042b 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Event processing
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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.
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/export.h>
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 17b45a0c7bc3..9fdb9c9fbda4 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Expander discovery and configuration
*
@@ -5,21 +6,6 @@
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
- *
- * 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.
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/scatterlist.h>
@@ -826,9 +812,14 @@ static struct domain_device *sas_ex_discover_end_dev(
#ifdef CONFIG_SCSI_SAS_ATA
if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
if (child->linkrate > parent->min_linkrate) {
+ struct sas_phy *cphy = child->phy;
+ enum sas_linkrate min_prate = cphy->minimum_linkrate,
+ parent_min_lrate = parent->min_linkrate,
+ min_linkrate = (min_prate > parent_min_lrate) ?
+ parent_min_lrate : 0;
struct sas_phy_linkrates rates = {
.maximum_linkrate = parent->min_linkrate,
- .minimum_linkrate = parent->min_linkrate,
+ .minimum_linkrate = min_linkrate,
};
int ret;
@@ -865,7 +856,7 @@ static struct domain_device *sas_ex_discover_end_dev(
res = sas_discover_sata(child);
if (res) {
- pr_notice("sas_discover_sata() for device %16llx at %016llx:0x%x returned 0x%x\n",
+ pr_notice("sas_discover_sata() for device %16llx at %016llx:%02d returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
@@ -890,7 +881,7 @@ static struct domain_device *sas_ex_discover_end_dev(
res = sas_discover_end_dev(child);
if (res) {
- pr_notice("sas_discover_end_dev() for device %16llx at %016llx:0x%x returned 0x%x\n",
+ pr_notice("sas_discover_end_dev() for device %16llx at %016llx:%02d returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
@@ -955,7 +946,7 @@ static struct domain_device *sas_ex_discover_expander(
int res;
if (phy->routing_attr == DIRECT_ROUTING) {
- pr_warn("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not allowed\n",
+ pr_warn("ex %016llx:%02d:D <--> ex %016llx:0x%x is not allowed\n",
SAS_ADDR(parent->sas_addr), phy_id,
SAS_ADDR(phy->attached_sas_addr),
phy->attached_phy_id);
@@ -1014,6 +1005,8 @@ static struct domain_device *sas_ex_discover_expander(
list_del(&child->dev_list_node);
spin_unlock_irq(&parent->port->dev_list_lock);
sas_put_device(child);
+ sas_port_delete(phy->port);
+ phy->port = NULL;
return NULL;
}
list_add_tail(&child->siblings, &parent->ex_dev.children);
@@ -1065,7 +1058,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
ex_phy->attached_dev_type != SAS_FANOUT_EXPANDER_DEVICE &&
ex_phy->attached_dev_type != SAS_EDGE_EXPANDER_DEVICE &&
ex_phy->attached_dev_type != SAS_SATA_PENDING) {
- pr_warn("unknown device type(0x%x) attached to ex %016llx phy 0x%x\n",
+ pr_warn("unknown device type(0x%x) attached to ex %016llx phy%02d\n",
ex_phy->attached_dev_type,
SAS_ADDR(dev->sas_addr),
phy_id);
@@ -1081,7 +1074,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
}
if (sas_ex_join_wide_port(dev, phy_id)) {
- pr_debug("Attaching ex phy%d to wide port %016llx\n",
+ pr_debug("Attaching ex phy%02d to wide port %016llx\n",
phy_id, SAS_ADDR(ex_phy->attached_sas_addr));
return res;
}
@@ -1093,13 +1086,13 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
break;
case SAS_FANOUT_EXPANDER_DEVICE:
if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) {
- pr_debug("second fanout expander %016llx phy 0x%x attached to ex %016llx phy 0x%x\n",
+ pr_debug("second fanout expander %016llx phy%02d attached to ex %016llx phy%02d\n",
SAS_ADDR(ex_phy->attached_sas_addr),
ex_phy->attached_phy_id,
SAS_ADDR(dev->sas_addr),
phy_id);
sas_ex_disable_phy(dev, phy_id);
- break;
+ return res;
} else
memcpy(dev->port->disc.fanout_sas_addr,
ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
@@ -1111,27 +1104,9 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
break;
}
- if (child) {
- int i;
-
- for (i = 0; i < ex->num_phys; i++) {
- if (ex->ex_phy[i].phy_state == PHY_VACANT ||
- ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
- continue;
- /*
- * Due to races, the phy might not get added to the
- * wide port, so we add the phy to the wide port here.
- */
- if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
- SAS_ADDR(child->sas_addr)) {
- ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
- if (sas_ex_join_wide_port(dev, i))
- pr_debug("Attaching ex phy%d to wide port %016llx\n",
- i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr));
- }
- }
- }
-
+ if (!child)
+ pr_notice("ex %016llx phy%02d failed to discover\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
return res;
}
@@ -1147,11 +1122,10 @@ static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
phy->phy_state == PHY_NOT_PRESENT)
continue;
- if ((phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE) &&
+ if (dev_is_expander(phy->attached_dev_type) &&
phy->routing_attr == SUBTRACTIVE_ROUTING) {
- memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE);
+ memcpy(sub_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
return 1;
}
@@ -1163,17 +1137,16 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev)
{
struct expander_device *ex = &dev->ex_dev;
struct domain_device *child;
- u8 sub_addr[8] = {0, };
+ u8 sub_addr[SAS_ADDR_SIZE] = {0, };
list_for_each_entry(child, &ex->children, siblings) {
- if (child->dev_type != SAS_EDGE_EXPANDER_DEVICE &&
- child->dev_type != SAS_FANOUT_EXPANDER_DEVICE)
+ if (!dev_is_expander(child->dev_type))
continue;
if (sub_addr[0] == 0) {
sas_find_sub_addr(child, sub_addr);
continue;
} else {
- u8 s2[8];
+ u8 s2[SAS_ADDR_SIZE];
if (sas_find_sub_addr(child, s2) &&
(SAS_ADDR(sub_addr) != SAS_ADDR(s2))) {
@@ -1252,8 +1225,7 @@ static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
phy->phy_state == PHY_NOT_PRESENT)
continue;
- if ((phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
- phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE) &&
+ if (dev_is_expander(phy->attached_dev_type) &&
phy->routing_attr == SUBTRACTIVE_ROUTING) {
if (!sub_sas_addr)
@@ -1261,7 +1233,7 @@ static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
else if (SAS_ADDR(sub_sas_addr) !=
SAS_ADDR(phy->attached_sas_addr)) {
- pr_notice("ex %016llx phy 0x%x diverges(%016llx) on subtractive boundary(%016llx). Disabled\n",
+ pr_notice("ex %016llx phy%02d diverges(%016llx) on subtractive boundary(%016llx). Disabled\n",
SAS_ADDR(dev->sas_addr), i,
SAS_ADDR(phy->attached_sas_addr),
SAS_ADDR(sub_sas_addr));
@@ -1282,7 +1254,7 @@ static void sas_print_parent_topology_bug(struct domain_device *child,
};
struct domain_device *parent = child->parent;
- pr_notice("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x has %c:%c routing link!\n",
+ pr_notice("%s ex %016llx phy%02d <--> %s ex %016llx phy%02d has %c:%c routing link!\n",
ex_type[parent->dev_type],
SAS_ADDR(parent->sas_addr),
parent_phy->phy_id,
@@ -1304,7 +1276,7 @@ static int sas_check_eeds(struct domain_device *child,
if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) {
res = -ENODEV;
- pr_warn("edge ex %016llx phy S:0x%x <--> edge ex %016llx phy S:0x%x, while there is a fanout ex %016llx\n",
+ pr_warn("edge ex %016llx phy S:%02d <--> edge ex %016llx phy S:%02d, while there is a fanout ex %016llx\n",
SAS_ADDR(parent->sas_addr),
parent_phy->phy_id,
SAS_ADDR(child->sas_addr),
@@ -1327,7 +1299,7 @@ static int sas_check_eeds(struct domain_device *child,
;
else {
res = -ENODEV;
- pr_warn("edge ex %016llx phy 0x%x <--> edge ex %016llx phy 0x%x link forms a third EEDS!\n",
+ pr_warn("edge ex %016llx phy%02d <--> edge ex %016llx phy%02d link forms a third EEDS!\n",
SAS_ADDR(parent->sas_addr),
parent_phy->phy_id,
SAS_ADDR(child->sas_addr),
@@ -1349,8 +1321,7 @@ static int sas_check_parent_topology(struct domain_device *child)
if (!child->parent)
return 0;
- if (child->parent->dev_type != SAS_EDGE_EXPANDER_DEVICE &&
- child->parent->dev_type != SAS_FANOUT_EXPANDER_DEVICE)
+ if (!dev_is_expander(child->parent->dev_type))
return 0;
parent_ex = &child->parent->ex_dev;
@@ -1445,11 +1416,11 @@ static int sas_configure_present(struct domain_device *dev, int phy_id,
goto out;
res = rri_resp[2];
if (res == SMP_RESP_NO_INDEX) {
- pr_warn("overflow of indexes: dev %016llx phy 0x%x index 0x%x\n",
+ pr_warn("overflow of indexes: dev %016llx phy%02d index 0x%x\n",
SAS_ADDR(dev->sas_addr), phy_id, i);
goto out;
} else if (res != SMP_RESP_FUNC_ACC) {
- pr_notice("%s: dev %016llx phy 0x%x index 0x%x result 0x%x\n",
+ pr_notice("%s: dev %016llx phy%02d index 0x%x result 0x%x\n",
__func__, SAS_ADDR(dev->sas_addr), phy_id,
i, res);
goto out;
@@ -1515,7 +1486,7 @@ static int sas_configure_set(struct domain_device *dev, int phy_id,
goto out;
res = cri_resp[2];
if (res == SMP_RESP_NO_INDEX) {
- pr_warn("overflow of indexes: dev %016llx phy 0x%x index 0x%x\n",
+ pr_warn("overflow of indexes: dev %016llx phy%02d index 0x%x\n",
SAS_ADDR(dev->sas_addr), phy_id, index);
}
out:
@@ -1646,8 +1617,7 @@ static int sas_ex_level_discovery(struct asd_sas_port *port, const int level)
struct domain_device *dev;
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
- if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+ if (dev_is_expander(dev->dev_type)) {
struct sas_expander_device *ex =
rphy_to_expander_device(dev->rphy);
@@ -1760,10 +1730,11 @@ static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
res = sas_get_phy_discover(dev, phy_id, disc_resp);
if (res == 0) {
- memcpy(sas_addr, disc_resp->disc.attached_sas_addr, 8);
+ memcpy(sas_addr, disc_resp->disc.attached_sas_addr,
+ SAS_ADDR_SIZE);
*type = to_dev_type(dr);
if (*type == 0)
- memset(sas_addr, 0, 8);
+ memset(sas_addr, 0, SAS_ADDR_SIZE);
}
kfree(disc_resp);
return res;
@@ -1870,13 +1841,15 @@ static int sas_find_bcast_dev(struct domain_device *dev,
if (phy_id != -1) {
*src_dev = dev;
ex->ex_change_count = ex_change_count;
- pr_info("Expander phy change count has changed\n");
+ pr_info("ex %016llx phy%02d change count has changed\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
return res;
} else
- pr_info("Expander phys DID NOT change\n");
+ pr_info("ex %016llx phys DID NOT change\n",
+ SAS_ADDR(dev->sas_addr));
}
list_for_each_entry(ch, &ex->children, siblings) {
- if (ch->dev_type == SAS_EDGE_EXPANDER_DEVICE || ch->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+ if (dev_is_expander(ch->dev_type)) {
res = sas_find_bcast_dev(ch, src_dev);
if (*src_dev)
return res;
@@ -1893,8 +1866,7 @@ static void sas_unregister_ex_tree(struct asd_sas_port *port, struct domain_devi
list_for_each_entry_safe(child, n, &ex->children, siblings) {
set_bit(SAS_DEV_GONE, &child->state);
- if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+ if (dev_is_expander(child->dev_type))
sas_unregister_ex_tree(port, child);
else
sas_unregister_dev(port, child);
@@ -1914,8 +1886,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
if (SAS_ADDR(child->sas_addr) ==
SAS_ADDR(phy->attached_sas_addr)) {
set_bit(SAS_DEV_GONE, &child->state);
- if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+ if (dev_is_expander(child->dev_type))
sas_unregister_ex_tree(parent->port, child);
else
sas_unregister_dev(parent->port, child);
@@ -1944,8 +1915,7 @@ static int sas_discover_bfs_by_root_level(struct domain_device *root,
int res = 0;
list_for_each_entry(child, &ex_root->children, siblings) {
- if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+ if (dev_is_expander(child->dev_type)) {
struct sas_expander_device *ex =
rphy_to_expander_device(child->rphy);
@@ -1983,7 +1953,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
struct domain_device *child;
int res;
- pr_debug("ex %016llx phy%d new device attached\n",
+ pr_debug("ex %016llx phy%02d new device attached\n",
SAS_ADDR(dev->sas_addr), phy_id);
res = sas_ex_phy_discover(dev, phy_id);
if (res)
@@ -1998,8 +1968,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id)
list_for_each_entry(child, &dev->ex_dev.children, siblings) {
if (SAS_ADDR(child->sas_addr) ==
SAS_ADDR(ex_phy->attached_sas_addr)) {
- if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
- child->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
+ if (dev_is_expander(child->dev_type))
res = sas_discover_bfs_by_root(child);
break;
}
@@ -2022,15 +1991,23 @@ static bool dev_type_flutter(enum sas_device_type new, enum sas_device_type old)
return false;
}
-static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
+static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
+ bool last, int sibling)
{
struct expander_device *ex = &dev->ex_dev;
struct ex_phy *phy = &ex->ex_phy[phy_id];
enum sas_device_type type = SAS_PHY_UNUSED;
- u8 sas_addr[8];
+ u8 sas_addr[SAS_ADDR_SIZE];
+ char msg[80] = "";
int res;
- memset(sas_addr, 0, 8);
+ if (!last)
+ sprintf(msg, ", part of a wide port with phy%02d", sibling);
+
+ pr_debug("ex %016llx rediscovering phy%02d%s\n",
+ SAS_ADDR(dev->sas_addr), phy_id, msg);
+
+ memset(sas_addr, 0, SAS_ADDR_SIZE);
res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type);
switch (res) {
case SMP_RESP_NO_PHY:
@@ -2052,6 +2029,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) {
phy->phy_state = PHY_EMPTY;
sas_unregister_devs_sas_addr(dev, phy_id, last);
+ /*
+ * Even though the PHY is empty, for convenience we discover
+ * the PHY to update the PHY info, like negotiated linkrate.
+ */
+ sas_ex_phy_discover(dev, phy_id);
return res;
} else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) &&
dev_type_flutter(type, phy->attached_dev_type)) {
@@ -2062,13 +2044,13 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
if (ata_dev && phy->attached_dev_type == SAS_SATA_PENDING)
action = ", needs recovery";
- pr_debug("ex %016llx phy 0x%x broadcast flutter%s\n",
+ pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
SAS_ADDR(dev->sas_addr), phy_id, action);
return res;
}
/* we always have to delete the old device when we went here */
- pr_info("ex %016llx phy 0x%x replace %016llx\n",
+ pr_info("ex %016llx phy%02d replace %016llx\n",
SAS_ADDR(dev->sas_addr), phy_id,
SAS_ADDR(phy->attached_sas_addr));
sas_unregister_devs_sas_addr(dev, phy_id, last);
@@ -2098,7 +2080,7 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id)
int i;
bool last = true; /* is this the last phy of the port */
- pr_debug("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
+ pr_debug("ex %016llx phy%02d originated BROADCAST(CHANGE)\n",
SAS_ADDR(dev->sas_addr), phy_id);
if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) {
@@ -2109,13 +2091,11 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id)
continue;
if (SAS_ADDR(phy->attached_sas_addr) ==
SAS_ADDR(changed_phy->attached_sas_addr)) {
- pr_debug("phy%d part of wide port with phy%d\n",
- phy_id, i);
last = false;
break;
}
}
- res = sas_rediscover_dev(dev, phy_id, last);
+ res = sas_rediscover_dev(dev, phy_id, last, i);
} else
res = sas_discover_new(dev, phy_id);
return res;
diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
index 9ead93df3a6e..eca2a6bf3601 100644
--- a/drivers/scsi/libsas/sas_host_smp.c
+++ b/drivers/scsi/libsas/sas_host_smp.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Serial Attached SCSI (SAS) Expander discovery and configuration
*
* Copyright (C) 2007 James E.J. Bottomley
* <James.Bottomley@HansenPartnership.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; version 2 only.
*/
#include <linux/scatterlist.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 221340ee8651..21c43b18d5d5 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -1,26 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Serial Attached SCSI (SAS) Transport Layer initialization
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
*/
#include <linux/module.h>
@@ -87,25 +70,27 @@ EXPORT_SYMBOL_GPL(sas_free_task);
/*------------ SAS addr hash -----------*/
void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
{
- const u32 poly = 0x00DB2777;
- u32 r = 0;
- int i;
-
- for (i = 0; i < 8; i++) {
- int b;
- for (b = 7; b >= 0; b--) {
- r <<= 1;
- if ((1 << b) & sas_addr[i]) {
- if (!(r & 0x01000000))
- r ^= poly;
- } else if (r & 0x01000000)
- r ^= poly;
- }
- }
-
- hashed[0] = (r >> 16) & 0xFF;
- hashed[1] = (r >> 8) & 0xFF ;
- hashed[2] = r & 0xFF;
+ const u32 poly = 0x00DB2777;
+ u32 r = 0;
+ int i;
+
+ for (i = 0; i < SAS_ADDR_SIZE; i++) {
+ int b;
+
+ for (b = (SAS_ADDR_SIZE - 1); b >= 0; b--) {
+ r <<= 1;
+ if ((1 << b) & sas_addr[i]) {
+ if (!(r & 0x01000000))
+ r ^= poly;
+ } else if (r & 0x01000000) {
+ r ^= poly;
+ }
+ }
+ }
+
+ hashed[0] = (r >> 16) & 0xFF;
+ hashed[1] = (r >> 8) & 0xFF;
+ hashed[2] = r & 0xFF;
}
int sas_register_ha(struct sas_ha_struct *sas_ha)
@@ -623,7 +608,7 @@ struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy)
if (atomic_read(&phy->event_nr) > phy->ha->event_thres) {
if (i->dft->lldd_control_phy) {
if (cmpxchg(&phy->in_shutdown, 0, 1) == 0) {
- pr_notice("The phy%02d bursting events, shut it down.\n",
+ pr_notice("The phy%d bursting events, shut it down.\n",
phy->id);
sas_notify_phy_event(phy, PHYE_SHUTDOWN);
}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 2cdb981cf476..01f1738ce6df 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -1,26 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Serial Attached SCSI (SAS) class internal header file
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
*/
#ifndef _SAS_INTERNAL_H_
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index 0374243c85d0..4ca4b1f30bd0 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Phy class
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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.
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include "sas_internal.h"
@@ -35,7 +19,6 @@ static void sas_phye_loss_of_signal(struct work_struct *work)
struct asd_sas_event *ev = to_asd_sas_event(work);
struct asd_sas_phy *phy = ev->phy;
- phy->in_shutdown = 0;
phy->error = 0;
sas_deform_port(phy, 1);
}
@@ -45,7 +28,6 @@ static void sas_phye_oob_done(struct work_struct *work)
struct asd_sas_event *ev = to_asd_sas_event(work);
struct asd_sas_phy *phy = ev->phy;
- phy->in_shutdown = 0;
phy->error = 0;
}
@@ -122,11 +104,11 @@ static void sas_phye_shutdown(struct work_struct *work)
phy->enabled = 0;
ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
if (ret)
- pr_notice("lldd disable phy%02d returned %d\n",
- phy->id, ret);
+ pr_notice("lldd disable phy%d returned %d\n", phy->id,
+ ret);
} else
- pr_notice("phy%02d is not enabled, cannot shutdown\n",
- phy->id);
+ pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id);
+ phy->in_shutdown = 0;
}
/* ---------- Phy class registration ---------- */
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 03fe479359b6..7c86fd248129 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Serial Attached SCSI (SAS) Port class
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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.
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include "sas_internal.h"
@@ -70,7 +54,7 @@ static void sas_resume_port(struct asd_sas_phy *phy)
continue;
}
- if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
+ if (dev_is_expander(dev->dev_type)) {
dev->ex_dev.ex_change_count = -1;
for (i = 0; i < dev->ex_dev.num_phys; i++) {
struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
@@ -95,6 +79,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
int i;
struct sas_ha_struct *sas_ha = phy->ha;
struct asd_sas_port *port = phy->port;
+ struct domain_device *port_dev;
struct sas_internal *si =
to_sas_internal(sas_ha->core.shost->transportt);
unsigned long flags;
@@ -153,8 +138,9 @@ static void sas_form_port(struct asd_sas_phy *phy)
}
/* add the phy to the port */
+ port_dev = port->port_dev;
list_add_tail(&phy->port_phy_el, &port->phy_list);
- sas_phy_set_target(phy, port->port_dev);
+ sas_phy_set_target(phy, port_dev);
phy->port = port;
port->num_phys++;
port->phy_mask |= (1U << phy->id);
@@ -184,14 +170,21 @@ static void sas_form_port(struct asd_sas_phy *phy)
port->phy_mask,
SAS_ADDR(port->attached_sas_addr));
- if (port->port_dev)
- port->port_dev->pathways = port->num_phys;
+ if (port_dev)
+ port_dev->pathways = port->num_phys;
/* Tell the LLDD about this port formation. */
if (si->dft->lldd_port_formed)
si->dft->lldd_port_formed(phy);
sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
+ /* Only insert a revalidate event after initial discovery */
+ if (port_dev && dev_is_expander(port_dev->dev_type)) {
+ struct expander_device *ex_dev = &port_dev->ex_dev;
+
+ ex_dev->ex_change_count = -1;
+ sas_discover_event(port, DISCE_REVALIDATE_DOMAIN);
+ }
flush_workqueue(sas_ha->disco_q);
}
@@ -254,6 +247,15 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
spin_unlock(&port->phy_list_lock);
spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
+ /* Only insert revalidate event if the port still has members */
+ if (port->port && dev && dev_is_expander(dev->dev_type)) {
+ struct expander_device *ex_dev = &dev->ex_dev;
+
+ ex_dev->ex_change_count = -1;
+ sas_discover_event(port, DISCE_REVALIDATE_DOMAIN);
+ }
+ flush_workqueue(sas_ha->disco_q);
+
return;
}
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index b775445892af..4f339f939a51 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -1,26 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Serial Attached SCSI (SAS) class SCSI Host glue.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
*/
#include <linux/kthread.h>
diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
index c3b9befad4e6..1ded7d85027e 100644
--- a/drivers/scsi/libsas/sas_task.c
+++ b/drivers/scsi/libsas/sas_task.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
#include "sas_internal.h"
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 41d849f283f6..2c3bb8a966e5 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -274,6 +274,7 @@ struct lpfc_stats {
uint32_t elsXmitADISC;
uint32_t elsXmitLOGO;
uint32_t elsXmitSCR;
+ uint32_t elsXmitRSCN;
uint32_t elsXmitRNID;
uint32_t elsXmitFARP;
uint32_t elsXmitFARPR;
@@ -819,6 +820,7 @@ struct lpfc_hba {
uint32_t cfg_use_msi;
uint32_t cfg_auto_imax;
uint32_t cfg_fcp_imax;
+ uint32_t cfg_force_rscn;
uint32_t cfg_cq_poll_threshold;
uint32_t cfg_cq_max_proc_limit;
uint32_t cfg_fcp_cpu_map;
@@ -942,6 +944,7 @@ struct lpfc_hba {
int brd_no; /* FC board number */
char SerialNumber[32]; /* adapter Serial Number */
char OptionROMVersion[32]; /* adapter BIOS / Fcode version */
+ char BIOSVersion[16]; /* Boot BIOS version */
char ModelDesc[256]; /* Model Description */
char ModelName[80]; /* Model Name */
char ProgramType[256]; /* Program Type */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index ce3e541434dc..ea62322ffe2b 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -71,6 +71,23 @@
#define LPFC_REG_WRITE_KEY_SIZE 4
#define LPFC_REG_WRITE_KEY "EMLX"
+const char *const trunk_errmsg[] = { /* map errcode */
+ "", /* There is no such error code at index 0*/
+ "link negotiated speed does not match existing"
+ " trunk - link was \"low\" speed",
+ "link negotiated speed does not match"
+ " existing trunk - link was \"middle\" speed",
+ "link negotiated speed does not match existing"
+ " trunk - link was \"high\" speed",
+ "Attached to non-trunking port - F_Port",
+ "Attached to non-trunking port - N_Port",
+ "FLOGI response timeout",
+ "non-FLOGI frame received",
+ "Invalid FLOGI response",
+ "Trunking initialization protocol",
+ "Trunk peer device mismatch",
+};
+
/**
* lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules
* @incr: integer to convert.
@@ -114,7 +131,7 @@ static ssize_t
lpfc_drvr_version_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n");
+ return scnprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n");
}
/**
@@ -134,9 +151,9 @@ lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
if (phba->hba_flag & HBA_FIP_SUPPORT)
- return snprintf(buf, PAGE_SIZE, "1\n");
+ return scnprintf(buf, PAGE_SIZE, "1\n");
else
- return snprintf(buf, PAGE_SIZE, "0\n");
+ return scnprintf(buf, PAGE_SIZE, "0\n");
}
static ssize_t
@@ -159,6 +176,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
int i;
int len = 0;
char tmp[LPFC_MAX_NVME_INFO_TMP_LEN] = {0};
+ unsigned long iflags = 0;
if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) {
len = scnprintf(buf, PAGE_SIZE, "NVME Disabled\n");
@@ -337,7 +355,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
phba->sli4_hba.io_xri_max,
lpfc_sli4_get_els_iocb_cnt(phba));
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
/* Port state is only one of two values for now. */
if (localport->port_id)
@@ -353,15 +371,15 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
wwn_to_u64(vport->fc_nodename.u.wwn),
localport->port_id, statep);
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
nrport = NULL;
- spin_lock(&vport->phba->hbalock);
+ spin_lock_irqsave(&vport->phba->hbalock, iflags);
rport = lpfc_ndlp_get_nrport(ndlp);
if (rport)
nrport = rport->remoteport;
- spin_unlock(&vport->phba->hbalock);
+ spin_unlock_irqrestore(&vport->phba->hbalock, iflags);
if (!nrport)
continue;
@@ -380,39 +398,39 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
/* Tab in to show lport ownership. */
if (strlcat(buf, "NVME RPORT ", PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
if (phba->brd_no >= 10) {
if (strlcat(buf, " ", PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
}
scnprintf(tmp, sizeof(tmp), "WWPN x%llx ",
nrport->port_name);
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
scnprintf(tmp, sizeof(tmp), "WWNN x%llx ",
nrport->node_name);
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
scnprintf(tmp, sizeof(tmp), "DID x%06x ",
nrport->port_id);
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
/* An NVME rport can have multiple roles. */
if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) {
if (strlcat(buf, "INITIATOR ", PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
}
if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) {
if (strlcat(buf, "TARGET ", PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
}
if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) {
if (strlcat(buf, "DISCSRVC ", PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
}
if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR |
FC_PORT_ROLE_NVME_TARGET |
@@ -420,12 +438,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
scnprintf(tmp, sizeof(tmp), "UNKNOWN ROLE x%x",
nrport->port_role);
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
}
scnprintf(tmp, sizeof(tmp), "%s\n", statep);
if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
- goto buffer_done;
+ goto rcu_unlock_buf_done;
}
rcu_read_unlock();
@@ -487,7 +505,13 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
atomic_read(&lport->cmpl_fcp_err));
strlcat(buf, tmp, PAGE_SIZE);
-buffer_done:
+ /* RCU is already unlocked. */
+ goto buffer_done;
+
+ rcu_unlock_buf_done:
+ rcu_read_unlock();
+
+ buffer_done:
len = strnlen(buf, PAGE_SIZE);
if (unlikely(len >= (PAGE_SIZE - 1))) {
@@ -564,14 +588,15 @@ lpfc_bg_info_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- if (phba->cfg_enable_bg)
+ if (phba->cfg_enable_bg) {
if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
- return snprintf(buf, PAGE_SIZE, "BlockGuard Enabled\n");
+ return scnprintf(buf, PAGE_SIZE,
+ "BlockGuard Enabled\n");
else
- return snprintf(buf, PAGE_SIZE,
+ return scnprintf(buf, PAGE_SIZE,
"BlockGuard Not Supported\n");
- else
- return snprintf(buf, PAGE_SIZE,
+ } else
+ return scnprintf(buf, PAGE_SIZE,
"BlockGuard Disabled\n");
}
@@ -583,7 +608,7 @@ lpfc_bg_guard_err_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%llu\n",
+ return scnprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)phba->bg_guard_err_cnt);
}
@@ -595,7 +620,7 @@ lpfc_bg_apptag_err_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%llu\n",
+ return scnprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)phba->bg_apptag_err_cnt);
}
@@ -607,7 +632,7 @@ lpfc_bg_reftag_err_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%llu\n",
+ return scnprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)phba->bg_reftag_err_cnt);
}
@@ -625,7 +650,7 @@ lpfc_info_show(struct device *dev, struct device_attribute *attr,
{
struct Scsi_Host *host = class_to_shost(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host));
+ return scnprintf(buf, PAGE_SIZE, "%s\n", lpfc_info(host));
}
/**
@@ -644,7 +669,7 @@ lpfc_serialnum_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", phba->SerialNumber);
}
/**
@@ -666,7 +691,7 @@ lpfc_temp_sensor_show(struct device *dev, struct device_attribute *attr,
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", phba->temp_sensor_support);
}
/**
@@ -685,7 +710,7 @@ lpfc_modeldesc_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ModelDesc);
}
/**
@@ -704,7 +729,7 @@ lpfc_modelname_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ModelName);
}
/**
@@ -723,7 +748,7 @@ lpfc_programtype_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ProgramType);
}
/**
@@ -741,7 +766,7 @@ lpfc_mlomgmt_show(struct device *dev, struct device_attribute *attr, char *buf)
struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
(phba->sli.sli_flag & LPFC_MENLO_MAINT));
}
@@ -761,7 +786,7 @@ lpfc_vportnum_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", phba->Port);
}
/**
@@ -789,10 +814,10 @@ lpfc_fwrev_show(struct device *dev, struct device_attribute *attr,
sli_family = phba->sli4_hba.pc_sli4_params.sli_family;
if (phba->sli_rev < LPFC_SLI_REV4)
- len = snprintf(buf, PAGE_SIZE, "%s, sli-%d\n",
+ len = scnprintf(buf, PAGE_SIZE, "%s, sli-%d\n",
fwrev, phba->sli_rev);
else
- len = snprintf(buf, PAGE_SIZE, "%s, sli-%d:%d:%x\n",
+ len = scnprintf(buf, PAGE_SIZE, "%s, sli-%d:%d:%x\n",
fwrev, phba->sli_rev, if_type, sli_family);
return len;
@@ -816,7 +841,7 @@ lpfc_hdw_show(struct device *dev, struct device_attribute *attr, char *buf)
lpfc_vpd_t *vp = &phba->vpd;
lpfc_jedec_to_ascii(vp->rev.biuRev, hdw);
- return snprintf(buf, PAGE_SIZE, "%s\n", hdw);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", hdw);
}
/**
@@ -837,10 +862,11 @@ lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr,
char fwrev[FW_REV_STR_SIZE];
if (phba->sli_rev < LPFC_SLI_REV4)
- return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
+ phba->OptionROMVersion);
lpfc_decode_firmware_rev(phba, fwrev, 1);
- return snprintf(buf, PAGE_SIZE, "%s\n", fwrev);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", fwrev);
}
/**
@@ -871,20 +897,20 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
case LPFC_LINK_DOWN:
case LPFC_HBA_ERROR:
if (phba->hba_flag & LINK_DISABLED)
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Link Down - User disabled\n");
else
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Link Down\n");
break;
case LPFC_LINK_UP:
case LPFC_CLEAR_LA:
case LPFC_HBA_READY:
- len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - ");
+ len += scnprintf(buf + len, PAGE_SIZE-len, "Link Up - ");
switch (vport->port_state) {
case LPFC_LOCAL_CFG_LINK:
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Configuring Link\n");
break;
case LPFC_FDISC:
@@ -894,38 +920,40 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
case LPFC_NS_QRY:
case LPFC_BUILD_DISC_LIST:
case LPFC_DISC_AUTH:
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Discovery\n");
break;
case LPFC_VPORT_READY:
- len += snprintf(buf + len, PAGE_SIZE - len, "Ready\n");
+ len += scnprintf(buf + len, PAGE_SIZE - len,
+ "Ready\n");
break;
case LPFC_VPORT_FAILED:
- len += snprintf(buf + len, PAGE_SIZE - len, "Failed\n");
+ len += scnprintf(buf + len, PAGE_SIZE - len,
+ "Failed\n");
break;
case LPFC_VPORT_UNKNOWN:
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Unknown\n");
break;
}
if (phba->sli.sli_flag & LPFC_MENLO_MAINT)
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
" Menlo Maint Mode\n");
else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
if (vport->fc_flag & FC_PUBLIC_LOOP)
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
" Public Loop\n");
else
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
" Private Loop\n");
} else {
if (vport->fc_flag & FC_FABRIC)
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
" Fabric\n");
else
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
" Point-2-Point\n");
}
}
@@ -937,28 +965,28 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
struct lpfc_trunk_link link = phba->trunk_link;
if (bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba))
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Trunk port 0: Link %s %s\n",
(link.link0.state == LPFC_LINK_UP) ?
"Up" : "Down. ",
trunk_errmsg[link.link0.fault]);
if (bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba))
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Trunk port 1: Link %s %s\n",
(link.link1.state == LPFC_LINK_UP) ?
"Up" : "Down. ",
trunk_errmsg[link.link1.fault]);
if (bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba))
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Trunk port 2: Link %s %s\n",
(link.link2.state == LPFC_LINK_UP) ?
"Up" : "Down. ",
trunk_errmsg[link.link2.fault]);
if (bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba))
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Trunk port 3: Link %s %s\n",
(link.link3.state == LPFC_LINK_UP) ?
"Up" : "Down. ",
@@ -986,15 +1014,15 @@ lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
if (phba->sli_rev < LPFC_SLI_REV4)
- return snprintf(buf, PAGE_SIZE, "fc\n");
+ return scnprintf(buf, PAGE_SIZE, "fc\n");
if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) {
if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_GE)
- return snprintf(buf, PAGE_SIZE, "fcoe\n");
+ return scnprintf(buf, PAGE_SIZE, "fcoe\n");
if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)
- return snprintf(buf, PAGE_SIZE, "fc\n");
+ return scnprintf(buf, PAGE_SIZE, "fc\n");
}
- return snprintf(buf, PAGE_SIZE, "unknown\n");
+ return scnprintf(buf, PAGE_SIZE, "unknown\n");
}
/**
@@ -1014,7 +1042,7 @@ lpfc_oas_supported_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
phba->sli4_hba.pc_sli4_params.oas_supported);
}
@@ -1072,7 +1100,7 @@ lpfc_num_discovered_ports_show(struct device *dev,
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
vport->fc_map_cnt + vport->fc_unmap_cnt);
}
@@ -1204,6 +1232,20 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
psli = &phba->sli;
+ /*
+ * If freeing the queues have already started, don't access them.
+ * Otherwise set FREE_WAIT to indicate that queues are being used
+ * to hold the freeing process until we finish.
+ */
+ spin_lock_irq(&phba->hbalock);
+ if (!(psli->sli_flag & LPFC_QUEUE_FREE_INIT)) {
+ psli->sli_flag |= LPFC_QUEUE_FREE_WAIT;
+ } else {
+ spin_unlock_irq(&phba->hbalock);
+ goto skip_wait;
+ }
+ spin_unlock_irq(&phba->hbalock);
+
/* Wait a little for things to settle down, but not
* long enough for dev loss timeout to expire.
*/
@@ -1225,6 +1267,11 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
}
}
out:
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag &= ~LPFC_QUEUE_FREE_WAIT;
+ spin_unlock_irq(&phba->hbalock);
+
+skip_wait:
init_completion(&online_compl);
rc = lpfc_workq_post_event(phba, &status, &online_compl, type);
if (rc == 0)
@@ -1258,7 +1305,7 @@ out:
* -EBUSY, port is not in offline state
* 0, successful
*/
-int
+static int
lpfc_reset_pci_bus(struct lpfc_hba *phba)
{
struct pci_dev *pdev = phba->pcidev;
@@ -1586,10 +1633,10 @@ lpfc_nport_evt_cnt_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}
-int
+static int
lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out)
{
LPFC_MBOXQ_t *mbox = NULL;
@@ -1675,7 +1722,7 @@ lpfc_board_mode_show(struct device *dev, struct device_attribute *attr,
else
state = "online";
- return snprintf(buf, PAGE_SIZE, "%s\n", state);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", state);
}
/**
@@ -1901,8 +1948,8 @@ lpfc_max_rpi_show(struct device *dev, struct device_attribute *attr,
uint32_t cnt;
if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL))
- return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
- return snprintf(buf, PAGE_SIZE, "Unknown\n");
+ return scnprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return scnprintf(buf, PAGE_SIZE, "Unknown\n");
}
/**
@@ -1929,8 +1976,8 @@ lpfc_used_rpi_show(struct device *dev, struct device_attribute *attr,
uint32_t cnt, acnt;
if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL))
- return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
- return snprintf(buf, PAGE_SIZE, "Unknown\n");
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return scnprintf(buf, PAGE_SIZE, "Unknown\n");
}
/**
@@ -1957,8 +2004,8 @@ lpfc_max_xri_show(struct device *dev, struct device_attribute *attr,
uint32_t cnt;
if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL))
- return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
- return snprintf(buf, PAGE_SIZE, "Unknown\n");
+ return scnprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return scnprintf(buf, PAGE_SIZE, "Unknown\n");
}
/**
@@ -1985,8 +2032,8 @@ lpfc_used_xri_show(struct device *dev, struct device_attribute *attr,
uint32_t cnt, acnt;
if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL))
- return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
- return snprintf(buf, PAGE_SIZE, "Unknown\n");
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return scnprintf(buf, PAGE_SIZE, "Unknown\n");
}
/**
@@ -2013,8 +2060,8 @@ lpfc_max_vpi_show(struct device *dev, struct device_attribute *attr,
uint32_t cnt;
if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL))
- return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
- return snprintf(buf, PAGE_SIZE, "Unknown\n");
+ return scnprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return scnprintf(buf, PAGE_SIZE, "Unknown\n");
}
/**
@@ -2041,8 +2088,8 @@ lpfc_used_vpi_show(struct device *dev, struct device_attribute *attr,
uint32_t cnt, acnt;
if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt))
- return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
- return snprintf(buf, PAGE_SIZE, "Unknown\n");
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return scnprintf(buf, PAGE_SIZE, "Unknown\n");
}
/**
@@ -2067,10 +2114,10 @@ lpfc_npiv_info_show(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
if (!(phba->max_vpi))
- return snprintf(buf, PAGE_SIZE, "NPIV Not Supported\n");
+ return scnprintf(buf, PAGE_SIZE, "NPIV Not Supported\n");
if (vport->port_type == LPFC_PHYSICAL_PORT)
- return snprintf(buf, PAGE_SIZE, "NPIV Physical\n");
- return snprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi);
+ return scnprintf(buf, PAGE_SIZE, "NPIV Physical\n");
+ return scnprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi);
}
/**
@@ -2092,7 +2139,7 @@ lpfc_poll_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll);
+ return scnprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll);
}
/**
@@ -2196,7 +2243,7 @@ lpfc_fips_level_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level);
}
/**
@@ -2215,7 +2262,7 @@ lpfc_fips_rev_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev);
}
/**
@@ -2234,7 +2281,7 @@ lpfc_dss_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "%s - %sOperational\n",
+ return scnprintf(buf, PAGE_SIZE, "%s - %sOperational\n",
(phba->cfg_enable_dss) ? "Enabled" : "Disabled",
(phba->sli3_options & LPFC_SLI3_DSS_ENABLED) ?
"" : "Not ");
@@ -2263,7 +2310,7 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev,
uint16_t max_nr_virtfn;
max_nr_virtfn = lpfc_sli_sriov_nr_virtfn_get(phba);
- return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
}
static inline bool lpfc_rangecheck(uint val, uint min, uint max)
@@ -2323,7 +2370,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
struct lpfc_hba *phba = vport->phba;\
- return snprintf(buf, PAGE_SIZE, "%d\n",\
+ return scnprintf(buf, PAGE_SIZE, "%d\n",\
phba->cfg_##attr);\
}
@@ -2351,7 +2398,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
struct lpfc_hba *phba = vport->phba;\
uint val = 0;\
val = phba->cfg_##attr;\
- return snprintf(buf, PAGE_SIZE, "%#x\n",\
+ return scnprintf(buf, PAGE_SIZE, "%#x\n",\
phba->cfg_##attr);\
}
@@ -2487,7 +2534,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
{ \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
- return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\
+ return scnprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\
}
/**
@@ -2512,7 +2559,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \
{ \
struct Scsi_Host *shost = class_to_shost(dev);\
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
- return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\
+ return scnprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\
}
/**
@@ -2784,7 +2831,7 @@ lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr,
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ return scnprintf(buf, PAGE_SIZE, "0x%llx\n",
(unsigned long long)phba->cfg_soft_wwpn);
}
@@ -2881,7 +2928,7 @@ lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr,
{
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ return scnprintf(buf, PAGE_SIZE, "0x%llx\n",
(unsigned long long)phba->cfg_soft_wwnn);
}
@@ -2947,7 +2994,7 @@ lpfc_oas_tgt_show(struct device *dev, struct device_attribute *attr,
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ return scnprintf(buf, PAGE_SIZE, "0x%llx\n",
wwn_to_u64(phba->cfg_oas_tgt_wwpn));
}
@@ -3015,7 +3062,7 @@ lpfc_oas_priority_show(struct device *dev, struct device_attribute *attr,
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_priority);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_priority);
}
/**
@@ -3078,7 +3125,7 @@ lpfc_oas_vpt_show(struct device *dev, struct device_attribute *attr,
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+ return scnprintf(buf, PAGE_SIZE, "0x%llx\n",
wwn_to_u64(phba->cfg_oas_vpt_wwpn));
}
@@ -3149,7 +3196,7 @@ lpfc_oas_lun_state_show(struct device *dev, struct device_attribute *attr,
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_state);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_state);
}
/**
@@ -3213,7 +3260,7 @@ lpfc_oas_lun_status_show(struct device *dev, struct device_attribute *attr,
if (!(phba->cfg_oas_flags & OAS_LUN_VALID))
return -EFAULT;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_status);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", phba->cfg_oas_lun_status);
}
static DEVICE_ATTR(lpfc_xlane_lun_status, S_IRUGO,
lpfc_oas_lun_status_show, NULL);
@@ -3365,7 +3412,7 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr,
if (oas_lun != NOT_OAS_ENABLED_LUN)
phba->cfg_oas_flags |= OAS_LUN_VALID;
- len += snprintf(buf + len, PAGE_SIZE-len, "0x%llx", oas_lun);
+ len += scnprintf(buf + len, PAGE_SIZE-len, "0x%llx", oas_lun);
return len;
}
@@ -3499,7 +3546,7 @@ lpfc_iocb_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max);
}
static DEVICE_ATTR(iocb_hw, S_IRUGO,
@@ -3511,7 +3558,7 @@ lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
struct lpfc_sli_ring *pring = lpfc_phba_elsring(phba);
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
pring ? pring->txq_max : 0);
}
@@ -3525,7 +3572,7 @@ lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
struct lpfc_sli_ring *pring = lpfc_phba_elsring(phba);
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
pring ? pring->txcmplq_max : 0);
}
@@ -3561,7 +3608,7 @@ lpfc_nodev_tmo_show(struct device *dev, struct device_attribute *attr,
struct Scsi_Host *shost = class_to_shost(dev);
struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_devloss_tmo);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_devloss_tmo);
}
/**
@@ -4912,6 +4959,64 @@ static DEVICE_ATTR(lpfc_req_fw_upgrade, S_IRUGO | S_IWUSR,
lpfc_request_firmware_upgrade_store);
/**
+ * lpfc_force_rscn_store
+ *
+ * @dev: class device that is converted into a Scsi_host.
+ * @attr: device attribute, not used.
+ * @buf: unused string
+ * @count: unused variable.
+ *
+ * Description:
+ * Force the switch to send a RSCN to all other NPorts in our zone
+ * If we are direct connect pt2pt, build the RSCN command ourself
+ * and send to the other NPort. Not supported for private loop.
+ *
+ * Returns:
+ * 0 - on success
+ * -EIO - if command is not sent
+ **/
+static ssize_t
+lpfc_force_rscn_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+ int i;
+
+ i = lpfc_issue_els_rscn(vport, 0);
+ if (i)
+ return -EIO;
+ return strlen(buf);
+}
+
+/*
+ * lpfc_force_rscn: Force an RSCN to be sent to all remote NPorts
+ * connected to the HBA.
+ *
+ * Value range is any ascii value
+ */
+static int lpfc_force_rscn;
+module_param(lpfc_force_rscn, int, 0644);
+MODULE_PARM_DESC(lpfc_force_rscn,
+ "Force an RSCN to be sent to all remote NPorts");
+lpfc_param_show(force_rscn)
+
+/**
+ * lpfc_force_rscn_init - Force an RSCN to be sent to all remote NPorts
+ * @phba: lpfc_hba pointer.
+ * @val: unused value.
+ *
+ * Returns:
+ * zero if val saved.
+ **/
+static int
+lpfc_force_rscn_init(struct lpfc_hba *phba, int val)
+{
+ return 0;
+}
+static DEVICE_ATTR_RW(lpfc_force_rscn);
+
+/**
* lpfc_fcp_imax_store
*
* @dev: class device that is converted into a Scsi_host.
@@ -5075,7 +5180,8 @@ lpfc_cq_max_proc_limit_store(struct device *dev, struct device_attribute *attr,
/* set the values on the cq's */
for (i = 0; i < phba->cfg_irq_chann; i++) {
- eq = phba->sli4_hba.hdwq[i].hba_eq;
+ /* Get the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[i].eq;
if (!eq)
continue;
@@ -5169,12 +5275,12 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
switch (phba->cfg_fcp_cpu_map) {
case 0:
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"fcp_cpu_map: No mapping (%d)\n",
phba->cfg_fcp_cpu_map);
return len;
case 1:
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"fcp_cpu_map: HBA centric mapping (%d): "
"%d of %d CPUs online from %d possible CPUs\n",
phba->cfg_fcp_cpu_map, num_online_cpus(),
@@ -5188,43 +5294,52 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
cpup = &phba->sli4_hba.cpu_map[phba->sli4_hba.curr_disp_cpu];
if (!cpu_present(phba->sli4_hba.curr_disp_cpu))
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"CPU %02d not present\n",
phba->sli4_hba.curr_disp_cpu);
else if (cpup->irq == LPFC_VECTOR_MAP_EMPTY) {
if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY)
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"CPU %02d hdwq None "
- "physid %d coreid %d ht %d\n",
+ "physid %d coreid %d ht %d ua %d\n",
phba->sli4_hba.curr_disp_cpu,
- cpup->phys_id,
- cpup->core_id, cpup->hyper);
+ cpup->phys_id, cpup->core_id,
+ (cpup->flag & LPFC_CPU_MAP_HYPER),
+ (cpup->flag & LPFC_CPU_MAP_UNASSIGN));
else
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"CPU %02d EQ %04d hdwq %04d "
- "physid %d coreid %d ht %d\n",
+ "physid %d coreid %d ht %d ua %d\n",
phba->sli4_hba.curr_disp_cpu,
cpup->eq, cpup->hdwq, cpup->phys_id,
- cpup->core_id, cpup->hyper);
+ cpup->core_id,
+ (cpup->flag & LPFC_CPU_MAP_HYPER),
+ (cpup->flag & LPFC_CPU_MAP_UNASSIGN));
} else {
if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY)
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"CPU %02d hdwq None "
- "physid %d coreid %d ht %d IRQ %d\n",
+ "physid %d coreid %d ht %d ua %d IRQ %d\n",
phba->sli4_hba.curr_disp_cpu,
cpup->phys_id,
- cpup->core_id, cpup->hyper, cpup->irq);
+ cpup->core_id,
+ (cpup->flag & LPFC_CPU_MAP_HYPER),
+ (cpup->flag & LPFC_CPU_MAP_UNASSIGN),
+ cpup->irq);
else
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"CPU %02d EQ %04d hdwq %04d "
- "physid %d coreid %d ht %d IRQ %d\n",
+ "physid %d coreid %d ht %d ua %d IRQ %d\n",
phba->sli4_hba.curr_disp_cpu,
cpup->eq, cpup->hdwq, cpup->phys_id,
- cpup->core_id, cpup->hyper, cpup->irq);
+ cpup->core_id,
+ (cpup->flag & LPFC_CPU_MAP_HYPER),
+ (cpup->flag & LPFC_CPU_MAP_UNASSIGN),
+ cpup->irq);
}
phba->sli4_hba.curr_disp_cpu++;
@@ -5233,7 +5348,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr,
if (phba->sli4_hba.curr_disp_cpu <
phba->sli4_hba.num_possible_cpu &&
(len >= (PAGE_SIZE - 64))) {
- len += snprintf(buf + len,
+ len += scnprintf(buf + len,
PAGE_SIZE - len, "more...\n");
break;
}
@@ -5753,10 +5868,10 @@ lpfc_sg_seg_cnt_show(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
int len;
- len = snprintf(buf, PAGE_SIZE, "SGL sz: %d total SGEs: %d\n",
+ len = scnprintf(buf, PAGE_SIZE, "SGL sz: %d total SGEs: %d\n",
phba->cfg_sg_dma_buf_size, phba->cfg_total_seg_cnt);
- len += snprintf(buf + len, PAGE_SIZE, "Cfg: %d SCSI: %d NVME: %d\n",
+ len += scnprintf(buf + len, PAGE_SIZE, "Cfg: %d SCSI: %d NVME: %d\n",
phba->cfg_sg_seg_cnt, phba->cfg_scsi_seg_cnt,
phba->cfg_nvme_seg_cnt);
return len;
@@ -5911,6 +6026,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_nvme_oas,
&dev_attr_lpfc_nvme_embed_cmd,
&dev_attr_lpfc_fcp_imax,
+ &dev_attr_lpfc_force_rscn,
&dev_attr_lpfc_cq_poll_threshold,
&dev_attr_lpfc_cq_max_proc_limit,
&dev_attr_lpfc_fcp_cpu_map,
@@ -6755,7 +6871,7 @@ lpfc_show_rport_##field (struct device *dev, \
{ \
struct fc_rport *rport = transport_class_to_rport(dev); \
struct lpfc_rport_data *rdata = rport->hostdata; \
- return snprintf(buf, sz, format_string, \
+ return scnprintf(buf, sz, format_string, \
(rdata->target) ? cast rdata->target->field : 0); \
}
@@ -6958,6 +7074,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_nvme_oas_init(phba, lpfc_nvme_oas);
lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
+ lpfc_force_rscn_init(phba, lpfc_force_rscn);
lpfc_cq_poll_threshold_init(phba, lpfc_cq_poll_threshold);
lpfc_cq_max_proc_limit_init(phba, lpfc_cq_max_proc_limit);
lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
@@ -7003,6 +7120,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
if (phba->sli_rev != LPFC_SLI_REV4) {
/* NVME only supported on SLI4 */
phba->nvmet_support = 0;
+ phba->cfg_nvmet_mrq = 0;
phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
phba->cfg_enable_bbcr = 0;
phba->cfg_xri_rebalancing = 0;
@@ -7104,7 +7222,7 @@ lpfc_nvme_mod_param_dep(struct lpfc_hba *phba)
} else {
/* Not NVME Target mode. Turn off Target parameters. */
phba->nvmet_support = 0;
- phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_OFF;
+ phba->cfg_nvmet_mrq = 0;
phba->cfg_nvmet_fb_size = 0;
}
}
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index f2494d3b365c..b7216d694bff 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2009-2015 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1968,14 +1968,17 @@ link_diag_state_set_out:
}
/**
- * lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic
+ * lpfc_sli4_bsg_set_loopback_mode - set sli4 internal loopback diagnostic
* @phba: Pointer to HBA context object.
+ * @mode: loopback mode to set
+ * @link_no: link number for loopback mode to set
*
* This function is responsible for issuing a sli4 mailbox command for setting
- * up internal loopback diagnostic.
+ * up loopback diagnostic for a link.
*/
static int
-lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba)
+lpfc_sli4_bsg_set_loopback_mode(struct lpfc_hba *phba, int mode,
+ uint32_t link_no)
{
LPFC_MBOXQ_t *pmboxq;
uint32_t req_len, alloc_len;
@@ -1996,11 +1999,19 @@ lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba)
}
link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback;
bf_set(lpfc_mbx_set_diag_state_link_num,
- &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_no);
- bf_set(lpfc_mbx_set_diag_state_link_type,
- &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp);
+ &link_diag_loopback->u.req, link_no);
+
+ if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
+ bf_set(lpfc_mbx_set_diag_state_link_type,
+ &link_diag_loopback->u.req, LPFC_LNK_FC_TRUNKED);
+ } else {
+ bf_set(lpfc_mbx_set_diag_state_link_type,
+ &link_diag_loopback->u.req,
+ phba->sli4_hba.lnk_info.lnk_tp);
+ }
+
bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req,
- LPFC_DIAG_LOOPBACK_TYPE_INTERNAL);
+ mode);
mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) {
@@ -2054,7 +2065,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
struct fc_bsg_request *bsg_request = job->request;
struct fc_bsg_reply *bsg_reply = job->reply;
struct diag_mode_set *loopback_mode;
- uint32_t link_flags, timeout;
+ uint32_t link_flags, timeout, link_no;
int i, rc = 0;
/* no data to return just the return code */
@@ -2069,12 +2080,39 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
(int)(sizeof(struct fc_bsg_request) +
sizeof(struct diag_mode_set)));
rc = -EINVAL;
- goto job_error;
+ goto job_done;
+ }
+
+ loopback_mode = (struct diag_mode_set *)
+ bsg_request->rqst_data.h_vendor.vendor_cmd;
+ link_flags = loopback_mode->type;
+ timeout = loopback_mode->timeout * 100;
+
+ if (loopback_mode->physical_link == -1)
+ link_no = phba->sli4_hba.lnk_info.lnk_no;
+ else
+ link_no = loopback_mode->physical_link;
+
+ if (link_flags == DISABLE_LOOP_BACK) {
+ rc = lpfc_sli4_bsg_set_loopback_mode(phba,
+ LPFC_DIAG_LOOPBACK_TYPE_DISABLE,
+ link_no);
+ if (!rc) {
+ /* Unset the need disable bit */
+ phba->sli4_hba.conf_trunk &= ~((1 << link_no) << 4);
+ }
+ goto job_done;
+ } else {
+ /* Check if we need to disable the loopback state */
+ if (phba->sli4_hba.conf_trunk & ((1 << link_no) << 4)) {
+ rc = -EPERM;
+ goto job_done;
+ }
}
rc = lpfc_bsg_diag_mode_enter(phba);
if (rc)
- goto job_error;
+ goto job_done;
/* indicate we are in loobpack diagnostic mode */
spin_lock_irq(&phba->hbalock);
@@ -2084,15 +2122,11 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
/* reset port to start frome scratch */
rc = lpfc_selective_reset(phba);
if (rc)
- goto job_error;
+ goto job_done;
/* bring the link to diagnostic mode */
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"3129 Bring link to diagnostic state.\n");
- loopback_mode = (struct diag_mode_set *)
- bsg_request->rqst_data.h_vendor.vendor_cmd;
- link_flags = loopback_mode->type;
- timeout = loopback_mode->timeout * 100;
rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1);
if (rc) {
@@ -2120,13 +2154,54 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct bsg_job *job)
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"3132 Set up loopback mode:x%x\n", link_flags);
- if (link_flags == INTERNAL_LOOP_BACK)
- rc = lpfc_sli4_bsg_set_internal_loopback(phba);
- else if (link_flags == EXTERNAL_LOOP_BACK)
- rc = lpfc_hba_init_link_fc_topology(phba,
- FLAGS_TOPOLOGY_MODE_PT_PT,
- MBX_NOWAIT);
- else {
+ switch (link_flags) {
+ case INTERNAL_LOOP_BACK:
+ if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
+ rc = lpfc_sli4_bsg_set_loopback_mode(phba,
+ LPFC_DIAG_LOOPBACK_TYPE_INTERNAL,
+ link_no);
+ } else {
+ /* Trunk is configured, but link is not in this trunk */
+ if (phba->sli4_hba.conf_trunk) {
+ rc = -ELNRNG;
+ goto loopback_mode_exit;
+ }
+
+ rc = lpfc_sli4_bsg_set_loopback_mode(phba,
+ LPFC_DIAG_LOOPBACK_TYPE_INTERNAL,
+ link_no);
+ }
+
+ if (!rc) {
+ /* Set the need disable bit */
+ phba->sli4_hba.conf_trunk |= (1 << link_no) << 4;
+ }
+
+ break;
+ case EXTERNAL_LOOP_BACK:
+ if (phba->sli4_hba.conf_trunk & (1 << link_no)) {
+ rc = lpfc_sli4_bsg_set_loopback_mode(phba,
+ LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED,
+ link_no);
+ } else {
+ /* Trunk is configured, but link is not in this trunk */
+ if (phba->sli4_hba.conf_trunk) {
+ rc = -ELNRNG;
+ goto loopback_mode_exit;
+ }
+
+ rc = lpfc_sli4_bsg_set_loopback_mode(phba,
+ LPFC_DIAG_LOOPBACK_TYPE_SERDES,
+ link_no);
+ }
+
+ if (!rc) {
+ /* Set the need disable bit */
+ phba->sli4_hba.conf_trunk |= (1 << link_no) << 4;
+ }
+
+ break;
+ default:
rc = -EINVAL;
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
"3141 Loopback mode:x%x not supported\n",
@@ -2185,7 +2260,7 @@ loopback_mode_exit:
}
lpfc_bsg_diag_mode_exit(phba);
-job_error:
+job_done:
/* make error code available to userspace */
bsg_reply->result = rc;
/* complete the job back to userspace if no error */
@@ -5666,7 +5741,7 @@ lpfc_get_trunk_info(struct bsg_job *job)
event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000;
event_reply->logical_speed =
- phba->sli4_hba.link_state.logical_speed / 100;
+ phba->sli4_hba.link_state.logical_speed / 1000;
job_error:
bsg_reply->result = rc;
bsg_job_done(job, bsg_reply->result,
diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h
index 9151824beea4..d1708133fd54 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.h
+++ b/drivers/scsi/lpfc/lpfc_bsg.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2010-2015 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -68,6 +68,7 @@ struct send_mgmt_resp {
};
+#define DISABLE_LOOP_BACK 0x0 /* disables loop back */
#define INTERNAL_LOOP_BACK 0x1 /* adapter short cuts the loop internally */
#define EXTERNAL_LOOP_BACK 0x2 /* requires an external loopback plug */
@@ -75,6 +76,7 @@ struct diag_mode_set {
uint32_t command;
uint32_t type;
uint32_t timeout;
+ uint32_t physical_link;
};
struct sli4_link_diag {
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index e0b14d791b8c..68e9f96242d3 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -141,6 +141,7 @@ int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
+int lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry);
int lpfc_issue_fabric_reglogin(struct lpfc_vport *);
int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
@@ -355,6 +356,7 @@ void lpfc_mbox_timeout_handler(struct lpfc_hba *);
struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
struct lpfc_name *);
+struct lpfc_nodelist *lpfc_findnode_mapped(struct lpfc_vport *vport);
int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
@@ -555,6 +557,8 @@ void lpfc_ras_stop_fwlog(struct lpfc_hba *phba);
int lpfc_check_fwlog_support(struct lpfc_hba *phba);
/* NVME interfaces. */
+void lpfc_nvme_rescan_port(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp);
void lpfc_nvme_unregister_port(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp);
int lpfc_nvme_register_port(struct lpfc_vport *vport,
@@ -568,7 +572,8 @@ void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba);
void lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba,
struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb);
void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx,
- struct rqb_dmabuf *nvmebuf, uint64_t isr_ts);
+ struct rqb_dmabuf *nvmebuf, uint64_t isr_ts,
+ uint8_t cqflag);
void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba);
void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba,
struct lpfc_iocbq *cmdiocb,
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 7290573110fe..ec72c39997d2 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -886,7 +886,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
if (lpfc_error_lost_link(irsp)) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "4101 NS query failed due to link event\n");
+ "4166 NS query failed due to link event\n");
if (vport->fc_flag & FC_RSCN_MODE)
lpfc_els_flush_rscn(vport);
goto out;
@@ -907,7 +907,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* Re-issue the NS cmd
*/
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- "4102 Process Deferred RSCN Data: x%x x%x\n",
+ "4167 Process Deferred RSCN Data: x%x x%x\n",
vport->fc_flag, vport->fc_rscn_id_cnt);
lpfc_els_handle_rscn(vport);
@@ -1430,7 +1430,7 @@ lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
* Name object. NPIV is not in play so this integer
* value is sufficient and unique per FC-ID.
*/
- n = snprintf(symbol, size, "%d", vport->phba->brd_no);
+ n = scnprintf(symbol, size, "%d", vport->phba->brd_no);
return n;
}
@@ -1444,26 +1444,26 @@ lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
- n = snprintf(symbol, size, "Emulex %s", vport->phba->ModelName);
+ n = scnprintf(symbol, size, "Emulex %s", vport->phba->ModelName);
if (size < n)
return n;
- n += snprintf(symbol + n, size - n, " FV%s", fwrev);
+ n += scnprintf(symbol + n, size - n, " FV%s", fwrev);
if (size < n)
return n;
- n += snprintf(symbol + n, size - n, " DV%s.",
+ n += scnprintf(symbol + n, size - n, " DV%s.",
lpfc_release_version);
if (size < n)
return n;
- n += snprintf(symbol + n, size - n, " HN:%s.",
+ n += scnprintf(symbol + n, size - n, " HN:%s.",
init_utsname()->nodename);
if (size < n)
return n;
/* Note :- OS name is "Linux" */
- n += snprintf(symbol + n, size - n, " OS:%s\n",
+ n += scnprintf(symbol + n, size - n, " OS:%s",
init_utsname()->sysname);
return n;
}
@@ -2005,8 +2005,11 @@ lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
memset(ae, 0, 256);
+ /* This string MUST be consistent with other FC platforms
+ * supported by Broadcom.
+ */
strncpy(ae->un.AttrString,
- "Broadcom Inc.",
+ "Emulex Corporation",
sizeof(ae->un.AttrString));
len = strnlen(ae->un.AttrString,
sizeof(ae->un.AttrString));
@@ -2301,7 +2304,8 @@ lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
memset(ae, 0, 256);
- lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ strlcat(ae->un.AttrString, phba->BIOSVersion,
+ sizeof(ae->un.AttrString));
len = strnlen(ae->un.AttrString,
sizeof(ae->un.AttrString));
len += (len & 3) ? (4 - (len & 3)) : 4;
@@ -2354,16 +2358,22 @@ static int
lpfc_fdmi_port_attr_fc4type(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;
memset(ae, 0, 32);
- ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
- ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
- ae->un.AttrTypes[6] = 0x01; /* Type 40 - NVME */
- ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+ ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */
+ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
+
+ /* Check to see if Firmware supports NVME and on physical port */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && (vport == phba->pport) &&
+ phba->sli4_hba.pc_sli4_params.nvme)
+ ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */
+
size = FOURBYTES + 32;
ad->AttrLen = cpu_to_be16(size);
ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
@@ -2673,9 +2683,14 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
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 */
+ ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */
+ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
+
+ /* Check to see if NVME is configured or not */
+ if (vport->phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
+ ae->un.AttrTypes[6] = 0x1; /* Type 0x28 - NVME */
+
size = FOURBYTES + 32;
ad->AttrLen = cpu_to_be16(size);
ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
@@ -3092,6 +3107,7 @@ port_out:
case SLI_MGMT_GHAT:
case SLI_MGMT_GRPL:
rsp_size = FC_MAX_NS_RSP;
+ /* fall through */
case SLI_MGMT_DHBA:
case SLI_MGMT_DHAT:
pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID;
@@ -3104,6 +3120,7 @@ port_out:
case SLI_MGMT_GPAT:
case SLI_MGMT_GPAS:
rsp_size = FC_MAX_NS_RSP;
+ /* fall through */
case SLI_MGMT_DPRT:
case SLI_MGMT_DPA:
pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 1215eaa530db..1ee857d9d165 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -170,7 +170,7 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
snprintf(buffer,
LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
dtp->seq_cnt, ms, dtp->fmt);
- len += snprintf(buf+len, size-len, buffer,
+ len += scnprintf(buf+len, size-len, buffer,
dtp->data1, dtp->data2, dtp->data3);
}
for (i = 0; i < index; i++) {
@@ -181,7 +181,7 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
snprintf(buffer,
LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
dtp->seq_cnt, ms, dtp->fmt);
- len += snprintf(buf+len, size-len, buffer,
+ len += scnprintf(buf+len, size-len, buffer,
dtp->data1, dtp->data2, dtp->data3);
}
@@ -236,7 +236,7 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
snprintf(buffer,
LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
dtp->seq_cnt, ms, dtp->fmt);
- len += snprintf(buf+len, size-len, buffer,
+ len += scnprintf(buf+len, size-len, buffer,
dtp->data1, dtp->data2, dtp->data3);
}
for (i = 0; i < index; i++) {
@@ -247,7 +247,7 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
snprintf(buffer,
LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
dtp->seq_cnt, ms, dtp->fmt);
- len += snprintf(buf+len, size-len, buffer,
+ len += scnprintf(buf+len, size-len, buffer,
dtp->data1, dtp->data2, dtp->data3);
}
@@ -307,7 +307,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
i = lpfc_debugfs_last_hbq;
- len += snprintf(buf+len, size-len, "HBQ %d Info\n", i);
+ len += scnprintf(buf+len, size-len, "HBQ %d Info\n", i);
hbqs = &phba->hbqs[i];
posted = 0;
@@ -315,21 +315,21 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
posted++;
hip = lpfc_hbq_defs[i];
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n",
hip->hbq_index, hip->profile, hip->rn,
hip->buffer_count, hip->init_count, hip->add_count, posted);
raw_index = phba->hbq_get[i];
getidx = le32_to_cpu(raw_index);
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"entries:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx,
hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx);
hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
for (j=0; j<hbqs->entry_count; j++) {
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"%03d: %08x %04x %05x ", j,
le32_to_cpu(hbqe->bde.addrLow),
le32_to_cpu(hbqe->bde.tus.w),
@@ -341,14 +341,16 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
low = hbqs->hbqPutIdx - posted;
if (low >= 0) {
if ((j >= hbqs->hbqPutIdx) || (j < low)) {
- len += snprintf(buf+len, size-len, "Unused\n");
+ len += scnprintf(buf + len, size - len,
+ "Unused\n");
goto skipit;
}
}
else {
if ((j >= hbqs->hbqPutIdx) &&
(j < (hbqs->entry_count+low))) {
- len += snprintf(buf+len, size-len, "Unused\n");
+ len += scnprintf(buf + len, size - len,
+ "Unused\n");
goto skipit;
}
}
@@ -358,7 +360,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
if (phys == le32_to_cpu(hbqe->bde.addrLow)) {
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"Buf%d: %p %06x\n", i,
hbq_buf->dbuf.virt, hbq_buf->tag);
found = 1;
@@ -367,7 +369,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
i++;
}
if (!found) {
- len += snprintf(buf+len, size-len, "No DMAinfo?\n");
+ len += scnprintf(buf+len, size-len, "No DMAinfo?\n");
}
skipit:
hbqe++;
@@ -413,14 +415,14 @@ lpfc_debugfs_commonxripools_data(struct lpfc_hba *phba, char *buf, int size)
break;
qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_xripool];
- len += snprintf(buf + len, size - len, "HdwQ %d Info ", i);
+ len += scnprintf(buf + len, size - len, "HdwQ %d Info ", i);
spin_lock_irqsave(&qp->abts_scsi_buf_list_lock, iflag);
spin_lock(&qp->abts_nvme_buf_list_lock);
spin_lock(&qp->io_buf_list_get_lock);
spin_lock(&qp->io_buf_list_put_lock);
out = qp->total_io_bufs - (qp->get_io_bufs + qp->put_io_bufs +
qp->abts_scsi_io_bufs + qp->abts_nvme_io_bufs);
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"tot:%d get:%d put:%d mt:%d "
"ABTS scsi:%d nvme:%d Out:%d\n",
qp->total_io_bufs, qp->get_io_bufs, qp->put_io_bufs,
@@ -612,9 +614,9 @@ lpfc_debugfs_lockstat_data(struct lpfc_hba *phba, char *buf, int size)
break;
qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_lock];
- len += snprintf(buf + len, size - len, "HdwQ %03d Lock ", i);
+ len += scnprintf(buf + len, size - len, "HdwQ %03d Lock ", i);
if (phba->cfg_xri_rebalancing) {
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"get_pvt:%d mv_pvt:%d "
"mv2pub:%d mv2pvt:%d "
"put_pvt:%d put_pub:%d wq:%d\n",
@@ -626,7 +628,7 @@ lpfc_debugfs_lockstat_data(struct lpfc_hba *phba, char *buf, int size)
qp->lock_conflict.free_pub_pool,
qp->lock_conflict.wq_access);
} else {
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"get:%d put:%d free:%d wq:%d\n",
qp->lock_conflict.alloc_xri_get,
qp->lock_conflict.alloc_xri_put,
@@ -678,7 +680,7 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
off = 0;
spin_lock_irq(&phba->hbalock);
- len += snprintf(buf+len, size-len, "HBA SLIM\n");
+ len += scnprintf(buf+len, size-len, "HBA SLIM\n");
lpfc_memcpy_from_slim(buffer,
phba->MBslimaddr + lpfc_debugfs_last_hba_slim_off, 1024);
@@ -692,7 +694,7 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
i = 1024;
while (i > 0) {
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
*(ptr+5), *(ptr+6), *(ptr+7));
@@ -736,11 +738,11 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
off = 0;
spin_lock_irq(&phba->hbalock);
- len += snprintf(buf+len, size-len, "SLIM Mailbox\n");
+ len += scnprintf(buf+len, size-len, "SLIM Mailbox\n");
ptr = (uint32_t *)phba->slim2p.virt;
i = sizeof(MAILBOX_t);
while (i > 0) {
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
*(ptr+5), *(ptr+6), *(ptr+7));
@@ -749,11 +751,11 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
off += (8 * sizeof(uint32_t));
}
- len += snprintf(buf+len, size-len, "SLIM PCB\n");
+ len += scnprintf(buf+len, size-len, "SLIM PCB\n");
ptr = (uint32_t *)phba->pcb;
i = sizeof(PCB_t);
while (i > 0) {
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
*(ptr+5), *(ptr+6), *(ptr+7));
@@ -766,7 +768,7 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
for (i = 0; i < 4; i++) {
pgpp = &phba->port_gp[i];
pring = &psli->sli3_ring[i];
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"Ring %d: CMD GetInx:%d "
"(Max:%d Next:%d "
"Local:%d flg:x%x) "
@@ -783,7 +785,7 @@ lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
word1 = readl(phba->CAregaddr);
word2 = readl(phba->HSregaddr);
word3 = readl(phba->HCregaddr);
- len += snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x "
+ len += scnprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x "
"HC:%08x\n", word0, word1, word2, word3);
}
spin_unlock_irq(&phba->hbalock);
@@ -821,12 +823,12 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
outio = 0;
- len += snprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n");
+ len += scnprintf(buf+len, size-len, "\nFCP Nodelist Entries ...\n");
spin_lock_irq(shost->host_lock);
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
iocnt = 0;
if (!cnt) {
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"Missing Nodelist Entries\n");
break;
}
@@ -864,63 +866,63 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
default:
statep = "UNKNOWN";
}
- len += snprintf(buf+len, size-len, "%s DID:x%06x ",
+ len += scnprintf(buf+len, size-len, "%s DID:x%06x ",
statep, ndlp->nlp_DID);
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"WWPN x%llx ",
wwn_to_u64(ndlp->nlp_portname.u.wwn));
- len += snprintf(buf+len, size-len,
+ len += scnprintf(buf+len, size-len,
"WWNN x%llx ",
wwn_to_u64(ndlp->nlp_nodename.u.wwn));
if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
- len += snprintf(buf+len, size-len, "RPI:%03d ",
+ len += scnprintf(buf+len, size-len, "RPI:%03d ",
ndlp->nlp_rpi);
else
- len += snprintf(buf+len, size-len, "RPI:none ");
- len += snprintf(buf+len, size-len, "flag:x%08x ",
+ len += scnprintf(buf+len, size-len, "RPI:none ");
+ len += scnprintf(buf+len, size-len, "flag:x%08x ",
ndlp->nlp_flag);
if (!ndlp->nlp_type)
- len += snprintf(buf+len, size-len, "UNKNOWN_TYPE ");
+ len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE ");
if (ndlp->nlp_type & NLP_FC_NODE)
- len += snprintf(buf+len, size-len, "FC_NODE ");
+ len += scnprintf(buf+len, size-len, "FC_NODE ");
if (ndlp->nlp_type & NLP_FABRIC) {
- len += snprintf(buf+len, size-len, "FABRIC ");
+ len += scnprintf(buf+len, size-len, "FABRIC ");
iocnt = 0;
}
if (ndlp->nlp_type & NLP_FCP_TARGET)
- len += snprintf(buf+len, size-len, "FCP_TGT sid:%d ",
+ len += scnprintf(buf+len, size-len, "FCP_TGT sid:%d ",
ndlp->nlp_sid);
if (ndlp->nlp_type & NLP_FCP_INITIATOR)
- len += snprintf(buf+len, size-len, "FCP_INITIATOR ");
+ len += scnprintf(buf+len, size-len, "FCP_INITIATOR ");
if (ndlp->nlp_type & NLP_NVME_TARGET)
- len += snprintf(buf + len,
+ len += scnprintf(buf + len,
size - len, "NVME_TGT sid:%d ",
NLP_NO_SID);
if (ndlp->nlp_type & NLP_NVME_INITIATOR)
- len += snprintf(buf + len,
+ len += scnprintf(buf + len,
size - len, "NVME_INITIATOR ");
- len += snprintf(buf+len, size-len, "usgmap:%x ",
+ len += scnprintf(buf+len, size-len, "usgmap:%x ",
ndlp->nlp_usg_map);
- len += snprintf(buf+len, size-len, "refcnt:%x",
+ len += scnprintf(buf+len, size-len, "refcnt:%x",
kref_read(&ndlp->kref));
if (iocnt) {
i = atomic_read(&ndlp->cmd_pending);
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
" OutIO:x%x Qdepth x%x",
i, ndlp->cmd_qdepth);
outio += i;
}
- len += snprintf(buf + len, size - len, "defer:%x ",
+ len += scnprintf(buf + len, size - len, "defer:%x ",
ndlp->nlp_defer_did);
- len += snprintf(buf+len, size-len, "\n");
+ len += scnprintf(buf+len, size-len, "\n");
}
spin_unlock_irq(shost->host_lock);
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"\nOutstanding IO x%x\n", outio);
if (phba->nvmet_support && phba->targetport && (vport == phba->pport)) {
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"\nNVME Targetport Entry ...\n");
/* Port state is only one of two values for now. */
@@ -928,18 +930,18 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
statep = "REGISTERED";
else
statep = "INIT";
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"TGT WWNN x%llx WWPN x%llx State %s\n",
wwn_to_u64(vport->fc_nodename.u.wwn),
wwn_to_u64(vport->fc_portname.u.wwn),
statep);
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
" Targetport DID x%06x\n",
phba->targetport->port_id);
goto out_exit;
}
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"\nNVME Lport/Rport Entries ...\n");
localport = vport->localport;
@@ -954,11 +956,11 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
else
statep = "UNKNOWN ";
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Lport DID x%06x PortState %s\n",
localport->port_id, statep);
- len += snprintf(buf + len, size - len, "\tRport List:\n");
+ len += scnprintf(buf + len, size - len, "\tRport List:\n");
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
/* local short-hand pointer. */
spin_lock(&phba->hbalock);
@@ -985,32 +987,32 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
}
/* Tab in to show lport ownership. */
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"\t%s Port ID:x%06x ",
statep, nrport->port_id);
- len += snprintf(buf + len, size - len, "WWPN x%llx ",
+ len += scnprintf(buf + len, size - len, "WWPN x%llx ",
nrport->port_name);
- len += snprintf(buf + len, size - len, "WWNN x%llx ",
+ len += scnprintf(buf + len, size - len, "WWNN x%llx ",
nrport->node_name);
/* An NVME rport can have multiple roles. */
if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR)
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"INITIATOR ");
if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET)
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"TARGET ");
if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY)
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"DISCSRVC ");
if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR |
FC_PORT_ROLE_NVME_TARGET |
FC_PORT_ROLE_NVME_DISCOVERY))
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"UNKNOWN ROLE x%x",
nrport->port_role);
/* Terminate the string. */
- len += snprintf(buf + len, size - len, "\n");
+ len += scnprintf(buf + len, size - len, "\n");
}
spin_unlock_irq(shost->host_lock);
@@ -1049,35 +1051,35 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
if (!phba->targetport)
return len;
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"\nNVME Targetport Statistics\n");
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"LS: Rcv %08x Drop %08x Abort %08x\n",
atomic_read(&tgtp->rcv_ls_req_in),
atomic_read(&tgtp->rcv_ls_req_drop),
atomic_read(&tgtp->xmt_ls_abort));
if (atomic_read(&tgtp->rcv_ls_req_in) !=
atomic_read(&tgtp->rcv_ls_req_out)) {
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Rcv LS: in %08x != out %08x\n",
atomic_read(&tgtp->rcv_ls_req_in),
atomic_read(&tgtp->rcv_ls_req_out));
}
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"LS: Xmt %08x Drop %08x Cmpl %08x\n",
atomic_read(&tgtp->xmt_ls_rsp),
atomic_read(&tgtp->xmt_ls_drop),
atomic_read(&tgtp->xmt_ls_rsp_cmpl));
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"LS: RSP Abort %08x xb %08x Err %08x\n",
atomic_read(&tgtp->xmt_ls_rsp_aborted),
atomic_read(&tgtp->xmt_ls_rsp_xb_set),
atomic_read(&tgtp->xmt_ls_rsp_error));
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"FCP: Rcv %08x Defer %08x Release %08x "
"Drop %08x\n",
atomic_read(&tgtp->rcv_fcp_cmd_in),
@@ -1087,13 +1089,13 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
if (atomic_read(&tgtp->rcv_fcp_cmd_in) !=
atomic_read(&tgtp->rcv_fcp_cmd_out)) {
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Rcv FCP: in %08x != out %08x\n",
atomic_read(&tgtp->rcv_fcp_cmd_in),
atomic_read(&tgtp->rcv_fcp_cmd_out));
}
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"FCP Rsp: read %08x readrsp %08x "
"write %08x rsp %08x\n",
atomic_read(&tgtp->xmt_fcp_read),
@@ -1101,31 +1103,31 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
atomic_read(&tgtp->xmt_fcp_write),
atomic_read(&tgtp->xmt_fcp_rsp));
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"FCP Rsp Cmpl: %08x err %08x drop %08x\n",
atomic_read(&tgtp->xmt_fcp_rsp_cmpl),
atomic_read(&tgtp->xmt_fcp_rsp_error),
atomic_read(&tgtp->xmt_fcp_rsp_drop));
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"FCP Rsp Abort: %08x xb %08x xricqe %08x\n",
atomic_read(&tgtp->xmt_fcp_rsp_aborted),
atomic_read(&tgtp->xmt_fcp_rsp_xb_set),
atomic_read(&tgtp->xmt_fcp_xri_abort_cqe));
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"ABORT: Xmt %08x Cmpl %08x\n",
atomic_read(&tgtp->xmt_fcp_abort),
atomic_read(&tgtp->xmt_fcp_abort_cmpl));
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"ABORT: Sol %08x Usol %08x Err %08x Cmpl %08x",
atomic_read(&tgtp->xmt_abort_sol),
atomic_read(&tgtp->xmt_abort_unsol),
atomic_read(&tgtp->xmt_abort_rsp),
atomic_read(&tgtp->xmt_abort_rsp_error));
- len += snprintf(buf + len, size - len, "\n");
+ len += scnprintf(buf + len, size - len, "\n");
cnt = 0;
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
@@ -1136,7 +1138,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
}
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
if (cnt) {
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"ABORT: %d ctx entries\n", cnt);
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
list_for_each_entry_safe(ctxp, next_ctxp,
@@ -1144,7 +1146,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
list) {
if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ))
break;
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Entry: oxid %x state %x "
"flag %x\n",
ctxp->oxid, ctxp->state,
@@ -1158,7 +1160,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
tot += atomic_read(&tgtp->xmt_fcp_release);
tot = atomic_read(&tgtp->rcv_fcp_cmd_in) - tot;
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"IO_CTX: %08x WAIT: cur %08x tot %08x\n"
"CTX Outstanding %08llx\n",
phba->sli4_hba.nvmet_xri_cnt,
@@ -1176,10 +1178,10 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
if (!lport)
return len;
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"\nNVME HDWQ Statistics\n");
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"LS: Xmt %016x Cmpl %016x\n",
atomic_read(&lport->fc4NvmeLsRequests),
atomic_read(&lport->fc4NvmeLsCmpls));
@@ -1199,20 +1201,20 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
if (i >= 32)
continue;
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"HDWQ (%d): Rd %016llx Wr %016llx "
"IO %016llx ",
i, data1, data2, data3);
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Cmpl %016llx OutIO %016llx\n",
tot, ((data1 + data2 + data3) - tot));
}
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Total FCP Cmpl %016llx Issue %016llx "
"OutIO %016llx\n",
totin, totout, totout - totin);
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"LS Xmt Err: Abrt %08x Err %08x "
"Cmpl Err: xb %08x Err %08x\n",
atomic_read(&lport->xmt_ls_abort),
@@ -1220,7 +1222,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
atomic_read(&lport->cmpl_ls_xb),
atomic_read(&lport->cmpl_ls_err));
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"FCP Xmt Err: noxri %06x nondlp %06x "
"qdepth %06x wqerr %06x err %06x Abrt %06x\n",
atomic_read(&lport->xmt_fcp_noxri),
@@ -1230,7 +1232,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size)
atomic_read(&lport->xmt_fcp_err),
atomic_read(&lport->xmt_fcp_abort));
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"FCP Cmpl Err: xb %08x Err %08x\n",
atomic_read(&lport->cmpl_fcp_xb),
atomic_read(&lport->cmpl_fcp_err));
@@ -1322,58 +1324,58 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
if (phba->nvmet_support == 0) {
/* NVME Initiator */
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"ktime %s: Total Samples: %lld\n",
(phba->ktime_on ? "Enabled" : "Disabled"),
phba->ktime_data_samples);
if (phba->ktime_data_samples == 0)
return len;
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"Segment 1: Last NVME Cmd cmpl "
"done -to- Start of next NVME cnd (in driver)\n");
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg1_total,
phba->ktime_data_samples),
phba->ktime_seg1_min,
phba->ktime_seg1_max);
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"Segment 2: Driver start of NVME cmd "
"-to- Firmware WQ doorbell\n");
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg2_total,
phba->ktime_data_samples),
phba->ktime_seg2_min,
phba->ktime_seg2_max);
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"Segment 3: Firmware WQ doorbell -to- "
"MSI-X ISR cmpl\n");
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg3_total,
phba->ktime_data_samples),
phba->ktime_seg3_min,
phba->ktime_seg3_max);
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"Segment 4: MSI-X ISR cmpl -to- "
"NVME cmpl done\n");
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg4_total,
phba->ktime_data_samples),
phba->ktime_seg4_min,
phba->ktime_seg4_max);
- len += snprintf(
+ len += scnprintf(
buf + len, PAGE_SIZE - len,
"Total IO avg time: %08lld\n",
div_u64(phba->ktime_seg1_total +
@@ -1385,7 +1387,7 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
}
/* NVME Target */
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"ktime %s: Total Samples: %lld %lld\n",
(phba->ktime_on ? "Enabled" : "Disabled"),
phba->ktime_data_samples,
@@ -1393,46 +1395,46 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
if (phba->ktime_data_samples == 0)
return len;
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 1: MSI-X ISR Rcv cmd -to- "
"cmd pass to NVME Layer\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg1_total,
phba->ktime_data_samples),
phba->ktime_seg1_min,
phba->ktime_seg1_max);
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 2: cmd pass to NVME Layer- "
"-to- Driver rcv cmd OP (action)\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg2_total,
phba->ktime_data_samples),
phba->ktime_seg2_min,
phba->ktime_seg2_max);
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 3: Driver rcv cmd OP -to- "
"Firmware WQ doorbell: cmd\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg3_total,
phba->ktime_data_samples),
phba->ktime_seg3_min,
phba->ktime_seg3_max);
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 4: Firmware WQ doorbell: cmd "
"-to- MSI-X ISR for cmd cmpl\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg4_total,
phba->ktime_data_samples),
phba->ktime_seg4_min,
phba->ktime_seg4_max);
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 5: MSI-X ISR for cmd cmpl "
"-to- NVME layer passed cmd done\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg5_total,
phba->ktime_data_samples),
@@ -1440,10 +1442,10 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
phba->ktime_seg5_max);
if (phba->ktime_status_samples == 0) {
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Total: cmd received by MSI-X ISR "
"-to- cmd completed on wire\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld "
"max %08lld\n",
div_u64(phba->ktime_seg10_total,
@@ -1453,46 +1455,46 @@ lpfc_debugfs_nvmektime_data(struct lpfc_vport *vport, char *buf, int size)
return len;
}
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 6: NVME layer passed cmd done "
"-to- Driver rcv rsp status OP\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg6_total,
phba->ktime_status_samples),
phba->ktime_seg6_min,
phba->ktime_seg6_max);
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 7: Driver rcv rsp status OP "
"-to- Firmware WQ doorbell: status\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg7_total,
phba->ktime_status_samples),
phba->ktime_seg7_min,
phba->ktime_seg7_max);
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 8: Firmware WQ doorbell: status"
" -to- MSI-X ISR for status cmpl\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg8_total,
phba->ktime_status_samples),
phba->ktime_seg8_min,
phba->ktime_seg8_max);
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Segment 9: MSI-X ISR for status cmpl "
"-to- NVME layer passed status done\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg9_total,
phba->ktime_status_samples),
phba->ktime_seg9_min,
phba->ktime_seg9_max);
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"Total: cmd received by MSI-X ISR -to- "
"cmd completed on wire\n");
- len += snprintf(buf + len, PAGE_SIZE-len,
+ len += scnprintf(buf + len, PAGE_SIZE-len,
"avg:%08lld min:%08lld max %08lld\n",
div_u64(phba->ktime_seg10_total,
phba->ktime_status_samples),
@@ -1527,7 +1529,7 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size)
(phba->nvmeio_trc_size - 1);
skip = phba->nvmeio_trc_output_idx;
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"%s IO Trace %s: next_idx %d skip %d size %d\n",
(phba->nvmet_support ? "NVME" : "NVMET"),
(state ? "Enabled" : "Disabled"),
@@ -1549,18 +1551,18 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size)
if (!dtp->fmt)
continue;
- len += snprintf(buf + len, size - len, dtp->fmt,
+ len += scnprintf(buf + len, size - len, dtp->fmt,
dtp->data1, dtp->data2, dtp->data3);
if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) {
phba->nvmeio_trc_output_idx = 0;
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Trace Complete\n");
goto out;
}
if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) {
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Trace Continue (%d of %d)\n",
phba->nvmeio_trc_output_idx,
phba->nvmeio_trc_size);
@@ -1578,18 +1580,18 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size)
if (!dtp->fmt)
continue;
- len += snprintf(buf + len, size - len, dtp->fmt,
+ len += scnprintf(buf + len, size - len, dtp->fmt,
dtp->data1, dtp->data2, dtp->data3);
if (phba->nvmeio_trc_output_idx >= phba->nvmeio_trc_size) {
phba->nvmeio_trc_output_idx = 0;
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Trace Complete\n");
goto out;
}
if (len >= (size - LPFC_DEBUG_OUT_LINE_SZ)) {
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Trace Continue (%d of %d)\n",
phba->nvmeio_trc_output_idx,
phba->nvmeio_trc_size);
@@ -1597,7 +1599,7 @@ lpfc_debugfs_nvmeio_trc_data(struct lpfc_hba *phba, char *buf, int size)
}
}
- len += snprintf(buf + len, size - len,
+ len += scnprintf(buf + len, size - len,
"Trace Done\n");
out:
return len;
@@ -1627,17 +1629,17 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size)
uint32_t tot_rcv;
uint32_t tot_cmpl;
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"CPUcheck %s ",
(phba->cpucheck_on & LPFC_CHECK_NVME_IO ?
"Enabled" : "Disabled"));
if (phba->nvmet_support) {
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"%s\n",
(phba->cpucheck_on & LPFC_CHECK_NVMET_RCV ?
"Rcv Enabled\n" : "Rcv Disabled\n"));
} else {
- len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
}
max_cnt = size - LPFC_DEBUG_OUT_LINE_SZ;
@@ -1658,7 +1660,7 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size)
if (!tot_xmt && !tot_cmpl && !tot_rcv)
continue;
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"HDWQ %03d: ", i);
for (j = 0; j < LPFC_CHECK_CPU_CNT; j++) {
/* Only display non-zero counters */
@@ -1667,22 +1669,22 @@ lpfc_debugfs_cpucheck_data(struct lpfc_vport *vport, char *buf, int size)
!qp->cpucheck_rcv_io[j])
continue;
if (phba->nvmet_support) {
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"CPU %03d: %x/%x/%x ", j,
qp->cpucheck_rcv_io[j],
qp->cpucheck_xmt_io[j],
qp->cpucheck_cmpl_io[j]);
} else {
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"CPU %03d: %x/%x ", j,
qp->cpucheck_xmt_io[j],
qp->cpucheck_cmpl_io[j]);
}
}
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Total: %x\n", tot_xmt);
if (len >= max_cnt) {
- len += snprintf(buf + len, PAGE_SIZE - len,
+ len += scnprintf(buf + len, PAGE_SIZE - len,
"Truncated ...\n");
return len;
}
@@ -2258,28 +2260,29 @@ lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
int cnt = 0;
if (dent == phba->debug_writeGuard)
- cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt);
+ cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt);
else if (dent == phba->debug_writeApp)
- cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt);
+ cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt);
else if (dent == phba->debug_writeRef)
- cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt);
+ cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt);
else if (dent == phba->debug_readGuard)
- cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt);
+ cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt);
else if (dent == phba->debug_readApp)
- cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt);
+ cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt);
else if (dent == phba->debug_readRef)
- cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt);
+ cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt);
else if (dent == phba->debug_InjErrNPortID)
- cnt = snprintf(cbuf, 32, "0x%06x\n", phba->lpfc_injerr_nportid);
+ cnt = scnprintf(cbuf, 32, "0x%06x\n",
+ phba->lpfc_injerr_nportid);
else if (dent == phba->debug_InjErrWWPN) {
memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name));
tmp = cpu_to_be64(tmp);
- cnt = snprintf(cbuf, 32, "0x%016llx\n", tmp);
+ cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp);
} else if (dent == phba->debug_InjErrLBA) {
if (phba->lpfc_injerr_lba == (sector_t)(-1))
- cnt = snprintf(cbuf, 32, "off\n");
+ cnt = scnprintf(cbuf, 32, "off\n");
else
- cnt = snprintf(cbuf, 32, "0x%llx\n",
+ cnt = scnprintf(cbuf, 32, "0x%llx\n",
(uint64_t) phba->lpfc_injerr_lba);
} else
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -3224,17 +3227,17 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes,
switch (count) {
case SIZE_U8: /* byte (8 bits) */
pci_read_config_byte(pdev, where, &u8val);
- len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
"%03x: %02x\n", where, u8val);
break;
case SIZE_U16: /* word (16 bits) */
pci_read_config_word(pdev, where, &u16val);
- len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
"%03x: %04x\n", where, u16val);
break;
case SIZE_U32: /* double word (32 bits) */
pci_read_config_dword(pdev, where, &u32val);
- len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
"%03x: %08x\n", where, u32val);
break;
case LPFC_PCI_CFG_BROWSE: /* browse all */
@@ -3254,25 +3257,25 @@ pcicfg_browse:
offset = offset_label;
/* Read PCI config space */
- len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
"%03x: ", offset_label);
while (index > 0) {
pci_read_config_dword(pdev, offset, &u32val);
- len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
"%08x ", u32val);
offset += sizeof(uint32_t);
if (offset >= LPFC_PCI_CFG_SIZE) {
- len += snprintf(pbuffer+len,
+ len += scnprintf(pbuffer+len,
LPFC_PCI_CFG_SIZE-len, "\n");
break;
}
index -= sizeof(uint32_t);
if (!index)
- len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
"\n");
else if (!(index % (8 * sizeof(uint32_t)))) {
offset_label += (8 * sizeof(uint32_t));
- len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
"\n%03x: ", offset_label);
}
}
@@ -3543,7 +3546,7 @@ lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes,
if (acc_range == SINGLE_WORD) {
offset_run = offset;
u32val = readl(mem_mapped_bar + offset_run);
- len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
"%05x: %08x\n", offset_run, u32val);
} else
goto baracc_browse;
@@ -3557,35 +3560,35 @@ baracc_browse:
offset_run = offset_label;
/* Read PCI bar memory mapped space */
- len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
"%05x: ", offset_label);
index = LPFC_PCI_BAR_RD_SIZE;
while (index > 0) {
u32val = readl(mem_mapped_bar + offset_run);
- len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
"%08x ", u32val);
offset_run += sizeof(uint32_t);
if (acc_range == LPFC_PCI_BAR_BROWSE) {
if (offset_run >= bar_size) {
- len += snprintf(pbuffer+len,
+ len += scnprintf(pbuffer+len,
LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
break;
}
} else {
if (offset_run >= offset +
(acc_range * sizeof(uint32_t))) {
- len += snprintf(pbuffer+len,
+ len += scnprintf(pbuffer+len,
LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
break;
}
}
index -= sizeof(uint32_t);
if (!index)
- len += snprintf(pbuffer+len,
+ len += scnprintf(pbuffer+len,
LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
else if (!(index % (8 * sizeof(uint32_t)))) {
offset_label += (8 * sizeof(uint32_t));
- len += snprintf(pbuffer+len,
+ len += scnprintf(pbuffer+len,
LPFC_PCI_BAR_RD_BUF_SIZE-len,
"\n%05x: ", offset_label);
}
@@ -3758,19 +3761,19 @@ __lpfc_idiag_print_wq(struct lpfc_queue *qp, char *wqtype,
if (!qp)
return len;
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"\t\t%s WQ info: ", wqtype);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"AssocCQID[%04d]: WQ-STAT[oflow:x%x posted:x%llx]\n",
qp->assoc_qid, qp->q_cnt_1,
(unsigned long long)qp->q_cnt_4);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"\t\tWQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
"HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]",
qp->queue_id, qp->entry_count,
qp->entry_size, qp->host_index,
qp->hba_index, qp->notify_interval);
- len += snprintf(pbuffer + len,
+ len += scnprintf(pbuffer + len,
LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n");
return len;
}
@@ -3810,21 +3813,22 @@ __lpfc_idiag_print_cq(struct lpfc_queue *qp, char *cqtype,
if (!qp)
return len;
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"\t%s CQ info: ", cqtype);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"AssocEQID[%02d]: CQ STAT[max:x%x relw:x%x "
"xabt:x%x wq:x%llx]\n",
qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2,
qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"\tCQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
"HST-IDX[%04d], NTFI[%03d], PLMT[%03d]",
qp->queue_id, qp->entry_count,
qp->entry_size, qp->host_index,
qp->notify_interval, qp->max_proc_limit);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n");
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ "\n");
return len;
}
@@ -3836,19 +3840,19 @@ __lpfc_idiag_print_rqpair(struct lpfc_queue *qp, struct lpfc_queue *datqp,
if (!qp || !datqp)
return len;
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"\t\t%s RQ info: ", rqtype);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"AssocCQID[%02d]: RQ-STAT[nopost:x%x nobuf:x%x "
"posted:x%x rcv:x%llx]\n",
qp->assoc_qid, qp->q_cnt_1, qp->q_cnt_2,
qp->q_cnt_3, (unsigned long long)qp->q_cnt_4);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"\t\tHQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
"HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n",
qp->queue_id, qp->entry_count, qp->entry_size,
qp->host_index, qp->hba_index, qp->notify_interval);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"\t\tDQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
"HST-IDX[%04d], PRT-IDX[%04d], NTFI[%03d]\n",
datqp->queue_id, datqp->entry_count,
@@ -3927,18 +3931,19 @@ __lpfc_idiag_print_eq(struct lpfc_queue *qp, char *eqtype,
if (!qp)
return len;
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"\n%s EQ info: EQ-STAT[max:x%x noE:x%x "
"cqe_proc:x%x eqe_proc:x%llx eqd %d]\n",
eqtype, qp->q_cnt_1, qp->q_cnt_2, qp->q_cnt_3,
(unsigned long long)qp->q_cnt_4, qp->q_mode);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
"EQID[%02d], QE-CNT[%04d], QE-SZ[%04d], "
"HST-IDX[%04d], NTFI[%03d], PLMT[%03d], AFFIN[%03d]",
qp->queue_id, qp->entry_count, qp->entry_size,
qp->host_index, qp->notify_interval,
qp->max_proc_limit, qp->chann);
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len, "\n");
+ len += scnprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ "\n");
return len;
}
@@ -3991,9 +3996,10 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes,
if (phba->lpfc_idiag_last_eq >= phba->cfg_hdw_queue)
phba->lpfc_idiag_last_eq = 0;
- len += snprintf(pbuffer + len, LPFC_QUE_INFO_GET_BUF_SIZE - len,
- "HDWQ %d out of %d HBA HDWQs\n",
- x, phba->cfg_hdw_queue);
+ len += scnprintf(pbuffer + len,
+ LPFC_QUE_INFO_GET_BUF_SIZE - len,
+ "HDWQ %d out of %d HBA HDWQs\n",
+ x, phba->cfg_hdw_queue);
/* Fast-path EQ */
qp = phba->sli4_hba.hdwq[x].hba_eq;
@@ -4075,7 +4081,7 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes,
return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
too_big:
- len += snprintf(pbuffer + len,
+ len += scnprintf(pbuffer + len,
LPFC_QUE_INFO_GET_BUF_SIZE - len, "Truncated ...\n");
out:
spin_unlock_irq(&phba->hbalock);
@@ -4131,22 +4137,22 @@ lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque,
return 0;
esize = pque->entry_size;
- len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
"QE-INDEX[%04d]:\n", index);
offset = 0;
- pentry = pque->qe[index].address;
+ pentry = lpfc_sli4_qe(pque, index);
while (esize > 0) {
- len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len,
"%08x ", *pentry);
pentry++;
offset += sizeof(uint32_t);
esize -= sizeof(uint32_t);
if (esize > 0 && !(offset % (4 * sizeof(uint32_t))))
- len += snprintf(pbuffer+len,
+ len += scnprintf(pbuffer+len,
LPFC_QUE_ACC_BUF_SIZE-len, "\n");
}
- len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n");
+ len += scnprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n");
return len;
}
@@ -4485,7 +4491,7 @@ pass_check:
pque = (struct lpfc_queue *)idiag.ptr_private;
if (offset > pque->entry_size/sizeof(uint32_t) - 1)
goto error_out;
- pentry = pque->qe[index].address;
+ pentry = lpfc_sli4_qe(pque, index);
pentry += offset;
if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR)
*pentry = value;
@@ -4506,7 +4512,7 @@ error_out:
* lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register
* @phba: The pointer to hba structure.
* @pbuffer: The pointer to the buffer to copy the data to.
- * @len: The lenght of bytes to copied.
+ * @len: The length of bytes to copied.
* @drbregid: The id to doorbell registers.
*
* Description:
@@ -4526,27 +4532,27 @@ lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
switch (drbregid) {
case LPFC_DRB_EQ:
- len += snprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE-len,
"EQ-DRB-REG: 0x%08x\n",
readl(phba->sli4_hba.EQDBregaddr));
break;
case LPFC_DRB_CQ:
- len += snprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len,
+ len += scnprintf(pbuffer + len, LPFC_DRB_ACC_BUF_SIZE - len,
"CQ-DRB-REG: 0x%08x\n",
readl(phba->sli4_hba.CQDBregaddr));
break;
case LPFC_DRB_MQ:
- len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
"MQ-DRB-REG: 0x%08x\n",
readl(phba->sli4_hba.MQDBregaddr));
break;
case LPFC_DRB_WQ:
- len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
"WQ-DRB-REG: 0x%08x\n",
readl(phba->sli4_hba.WQDBregaddr));
break;
case LPFC_DRB_RQ:
- len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
"RQ-DRB-REG: 0x%08x\n",
readl(phba->sli4_hba.RQDBregaddr));
break;
@@ -4716,7 +4722,7 @@ error_out:
* lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers
* @phba: The pointer to hba structure.
* @pbuffer: The pointer to the buffer to copy the data to.
- * @len: The lenght of bytes to copied.
+ * @len: The length of bytes to copied.
* @drbregid: The id to doorbell registers.
*
* Description:
@@ -4736,37 +4742,37 @@ lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
switch (ctlregid) {
case LPFC_CTL_PORT_SEM:
- len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
"Port SemReg: 0x%08x\n",
readl(phba->sli4_hba.conf_regs_memmap_p +
LPFC_CTL_PORT_SEM_OFFSET));
break;
case LPFC_CTL_PORT_STA:
- len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
"Port StaReg: 0x%08x\n",
readl(phba->sli4_hba.conf_regs_memmap_p +
LPFC_CTL_PORT_STA_OFFSET));
break;
case LPFC_CTL_PORT_CTL:
- len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
"Port CtlReg: 0x%08x\n",
readl(phba->sli4_hba.conf_regs_memmap_p +
LPFC_CTL_PORT_CTL_OFFSET));
break;
case LPFC_CTL_PORT_ER1:
- len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
"Port Er1Reg: 0x%08x\n",
readl(phba->sli4_hba.conf_regs_memmap_p +
LPFC_CTL_PORT_ER1_OFFSET));
break;
case LPFC_CTL_PORT_ER2:
- len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
"Port Er2Reg: 0x%08x\n",
readl(phba->sli4_hba.conf_regs_memmap_p +
LPFC_CTL_PORT_ER2_OFFSET));
break;
case LPFC_CTL_PDEV_CTL:
- len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
"PDev CtlReg: 0x%08x\n",
readl(phba->sli4_hba.conf_regs_memmap_p +
LPFC_CTL_PDEV_CTL_OFFSET));
@@ -4959,13 +4965,13 @@ lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer)
mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
- len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
"mbx_dump_map: 0x%08x\n", mbx_dump_map);
- len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
"mbx_dump_cnt: %04d\n", mbx_dump_cnt);
- len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
"mbx_word_cnt: %04d\n", mbx_word_cnt);
- len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
"mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd);
return len;
@@ -5114,35 +5120,35 @@ lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len)
{
uint16_t ext_cnt, ext_size;
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\nAvailable Extents Information:\n");
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tPort Available VPI extents: ");
lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI,
&ext_cnt, &ext_size);
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"Count %3d, Size %3d\n", ext_cnt, ext_size);
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tPort Available VFI extents: ");
lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI,
&ext_cnt, &ext_size);
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"Count %3d, Size %3d\n", ext_cnt, ext_size);
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tPort Available RPI extents: ");
lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI,
&ext_cnt, &ext_size);
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"Count %3d, Size %3d\n", ext_cnt, ext_size);
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tPort Available XRI extents: ");
lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI,
&ext_cnt, &ext_size);
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"Count %3d, Size %3d\n", ext_cnt, ext_size);
return len;
@@ -5166,55 +5172,55 @@ lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len)
uint16_t ext_cnt, ext_size;
int rc;
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\nAllocated Extents Information:\n");
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tHost Allocated VPI extents: ");
rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI,
&ext_cnt, &ext_size);
if (!rc)
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"Port %d Extent %3d, Size %3d\n",
phba->brd_no, ext_cnt, ext_size);
else
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"N/A\n");
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tHost Allocated VFI extents: ");
rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI,
&ext_cnt, &ext_size);
if (!rc)
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"Port %d Extent %3d, Size %3d\n",
phba->brd_no, ext_cnt, ext_size);
else
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"N/A\n");
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tHost Allocated RPI extents: ");
rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI,
&ext_cnt, &ext_size);
if (!rc)
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"Port %d Extent %3d, Size %3d\n",
phba->brd_no, ext_cnt, ext_size);
else
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"N/A\n");
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tHost Allocated XRI extents: ");
rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI,
&ext_cnt, &ext_size);
if (!rc)
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"Port %d Extent %3d, Size %3d\n",
phba->brd_no, ext_cnt, ext_size);
else
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"N/A\n");
return len;
@@ -5238,49 +5244,49 @@ lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len)
struct lpfc_rsrc_blks *rsrc_blks;
int index;
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\nDriver Extents Information:\n");
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tVPI extents:\n");
index = 0;
list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) {
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\t\tBlock %3d: Start %4d, Count %4d\n",
index, rsrc_blks->rsrc_start,
rsrc_blks->rsrc_size);
index++;
}
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tVFI extents:\n");
index = 0;
list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list,
list) {
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\t\tBlock %3d: Start %4d, Count %4d\n",
index, rsrc_blks->rsrc_start,
rsrc_blks->rsrc_size);
index++;
}
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tRPI extents:\n");
index = 0;
list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list,
list) {
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\t\tBlock %3d: Start %4d, Count %4d\n",
index, rsrc_blks->rsrc_start,
rsrc_blks->rsrc_size);
index++;
}
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\tXRI extents:\n");
index = 0;
list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list,
list) {
- len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+ len += scnprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
"\t\tBlock %3d: Start %4d, Count %4d\n",
index, rsrc_blks->rsrc_start,
rsrc_blks->rsrc_size);
@@ -5706,11 +5712,11 @@ lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp,
if (i != 0)
pr_err("%s\n", line_buf);
len = 0;
- len += snprintf(line_buf+len,
+ len += scnprintf(line_buf+len,
LPFC_MBX_ACC_LBUF_SZ-len,
"%03d: ", i);
}
- len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
+ len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
"%08x ", (uint32_t)*pword);
pword++;
}
@@ -5773,11 +5779,11 @@ lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox)
pr_err("%s\n", line_buf);
len = 0;
memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
- len += snprintf(line_buf+len,
+ len += scnprintf(line_buf+len,
LPFC_MBX_ACC_LBUF_SZ-len,
"%03d: ", i);
}
- len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
+ len += scnprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
"%08x ",
((uint32_t)*pword) & 0xffffffff);
pword++;
@@ -5796,18 +5802,18 @@ lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox)
pr_err("%s\n", line_buf);
len = 0;
memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
- len += snprintf(line_buf+len,
+ len += scnprintf(line_buf+len,
LPFC_MBX_ACC_LBUF_SZ-len,
"%03d: ", i);
}
for (j = 0; j < 4; j++) {
- len += snprintf(line_buf+len,
+ len += scnprintf(line_buf+len,
LPFC_MBX_ACC_LBUF_SZ-len,
"%02x",
((uint8_t)*pbyte) & 0xff);
pbyte++;
}
- len += snprintf(line_buf+len,
+ len += scnprintf(line_buf+len,
LPFC_MBX_ACC_LBUF_SZ-len, " ");
}
if ((i - 1) % 8)
@@ -5891,7 +5897,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
phba, &lpfc_debugfs_op_lockstat);
if (!phba->debug_lockstat) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "0913 Cant create debugfs lockstat\n");
+ "4610 Cant create debugfs lockstat\n");
goto debug_failed;
}
#endif
@@ -6134,7 +6140,7 @@ nvmeio_off:
vport, &lpfc_debugfs_op_scsistat);
if (!vport->debug_scsistat) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
- "0914 Cannot create debugfs scsistat\n");
+ "4611 Cannot create debugfs scsistat\n");
goto debug_failed;
}
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
index 93ab7dfb8ee0..2322ddb085c0 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.h
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -345,10 +345,10 @@ lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx)
esize = q->entry_size;
qe_word_cnt = esize / sizeof(uint32_t);
- pword = q->qe[idx].address;
+ pword = lpfc_sli4_qe(q, idx);
len = 0;
- len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "QE[%04d]: ", idx);
+ len += scnprintf(line_buf+len, LPFC_LBUF_SZ-len, "QE[%04d]: ", idx);
if (qe_word_cnt > 8)
printk(KERN_ERR "%s\n", line_buf);
@@ -359,11 +359,11 @@ lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx)
if (qe_word_cnt > 8) {
len = 0;
memset(line_buf, 0, LPFC_LBUF_SZ);
- len += snprintf(line_buf+len, LPFC_LBUF_SZ-len,
+ len += scnprintf(line_buf+len, LPFC_LBUF_SZ-len,
"%03d: ", i);
}
}
- len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "%08x ",
+ len += scnprintf(line_buf+len, LPFC_LBUF_SZ-len, "%08x ",
((uint32_t)*pword) & 0xffffffff);
pword++;
}
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index fc077cb87900..f12780f4cfbb 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -30,6 +30,8 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
+#include <uapi/scsi/fc/fc_fs.h>
+#include <uapi/scsi/fc/fc_els.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
@@ -1961,7 +1963,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
struct lpfc_dmabuf *prsp;
- int disc, rc;
+ int disc;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
@@ -1990,7 +1992,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
spin_unlock_irq(shost->host_lock);
- rc = 0;
/* PLOGI completes to NPort <nlp_DID> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -2029,18 +2030,16 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ndlp->nlp_DID, irsp->ulpStatus,
irsp->un.ulpWord[4]);
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if (lpfc_error_lost_link(irsp))
- rc = NLP_STE_FREED_NODE;
- else
- rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
- NLP_EVT_CMPL_PLOGI);
+ if (!lpfc_error_lost_link(irsp))
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PLOGI);
} else {
/* Good status, call state machine */
prsp = list_entry(((struct lpfc_dmabuf *)
cmdiocb->context2)->list.next,
struct lpfc_dmabuf, list);
ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
- rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_PLOGI);
}
@@ -3082,6 +3081,116 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
}
/**
+ * lpfc_issue_els_rscn - Issue an RSCN to the Fabric Controller (Fabric)
+ * or the other nport (pt2pt).
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @retry: number of retries to the command IOCB.
+ *
+ * This routine issues a RSCN to the Fabric Controller (DID 0xFFFFFD)
+ * when connected to a fabric, or to the remote port when connected
+ * in point-to-point mode. When sent to the Fabric Controller, it will
+ * replay the RSCN to registered recipients.
+ *
+ * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp
+ * will be incremented by 1 for holding the ndlp and the reference to ndlp
+ * will be stored into the context1 field of the IOCB for the completion
+ * callback function to the RSCN ELS command.
+ *
+ * Return code
+ * 0 - Successfully issued RSCN command
+ * 1 - Failed to issue RSCN command
+ **/
+int
+lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *elsiocb;
+ struct lpfc_nodelist *ndlp;
+ struct {
+ struct fc_els_rscn rscn;
+ struct fc_els_rscn_page portid;
+ } *event;
+ uint32_t nportid;
+ uint16_t cmdsize = sizeof(*event);
+
+ /* Not supported for private loop */
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP &&
+ !(vport->fc_flag & FC_PUBLIC_LOOP))
+ return 1;
+
+ if (vport->fc_flag & FC_PT2PT) {
+ /* find any mapped nport - that would be the other nport */
+ ndlp = lpfc_findnode_mapped(vport);
+ if (!ndlp)
+ return 1;
+ } else {
+ nportid = FC_FID_FCTRL;
+ /* find the fabric controller node */
+ ndlp = lpfc_findnode_did(vport, nportid);
+ if (!ndlp) {
+ /* if one didn't exist, make one */
+ ndlp = lpfc_nlp_init(vport, nportid);
+ if (!ndlp)
+ return 1;
+ lpfc_enqueue_node(vport, ndlp);
+ } else if (!NLP_CHK_NODE_ACT(ndlp)) {
+ ndlp = lpfc_enable_node(vport, ndlp,
+ NLP_STE_UNUSED_NODE);
+ if (!ndlp)
+ return 1;
+ }
+ }
+
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_RSCN_XMT);
+
+ if (!elsiocb) {
+ /* This will trigger the release of the node just
+ * allocated
+ */
+ lpfc_nlp_put(ndlp);
+ return 1;
+ }
+
+ event = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
+
+ event->rscn.rscn_cmd = ELS_RSCN;
+ event->rscn.rscn_page_len = sizeof(struct fc_els_rscn_page);
+ event->rscn.rscn_plen = cpu_to_be16(cmdsize);
+
+ nportid = vport->fc_myDID;
+ /* appears that page flags must be 0 for fabric to broadcast RSCN */
+ event->portid.rscn_page_flags = 0;
+ event->portid.rscn_fid[0] = (nportid & 0x00FF0000) >> 16;
+ event->portid.rscn_fid[1] = (nportid & 0x0000FF00) >> 8;
+ event->portid.rscn_fid[2] = nportid & 0x000000FF;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue RSCN: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
+ phba->fc_stat.elsXmitRSCN++;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
+ if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) ==
+ IOCB_ERROR) {
+ /* The additional lpfc_nlp_put will cause the following
+ * lpfc_els_free_iocb routine to trigger the rlease of
+ * the node.
+ */
+ lpfc_nlp_put(ndlp);
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ /* This will cause the callback-function lpfc_cmpl_els_cmd to
+ * trigger the release of node.
+ */
+ if (!(vport->fc_flag & FC_PT2PT))
+ lpfc_nlp_put(ndlp);
+
+ return 0;
+}
+
+/**
* lpfc_issue_els_farpr - Issue a farp to an node on a vport
* @vport: pointer to a host virtual N_Port data structure.
* @nportid: N_Port identifier to the remote node.
@@ -4199,6 +4308,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if ((rspiocb->iocb.ulpStatus == 0)
&& (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
if (!lpfc_unreg_rpi(vport, ndlp) &&
+ (!(vport->fc_flag & FC_PT2PT)) &&
(ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE)) {
lpfc_printf_vlog(vport, KERN_INFO,
@@ -6217,6 +6327,8 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport)
continue;
}
+ if (ndlp->nlp_fc4_type & NLP_FC4_NVME)
+ lpfc_nvme_rescan_port(vport, ndlp);
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
@@ -6321,6 +6433,19 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
fc_host_post_event(shost, fc_get_event_number(),
FCH_EVT_RSCN, lp[i]);
+ /* Check if RSCN is coming from a direct-connected remote NPort */
+ if (vport->fc_flag & FC_PT2PT) {
+ /* If so, just ACC it, no other action needed for now */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "2024 pt2pt RSCN %08x Data: x%x x%x\n",
+ *lp, vport->fc_flag, payload_len);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
+
+ if (ndlp->nlp_fc4_type & NLP_FC4_NVME)
+ lpfc_nvme_rescan_port(vport, ndlp);
+ return 0;
+ }
+
/* If we are about to begin discovery, just ACC the RSCN.
* Discovery processing will satisfy it.
*/
@@ -6744,12 +6869,11 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
uint32_t *lp;
RNID *rn;
struct ls_rjt stat;
- uint32_t cmd;
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
- cmd = *lp++;
+ lp++;
rn = (RNID *) lp;
/* RNID received */
@@ -7338,7 +7462,10 @@ int
lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq)
{
struct lpfc_nodelist *ndlp = lpfc_findnode_did(rrq->vport,
- rrq->nlp_DID);
+ rrq->nlp_DID);
+ if (!ndlp)
+ return 1;
+
if (lpfc_test_rrq_active(phba, ndlp, rrq->xritag))
return lpfc_issue_els_rrq(rrq->vport, ndlp,
rrq->nlp_DID, rrq);
@@ -7508,14 +7635,14 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
uint32_t *lp;
IOCB_t *icmd;
FARP *fp;
- uint32_t cmd, cnt, did;
+ uint32_t cnt, did;
icmd = &cmdiocb->iocb;
did = icmd->un.elsreq64.remoteID;
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
- cmd = *lp++;
+ lp++;
fp = (FARP *) lp;
/* FARP-REQ received from DID <did> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -7580,14 +7707,14 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
IOCB_t *icmd;
- uint32_t cmd, did;
+ uint32_t did;
icmd = &cmdiocb->iocb;
did = icmd->un.elsreq64.remoteID;
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
- cmd = *lp++;
+ lp++;
/* FARP-RSP received from DID <did> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0600 FARP-RSP received from DID x%x\n", did);
@@ -8454,6 +8581,14 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
rjt_err = LSRJT_UNABLE_TPC;
rjt_exp = LSEXP_INVALID_OX_RX;
break;
+ case ELS_CMD_FPIN:
+ /*
+ * Received FPIN from fabric - pass it to the
+ * transport FPIN handler.
+ */
+ fc_host_fpin_rcv(shost, elsiocb->iocb.unsli3.rcvsli3.acc_len,
+ (char *)payload);
+ break;
default:
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
"RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
@@ -8775,7 +8910,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
lpfc_nlp_put(ndlp);
return;
}
-
+ /* fall through */
default:
/* Try to recover from this error */
if (phba->sli_rev == LPFC_SLI_REV4)
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index aa4961a2caf8..28ecaa7fc715 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -885,15 +885,9 @@ lpfc_linkdown(struct lpfc_hba *phba)
LPFC_MBOXQ_t *mb;
int i;
- if (phba->link_state == LPFC_LINK_DOWN) {
- if (phba->sli4_hba.conf_trunk) {
- phba->trunk_link.link0.state = 0;
- phba->trunk_link.link1.state = 0;
- phba->trunk_link.link2.state = 0;
- phba->trunk_link.link3.state = 0;
- }
+ if (phba->link_state == LPFC_LINK_DOWN)
return 0;
- }
+
/* Block all SCSI stack I/Os */
lpfc_scsi_dev_block(phba);
@@ -932,7 +926,11 @@ lpfc_linkdown(struct lpfc_hba *phba)
}
}
lpfc_destroy_vport_work_array(phba, vports);
- /* Clean up any firmware default rpi's */
+
+ /* Clean up any SLI3 firmware default rpi's */
+ if (phba->sli_rev > LPFC_SLI_REV3)
+ goto skip_unreg_did;
+
mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mb) {
lpfc_unreg_did(phba, 0xffff, LPFC_UNREG_ALL_DFLT_RPIS, mb);
@@ -944,6 +942,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
}
}
+ skip_unreg_did:
/* Setup myDID for link up if we are in pt2pt mode */
if (phba->pport->fc_flag & FC_PT2PT) {
mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -4147,9 +4146,15 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
rdata->pnode = lpfc_nlp_get(ndlp);
if (ndlp->nlp_type & NLP_FCP_TARGET)
- rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
+ rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET;
if (ndlp->nlp_type & NLP_FCP_INITIATOR)
- rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+ rport_ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
+ if (ndlp->nlp_type & NLP_NVME_INITIATOR)
+ rport_ids.roles |= FC_PORT_ROLE_NVME_INITIATOR;
+ if (ndlp->nlp_type & NLP_NVME_TARGET)
+ rport_ids.roles |= FC_PORT_ROLE_NVME_TARGET;
+ if (ndlp->nlp_type & NLP_NVME_DISCOVERY)
+ rport_ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY;
if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN)
fc_remote_port_rolechg(rport, rport_ids.roles);
@@ -4667,12 +4672,15 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba,
case CMD_GEN_REQUEST64_CR:
if (iocb->context_un.ndlp == ndlp)
return 1;
+ /* fall through */
case CMD_ELS_REQUEST64_CR:
if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID)
return 1;
+ /* fall through */
case CMD_XMIT_ELS_RSP64_CX:
if (iocb->context1 == (uint8_t *) ndlp)
return 1;
+ /* fall through */
}
} else if (pring->ringno == LPFC_FCP_RING) {
/* Skip match check if waiting to relogin to FCP target */
@@ -4868,6 +4876,10 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
* accept PLOGIs after unreg_rpi_cmpl
*/
acc_plogi = 0;
+ } else if (vport->load_flag & FC_UNLOADING) {
+ mbox->ctx_ndlp = NULL;
+ mbox->mbox_cmpl =
+ lpfc_sli_def_mbox_cmpl;
} else {
mbox->ctx_ndlp = ndlp;
mbox->mbox_cmpl =
@@ -4979,6 +4991,10 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
LPFC_MBOXQ_t *mbox;
int rc;
+ /* Unreg DID is an SLI3 operation. */
+ if (phba->sli_rev > LPFC_SLI_REV3)
+ return;
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox) {
lpfc_unreg_did(phba, vport->vpi, LPFC_UNREG_ALL_DFLT_RPIS,
@@ -5261,6 +5277,41 @@ lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
}
struct lpfc_nodelist *
+lpfc_findnode_mapped(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp;
+ uint32_t data1;
+ unsigned long iflags;
+
+ spin_lock_irqsave(shost->host_lock, iflags);
+
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE ||
+ ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
+ data1 = (((uint32_t)ndlp->nlp_state << 24) |
+ ((uint32_t)ndlp->nlp_xri << 16) |
+ ((uint32_t)ndlp->nlp_type << 8) |
+ ((uint32_t)ndlp->nlp_rpi & 0xff));
+ spin_unlock_irqrestore(shost->host_lock, iflags);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "2025 FIND node DID "
+ "Data: x%p x%x x%x x%x %p\n",
+ ndlp, ndlp->nlp_DID,
+ ndlp->nlp_flag, data1,
+ ndlp->active_rrqs_xri_bitmap);
+ return ndlp;
+ }
+ }
+ spin_unlock_irqrestore(shost->host_lock, iflags);
+
+ /* FIND node did <did> NOT FOUND */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+ "2026 FIND mapped did NOT FOUND.\n");
+ return NULL;
+}
+
+struct lpfc_nodelist *
lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
@@ -5856,7 +5907,7 @@ restart_disc:
case LPFC_LINK_UP:
lpfc_issue_clear_la(phba, vport);
- /* Drop thru */
+ /* fall through */
case LPFC_LINK_UNKNOWN:
case LPFC_WARM_START:
case LPFC_INIT_START:
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index ec1227018913..5b439a6dcde1 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -560,6 +560,8 @@ struct fc_vft_header {
#define fc_vft_hdr_hopct_WORD word1
};
+#include <uapi/scsi/fc/fc_els.h>
+
/*
* Extended Link Service LS_COMMAND codes (Payload Word 0)
*/
@@ -599,10 +601,12 @@ struct fc_vft_header {
#define ELS_CMD_RPL 0x57000000
#define ELS_CMD_FAN 0x60000000
#define ELS_CMD_RSCN 0x61040000
+#define ELS_CMD_RSCN_XMT 0x61040008
#define ELS_CMD_SCR 0x62000000
#define ELS_CMD_RNID 0x78000000
#define ELS_CMD_LIRR 0x7A000000
#define ELS_CMD_LCB 0x81000000
+#define ELS_CMD_FPIN 0x16000000
#else /* __LITTLE_ENDIAN_BITFIELD */
#define ELS_CMD_MASK 0xffff
#define ELS_RSP_MASK 0xff
@@ -639,10 +643,12 @@ struct fc_vft_header {
#define ELS_CMD_RPL 0x57
#define ELS_CMD_FAN 0x60
#define ELS_CMD_RSCN 0x0461
+#define ELS_CMD_RSCN_XMT 0x08000461
#define ELS_CMD_SCR 0x62
#define ELS_CMD_RNID 0x78
#define ELS_CMD_LIRR 0x7A
#define ELS_CMD_LCB 0x81
+#define ELS_CMD_FPIN ELS_FPIN
#endif
/*
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index ff875b833192..77f9a55a3f54 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1894,18 +1894,19 @@ struct lpfc_mbx_set_link_diag_loopback {
union {
struct {
uint32_t word0;
-#define lpfc_mbx_set_diag_lpbk_type_SHIFT 0
-#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003
-#define lpfc_mbx_set_diag_lpbk_type_WORD word0
-#define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0
-#define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1
-#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2
-#define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16
-#define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F
-#define lpfc_mbx_set_diag_lpbk_link_num_WORD word0
-#define lpfc_mbx_set_diag_lpbk_link_type_SHIFT 22
-#define lpfc_mbx_set_diag_lpbk_link_type_MASK 0x00000003
-#define lpfc_mbx_set_diag_lpbk_link_type_WORD word0
+#define lpfc_mbx_set_diag_lpbk_type_SHIFT 0
+#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003
+#define lpfc_mbx_set_diag_lpbk_type_WORD word0
+#define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0
+#define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1
+#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2
+#define LPFC_DIAG_LOOPBACK_TYPE_EXTERNAL_TRUNKED 0x3
+#define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16
+#define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F
+#define lpfc_mbx_set_diag_lpbk_link_num_WORD word0
+#define lpfc_mbx_set_diag_lpbk_link_type_SHIFT 22
+#define lpfc_mbx_set_diag_lpbk_link_type_MASK 0x00000003
+#define lpfc_mbx_set_diag_lpbk_link_type_WORD word0
} req;
struct {
uint32_t word0;
@@ -4083,22 +4084,7 @@ struct lpfc_acqe_grp5 {
uint32_t trailer;
};
-static char *const trunk_errmsg[] = { /* map errcode */
- "", /* There is no such error code at index 0*/
- "link negotiated speed does not match existing"
- " trunk - link was \"low\" speed",
- "link negotiated speed does not match"
- " existing trunk - link was \"middle\" speed",
- "link negotiated speed does not match existing"
- " trunk - link was \"high\" speed",
- "Attached to non-trunking port - F_Port",
- "Attached to non-trunking port - N_Port",
- "FLOGI response timeout",
- "non-FLOGI frame received",
- "Invalid FLOGI response",
- "Trunking initialization protocol",
- "Trunk peer device mismatch",
-};
+extern const char *const trunk_errmsg[];
struct lpfc_acqe_fc_la {
uint32_t word0;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 7fcdaed3fa94..faf43b1d3dbe 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -72,7 +72,7 @@ unsigned long _dump_buf_dif_order;
spinlock_t _dump_buf_lock;
/* Used when mapping IRQ vectors in a driver centric manner */
-uint32_t lpfc_present_cpu;
+static uint32_t lpfc_present_cpu;
static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
static int lpfc_post_rcv_buf(struct lpfc_hba *);
@@ -93,8 +93,8 @@ static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);
static void lpfc_sli4_disable_intr(struct lpfc_hba *);
static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t);
static void lpfc_sli4_oas_verify(struct lpfc_hba *phba);
-static uint16_t lpfc_find_eq_handle(struct lpfc_hba *, uint16_t);
static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int);
+static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *);
static struct scsi_transport_template *lpfc_transport_template = NULL;
static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -1117,19 +1117,19 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)
}
}
+ spin_unlock_irq(&phba->hbalock);
if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
- spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
+ spin_lock_irq(&phba->sli4_hba.abts_nvmet_buf_list_lock);
list_splice_init(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
&nvmet_aborts);
- spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
+ spin_unlock_irq(&phba->sli4_hba.abts_nvmet_buf_list_lock);
list_for_each_entry_safe(ctxp, ctxp_next, &nvmet_aborts, list) {
ctxp->flag &= ~(LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP);
lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf);
}
}
- spin_unlock_irq(&phba->hbalock);
lpfc_sli4_free_sp_events(phba);
return cnt;
}
@@ -1274,8 +1274,10 @@ lpfc_hb_eq_delay_work(struct work_struct *work)
if (!eqcnt)
goto requeue;
+ /* Loop thru all IRQ vectors */
for (i = 0; i < phba->cfg_irq_chann; i++) {
- eq = phba->sli4_hba.hdwq[i].hba_eq;
+ /* Get the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[i].eq;
if (eq && eqcnt[eq->last_cpu] < 2)
eqcnt[eq->last_cpu]++;
continue;
@@ -1844,8 +1846,12 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
/* If the pci channel is offline, ignore possible errors, since
* we cannot communicate with the pci card anyway.
*/
- if (pci_channel_offline(phba->pcidev))
+ if (pci_channel_offline(phba->pcidev)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3166 pci channel is offline\n");
+ lpfc_sli4_offline_eratt(phba);
return;
+ }
memset(&portsmphr_reg, 0, sizeof(portsmphr_reg));
if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
@@ -1922,6 +1928,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3151 PCI bus read access failure: x%x\n",
readl(phba->sli4_hba.u.if_type2.STATUSregaddr));
+ lpfc_sli4_offline_eratt(phba);
return;
}
reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
@@ -2958,7 +2965,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba)
del_timer_sync(&phba->fcp_poll_timer);
break;
case LPFC_PCI_DEV_OC:
- /* Stop any OneConnect device sepcific driver timers */
+ /* Stop any OneConnect device specific driver timers */
lpfc_sli4_stop_fcf_redisc_wait_timer(phba);
break;
default:
@@ -3075,7 +3082,7 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba)
* This routine moves a batch of XRIs from lpfc_io_buf_list_put of HWQ 0
* to expedite pool. Mark them as expedite.
**/
-void lpfc_create_expedite_pool(struct lpfc_hba *phba)
+static void lpfc_create_expedite_pool(struct lpfc_hba *phba)
{
struct lpfc_sli4_hdw_queue *qp;
struct lpfc_io_buf *lpfc_ncmd;
@@ -3110,7 +3117,7 @@ void lpfc_create_expedite_pool(struct lpfc_hba *phba)
* This routine returns XRIs from expedite pool to lpfc_io_buf_list_put
* of HWQ 0. Clear the mark.
**/
-void lpfc_destroy_expedite_pool(struct lpfc_hba *phba)
+static void lpfc_destroy_expedite_pool(struct lpfc_hba *phba)
{
struct lpfc_sli4_hdw_queue *qp;
struct lpfc_io_buf *lpfc_ncmd;
@@ -3230,7 +3237,7 @@ void lpfc_create_multixri_pools(struct lpfc_hba *phba)
*
* This routine returns XRIs from public/private to lpfc_io_buf_list_put.
**/
-void lpfc_destroy_multixri_pools(struct lpfc_hba *phba)
+static void lpfc_destroy_multixri_pools(struct lpfc_hba *phba)
{
u32 i;
u32 hwq_count;
@@ -3245,6 +3252,13 @@ void lpfc_destroy_multixri_pools(struct lpfc_hba *phba)
if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
lpfc_destroy_expedite_pool(phba);
+ if (!(phba->pport->load_flag & FC_UNLOADING)) {
+ lpfc_sli_flush_fcp_rings(phba);
+
+ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
+ lpfc_sli_flush_nvme_rings(phba);
+ }
+
hwq_count = phba->cfg_hdw_queue;
for (i = 0; i < hwq_count; i++) {
@@ -3611,8 +3625,6 @@ lpfc_io_free(struct lpfc_hba *phba)
struct lpfc_sli4_hdw_queue *qp;
int idx;
- spin_lock_irq(&phba->hbalock);
-
for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
qp = &phba->sli4_hba.hdwq[idx];
/* Release all the lpfc_nvme_bufs maintained by this host. */
@@ -3642,8 +3654,6 @@ lpfc_io_free(struct lpfc_hba *phba)
}
spin_unlock(&qp->io_buf_list_get_lock);
}
-
- spin_unlock_irq(&phba->hbalock);
}
/**
@@ -4106,14 +4116,13 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc)
* pci bus space for an I/O. The DMA buffer includes the
* number of SGE's necessary to support the sg_tablesize.
*/
- lpfc_ncmd->data = dma_pool_alloc(phba->lpfc_sg_dma_buf_pool,
- GFP_KERNEL,
- &lpfc_ncmd->dma_handle);
+ lpfc_ncmd->data = dma_pool_zalloc(phba->lpfc_sg_dma_buf_pool,
+ GFP_KERNEL,
+ &lpfc_ncmd->dma_handle);
if (!lpfc_ncmd->data) {
kfree(lpfc_ncmd);
break;
}
- memset(lpfc_ncmd->data, 0, phba->cfg_sg_dma_buf_size);
/*
* 4K Page alignment is CRITICAL to BlockGuard, double check
@@ -4339,6 +4348,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
timer_setup(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo, 0);
+ if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
+ lpfc_setup_bg(phba, shost);
+
error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
if (error)
goto out_put_shost;
@@ -4457,7 +4469,7 @@ finished:
return stat;
}
-void lpfc_host_supported_speeds_set(struct Scsi_Host *shost)
+static void lpfc_host_supported_speeds_set(struct Scsi_Host *shost)
{
struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
struct lpfc_hba *phba = vport->phba;
@@ -5047,7 +5059,7 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba,
bf_get(lpfc_acqe_fc_la_speed, acqe_fc));
phba->sli4_hba.link_state.logical_speed =
- bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc);
+ bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10;
/* We got FC link speed, convert to fc_linkspeed (READ_TOPOLOGY) */
phba->fc_linkspeed =
lpfc_async_link_speed_to_read_top(
@@ -5150,8 +5162,14 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
bf_get(lpfc_acqe_fc_la_port_number, acqe_fc);
phba->sli4_hba.link_state.fault =
bf_get(lpfc_acqe_link_fault, acqe_fc);
- phba->sli4_hba.link_state.logical_speed =
+
+ if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) ==
+ LPFC_FC_LA_TYPE_LINK_DOWN)
+ phba->sli4_hba.link_state.logical_speed = 0;
+ else if (!phba->sli4_hba.conf_trunk)
+ phba->sli4_hba.link_state.logical_speed =
bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10;
+
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"2896 Async FC event - Speed:%dGBaud Topology:x%x "
"LA Type:x%x Port Type:%d Port Number:%d Logical speed:"
@@ -6543,6 +6561,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
spin_lock_init(&phba->sli4_hba.abts_nvmet_buf_list_lock);
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list);
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_nvmet_io_wait_list);
+ spin_lock_init(&phba->sli4_hba.t_active_list_lock);
+ INIT_LIST_HEAD(&phba->sli4_hba.t_active_ctx_list);
}
/* This abort list used by worker thread */
@@ -7652,8 +7672,6 @@ lpfc_post_init_setup(struct lpfc_hba *phba)
*/
shost = pci_get_drvdata(phba->pcidev);
shost->can_queue = phba->cfg_hba_queue_depth - 10;
- if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
- lpfc_setup_bg(phba, shost);
lpfc_host_attrib_init(shost);
@@ -8603,9 +8621,9 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
if (phba->nvmet_support) {
if (phba->cfg_irq_chann < phba->cfg_nvmet_mrq)
phba->cfg_nvmet_mrq = phba->cfg_irq_chann;
+ if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX)
+ phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX;
}
- if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX)
- phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX;
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2574 IO channels: hdwQ %d IRQ %d MRQ: %d\n",
@@ -8626,10 +8644,12 @@ static int
lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx)
{
struct lpfc_queue *qdesc;
+ int cpu;
+ cpu = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ);
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
phba->sli4_hba.cq_esize,
- LPFC_CQE_EXP_COUNT);
+ LPFC_CQE_EXP_COUNT, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0508 Failed allocate fast-path NVME CQ (%d)\n",
@@ -8638,11 +8658,12 @@ lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx)
}
qdesc->qe_valid = 1;
qdesc->hdwq = wqidx;
- qdesc->chann = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ);
+ qdesc->chann = cpu;
phba->sli4_hba.hdwq[wqidx].nvme_cq = qdesc;
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
- LPFC_WQE128_SIZE, LPFC_WQE_EXP_COUNT);
+ LPFC_WQE128_SIZE, LPFC_WQE_EXP_COUNT,
+ cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0509 Failed allocate fast-path NVME WQ (%d)\n",
@@ -8661,18 +8682,20 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
{
struct lpfc_queue *qdesc;
uint32_t wqesize;
+ int cpu;
+ cpu = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ);
/* Create Fast Path FCP CQs */
if (phba->enab_exp_wqcq_pages)
/* Increase the CQ size when WQEs contain an embedded cdb */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
phba->sli4_hba.cq_esize,
- LPFC_CQE_EXP_COUNT);
+ LPFC_CQE_EXP_COUNT, cpu);
else
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.cq_esize,
- phba->sli4_hba.cq_ecount);
+ phba->sli4_hba.cq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0499 Failed allocate fast-path FCP CQ (%d)\n", wqidx);
@@ -8680,7 +8703,7 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
}
qdesc->qe_valid = 1;
qdesc->hdwq = wqidx;
- qdesc->chann = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ);
+ qdesc->chann = cpu;
phba->sli4_hba.hdwq[wqidx].fcp_cq = qdesc;
/* Create Fast Path FCP WQs */
@@ -8690,11 +8713,11 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize;
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
wqesize,
- LPFC_WQE_EXP_COUNT);
+ LPFC_WQE_EXP_COUNT, cpu);
} else
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.wq_esize,
- phba->sli4_hba.wq_ecount);
+ phba->sli4_hba.wq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -8727,8 +8750,10 @@ int
lpfc_sli4_queue_create(struct lpfc_hba *phba)
{
struct lpfc_queue *qdesc;
- int idx, eqidx;
+ int idx, cpu, eqcpu;
struct lpfc_sli4_hdw_queue *qp;
+ struct lpfc_vector_map_info *cpup;
+ struct lpfc_vector_map_info *eqcpup;
struct lpfc_eq_intr_info *eqi;
/*
@@ -8813,40 +8838,60 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_wq_list);
/* Create HBA Event Queues (EQs) */
- for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
- /*
- * If there are more Hardware Queues than available
- * CQs, multiple Hardware Queues may share a common EQ.
+ for_each_present_cpu(cpu) {
+ /* We only want to create 1 EQ per vector, even though
+ * multiple CPUs might be using that vector. so only
+ * selects the CPUs that are LPFC_CPU_FIRST_IRQ.
*/
- if (idx >= phba->cfg_irq_chann) {
- /* Share an existing EQ */
- eqidx = lpfc_find_eq_handle(phba, idx);
- phba->sli4_hba.hdwq[idx].hba_eq =
- phba->sli4_hba.hdwq[eqidx].hba_eq;
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+ if (!(cpup->flag & LPFC_CPU_FIRST_IRQ))
continue;
- }
- /* Create an EQ */
+
+ /* Get a ptr to the Hardware Queue associated with this CPU */
+ qp = &phba->sli4_hba.hdwq[cpup->hdwq];
+
+ /* Allocate an EQ */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.eq_esize,
- phba->sli4_hba.eq_ecount);
+ phba->sli4_hba.eq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0497 Failed allocate EQ (%d)\n", idx);
+ "0497 Failed allocate EQ (%d)\n",
+ cpup->hdwq);
goto out_error;
}
qdesc->qe_valid = 1;
- qdesc->hdwq = idx;
-
- /* Save the CPU this EQ is affinitised to */
- eqidx = lpfc_find_eq_handle(phba, idx);
- qdesc->chann = lpfc_find_cpu_handle(phba, eqidx,
- LPFC_FIND_BY_EQ);
- phba->sli4_hba.hdwq[idx].hba_eq = qdesc;
+ qdesc->hdwq = cpup->hdwq;
+ qdesc->chann = cpu; /* First CPU this EQ is affinitised to */
qdesc->last_cpu = qdesc->chann;
+
+ /* Save the allocated EQ in the Hardware Queue */
+ qp->hba_eq = qdesc;
+
eqi = per_cpu_ptr(phba->sli4_hba.eq_info, qdesc->last_cpu);
list_add(&qdesc->cpu_list, &eqi->list);
}
+ /* Now we need to populate the other Hardware Queues, that share
+ * an IRQ vector, with the associated EQ ptr.
+ */
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Check for EQ already allocated in previous loop */
+ if (cpup->flag & LPFC_CPU_FIRST_IRQ)
+ continue;
+
+ /* Check for multiple CPUs per hdwq */
+ qp = &phba->sli4_hba.hdwq[cpup->hdwq];
+ if (qp->hba_eq)
+ continue;
+
+ /* We need to share an EQ for this hdwq */
+ eqcpu = lpfc_find_cpu_handle(phba, cpup->eq, LPFC_FIND_BY_EQ);
+ eqcpup = &phba->sli4_hba.cpu_map[eqcpu];
+ qp->hba_eq = phba->sli4_hba.hdwq[eqcpup->hdwq].hba_eq;
+ }
/* Allocate SCSI SLI4 CQ/WQs */
for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
@@ -8863,11 +8908,14 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
if (phba->nvmet_support) {
for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) {
+ cpu = lpfc_find_cpu_handle(phba, idx,
+ LPFC_FIND_BY_HDWQ);
qdesc = lpfc_sli4_queue_alloc(
phba,
LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.cq_esize,
- phba->sli4_hba.cq_ecount);
+ phba->sli4_hba.cq_ecount,
+ cpu);
if (!qdesc) {
lpfc_printf_log(
phba, KERN_ERR, LOG_INIT,
@@ -8877,7 +8925,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
}
qdesc->qe_valid = 1;
qdesc->hdwq = idx;
- qdesc->chann = idx;
+ qdesc->chann = cpu;
phba->sli4_hba.nvmet_cqset[idx] = qdesc;
}
}
@@ -8887,10 +8935,11 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
* Create Slow Path Completion Queues (CQs)
*/
+ cpu = lpfc_find_cpu_handle(phba, 0, LPFC_FIND_BY_EQ);
/* Create slow-path Mailbox Command Complete Queue */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.cq_esize,
- phba->sli4_hba.cq_ecount);
+ phba->sli4_hba.cq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0500 Failed allocate slow-path mailbox CQ\n");
@@ -8902,7 +8951,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
/* Create slow-path ELS Complete Queue */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.cq_esize,
- phba->sli4_hba.cq_ecount);
+ phba->sli4_hba.cq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0501 Failed allocate slow-path ELS CQ\n");
@@ -8921,7 +8970,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.mq_esize,
- phba->sli4_hba.mq_ecount);
+ phba->sli4_hba.mq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0505 Failed allocate slow-path MQ\n");
@@ -8937,7 +8986,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
/* Create slow-path ELS Work Queue */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.wq_esize,
- phba->sli4_hba.wq_ecount);
+ phba->sli4_hba.wq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0504 Failed allocate slow-path ELS WQ\n");
@@ -8951,7 +9000,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
/* Create NVME LS Complete Queue */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.cq_esize,
- phba->sli4_hba.cq_ecount);
+ phba->sli4_hba.cq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"6079 Failed allocate NVME LS CQ\n");
@@ -8964,7 +9013,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
/* Create NVME LS Work Queue */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.wq_esize,
- phba->sli4_hba.wq_ecount);
+ phba->sli4_hba.wq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"6080 Failed allocate NVME LS WQ\n");
@@ -8982,7 +9031,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
/* Create Receive Queue for header */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.rq_esize,
- phba->sli4_hba.rq_ecount);
+ phba->sli4_hba.rq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0506 Failed allocate receive HRQ\n");
@@ -8993,7 +9042,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
/* Create Receive Queue for data */
qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.rq_esize,
- phba->sli4_hba.rq_ecount);
+ phba->sli4_hba.rq_ecount, cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0507 Failed allocate receive DRQ\n");
@@ -9004,11 +9053,14 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
if ((phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) &&
phba->nvmet_support) {
for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) {
+ cpu = lpfc_find_cpu_handle(phba, idx,
+ LPFC_FIND_BY_HDWQ);
/* Create NVMET Receive Queue for header */
qdesc = lpfc_sli4_queue_alloc(phba,
LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.rq_esize,
- LPFC_NVMET_RQE_DEF_COUNT);
+ LPFC_NVMET_RQE_DEF_COUNT,
+ cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3146 Failed allocate "
@@ -9019,8 +9071,9 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
phba->sli4_hba.nvmet_mrq_hdr[idx] = qdesc;
/* Only needed for header of RQ pair */
- qdesc->rqbp = kzalloc(sizeof(struct lpfc_rqb),
- GFP_KERNEL);
+ qdesc->rqbp = kzalloc_node(sizeof(*qdesc->rqbp),
+ GFP_KERNEL,
+ cpu_to_node(cpu));
if (qdesc->rqbp == NULL) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"6131 Failed allocate "
@@ -9035,7 +9088,8 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
qdesc = lpfc_sli4_queue_alloc(phba,
LPFC_DEFAULT_PAGE_SIZE,
phba->sli4_hba.rq_esize,
- LPFC_NVMET_RQE_DEF_COUNT);
+ LPFC_NVMET_RQE_DEF_COUNT,
+ cpu);
if (!qdesc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3156 Failed allocate "
@@ -9100,23 +9154,31 @@ static inline void
lpfc_sli4_release_hdwq(struct lpfc_hba *phba)
{
struct lpfc_sli4_hdw_queue *hdwq;
+ struct lpfc_queue *eq;
uint32_t idx;
hdwq = phba->sli4_hba.hdwq;
- for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
- if (idx < phba->cfg_irq_chann)
- lpfc_sli4_queue_free(hdwq[idx].hba_eq);
- hdwq[idx].hba_eq = NULL;
+ /* Loop thru all Hardware Queues */
+ for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
+ /* Free the CQ/WQ corresponding to the Hardware Queue */
lpfc_sli4_queue_free(hdwq[idx].fcp_cq);
lpfc_sli4_queue_free(hdwq[idx].nvme_cq);
lpfc_sli4_queue_free(hdwq[idx].fcp_wq);
lpfc_sli4_queue_free(hdwq[idx].nvme_wq);
+ hdwq[idx].hba_eq = NULL;
hdwq[idx].fcp_cq = NULL;
hdwq[idx].nvme_cq = NULL;
hdwq[idx].fcp_wq = NULL;
hdwq[idx].nvme_wq = NULL;
}
+ /* Loop thru all IRQ vectors */
+ for (idx = 0; idx < phba->cfg_irq_chann; idx++) {
+ /* Free the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[idx].eq;
+ lpfc_sli4_queue_free(eq);
+ phba->sli4_hba.hba_eq_hdl[idx].eq = NULL;
+ }
}
/**
@@ -9134,6 +9196,20 @@ lpfc_sli4_release_hdwq(struct lpfc_hba *phba)
void
lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
{
+ /*
+ * Set FREE_INIT before beginning to free the queues.
+ * Wait until the users of queues to acknowledge to
+ * release queues by clearing FREE_WAIT.
+ */
+ spin_lock_irq(&phba->hbalock);
+ phba->sli.sli_flag |= LPFC_QUEUE_FREE_INIT;
+ while (phba->sli.sli_flag & LPFC_QUEUE_FREE_WAIT) {
+ spin_unlock_irq(&phba->hbalock);
+ msleep(20);
+ spin_lock_irq(&phba->hbalock);
+ }
+ spin_unlock_irq(&phba->hbalock);
+
/* Release HBA eqs */
if (phba->sli4_hba.hdwq)
lpfc_sli4_release_hdwq(phba);
@@ -9172,6 +9248,11 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
/* Everything on this list has been freed */
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_wq_list);
+
+ /* Done with freeing the queues */
+ spin_lock_irq(&phba->hbalock);
+ phba->sli.sli_flag &= ~LPFC_QUEUE_FREE_INIT;
+ spin_unlock_irq(&phba->hbalock);
}
int
@@ -9231,7 +9312,7 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq,
rc = lpfc_wq_create(phba, wq, cq, qtype);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "6123 Fail setup fastpath WQ (%d), rc = 0x%x\n",
+ "4618 Fail setup fastpath WQ (%d), rc = 0x%x\n",
qidx, (uint32_t)rc);
/* no need to tear down cq - caller will do so */
return rc;
@@ -9271,20 +9352,21 @@ lpfc_create_wq_cq(struct lpfc_hba *phba, struct lpfc_queue *eq,
* This routine will populate the cq_lookup table by all
* available CQ queue_id's.
**/
-void
+static void
lpfc_setup_cq_lookup(struct lpfc_hba *phba)
{
struct lpfc_queue *eq, *childq;
- struct lpfc_sli4_hdw_queue *qp;
int qidx;
- qp = phba->sli4_hba.hdwq;
memset(phba->sli4_hba.cq_lookup, 0,
(sizeof(struct lpfc_queue *) * (phba->sli4_hba.cq_max + 1)));
+ /* Loop thru all IRQ vectors */
for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
- eq = qp[qidx].hba_eq;
+ /* Get the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
if (!eq)
continue;
+ /* Loop through all CQs associated with that EQ */
list_for_each_entry(childq, &eq->child_list, list) {
if (childq->queue_id > phba->sli4_hba.cq_max)
continue;
@@ -9313,9 +9395,10 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
{
uint32_t shdr_status, shdr_add_status;
union lpfc_sli4_cfg_shdr *shdr;
+ struct lpfc_vector_map_info *cpup;
struct lpfc_sli4_hdw_queue *qp;
LPFC_MBOXQ_t *mboxq;
- int qidx;
+ int qidx, cpu;
uint32_t length, usdelay;
int rc = -ENOMEM;
@@ -9376,32 +9459,55 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
rc = -ENOMEM;
goto out_error;
}
+
+ /* Loop thru all IRQ vectors */
for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
- if (!qp[qidx].hba_eq) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0522 Fast-path EQ (%d) not "
- "allocated\n", qidx);
- rc = -ENOMEM;
- goto out_destroy;
- }
- rc = lpfc_eq_create(phba, qp[qidx].hba_eq,
- phba->cfg_fcp_imax);
- if (rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0523 Failed setup of fast-path EQ "
- "(%d), rc = 0x%x\n", qidx,
- (uint32_t)rc);
- goto out_destroy;
+ /* Create HBA Event Queues (EQs) in order */
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Look for the CPU thats using that vector with
+ * LPFC_CPU_FIRST_IRQ set.
+ */
+ if (!(cpup->flag & LPFC_CPU_FIRST_IRQ))
+ continue;
+ if (qidx != cpup->eq)
+ continue;
+
+ /* Create an EQ for that vector */
+ rc = lpfc_eq_create(phba, qp[cpup->hdwq].hba_eq,
+ phba->cfg_fcp_imax);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "0523 Failed setup of fast-path"
+ " EQ (%d), rc = 0x%x\n",
+ cpup->eq, (uint32_t)rc);
+ goto out_destroy;
+ }
+
+ /* Save the EQ for that vector in the hba_eq_hdl */
+ phba->sli4_hba.hba_eq_hdl[cpup->eq].eq =
+ qp[cpup->hdwq].hba_eq;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2584 HBA EQ setup: queue[%d]-id=%d\n",
+ cpup->eq,
+ qp[cpup->hdwq].hba_eq->queue_id);
}
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "2584 HBA EQ setup: queue[%d]-id=%d\n", qidx,
- qp[qidx].hba_eq->queue_id);
}
+ /* Loop thru all Hardware Queues */
if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+ cpu = lpfc_find_cpu_handle(phba, qidx,
+ LPFC_FIND_BY_HDWQ);
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Create the CQ/WQ corresponding to the
+ * Hardware Queue
+ */
rc = lpfc_create_wq_cq(phba,
- qp[qidx].hba_eq,
+ phba->sli4_hba.hdwq[cpup->hdwq].hba_eq,
qp[qidx].nvme_cq,
qp[qidx].nvme_wq,
&phba->sli4_hba.hdwq[qidx].nvme_cq_map,
@@ -9417,8 +9523,12 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)
}
for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+ cpu = lpfc_find_cpu_handle(phba, qidx, LPFC_FIND_BY_HDWQ);
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Create the CQ/WQ corresponding to the Hardware Queue */
rc = lpfc_create_wq_cq(phba,
- qp[qidx].hba_eq,
+ phba->sli4_hba.hdwq[cpup->hdwq].hba_eq,
qp[qidx].fcp_cq,
qp[qidx].fcp_wq,
&phba->sli4_hba.hdwq[qidx].fcp_cq_map,
@@ -9670,6 +9780,7 @@ void
lpfc_sli4_queue_unset(struct lpfc_hba *phba)
{
struct lpfc_sli4_hdw_queue *qp;
+ struct lpfc_queue *eq;
int qidx;
/* Unset mailbox command work queue */
@@ -9721,14 +9832,20 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba)
/* Unset fast-path SLI4 queues */
if (phba->sli4_hba.hdwq) {
+ /* Loop thru all Hardware Queues */
for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
+ /* Destroy the CQ/WQ corresponding to Hardware Queue */
qp = &phba->sli4_hba.hdwq[qidx];
lpfc_wq_destroy(phba, qp->fcp_wq);
lpfc_wq_destroy(phba, qp->nvme_wq);
lpfc_cq_destroy(phba, qp->fcp_cq);
lpfc_cq_destroy(phba, qp->nvme_cq);
- if (qidx < phba->cfg_irq_chann)
- lpfc_eq_destroy(phba, qp->hba_eq);
+ }
+ /* Loop thru all IRQ vectors */
+ for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
+ /* Destroy the EQ corresponding to the IRQ vector */
+ eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
+ lpfc_eq_destroy(phba, eq);
}
}
@@ -10518,11 +10635,12 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba)
}
/**
- * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified EQ
+ * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified Queue
* @phba: pointer to lpfc hba data structure.
* @id: EQ vector index or Hardware Queue index
* @match: LPFC_FIND_BY_EQ = match by EQ
* LPFC_FIND_BY_HDWQ = match by Hardware Queue
+ * Return the CPU that matches the selection criteria
*/
static uint16_t
lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match)
@@ -10530,40 +10648,27 @@ lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match)
struct lpfc_vector_map_info *cpup;
int cpu;
- /* Find the desired phys_id for the specified EQ */
+ /* Loop through all CPUs */
for_each_present_cpu(cpu) {
cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* If we are matching by EQ, there may be multiple CPUs using
+ * using the same vector, so select the one with
+ * LPFC_CPU_FIRST_IRQ set.
+ */
if ((match == LPFC_FIND_BY_EQ) &&
+ (cpup->flag & LPFC_CPU_FIRST_IRQ) &&
(cpup->irq != LPFC_VECTOR_MAP_EMPTY) &&
(cpup->eq == id))
return cpu;
+
+ /* If matching by HDWQ, select the first CPU that matches */
if ((match == LPFC_FIND_BY_HDWQ) && (cpup->hdwq == id))
return cpu;
}
return 0;
}
-/**
- * lpfc_find_eq_handle - Find the EQ that corresponds to the specified
- * Hardware Queue
- * @phba: pointer to lpfc hba data structure.
- * @hdwq: Hardware Queue index
- */
-static uint16_t
-lpfc_find_eq_handle(struct lpfc_hba *phba, uint16_t hdwq)
-{
- struct lpfc_vector_map_info *cpup;
- int cpu;
-
- /* Find the desired phys_id for the specified EQ */
- for_each_present_cpu(cpu) {
- cpup = &phba->sli4_hba.cpu_map[cpu];
- if (cpup->hdwq == hdwq)
- return cpup->eq;
- }
- return 0;
-}
-
#ifdef CONFIG_X86
/**
* lpfc_find_hyper - Determine if the CPU map entry is hyper-threaded
@@ -10604,24 +10709,31 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu,
static void
lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
{
- int i, cpu, idx;
+ int i, cpu, idx, new_cpu, start_cpu, first_cpu;
int max_phys_id, min_phys_id;
int max_core_id, min_core_id;
struct lpfc_vector_map_info *cpup;
+ struct lpfc_vector_map_info *new_cpup;
const struct cpumask *maskp;
#ifdef CONFIG_X86
struct cpuinfo_x86 *cpuinfo;
#endif
/* Init cpu_map array */
- memset(phba->sli4_hba.cpu_map, 0xff,
- (sizeof(struct lpfc_vector_map_info) *
- phba->sli4_hba.num_possible_cpu));
+ for_each_possible_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+ cpup->phys_id = LPFC_VECTOR_MAP_EMPTY;
+ cpup->core_id = LPFC_VECTOR_MAP_EMPTY;
+ cpup->hdwq = LPFC_VECTOR_MAP_EMPTY;
+ cpup->eq = LPFC_VECTOR_MAP_EMPTY;
+ cpup->irq = LPFC_VECTOR_MAP_EMPTY;
+ cpup->flag = 0;
+ }
max_phys_id = 0;
- min_phys_id = 0xffff;
+ min_phys_id = LPFC_VECTOR_MAP_EMPTY;
max_core_id = 0;
- min_core_id = 0xffff;
+ min_core_id = LPFC_VECTOR_MAP_EMPTY;
/* Update CPU map with physical id and core id of each CPU */
for_each_present_cpu(cpu) {
@@ -10630,13 +10742,12 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
cpuinfo = &cpu_data(cpu);
cpup->phys_id = cpuinfo->phys_proc_id;
cpup->core_id = cpuinfo->cpu_core_id;
- cpup->hyper = lpfc_find_hyper(phba, cpu,
- cpup->phys_id, cpup->core_id);
+ if (lpfc_find_hyper(phba, cpu, cpup->phys_id, cpup->core_id))
+ cpup->flag |= LPFC_CPU_MAP_HYPER;
#else
/* No distinction between CPUs for other platforms */
cpup->phys_id = 0;
cpup->core_id = cpu;
- cpup->hyper = 0;
#endif
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -10662,23 +10773,216 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors)
eqi->icnt = 0;
}
+ /* This loop sets up all CPUs that are affinitized with a
+ * irq vector assigned to the driver. All affinitized CPUs
+ * will get a link to that vectors IRQ and EQ.
+ */
for (idx = 0; idx < phba->cfg_irq_chann; idx++) {
+ /* Get a CPU mask for all CPUs affinitized to this vector */
maskp = pci_irq_get_affinity(phba->pcidev, idx);
if (!maskp)
continue;
+ i = 0;
+ /* Loop through all CPUs associated with vector idx */
for_each_cpu_and(cpu, maskp, cpu_present_mask) {
+ /* Set the EQ index and IRQ for that vector */
cpup = &phba->sli4_hba.cpu_map[cpu];
cpup->eq = idx;
- cpup->hdwq = idx;
cpup->irq = pci_irq_vector(phba->pcidev, idx);
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"3336 Set Affinity: CPU %d "
- "hdwq %d irq %d\n",
- cpu, cpup->hdwq, cpup->irq);
+ "irq %d eq %d\n",
+ cpu, cpup->irq, cpup->eq);
+
+ /* If this is the first CPU thats assigned to this
+ * vector, set LPFC_CPU_FIRST_IRQ.
+ */
+ if (!i)
+ cpup->flag |= LPFC_CPU_FIRST_IRQ;
+ i++;
}
}
+
+ /* After looking at each irq vector assigned to this pcidev, its
+ * possible to see that not ALL CPUs have been accounted for.
+ * Next we will set any unassigned (unaffinitized) cpu map
+ * entries to a IRQ on the same phys_id.
+ */
+ first_cpu = cpumask_first(cpu_present_mask);
+ start_cpu = first_cpu;
+
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Is this CPU entry unassigned */
+ if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) {
+ /* Mark CPU as IRQ not assigned by the kernel */
+ cpup->flag |= LPFC_CPU_MAP_UNASSIGN;
+
+ /* If so, find a new_cpup thats on the the SAME
+ * phys_id as cpup. start_cpu will start where we
+ * left off so all unassigned entries don't get assgined
+ * the IRQ of the first entry.
+ */
+ new_cpu = start_cpu;
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+ if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) &&
+ (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY) &&
+ (new_cpup->phys_id == cpup->phys_id))
+ goto found_same;
+ new_cpu = cpumask_next(
+ new_cpu, cpu_present_mask);
+ if (new_cpu == nr_cpumask_bits)
+ new_cpu = first_cpu;
+ }
+ /* At this point, we leave the CPU as unassigned */
+ continue;
+found_same:
+ /* We found a matching phys_id, so copy the IRQ info */
+ cpup->eq = new_cpup->eq;
+ cpup->irq = new_cpup->irq;
+
+ /* Bump start_cpu to the next slot to minmize the
+ * chance of having multiple unassigned CPU entries
+ * selecting the same IRQ.
+ */
+ start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+ if (start_cpu == nr_cpumask_bits)
+ start_cpu = first_cpu;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3337 Set Affinity: CPU %d "
+ "irq %d from id %d same "
+ "phys_id (%d)\n",
+ cpu, cpup->irq, new_cpu, cpup->phys_id);
+ }
+ }
+
+ /* Set any unassigned cpu map entries to a IRQ on any phys_id */
+ start_cpu = first_cpu;
+
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+
+ /* Is this entry unassigned */
+ if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) {
+ /* Mark it as IRQ not assigned by the kernel */
+ cpup->flag |= LPFC_CPU_MAP_UNASSIGN;
+
+ /* If so, find a new_cpup thats on ANY phys_id
+ * as the cpup. start_cpu will start where we
+ * left off so all unassigned entries don't get
+ * assigned the IRQ of the first entry.
+ */
+ new_cpu = start_cpu;
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+ if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) &&
+ (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY))
+ goto found_any;
+ new_cpu = cpumask_next(
+ new_cpu, cpu_present_mask);
+ if (new_cpu == nr_cpumask_bits)
+ new_cpu = first_cpu;
+ }
+ /* We should never leave an entry unassigned */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3339 Set Affinity: CPU %d "
+ "irq %d UNASSIGNED\n",
+ cpup->hdwq, cpup->irq);
+ continue;
+found_any:
+ /* We found an available entry, copy the IRQ info */
+ cpup->eq = new_cpup->eq;
+ cpup->irq = new_cpup->irq;
+
+ /* Bump start_cpu to the next slot to minmize the
+ * chance of having multiple unassigned CPU entries
+ * selecting the same IRQ.
+ */
+ start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+ if (start_cpu == nr_cpumask_bits)
+ start_cpu = first_cpu;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3338 Set Affinity: CPU %d "
+ "irq %d from id %d (%d/%d)\n",
+ cpu, cpup->irq, new_cpu,
+ new_cpup->phys_id, new_cpup->core_id);
+ }
+ }
+
+ /* Finally we need to associate a hdwq with each cpu_map entry
+ * This will be 1 to 1 - hdwq to cpu, unless there are less
+ * hardware queues then CPUs. For that case we will just round-robin
+ * the available hardware queues as they get assigned to CPUs.
+ */
+ idx = 0;
+ start_cpu = 0;
+ for_each_present_cpu(cpu) {
+ cpup = &phba->sli4_hba.cpu_map[cpu];
+ if (idx >= phba->cfg_hdw_queue) {
+ /* We need to reuse a Hardware Queue for another CPU,
+ * so be smart about it and pick one that has its
+ * IRQ/EQ mapped to the same phys_id (CPU package).
+ * and core_id.
+ */
+ new_cpu = start_cpu;
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+ if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) &&
+ (new_cpup->phys_id == cpup->phys_id) &&
+ (new_cpup->core_id == cpup->core_id))
+ goto found_hdwq;
+ new_cpu = cpumask_next(
+ new_cpu, cpu_present_mask);
+ if (new_cpu == nr_cpumask_bits)
+ new_cpu = first_cpu;
+ }
+
+ /* If we can't match both phys_id and core_id,
+ * settle for just a phys_id match.
+ */
+ new_cpu = start_cpu;
+ for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+ new_cpup = &phba->sli4_hba.cpu_map[new_cpu];
+ if ((new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) &&
+ (new_cpup->phys_id == cpup->phys_id))
+ goto found_hdwq;
+ new_cpu = cpumask_next(
+ new_cpu, cpu_present_mask);
+ if (new_cpu == nr_cpumask_bits)
+ new_cpu = first_cpu;
+ }
+
+ /* Otherwise just round robin on cfg_hdw_queue */
+ cpup->hdwq = idx % phba->cfg_hdw_queue;
+ goto logit;
+found_hdwq:
+ /* We found an available entry, copy the IRQ info */
+ start_cpu = cpumask_next(new_cpu, cpu_present_mask);
+ if (start_cpu == nr_cpumask_bits)
+ start_cpu = first_cpu;
+ cpup->hdwq = new_cpup->hdwq;
+ } else {
+ /* 1 to 1, CPU to hdwq */
+ cpup->hdwq = idx;
+ }
+logit:
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "3335 Set Affinity: CPU %d (phys %d core %d): "
+ "hdwq %d eq %d irq %d flg x%x\n",
+ cpu, cpup->phys_id, cpup->core_id,
+ cpup->hdwq, cpup->eq, cpup->irq, cpup->flag);
+ idx++;
+ }
+
+ /* The cpu_map array will be used later during initialization
+ * when EQ / CQ / WQs are allocated and configured.
+ */
return;
}
@@ -10740,7 +11044,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
phba->cfg_irq_chann, vectors);
if (phba->cfg_irq_chann > vectors)
phba->cfg_irq_chann = vectors;
- if (phba->cfg_nvmet_mrq > vectors)
+ if (phba->nvmet_support && (phba->cfg_nvmet_mrq > vectors))
phba->cfg_nvmet_mrq = vectors;
}
@@ -11290,24 +11594,43 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
mbx_sli4_parameters);
phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters);
phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters);
- phba->nvme_support = (bf_get(cfg_nvme, mbx_sli4_parameters) &&
- bf_get(cfg_xib, mbx_sli4_parameters));
-
- if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) ||
- !phba->nvme_support) {
- phba->nvme_support = 0;
- phba->nvmet_support = 0;
- phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_OFF;
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME,
- "6101 Disabling NVME support: "
- "Not supported by firmware: %d %d\n",
- bf_get(cfg_nvme, mbx_sli4_parameters),
- bf_get(cfg_xib, mbx_sli4_parameters));
-
- /* If firmware doesn't support NVME, just use SCSI support */
- if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
- return -ENODEV;
- phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
+
+ /* Check for firmware nvme support */
+ rc = (bf_get(cfg_nvme, mbx_sli4_parameters) &&
+ bf_get(cfg_xib, mbx_sli4_parameters));
+
+ if (rc) {
+ /* Save this to indicate the Firmware supports NVME */
+ sli4_params->nvme = 1;
+
+ /* Firmware NVME support, check driver FC4 NVME support */
+ if (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME,
+ "6133 Disabling NVME support: "
+ "FC4 type not supported: x%x\n",
+ phba->cfg_enable_fc4_type);
+ goto fcponly;
+ }
+ } else {
+ /* No firmware NVME support, check driver FC4 NVME support */
+ sli4_params->nvme = 0;
+ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME,
+ "6101 Disabling NVME support: Not "
+ "supported by firmware (%d %d) x%x\n",
+ bf_get(cfg_nvme, mbx_sli4_parameters),
+ bf_get(cfg_xib, mbx_sli4_parameters),
+ phba->cfg_enable_fc4_type);
+fcponly:
+ phba->nvme_support = 0;
+ phba->nvmet_support = 0;
+ phba->cfg_nvmet_mrq = 0;
+
+ /* If no FC4 type support, move to just SCSI support */
+ if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
+ return -ENODEV;
+ phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
+ }
}
/* Only embed PBDE for if_type 6, PBDE support requires xib be set */
@@ -13046,7 +13369,7 @@ lpfc_io_resume(struct pci_dev *pdev)
* is destroyed.
*
**/
-void
+static void
lpfc_sli4_oas_verify(struct lpfc_hba *phba)
{
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 6172682a24ba..59252bfca14e 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -360,6 +360,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
case NLP_STE_NPR_NODE:
if (!(ndlp->nlp_flag & NLP_NPR_ADISC))
break;
+ /* fall through */
case NLP_STE_REG_LOGIN_ISSUE:
case NLP_STE_PRLI_ISSUE:
case NLP_STE_UNMAPPED_NODE:
@@ -870,7 +871,7 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
* This function will send a unreg_login mailbox command to the firmware
* to release a rpi.
**/
-void
+static void
lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp, uint16_t rpi)
{
@@ -1732,7 +1733,6 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
MAILBOX_t *mb = &pmb->u.mb;
uint32_t did = mb->un.varWords[1];
- int rc = 0;
if (mb->mbxStatus) {
/* RegLogin failed */
@@ -1805,8 +1805,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
* GFT_ID to determine if remote port supports NVME.
*/
if (vport->cfg_enable_fc4_type != LPFC_ENABLE_FCP) {
- rc = lpfc_ns_cmd(vport, SLI_CTNS_GFT_ID,
- 0, ndlp->nlp_DID);
+ lpfc_ns_cmd(vport, SLI_CTNS_GFT_ID, 0,
+ ndlp->nlp_DID);
return ndlp->nlp_state;
}
ndlp->nlp_fc4_type = NLP_FC4_FCP;
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 1aa00d2c3f74..946642cee3df 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -229,7 +229,7 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport,
if (qhandle == NULL)
return -ENOMEM;
- qhandle->cpu_id = smp_processor_id();
+ qhandle->cpu_id = raw_smp_processor_id();
qhandle->qidx = qidx;
/*
* NVME qidx == 0 is the admin queue, so both admin queue
@@ -312,7 +312,7 @@ lpfc_nvme_localport_delete(struct nvme_fc_local_port *localport)
* Return value :
* None
*/
-void
+static void
lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport)
{
struct lpfc_nvme_rport *rport = remoteport->private;
@@ -1106,13 +1106,16 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
lpfc_ncmd, nCmd,
lpfc_ncmd->cur_iocbq.sli4_xritag,
bf_get(lpfc_wcqe_c_xb, wcqe));
+ /* fall through */
default:
out_err:
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR,
"6072 NVME Completion Error: xri %x "
- "status x%x result x%x placed x%x\n",
+ "status x%x result x%x [x%x] "
+ "placed x%x\n",
lpfc_ncmd->cur_iocbq.sli4_xritag,
lpfc_ncmd->status, lpfc_ncmd->result,
+ wcqe->parameter,
wcqe->total_data_placed);
nCmd->transferred_length = 0;
nCmd->rcv_rsplen = 0;
@@ -1140,7 +1143,7 @@ out_err:
if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) {
uint32_t cpu;
idx = lpfc_ncmd->cur_iocbq.hba_wqidx;
- cpu = smp_processor_id();
+ cpu = raw_smp_processor_id();
if (cpu < LPFC_CHECK_CPU_CNT) {
if (lpfc_ncmd->cpu != cpu)
lpfc_printf_vlog(vport,
@@ -1558,7 +1561,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport,
if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) {
idx = lpfc_queue_info->index;
} else {
- cpu = smp_processor_id();
+ cpu = raw_smp_processor_id();
idx = phba->sli4_hba.cpu_map[cpu].hdwq;
}
@@ -1638,7 +1641,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport,
lpfc_ncmd->ts_cmd_wqput = ktime_get_ns();
if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) {
- cpu = smp_processor_id();
+ cpu = raw_smp_processor_id();
if (cpu < LPFC_CHECK_CPU_CNT) {
lpfc_ncmd->cpu = cpu;
if (idx != cpu)
@@ -2080,15 +2083,15 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport)
lpfc_nvme_template.max_hw_queues =
phba->sli4_hba.num_present_cpu;
+ if (!IS_ENABLED(CONFIG_NVME_FC))
+ return ret;
+
/* localport is allocated from the stack, but the registration
* call allocates heap memory as well as the private area.
*/
-#if (IS_ENABLED(CONFIG_NVME_FC))
+
ret = nvme_fc_register_localport(&nfcp_info, &lpfc_nvme_template,
&vport->phba->pcidev->dev, &localport);
-#else
- ret = -ENOMEM;
-#endif
if (!ret) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME | LOG_NVME_DISC,
"6005 Successfully registered local "
@@ -2123,6 +2126,7 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport)
return ret;
}
+#if (IS_ENABLED(CONFIG_NVME_FC))
/* lpfc_nvme_lport_unreg_wait - Wait for the host to complete an lport unreg.
*
* The driver has to wait for the host nvme transport to callback
@@ -2133,14 +2137,15 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport)
* An uninterruptible wait is used because of the risk of transport-to-
* driver state mismatch.
*/
-void
+static void
lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
struct lpfc_nvme_lport *lport,
struct completion *lport_unreg_cmp)
{
-#if (IS_ENABLED(CONFIG_NVME_FC))
u32 wait_tmo;
- int ret;
+ int ret, i, pending = 0;
+ struct lpfc_sli_ring *pring;
+ struct lpfc_hba *phba = vport->phba;
/* Host transport has to clean up and confirm requiring an indefinite
* wait. Print a message if a 10 second wait expires and renew the
@@ -2150,10 +2155,18 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
while (true) {
ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo);
if (unlikely(!ret)) {
+ pending = 0;
+ for (i = 0; i < phba->cfg_hdw_queue; i++) {
+ pring = phba->sli4_hba.hdwq[i].nvme_wq->pring;
+ if (!pring)
+ continue;
+ if (pring->txcmplq_cnt)
+ pending += pring->txcmplq_cnt;
+ }
lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR,
"6176 Lport %p Localport %p wait "
- "timed out. Renewing.\n",
- lport, vport->localport);
+ "timed out. Pending %d. Renewing.\n",
+ lport, vport->localport, pending);
continue;
}
break;
@@ -2161,8 +2174,8 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR,
"6177 Lport %p Localport %p Complete Success\n",
lport, vport->localport);
-#endif
}
+#endif
/**
* lpfc_nvme_destroy_localport - Destroy lpfc_nvme bound to nvme transport.
@@ -2399,6 +2412,50 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
#endif
}
+/**
+ * lpfc_nvme_rescan_port - Check to see if we should rescan this remoteport
+ *
+ * If the ndlp represents an NVME Target, that we are logged into,
+ * ping the NVME FC Transport layer to initiate a device rescan
+ * on this remote NPort.
+ */
+void
+lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+{
+#if (IS_ENABLED(CONFIG_NVME_FC))
+ struct lpfc_nvme_rport *rport;
+ struct nvme_fc_remote_port *remoteport;
+
+ rport = ndlp->nrport;
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
+ "6170 Rescan NPort DID x%06x type x%x "
+ "state x%x rport %p\n",
+ ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_state, rport);
+ if (!rport)
+ goto input_err;
+ remoteport = rport->remoteport;
+ if (!remoteport)
+ goto input_err;
+
+ /* Only rescan if we are an NVME target in the MAPPED state */
+ if (remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY &&
+ ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
+ nvme_fc_rescan_remoteport(remoteport);
+
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC,
+ "6172 NVME rescanned DID x%06x "
+ "port_state x%x\n",
+ ndlp->nlp_DID, remoteport->port_state);
+ }
+ return;
+input_err:
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC,
+ "6169 State error: lport %p, rport%p FCID x%06x\n",
+ vport->localport, ndlp->rport, ndlp->nlp_DID);
+#endif
+}
+
/* lpfc_nvme_unregister_port - unbind the DID and port_role from this rport.
*
* There is no notion of Devloss or rport recovery from the current
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c
index 361e2b103648..faa596f9e861 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.c
+++ b/drivers/scsi/lpfc/lpfc_nvmet.c
@@ -220,19 +220,68 @@ lpfc_nvmet_cmd_template(void)
/* Word 12, 13, 14, 15 - is zero */
}
-void
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
+static struct lpfc_nvmet_rcv_ctx *
+lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri)
+{
+ struct lpfc_nvmet_rcv_ctx *ctxp;
+ unsigned long iflag;
+ bool found = false;
+
+ spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+ list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) {
+ if (ctxp->ctxbuf->sglq->sli4_xritag != xri)
+ continue;
+
+ found = true;
+ break;
+ }
+ spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
+ if (found)
+ return ctxp;
+
+ return NULL;
+}
+
+static struct lpfc_nvmet_rcv_ctx *
+lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid)
+{
+ struct lpfc_nvmet_rcv_ctx *ctxp;
+ unsigned long iflag;
+ bool found = false;
+
+ spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+ list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) {
+ if (ctxp->oxid != oxid || ctxp->sid != sid)
+ continue;
+
+ found = true;
+ break;
+ }
+ spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
+ if (found)
+ return ctxp;
+
+ return NULL;
+}
+#endif
+
+static void
lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp)
{
lockdep_assert_held(&ctxp->ctxlock);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6313 NVMET Defer ctx release xri x%x flg x%x\n",
+ "6313 NVMET Defer ctx release oxid x%x flg x%x\n",
ctxp->oxid, ctxp->flag);
if (ctxp->flag & LPFC_NVMET_CTX_RLS)
return;
ctxp->flag |= LPFC_NVMET_CTX_RLS;
+ spin_lock(&phba->sli4_hba.t_active_list_lock);
+ list_del(&ctxp->list);
+ spin_unlock(&phba->sli4_hba.t_active_list_lock);
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
list_add_tail(&ctxp->list, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list);
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
@@ -325,7 +374,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
struct fc_frame_header *fc_hdr;
struct rqb_dmabuf *nvmebuf;
struct lpfc_nvmet_ctx_info *infop;
- uint32_t *payload;
uint32_t size, oxid, sid;
int cpu;
unsigned long iflag;
@@ -344,16 +392,23 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
}
if (ctxp->rqb_buffer) {
- nvmebuf = ctxp->rqb_buffer;
spin_lock_irqsave(&ctxp->ctxlock, iflag);
- ctxp->rqb_buffer = NULL;
- if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
- ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ;
- spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
- nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
+ nvmebuf = ctxp->rqb_buffer;
+ /* check if freed in another path whilst acquiring lock */
+ if (nvmebuf) {
+ ctxp->rqb_buffer = NULL;
+ if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
+ ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ;
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+ nvmebuf->hrq->rqbp->rqb_free_buffer(phba,
+ nvmebuf);
+ } else {
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+ /* repost */
+ lpfc_rq_buf_free(phba, &nvmebuf->hbuf);
+ }
} else {
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
- lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */
}
}
ctxp->state = LPFC_NVMET_STE_FREE;
@@ -370,7 +425,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt);
oxid = be16_to_cpu(fc_hdr->fh_ox_id);
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
- payload = (uint32_t *)(nvmebuf->dbuf.virt);
size = nvmebuf->bytes_recv;
sid = sli4_sid_from_fc_hdr(fc_hdr);
@@ -390,8 +444,9 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
spin_lock_init(&ctxp->ctxlock);
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
- if (ctxp->ts_cmd_nvme) {
- ctxp->ts_cmd_nvme = ktime_get_ns();
+ /* NOTE: isr time stamp is stale when context is re-assigned*/
+ if (ctxp->ts_isr_cmd) {
+ ctxp->ts_cmd_nvme = 0;
ctxp->ts_nvme_data = 0;
ctxp->ts_data_wqput = 0;
ctxp->ts_isr_data = 0;
@@ -404,9 +459,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
#endif
atomic_inc(&tgtp->rcv_fcp_cmd_in);
- /* flag new work queued, replacement buffer has already
- * been reposted
- */
+ /* Indicate that a replacement buffer has been posted */
spin_lock_irqsave(&ctxp->ctxlock, iflag);
ctxp->flag |= LPFC_NVMET_CTX_REUSE_WQ;
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
@@ -435,7 +488,10 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
* Use the CPU context list, from the MRQ the IO was received on
* (ctxp->idx), to save context structure.
*/
- cpu = smp_processor_id();
+ spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+ list_del_init(&ctxp->list);
+ spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
+ cpu = raw_smp_processor_id();
infop = lpfc_get_ctx_list(phba, cpu, ctxp->idx);
spin_lock_irqsave(&infop->nvmet_ctx_list_lock, iflag);
list_add_tail(&ctx_buf->list, &infop->nvmet_ctx_list);
@@ -702,8 +758,10 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
}
lpfc_printf_log(phba, KERN_INFO, logerr,
- "6315 IO Error Cmpl xri x%x: %x/%x XBUSY:x%x\n",
- ctxp->oxid, status, result, ctxp->flag);
+ "6315 IO Error Cmpl oxid: x%x xri: x%x %x/%x "
+ "XBUSY:x%x\n",
+ ctxp->oxid, ctxp->ctxbuf->sglq->sli4_xritag,
+ status, result, ctxp->flag);
} else {
rsp->fcp_error = NVME_SC_SUCCESS;
@@ -765,7 +823,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
}
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) {
- id = smp_processor_id();
+ id = raw_smp_processor_id();
if (id < LPFC_CHECK_CPU_CNT) {
if (ctxp->cpu != id)
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
@@ -851,7 +909,6 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport,
* before freeing ctxp and iocbq.
*/
lpfc_in_buf_free(phba, &nvmebuf->dbuf);
- ctxp->rqb_buffer = 0;
atomic_inc(&nvmep->xmt_ls_rsp);
return 0;
}
@@ -906,7 +963,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
ctxp->hdwq = &phba->sli4_hba.hdwq[rsp->hwqid];
if (phba->cpucheck_on & LPFC_CHECK_NVMET_IO) {
- int id = smp_processor_id();
+ int id = raw_smp_processor_id();
if (id < LPFC_CHECK_CPU_CNT) {
if (rsp->hwqid != id)
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
@@ -924,7 +981,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
(ctxp->state == LPFC_NVMET_STE_ABORT)) {
atomic_inc(&lpfc_nvmep->xmt_fcp_drop);
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
- "6102 IO xri x%x aborted\n",
+ "6102 IO oxid x%x aborted\n",
ctxp->oxid);
rc = -ENXIO;
goto aerr;
@@ -1024,7 +1081,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
ctxp->hdwq = &phba->sli4_hba.hdwq[0];
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6103 NVMET Abort op: oxri x%x flg x%x ste %d\n",
+ "6103 NVMET Abort op: oxid x%x flg x%x ste %d\n",
ctxp->oxid, ctxp->flag, ctxp->state);
lpfc_nvmeio_data(phba, "NVMET FCP ABRT: xri x%x flg x%x ste x%x\n",
@@ -1037,7 +1094,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
/* Since iaab/iaar are NOT set, we need to check
* if the firmware is in process of aborting IO
*/
- if (ctxp->flag & LPFC_NVMET_XBUSY) {
+ if (ctxp->flag & (LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP)) {
spin_unlock_irqrestore(&ctxp->ctxlock, flags);
return;
}
@@ -1100,6 +1157,7 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport,
ctxp->state, aborting);
atomic_inc(&lpfc_nvmep->xmt_fcp_release);
+ ctxp->flag &= ~LPFC_NVMET_TNOTIFY;
if (aborting)
return;
@@ -1120,11 +1178,11 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
lpfc_nvmeio_data(phba, "NVMET DEFERRCV: xri x%x sz %d CPU %02x\n",
- ctxp->oxid, ctxp->size, smp_processor_id());
+ ctxp->oxid, ctxp->size, raw_smp_processor_id());
if (!nvmebuf) {
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR,
- "6425 Defer rcv: no buffer xri x%x: "
+ "6425 Defer rcv: no buffer oxid x%x: "
"flg %x ste %x\n",
ctxp->oxid, ctxp->flag, ctxp->state);
return;
@@ -1141,6 +1199,22 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
}
+static void
+lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport)
+{
+ struct lpfc_nvmet_tgtport *tgtp;
+ struct lpfc_hba *phba;
+ uint32_t rc;
+
+ tgtp = tgtport->private;
+ phba = tgtp->phba;
+
+ rc = lpfc_issue_els_rscn(phba->pport, 0);
+ lpfc_printf_log(phba, KERN_ERR, LOG_NVME,
+ "6420 NVMET subsystem change: Notification %s\n",
+ (rc) ? "Failed" : "Sent");
+}
+
static struct nvmet_fc_target_template lpfc_tgttemplate = {
.targetport_delete = lpfc_nvmet_targetport_delete,
.xmt_ls_rsp = lpfc_nvmet_xmt_ls_rsp,
@@ -1148,6 +1222,7 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = {
.fcp_abort = lpfc_nvmet_xmt_fcp_abort,
.fcp_req_release = lpfc_nvmet_xmt_fcp_release,
.defer_rcv = lpfc_nvmet_defer_rcv,
+ .discovery_event = lpfc_nvmet_discovery_event,
.max_hw_queues = 1,
.max_sgl_segments = LPFC_NVMET_DEFAULT_SEGS,
@@ -1499,10 +1574,12 @@ void
lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
struct sli4_wcqe_xri_aborted *axri)
{
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp;
struct lpfc_nvmet_tgtport *tgtp;
+ struct nvmefc_tgt_fcp_req *req = NULL;
struct lpfc_nodelist *ndlp;
unsigned long iflag = 0;
int rrq_empty = 0;
@@ -1533,7 +1610,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
*/
if (ctxp->flag & LPFC_NVMET_CTX_RLS &&
!(ctxp->flag & LPFC_NVMET_ABORT_OP)) {
- list_del(&ctxp->list);
+ list_del_init(&ctxp->list);
released = true;
}
ctxp->flag &= ~LPFC_NVMET_XBUSY;
@@ -1553,7 +1630,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
}
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6318 XB aborted oxid %x flg x%x (%x)\n",
+ "6318 XB aborted oxid x%x flg x%x (%x)\n",
ctxp->oxid, ctxp->flag, released);
if (released)
lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf);
@@ -1564,6 +1641,33 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba,
}
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
+
+ ctxp = lpfc_nvmet_get_ctx_for_xri(phba, xri);
+ if (ctxp) {
+ /*
+ * Abort already done by FW, so BA_ACC sent.
+ * However, the transport may be unaware.
+ */
+ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+ "6323 NVMET Rcv ABTS xri x%x ctxp state x%x "
+ "flag x%x oxid x%x rxid x%x\n",
+ xri, ctxp->state, ctxp->flag, ctxp->oxid,
+ rxid);
+
+ spin_lock_irqsave(&ctxp->ctxlock, iflag);
+ ctxp->flag |= LPFC_NVMET_ABTS_RCV;
+ ctxp->state = LPFC_NVMET_STE_ABORT;
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+
+ lpfc_nvmeio_data(phba,
+ "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
+ xri, raw_smp_processor_id(), 0);
+
+ req = &ctxp->ctx.fcp_req;
+ if (req)
+ nvmet_fc_rcv_fcp_abort(phba->targetport, req);
+ }
+#endif
}
int
@@ -1574,19 +1678,23 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
struct lpfc_hba *phba = vport->phba;
struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp;
struct nvmefc_tgt_fcp_req *rsp;
- uint16_t xri;
+ uint32_t sid;
+ uint16_t oxid, xri;
unsigned long iflag = 0;
- xri = be16_to_cpu(fc_hdr->fh_ox_id);
+ sid = sli4_sid_from_fc_hdr(fc_hdr);
+ oxid = be16_to_cpu(fc_hdr->fh_ox_id);
spin_lock_irqsave(&phba->hbalock, iflag);
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
list_for_each_entry_safe(ctxp, next_ctxp,
&phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
list) {
- if (ctxp->ctxbuf->sglq->sli4_xritag != xri)
+ if (ctxp->oxid != oxid || ctxp->sid != sid)
continue;
+ xri = ctxp->ctxbuf->sglq->sli4_xritag;
+
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
@@ -1596,7 +1704,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
lpfc_nvmeio_data(phba,
"NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
- xri, smp_processor_id(), 0);
+ xri, raw_smp_processor_id(), 0);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
"6319 NVMET Rcv ABTS:acc xri x%x\n", xri);
@@ -1611,11 +1719,93 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
- lpfc_nvmeio_data(phba, "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
- xri, smp_processor_id(), 1);
+ /* check the wait list */
+ if (phba->sli4_hba.nvmet_io_wait_cnt) {
+ struct rqb_dmabuf *nvmebuf;
+ struct fc_frame_header *fc_hdr_tmp;
+ u32 sid_tmp;
+ u16 oxid_tmp;
+ bool found = false;
+
+ spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag);
+
+ /* match by oxid and s_id */
+ list_for_each_entry(nvmebuf,
+ &phba->sli4_hba.lpfc_nvmet_io_wait_list,
+ hbuf.list) {
+ fc_hdr_tmp = (struct fc_frame_header *)
+ (nvmebuf->hbuf.virt);
+ oxid_tmp = be16_to_cpu(fc_hdr_tmp->fh_ox_id);
+ sid_tmp = sli4_sid_from_fc_hdr(fc_hdr_tmp);
+ if (oxid_tmp != oxid || sid_tmp != sid)
+ continue;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+ "6321 NVMET Rcv ABTS oxid x%x from x%x "
+ "is waiting for a ctxp\n",
+ oxid, sid);
+
+ list_del_init(&nvmebuf->hbuf.list);
+ phba->sli4_hba.nvmet_io_wait_cnt--;
+ found = true;
+ break;
+ }
+ spin_unlock_irqrestore(&phba->sli4_hba.nvmet_io_wait_lock,
+ iflag);
+
+ /* free buffer since already posted a new DMA buffer to RQ */
+ if (found) {
+ nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
+ /* Respond with BA_ACC accordingly */
+ lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1);
+ return 0;
+ }
+ }
+
+ /* check active list */
+ ctxp = lpfc_nvmet_get_ctx_for_oxid(phba, oxid, sid);
+ if (ctxp) {
+ xri = ctxp->ctxbuf->sglq->sli4_xritag;
+
+ spin_lock_irqsave(&ctxp->ctxlock, iflag);
+ ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP);
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+
+ lpfc_nvmeio_data(phba,
+ "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n",
+ xri, raw_smp_processor_id(), 0);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
+ "6322 NVMET Rcv ABTS:acc oxid x%x xri x%x "
+ "flag x%x state x%x\n",
+ ctxp->oxid, xri, ctxp->flag, ctxp->state);
+
+ if (ctxp->flag & LPFC_NVMET_TNOTIFY) {
+ /* Notify the transport */
+ nvmet_fc_rcv_fcp_abort(phba->targetport,
+ &ctxp->ctx.fcp_req);
+ } else {
+ cancel_work_sync(&ctxp->ctxbuf->defer_work);
+ spin_lock_irqsave(&ctxp->ctxlock, iflag);
+ lpfc_nvmet_defer_release(phba, ctxp);
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+ }
+ if (ctxp->state == LPFC_NVMET_STE_RCV)
+ lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+ ctxp->oxid);
+ else
+ lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+ ctxp->oxid);
+
+ lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1);
+ return 0;
+ }
+
+ lpfc_nvmeio_data(phba, "NVMET ABTS RCV: oxid x%x CPU %02x rjt %d\n",
+ oxid, raw_smp_processor_id(), 1);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6320 NVMET Rcv ABTS:rjt xri x%x\n", xri);
+ "6320 NVMET Rcv ABTS:rjt oxid x%x\n", oxid);
/* Respond with BA_RJT accordingly */
lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0);
@@ -1699,6 +1889,18 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba,
spin_unlock_irqrestore(&pring->ring_lock, iflags);
return;
}
+ if (rc == WQE_SUCCESS) {
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+ if (ctxp->ts_cmd_nvme) {
+ if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP)
+ ctxp->ts_status_wqput = ktime_get_ns();
+ else
+ ctxp->ts_data_wqput = ktime_get_ns();
+ }
+#endif
+ } else {
+ WARN_ON(rc);
+ }
}
wq->q_flag &= ~HBA_NVMET_WQFULL;
spin_unlock_irqrestore(&pring->ring_lock, iflags);
@@ -1725,7 +1927,11 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
}
tgtp->tport_unreg_cmp = &tport_unreg_cmp;
nvmet_fc_unregister_targetport(phba->targetport);
- wait_for_completion_timeout(&tport_unreg_cmp, 5);
+ if (!wait_for_completion_timeout(tgtp->tport_unreg_cmp,
+ msecs_to_jiffies(LPFC_NVMET_WAIT_TMO)))
+ lpfc_printf_log(phba, KERN_ERR, LOG_NVME,
+ "6179 Unreg targetport %p timeout "
+ "reached.\n", phba->targetport);
lpfc_nvmet_cleanup_io_context(phba);
}
phba->targetport = NULL;
@@ -1843,7 +2049,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf)
struct lpfc_hba *phba = ctxp->phba;
struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer;
struct lpfc_nvmet_tgtport *tgtp;
- uint32_t *payload;
+ uint32_t *payload, qno;
uint32_t rc;
unsigned long iflags;
@@ -1860,8 +2066,20 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf)
return;
}
+ if (ctxp->flag & LPFC_NVMET_ABTS_RCV) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
+ "6324 IO oxid x%x aborted\n",
+ ctxp->oxid);
+ return;
+ }
+
payload = (uint32_t *)(nvmebuf->dbuf.virt);
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+ ctxp->flag |= LPFC_NVMET_TNOTIFY;
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+ if (ctxp->ts_isr_cmd)
+ ctxp->ts_cmd_nvme = ktime_get_ns();
+#endif
/*
* The calling sequence should be:
* nvmet_fc_rcv_fcp_req->lpfc_nvmet_xmt_fcp_op/cmp- req->done
@@ -1876,6 +2094,15 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf)
/* Process FCP command */
if (rc == 0) {
atomic_inc(&tgtp->rcv_fcp_cmd_out);
+ spin_lock_irqsave(&ctxp->ctxlock, iflags);
+ if ((ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) ||
+ (nvmebuf != ctxp->rqb_buffer)) {
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflags);
+ return;
+ }
+ ctxp->rqb_buffer = NULL;
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflags);
+ lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */
return;
}
@@ -1886,8 +2113,23 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf)
ctxp->oxid, ctxp->size, ctxp->sid);
atomic_inc(&tgtp->rcv_fcp_cmd_out);
atomic_inc(&tgtp->defer_fod);
+ spin_lock_irqsave(&ctxp->ctxlock, iflags);
+ if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) {
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflags);
+ return;
+ }
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflags);
+ /*
+ * Post a replacement DMA buffer to RQ and defer
+ * freeing rcv buffer till .defer_rcv callback
+ */
+ qno = nvmebuf->idx;
+ lpfc_post_rq_buffer(
+ phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
+ phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
return;
}
+ ctxp->flag &= ~LPFC_NVMET_TNOTIFY;
atomic_inc(&tgtp->rcv_fcp_cmd_drop);
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
"2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n",
@@ -1977,6 +2219,8 @@ lpfc_nvmet_replenish_context(struct lpfc_hba *phba,
* @phba: pointer to lpfc hba data structure.
* @idx: relative index of MRQ vector
* @nvmebuf: pointer to lpfc nvme command HBQ data structure.
+ * @isr_timestamp: in jiffies.
+ * @cqflag: cq processing information regarding workload.
*
* This routine is used for processing the WQE associated with a unsolicited
* event. It first determines whether there is an existing ndlp that matches
@@ -1989,14 +2233,14 @@ static void
lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
uint32_t idx,
struct rqb_dmabuf *nvmebuf,
- uint64_t isr_timestamp)
+ uint64_t isr_timestamp,
+ uint8_t cqflag)
{
struct lpfc_nvmet_rcv_ctx *ctxp;
struct lpfc_nvmet_tgtport *tgtp;
struct fc_frame_header *fc_hdr;
struct lpfc_nvmet_ctxbuf *ctx_buf;
struct lpfc_nvmet_ctx_info *current_infop;
- uint32_t *payload;
uint32_t size, oxid, sid, qno;
unsigned long iflag;
int current_cpu;
@@ -2020,7 +2264,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
* be empty, thus it would need to be replenished with the
* context list from another CPU for this MRQ.
*/
- current_cpu = smp_processor_id();
+ current_cpu = raw_smp_processor_id();
current_infop = lpfc_get_ctx_list(phba, current_cpu, idx);
spin_lock_irqsave(&current_infop->nvmet_ctx_list_lock, iflag);
if (current_infop->nvmet_ctx_list_cnt) {
@@ -2050,7 +2294,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
#endif
lpfc_nvmeio_data(phba, "NVMET FCP RCV: xri x%x sz %d CPU %02x\n",
- oxid, size, smp_processor_id());
+ oxid, size, raw_smp_processor_id());
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
@@ -2074,10 +2318,12 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
return;
}
- payload = (uint32_t *)(nvmebuf->dbuf.virt);
sid = sli4_sid_from_fc_hdr(fc_hdr);
ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context;
+ spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag);
+ list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list);
+ spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag);
if (ctxp->state != LPFC_NVMET_STE_FREE) {
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
"6414 NVMET Context corrupt %d %d oxid x%x\n",
@@ -2100,24 +2346,41 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
spin_lock_init(&ctxp->ctxlock);
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
- if (isr_timestamp) {
+ if (isr_timestamp)
ctxp->ts_isr_cmd = isr_timestamp;
- ctxp->ts_cmd_nvme = ktime_get_ns();
- ctxp->ts_nvme_data = 0;
- ctxp->ts_data_wqput = 0;
- ctxp->ts_isr_data = 0;
- ctxp->ts_data_nvme = 0;
- ctxp->ts_nvme_status = 0;
- ctxp->ts_status_wqput = 0;
- ctxp->ts_isr_status = 0;
- ctxp->ts_status_nvme = 0;
- } else {
- ctxp->ts_cmd_nvme = 0;
- }
+ ctxp->ts_cmd_nvme = 0;
+ ctxp->ts_nvme_data = 0;
+ ctxp->ts_data_wqput = 0;
+ ctxp->ts_isr_data = 0;
+ ctxp->ts_data_nvme = 0;
+ ctxp->ts_nvme_status = 0;
+ ctxp->ts_status_wqput = 0;
+ ctxp->ts_isr_status = 0;
+ ctxp->ts_status_nvme = 0;
#endif
atomic_inc(&tgtp->rcv_fcp_cmd_in);
- lpfc_nvmet_process_rcv_fcp_req(ctx_buf);
+ /* check for cq processing load */
+ if (!cqflag) {
+ lpfc_nvmet_process_rcv_fcp_req(ctx_buf);
+ return;
+ }
+
+ if (!queue_work(phba->wq, &ctx_buf->defer_work)) {
+ atomic_inc(&tgtp->rcv_fcp_cmd_drop);
+ lpfc_printf_log(phba, KERN_ERR, LOG_NVME,
+ "6325 Unable to queue work for oxid x%x. "
+ "FCP Drop IO [x%x x%x x%x]\n",
+ ctxp->oxid,
+ atomic_read(&tgtp->rcv_fcp_cmd_in),
+ atomic_read(&tgtp->rcv_fcp_cmd_out),
+ atomic_read(&tgtp->xmt_fcp_release));
+
+ spin_lock_irqsave(&ctxp->ctxlock, iflag);
+ lpfc_nvmet_defer_release(phba, ctxp);
+ spin_unlock_irqrestore(&ctxp->ctxlock, iflag);
+ lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, sid, oxid);
+ }
}
/**
@@ -2154,6 +2417,8 @@ lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* @phba: pointer to lpfc hba data structure.
* @idx: relative index of MRQ vector
* @nvmebuf: pointer to received nvme data structure.
+ * @isr_timestamp: in jiffies.
+ * @cqflag: cq processing information regarding workload.
*
* This routine is used to process an unsolicited event received from a SLI
* (Service Level Interface) ring. The actual processing of the data buffer
@@ -2165,14 +2430,14 @@ void
lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba,
uint32_t idx,
struct rqb_dmabuf *nvmebuf,
- uint64_t isr_timestamp)
+ uint64_t isr_timestamp,
+ uint8_t cqflag)
{
if (phba->nvmet_support == 0) {
lpfc_rq_buf_free(phba, &nvmebuf->hbuf);
return;
}
- lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf,
- isr_timestamp);
+ lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf, isr_timestamp, cqflag);
}
/**
@@ -2639,8 +2904,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT;
nvmewqe->context1 = ndlp;
- for (i = 0; i < rsp->sg_cnt; i++) {
- sgel = &rsp->sg[i];
+ for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) {
physaddr = sg_dma_address(sgel);
cnt = sg_dma_len(sgel);
sgl->addr_hi = putPaddrHigh(physaddr);
@@ -2690,12 +2954,11 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
{
struct lpfc_nvmet_rcv_ctx *ctxp;
struct lpfc_nvmet_tgtport *tgtp;
- uint32_t status, result;
+ uint32_t result;
unsigned long flags;
bool released = false;
ctxp = cmdwqe->context2;
- status = bf_get(lpfc_wcqe_c_status, wcqe);
result = wcqe->parameter;
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
@@ -2711,7 +2974,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
if ((ctxp->flag & LPFC_NVMET_CTX_RLS) &&
!(ctxp->flag & LPFC_NVMET_XBUSY)) {
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
- list_del(&ctxp->list);
+ list_del_init(&ctxp->list);
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
released = true;
}
@@ -2720,7 +2983,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
atomic_inc(&tgtp->xmt_abort_rsp);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6165 ABORT cmpl: xri x%x flg x%x (%d) "
+ "6165 ABORT cmpl: oxid x%x flg x%x (%d) "
"WCQE: %08x %08x %08x %08x\n",
ctxp->oxid, ctxp->flag, released,
wcqe->word0, wcqe->total_data_placed,
@@ -2761,11 +3024,10 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
struct lpfc_nvmet_rcv_ctx *ctxp;
struct lpfc_nvmet_tgtport *tgtp;
unsigned long flags;
- uint32_t status, result;
+ uint32_t result;
bool released = false;
ctxp = cmdwqe->context2;
- status = bf_get(lpfc_wcqe_c_status, wcqe);
result = wcqe->parameter;
if (!ctxp) {
@@ -2796,7 +3058,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
if ((ctxp->flag & LPFC_NVMET_CTX_RLS) &&
!(ctxp->flag & LPFC_NVMET_XBUSY)) {
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
- list_del(&ctxp->list);
+ list_del_init(&ctxp->list);
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
released = true;
}
@@ -2805,7 +3067,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
atomic_inc(&tgtp->xmt_abort_rsp);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
- "6316 ABTS cmpl xri x%x flg x%x (%x) "
+ "6316 ABTS cmpl oxid x%x flg x%x (%x) "
"WCQE: %08x %08x %08x %08x\n",
ctxp->oxid, ctxp->flag, released,
wcqe->word0, wcqe->total_data_placed,
@@ -2842,10 +3104,9 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
{
struct lpfc_nvmet_rcv_ctx *ctxp;
struct lpfc_nvmet_tgtport *tgtp;
- uint32_t status, result;
+ uint32_t result;
ctxp = cmdwqe->context2;
- status = bf_get(lpfc_wcqe_c_status, wcqe);
result = wcqe->parameter;
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
@@ -3177,7 +3438,7 @@ aerr:
spin_lock_irqsave(&ctxp->ctxlock, flags);
if (ctxp->flag & LPFC_NVMET_CTX_RLS) {
spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
- list_del(&ctxp->list);
+ list_del_init(&ctxp->list);
spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock);
released = true;
}
@@ -3186,8 +3447,9 @@ aerr:
atomic_inc(&tgtp->xmt_abort_rsp_error);
lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS,
- "6135 Failed to Issue ABTS for oxid x%x. Status x%x\n",
- ctxp->oxid, rc);
+ "6135 Failed to Issue ABTS for oxid x%x. Status x%x "
+ "(%x)\n",
+ ctxp->oxid, rc, released);
if (released)
lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf);
return 1;
@@ -3200,7 +3462,6 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba,
{
struct lpfc_nvmet_tgtport *tgtp;
struct lpfc_iocbq *abts_wqeq;
- union lpfc_wqe128 *wqe_abts;
unsigned long flags;
int rc;
@@ -3230,7 +3491,6 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba,
}
}
abts_wqeq = ctxp->wqeq;
- wqe_abts = &abts_wqeq->wqe;
if (lpfc_nvmet_unsol_issue_abort(phba, ctxp, sid, xri) == 0) {
rc = WQE_BUSY;
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h
index 368deea2bcf8..8ff67deac10a 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.h
+++ b/drivers/scsi/lpfc/lpfc_nvmet.h
@@ -27,10 +27,11 @@
#define LPFC_NVMET_RQE_DEF_COUNT 2048
#define LPFC_NVMET_SUCCESS_LEN 12
-#define LPFC_NVMET_MRQ_OFF 0xffff
#define LPFC_NVMET_MRQ_AUTO 0
#define LPFC_NVMET_MRQ_MAX 16
+#define LPFC_NVMET_WAIT_TMO (5 * MSEC_PER_SEC)
+
/* Used for NVME Target */
struct lpfc_nvmet_tgtport {
struct lpfc_hba *phba;
@@ -139,6 +140,7 @@ struct lpfc_nvmet_rcv_ctx {
#define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */
#define LPFC_NVMET_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */
#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */
+#define LPFC_NVMET_TNOTIFY 0x80 /* notify transport of abts */
struct rqb_dmabuf *rqb_buffer;
struct lpfc_nvmet_ctxbuf *ctxbuf;
struct lpfc_sli4_hdw_queue *hdwq;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index a497b2c0cb79..f9df800e7067 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -688,7 +688,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
uint32_t sgl_size, cpu, idx;
int tag;
- cpu = smp_processor_id();
+ cpu = raw_smp_processor_id();
if (cmnd && phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) {
tag = blk_mq_unique_tag(cmnd->request);
idx = blk_mq_unique_tag_to_hwq(tag);
@@ -1137,7 +1137,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
break;
}
- /* Drop thru */
+ /* fall through */
case SCSI_PROT_WRITE_INSERT:
/*
* For WRITE_INSERT, force the error
@@ -1256,7 +1256,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
rc = BG_ERR_TGT | BG_ERR_CHECK;
break;
}
- /* Drop thru */
+ /* fall through */
case SCSI_PROT_WRITE_INSERT:
/*
* For WRITE_INSERT, force the
@@ -1338,7 +1338,7 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
switch (op) {
case SCSI_PROT_WRITE_PASS:
rc = BG_ERR_CHECK;
- /* Drop thru */
+ /* fall through */
case SCSI_PROT_WRITE_INSERT:
/*
@@ -3669,8 +3669,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) {
- cpu = smp_processor_id();
- if (cpu < LPFC_CHECK_CPU_CNT)
+ cpu = raw_smp_processor_id();
+ if (cpu < LPFC_CHECK_CPU_CNT && phba->sli4_hba.hdwq)
phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++;
}
#endif
@@ -3822,7 +3822,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
lpfc_cmd->cur_iocbq.sli4_lxritag,
0, 0);
}
- /* else: fall through */
+ /* fall through */
default:
cmd->result = DID_ERROR << 16;
break;
@@ -3879,10 +3879,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
*/
spin_lock(&lpfc_cmd->buf_lock);
lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED;
- if (lpfc_cmd->waitq) {
+ if (lpfc_cmd->waitq)
wake_up(lpfc_cmd->waitq);
- lpfc_cmd->waitq = NULL;
- }
spin_unlock(&lpfc_cmd->buf_lock);
lpfc_release_scsi_buf(phba, lpfc_cmd);
@@ -4463,7 +4461,7 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) {
- cpu = smp_processor_id();
+ cpu = raw_smp_processor_id();
if (cpu < LPFC_CHECK_CPU_CNT) {
struct lpfc_sli4_hdw_queue *hdwq =
&phba->sli4_hba.hdwq[lpfc_cmd->hdwq_no];
@@ -4718,6 +4716,9 @@ wait_for_cmpl:
iocb->sli4_xritag, ret,
cmnd->device->id, cmnd->device->lun);
}
+
+ lpfc_cmd->waitq = NULL;
+
spin_unlock(&lpfc_cmd->buf_lock);
goto out;
@@ -4797,7 +4798,12 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd)
rsp_info,
rsp_len, rsp_info_code);
- if ((fcprsp->rspStatus2&RSP_LEN_VALID) && (rsp_len == 8)) {
+ /* If FCP_RSP_LEN_VALID bit is one, then the FCP_RSP_LEN
+ * field specifies the number of valid bytes of FCP_RSP_INFO.
+ * The FCP_RSP_LEN field shall be set to 0x04 or 0x08
+ */
+ if ((fcprsp->rspStatus2 & RSP_LEN_VALID) &&
+ ((rsp_len == 8) || (rsp_len == 4))) {
switch (rsp_info_code) {
case RSP_NO_FAILURE:
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
@@ -5048,7 +5054,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
if (!rdata || !rdata->pnode) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
- "0798 Device Reset rport failure: rdata x%p\n",
+ "0798 Device Reset rdata failure: rdata x%p\n",
rdata);
return FAILED;
}
@@ -5117,9 +5123,10 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd)
int status;
rdata = lpfc_rport_data_from_scsi_device(cmnd->device);
- if (!rdata) {
+ if (!rdata || !rdata->pnode) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
- "0799 Target Reset rport failure: rdata x%p\n", rdata);
+ "0799 Target Reset rdata failure: rdata x%p\n",
+ rdata);
return FAILED;
}
pnode = rdata->pnode;
@@ -5740,7 +5747,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
/* Create an lun info structure and add to list of luns */
lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun,
- pri, false);
+ pri, true);
if (lun_info) {
lun_info->oas_enabled = true;
lun_info->priority = pri;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 57b4a463b589..f9e6a135d656 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -87,9 +87,6 @@ static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba,
struct lpfc_eqe *eqe);
static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba);
static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba);
-static int lpfc_sli4_abort_nvme_io(struct lpfc_hba *phba,
- struct lpfc_sli_ring *pring,
- struct lpfc_iocbq *cmdiocb);
static IOCB_t *
lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
@@ -111,7 +108,7 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
* endianness. This function can be called with or without
* lock.
**/
-void
+static void
lpfc_sli4_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
{
uint64_t *src = srcp;
@@ -151,7 +148,7 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe)
/* sanity check on queue memory */
if (unlikely(!q))
return -ENOMEM;
- temp_wqe = q->qe[q->host_index].wqe;
+ temp_wqe = lpfc_sli4_qe(q, q->host_index);
/* If the host has not yet processed the next entry then we are done */
idx = ((q->host_index + 1) % q->entry_count);
@@ -271,7 +268,7 @@ lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe)
/* sanity check on queue memory */
if (unlikely(!q))
return -ENOMEM;
- temp_mqe = q->qe[q->host_index].mqe;
+ temp_mqe = lpfc_sli4_qe(q, q->host_index);
/* If the host has not yet processed the next entry then we are done */
if (((q->host_index + 1) % q->entry_count) == q->hba_index)
@@ -331,7 +328,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
/* sanity check on queue memory */
if (unlikely(!q))
return NULL;
- eqe = q->qe[q->host_index].eqe;
+ eqe = lpfc_sli4_qe(q, q->host_index);
/* If the next EQE is not valid then we are done */
if (bf_get_le32(lpfc_eqe_valid, eqe) != q->qe_valid)
@@ -355,7 +352,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
* @q: The Event Queue to disable interrupts
*
**/
-inline void
+void
lpfc_sli4_eq_clr_intr(struct lpfc_queue *q)
{
struct lpfc_register doorbell;
@@ -374,7 +371,7 @@ lpfc_sli4_eq_clr_intr(struct lpfc_queue *q)
* @q: The Event Queue to disable interrupts
*
**/
-inline void
+void
lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q)
{
struct lpfc_register doorbell;
@@ -545,7 +542,7 @@ lpfc_sli4_cq_get(struct lpfc_queue *q)
/* sanity check on queue memory */
if (unlikely(!q))
return NULL;
- cqe = q->qe[q->host_index].cqe;
+ cqe = lpfc_sli4_qe(q, q->host_index);
/* If the next CQE is not valid then we are done */
if (bf_get_le32(lpfc_cqe_valid, cqe) != q->qe_valid)
@@ -667,8 +664,8 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq,
return -ENOMEM;
hq_put_index = hq->host_index;
dq_put_index = dq->host_index;
- temp_hrqe = hq->qe[hq_put_index].rqe;
- temp_drqe = dq->qe[dq_put_index].rqe;
+ temp_hrqe = lpfc_sli4_qe(hq, hq_put_index);
+ temp_drqe = lpfc_sli4_qe(dq, dq_put_index);
if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ)
return -EINVAL;
@@ -907,10 +904,10 @@ lpfc_handle_rrq_active(struct lpfc_hba *phba)
mod_timer(&phba->rrq_tmr, next_time);
list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) {
list_del(&rrq->list);
- if (!rrq->send_rrq)
+ if (!rrq->send_rrq) {
/* this call will free the rrq */
- lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
- else if (lpfc_send_rrq(phba, rrq)) {
+ lpfc_clr_rrq_active(phba, rrq->xritag, rrq);
+ } else if (lpfc_send_rrq(phba, rrq)) {
/* if we send the rrq then the completion handler
* will clear the bit in the xribitmap.
*/
@@ -994,15 +991,14 @@ lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
* @ndlp: Targets nodelist pointer for this exchange.
* @xritag the xri in the bitmap to test.
*
- * This function is called with hbalock held. This function
- * returns 0 = rrq not active for this xri
- * 1 = rrq is valid for this xri.
+ * This function returns:
+ * 0 = rrq not active for this xri
+ * 1 = rrq is valid for this xri.
**/
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)
@@ -1105,10 +1101,11 @@ out:
* @phba: Pointer to HBA context object.
* @piocb: Pointer to the iocbq.
*
- * This function is called with the ring lock held. This function
- * gets a new driver sglq object from the sglq list. If the
- * list is not empty then it is successful, it returns pointer to the newly
- * allocated sglq object else it returns NULL.
+ * The driver calls this function with either the nvme ls ring lock
+ * or the fc els ring lock held depending on the iocb usage. This function
+ * gets a new driver sglq object from the sglq list. If the list is not empty
+ * then it is successful, it returns pointer to the newly allocated sglq
+ * object else it returns NULL.
**/
static struct lpfc_sglq *
__lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
@@ -1118,9 +1115,15 @@ __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
struct lpfc_sglq *start_sglq = NULL;
struct lpfc_io_buf *lpfc_cmd;
struct lpfc_nodelist *ndlp;
+ struct lpfc_sli_ring *pring = NULL;
int found = 0;
- lockdep_assert_held(&phba->hbalock);
+ if (piocbq->iocb_flag & LPFC_IO_NVME_LS)
+ pring = phba->sli4_hba.nvmels_wq->pring;
+ else
+ pring = lpfc_phba_elsring(phba);
+
+ lockdep_assert_held(&pring->ring_lock);
if (piocbq->iocb_flag & LPFC_IO_FCP) {
lpfc_cmd = (struct lpfc_io_buf *) piocbq->context1;
@@ -1563,7 +1566,8 @@ lpfc_sli_ring_map(struct lpfc_hba *phba)
* @pring: Pointer to driver SLI ring object.
* @piocb: Pointer to the driver iocb object.
*
- * This function is called with hbalock held. The function adds the
+ * The driver calls this function with the hbalock held for SLI3 ports or
+ * the ring lock held for SLI4 ports. The function adds the
* new iocb to txcmplq of the given ring. This function always returns
* 0. If this function is called for ELS ring, this function checks if
* there is a vport associated with the ELS command. This function also
@@ -1573,7 +1577,10 @@ static int
lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
- lockdep_assert_held(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lockdep_assert_held(&pring->ring_lock);
+ else
+ lockdep_assert_held(&phba->hbalock);
BUG_ON(!piocb);
@@ -2502,8 +2509,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
} else {
ndlp->nlp_flag &= ~NLP_UNREG_INP;
}
+ pmb->ctx_ndlp = NULL;
}
- pmb->ctx_ndlp = NULL;
}
/* Check security permission status on INIT_LINK mailbox command */
@@ -2970,8 +2977,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
*
* This function looks up the iocb_lookup table to get the command iocb
* corresponding to the given response iocb using the iotag of the
- * response iocb. This function is called with the hbalock held
- * for sli3 devices or the ring_lock for sli4 devices.
+ * response iocb. The driver calls this function with the hbalock held
+ * for SLI3 ports or the ring lock held for SLI4 ports.
* This function returns the command iocb object if it finds the command
* iocb else returns NULL.
**/
@@ -2982,8 +2989,15 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
{
struct lpfc_iocbq *cmd_iocb = NULL;
uint16_t iotag;
- lockdep_assert_held(&phba->hbalock);
+ spinlock_t *temp_lock = NULL;
+ unsigned long iflag = 0;
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ temp_lock = &pring->ring_lock;
+ else
+ temp_lock = &phba->hbalock;
+ spin_lock_irqsave(temp_lock, iflag);
iotag = prspiocb->iocb.ulpIoTag;
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
@@ -2993,10 +3007,12 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
list_del_init(&cmd_iocb->list);
cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
pring->txcmplq_cnt--;
+ spin_unlock_irqrestore(temp_lock, iflag);
return cmd_iocb;
}
}
+ spin_unlock_irqrestore(temp_lock, iflag);
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0317 iotag x%x is out of "
"range: max iotag x%x wd0 x%x\n",
@@ -3012,8 +3028,8 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
* @iotag: IOCB tag.
*
* This function looks up the iocb_lookup table to get the command iocb
- * corresponding to the given iotag. This function is called with the
- * hbalock held.
+ * corresponding to the given iotag. The driver calls this function with
+ * the ring lock held because this function is an SLI4 port only helper.
* This function returns the command iocb object if it finds the command
* iocb else returns NULL.
**/
@@ -3022,8 +3038,15 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
struct lpfc_sli_ring *pring, uint16_t iotag)
{
struct lpfc_iocbq *cmd_iocb = NULL;
+ spinlock_t *temp_lock = NULL;
+ unsigned long iflag = 0;
- lockdep_assert_held(&phba->hbalock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ temp_lock = &pring->ring_lock;
+ else
+ temp_lock = &phba->hbalock;
+
+ spin_lock_irqsave(temp_lock, iflag);
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
@@ -3031,10 +3054,12 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
list_del_init(&cmd_iocb->list);
cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
pring->txcmplq_cnt--;
+ spin_unlock_irqrestore(temp_lock, iflag);
return cmd_iocb;
}
}
+ spin_unlock_irqrestore(temp_lock, iflag);
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0372 iotag x%x lookup error: max iotag (x%x) "
"iocb_flag x%x\n",
@@ -3068,17 +3093,7 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
int rc = 1;
unsigned long iflag;
- /* Based on the iotag field, get the cmd IOCB from the txcmplq */
- if (phba->sli_rev == LPFC_SLI_REV4)
- spin_lock_irqsave(&pring->ring_lock, iflag);
- else
- spin_lock_irqsave(&phba->hbalock, iflag);
cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq);
- if (phba->sli_rev == LPFC_SLI_REV4)
- spin_unlock_irqrestore(&pring->ring_lock, iflag);
- else
- spin_unlock_irqrestore(&phba->hbalock, iflag);
-
if (cmdiocbp) {
if (cmdiocbp->iocb_cmpl) {
/*
@@ -3409,8 +3424,10 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
break;
}
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
&rspiocbq);
+ spin_lock_irqsave(&phba->hbalock, iflag);
if (unlikely(!cmdiocbq))
break;
if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED)
@@ -3604,9 +3621,12 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
case LPFC_ABORT_IOCB:
cmdiocbp = NULL;
- if (irsp->ulpCommand != CMD_XRI_ABORTED_CX)
+ if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring,
saveq);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ }
if (cmdiocbp) {
/* Call the specified completion routine */
if (cmdiocbp->iocb_cmpl) {
@@ -3922,33 +3942,6 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
}
/**
- * lpfc_sli_abort_wqe_ring - Abort all iocbs in the ring
- * @phba: Pointer to HBA context object.
- * @pring: Pointer to driver SLI ring object.
- *
- * This function aborts all iocbs in the given ring and frees all the iocb
- * objects in txq. This function issues an abort iocb for all the iocb commands
- * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before
- * the return of this function. The caller is not required to hold any locks.
- **/
-void
-lpfc_sli_abort_wqe_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
-{
- LIST_HEAD(completions);
- struct lpfc_iocbq *iocb, *next_iocb;
-
- if (pring->ringno == LPFC_ELS_RING)
- lpfc_fabric_abort_hba(phba);
-
- spin_lock_irq(&phba->hbalock);
- /* Next issue ABTS for everything on the txcmplq */
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
- lpfc_sli4_abort_nvme_io(phba, pring, iocb);
- spin_unlock_irq(&phba->hbalock);
-}
-
-
-/**
* lpfc_sli_abort_fcp_rings - Abort all iocbs in all FCP rings
* @phba: Pointer to HBA context object.
* @pring: Pointer to driver SLI ring object.
@@ -3978,33 +3971,6 @@ lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba)
}
/**
- * lpfc_sli_abort_nvme_rings - Abort all wqes in all NVME rings
- * @phba: Pointer to HBA context object.
- *
- * This function aborts all wqes in NVME rings. This function issues an
- * abort wqe for all the outstanding IO commands in txcmplq. The iocbs in
- * the txcmplq is not guaranteed to complete before the return of this
- * function. The caller is not required to hold any locks.
- **/
-void
-lpfc_sli_abort_nvme_rings(struct lpfc_hba *phba)
-{
- struct lpfc_sli_ring *pring;
- uint32_t i;
-
- if ((phba->sli_rev < LPFC_SLI_REV4) ||
- !(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME))
- return;
-
- /* Abort all IO on each NVME ring. */
- for (i = 0; i < phba->cfg_hdw_queue; i++) {
- pring = phba->sli4_hba.hdwq[i].nvme_wq->pring;
- lpfc_sli_abort_wqe_ring(phba, pring);
- }
-}
-
-
-/**
* lpfc_sli_flush_fcp_rings - flush all iocbs in the fcp ring
* @phba: Pointer to HBA context object.
*
@@ -4487,7 +4453,9 @@ lpfc_sli_brdreset(struct lpfc_hba *phba)
}
/* Turn off parity checking and serr during the physical reset */
- pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
+ if (pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value))
+ return -EIO;
+
pci_write_config_word(phba->pcidev, PCI_COMMAND,
(cfg_value &
~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
@@ -4564,7 +4532,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba)
"0389 Performing PCI function reset!\n");
/* Turn off parity checking and serr during the physical reset */
- pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
+ if (pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value)) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "3205 PCI read Config failed\n");
+ return -EIO;
+ }
+
pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value &
~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
@@ -5395,7 +5368,7 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
}
/**
- * lpfc_sli4_retrieve_pport_name - Retrieve SLI4 device physical port name
+ * lpfc_sli4_get_ctl_attr - Retrieve SLI4 device controller attributes
* @phba: pointer to lpfc hba data structure.
*
* This routine retrieves SLI4 device physical port name this PCI function
@@ -5403,40 +5376,30 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
*
* Return codes
* 0 - successful
- * otherwise - failed to retrieve physical port name
+ * otherwise - failed to retrieve controller attributes
**/
static int
-lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba)
+lpfc_sli4_get_ctl_attr(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *mboxq;
struct lpfc_mbx_get_cntl_attributes *mbx_cntl_attr;
struct lpfc_controller_attribute *cntl_attr;
- struct lpfc_mbx_get_port_name *get_port_name;
void *virtaddr = NULL;
uint32_t alloclen, reqlen;
uint32_t shdr_status, shdr_add_status;
union lpfc_sli4_cfg_shdr *shdr;
- char cport_name = 0;
int rc;
- /* We assume nothing at this point */
- phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL;
- phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_NON;
-
mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mboxq)
return -ENOMEM;
- /* obtain link type and link number via READ_CONFIG */
- phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL;
- lpfc_sli4_read_config(phba);
- if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL)
- goto retrieve_ppname;
- /* obtain link type and link number via COMMON_GET_CNTL_ATTRIBUTES */
+ /* Send COMMON_GET_CNTL_ATTRIBUTES mbox cmd */
reqlen = sizeof(struct lpfc_mbx_get_cntl_attributes);
alloclen = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES, reqlen,
LPFC_SLI4_MBX_NEMBED);
+
if (alloclen < reqlen) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"3084 Allocated DMA memory size (%d) is "
@@ -5462,16 +5425,71 @@ lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba)
rc = -ENXIO;
goto out_free_mboxq;
}
+
cntl_attr = &mbx_cntl_attr->cntl_attr;
phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL;
phba->sli4_hba.lnk_info.lnk_tp =
bf_get(lpfc_cntl_attr_lnk_type, cntl_attr);
phba->sli4_hba.lnk_info.lnk_no =
bf_get(lpfc_cntl_attr_lnk_numb, cntl_attr);
+
+ memset(phba->BIOSVersion, 0, sizeof(phba->BIOSVersion));
+ strlcat(phba->BIOSVersion, (char *)cntl_attr->bios_ver_str,
+ sizeof(phba->BIOSVersion));
+
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "3086 lnk_type:%d, lnk_numb:%d\n",
+ "3086 lnk_type:%d, lnk_numb:%d, bios_ver:%s\n",
phba->sli4_hba.lnk_info.lnk_tp,
- phba->sli4_hba.lnk_info.lnk_no);
+ phba->sli4_hba.lnk_info.lnk_no,
+ phba->BIOSVersion);
+out_free_mboxq:
+ if (rc != MBX_TIMEOUT) {
+ if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG)
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ else
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ }
+ return rc;
+}
+
+/**
+ * lpfc_sli4_retrieve_pport_name - Retrieve SLI4 device physical port name
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine retrieves SLI4 device physical port name this PCI function
+ * is attached to.
+ *
+ * Return codes
+ * 0 - successful
+ * otherwise - failed to retrieve physical port name
+ **/
+static int
+lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba)
+{
+ LPFC_MBOXQ_t *mboxq;
+ struct lpfc_mbx_get_port_name *get_port_name;
+ uint32_t shdr_status, shdr_add_status;
+ union lpfc_sli4_cfg_shdr *shdr;
+ char cport_name = 0;
+ int rc;
+
+ /* We assume nothing at this point */
+ phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL;
+ phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_NON;
+
+ mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mboxq)
+ return -ENOMEM;
+ /* obtain link type and link number via READ_CONFIG */
+ phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL;
+ lpfc_sli4_read_config(phba);
+ if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL)
+ goto retrieve_ppname;
+
+ /* obtain link type and link number via COMMON_GET_CNTL_ATTRIBUTES */
+ rc = lpfc_sli4_get_ctl_attr(phba);
+ if (rc)
+ goto out_free_mboxq;
retrieve_ppname:
lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
@@ -5553,6 +5571,7 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
int qidx;
struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
struct lpfc_sli4_hdw_queue *qp;
+ struct lpfc_queue *eq;
sli4_hba->sli4_write_cq_db(phba, sli4_hba->mbx_cq, 0, LPFC_QUEUE_REARM);
sli4_hba->sli4_write_cq_db(phba, sli4_hba->els_cq, 0, LPFC_QUEUE_REARM);
@@ -5560,18 +5579,24 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
sli4_hba->sli4_write_cq_db(phba, sli4_hba->nvmels_cq, 0,
LPFC_QUEUE_REARM);
- qp = sli4_hba->hdwq;
if (sli4_hba->hdwq) {
+ /* Loop thru all Hardware Queues */
for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) {
- sli4_hba->sli4_write_cq_db(phba, qp[qidx].fcp_cq, 0,
+ qp = &sli4_hba->hdwq[qidx];
+ /* ARM the corresponding CQ */
+ sli4_hba->sli4_write_cq_db(phba, qp->fcp_cq, 0,
LPFC_QUEUE_REARM);
- sli4_hba->sli4_write_cq_db(phba, qp[qidx].nvme_cq, 0,
+ sli4_hba->sli4_write_cq_db(phba, qp->nvme_cq, 0,
LPFC_QUEUE_REARM);
}
- for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++)
- sli4_hba->sli4_write_eq_db(phba, qp[qidx].hba_eq,
- 0, LPFC_QUEUE_REARM);
+ /* Loop thru all IRQ vectors */
+ for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) {
+ eq = sli4_hba->hba_eq_hdl[qidx].eq;
+ /* ARM the corresponding EQ */
+ sli4_hba->sli4_write_eq_db(phba, eq,
+ 0, LPFC_QUEUE_REARM);
+ }
}
if (phba->nvmet_support) {
@@ -7047,7 +7072,7 @@ lpfc_sli4_repost_sgl_list(struct lpfc_hba *phba,
*
* Returns: 0 = success, non-zero failure.
**/
-int
+static int
lpfc_sli4_repost_io_sgl_list(struct lpfc_hba *phba)
{
LIST_HEAD(post_nblist);
@@ -7067,7 +7092,7 @@ lpfc_sli4_repost_io_sgl_list(struct lpfc_hba *phba)
return rc;
}
-void
+static void
lpfc_set_host_data(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
{
uint32_t len;
@@ -7250,6 +7275,12 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
"3080 Successful retrieving SLI4 device "
"physical port name: %s.\n", phba->Port);
+ rc = lpfc_sli4_get_ctl_attr(phba);
+ if (!rc)
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+ "8351 Successful retrieving SLI4 device "
+ "CTL ATTR\n");
+
/*
* Evaluate the read rev and vpd data. Populate the driver
* state with the results. If this routine fails, the failure
@@ -7652,12 +7683,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
phba->cfg_xri_rebalancing = 0;
}
- /* Arm the CQs and then EQs on device */
- lpfc_sli4_arm_cqeq_intr(phba);
-
- /* Indicate device interrupt mode */
- phba->sli4_hba.intr_enable = 1;
-
/* Allow asynchronous mailbox command to go through */
spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK;
@@ -7726,6 +7751,12 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
phba->trunk_link.link3.state = LPFC_LINK_DOWN;
spin_unlock_irq(&phba->hbalock);
+ /* Arm the CQs and then EQs on device */
+ lpfc_sli4_arm_cqeq_intr(phba);
+
+ /* Indicate device interrupt mode */
+ phba->sli4_hba.intr_enable = 1;
+
if (!(phba->hba_flag & HBA_FCOE_MODE) &&
(phba->hba_flag & LINK_DISABLED)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI,
@@ -7820,8 +7851,9 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
mcq = phba->sli4_hba.mbx_cq;
idx = mcq->hba_index;
qe_valid = mcq->qe_valid;
- while (bf_get_le32(lpfc_cqe_valid, mcq->qe[idx].cqe) == qe_valid) {
- mcqe = (struct lpfc_mcqe *)mcq->qe[idx].cqe;
+ while (bf_get_le32(lpfc_cqe_valid,
+ (struct lpfc_cqe *)lpfc_sli4_qe(mcq, idx)) == qe_valid) {
+ mcqe = (struct lpfc_mcqe *)(lpfc_sli4_qe(mcq, idx));
if (bf_get_le32(lpfc_trailer_completed, mcqe) &&
(!bf_get_le32(lpfc_trailer_async, mcqe))) {
pending_completions = true;
@@ -7850,26 +7882,28 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
* and will process all the completions associated with the eq for the
* mailbox completion queue.
**/
-bool
+static bool
lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
{
struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
uint32_t eqidx;
struct lpfc_queue *fpeq = NULL;
+ struct lpfc_queue *eq;
bool mbox_pending;
if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
return false;
- /* Find the eq associated with the mcq */
-
- if (sli4_hba->hdwq)
- for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++)
- if (sli4_hba->hdwq[eqidx].hba_eq->queue_id ==
- sli4_hba->mbx_cq->assoc_qid) {
- fpeq = sli4_hba->hdwq[eqidx].hba_eq;
+ /* Find the EQ associated with the mbox CQ */
+ if (sli4_hba->hdwq) {
+ for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) {
+ eq = phba->sli4_hba.hba_eq_hdl[eqidx].eq;
+ if (eq->queue_id == sli4_hba->mbx_cq->assoc_qid) {
+ fpeq = eq;
break;
}
+ }
+ }
if (!fpeq)
return false;
@@ -8500,7 +8534,7 @@ lpfc_sli4_wait_bmbx_ready(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr);
db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg);
if (!db_ready)
- msleep(2);
+ mdelay(2);
if (time_after(jiffies, timeout))
return MBXERR_ERROR;
@@ -9373,6 +9407,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
*pcmd == ELS_CMD_SCR ||
+ *pcmd == ELS_CMD_RSCN_XMT ||
*pcmd == ELS_CMD_FDISC ||
*pcmd == ELS_CMD_LOGO ||
*pcmd == ELS_CMD_PLOGI)) {
@@ -11264,102 +11299,6 @@ abort_iotag_exit:
}
/**
- * lpfc_sli4_abort_nvme_io - Issue abort for a command iocb
- * @phba: Pointer to HBA context object.
- * @pring: Pointer to driver SLI ring object.
- * @cmdiocb: Pointer to driver command iocb object.
- *
- * This function issues an abort iocb for the provided command iocb down to
- * the port. Other than the case the outstanding command iocb is an abort
- * request, this function issues abort out unconditionally. This function is
- * called with hbalock held. The function returns 0 when it fails due to
- * memory allocation failure or when the command iocb is an abort request.
- **/
-static int
-lpfc_sli4_abort_nvme_io(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- struct lpfc_iocbq *cmdiocb)
-{
- struct lpfc_vport *vport = cmdiocb->vport;
- struct lpfc_iocbq *abtsiocbp;
- union lpfc_wqe128 *abts_wqe;
- int retval;
- int idx = cmdiocb->hba_wqidx;
-
- /*
- * 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
- * being aborted.
- */
- if (cmdiocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
- cmdiocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN ||
- (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
- return 0;
-
- /* issue ABTS for this io based on iotag */
- abtsiocbp = __lpfc_sli_get_iocbq(phba);
- if (abtsiocbp == NULL)
- return 0;
-
- /* This signals the response to set the correct status
- * before calling the completion handler
- */
- cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
-
- /* Complete prepping the abort wqe and issue to the FW. */
- abts_wqe = &abtsiocbp->wqe;
-
- /* Clear any stale WQE contents */
- memset(abts_wqe, 0, sizeof(union lpfc_wqe));
- bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG);
-
- /* word 7 */
- bf_set(wqe_cmnd, &abts_wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX);
- bf_set(wqe_class, &abts_wqe->abort_cmd.wqe_com,
- cmdiocb->iocb.ulpClass);
-
- /* word 8 - tell the FW to abort the IO associated with this
- * outstanding exchange ID.
- */
- abts_wqe->abort_cmd.wqe_com.abort_tag = cmdiocb->sli4_xritag;
-
- /* word 9 - this is the iotag for the abts_wqe completion. */
- bf_set(wqe_reqtag, &abts_wqe->abort_cmd.wqe_com,
- abtsiocbp->iotag);
-
- /* word 10 */
- bf_set(wqe_qosd, &abts_wqe->abort_cmd.wqe_com, 1);
- bf_set(wqe_lenloc, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE);
-
- /* word 11 */
- bf_set(wqe_cmd_type, &abts_wqe->abort_cmd.wqe_com, OTHER_COMMAND);
- bf_set(wqe_wqec, &abts_wqe->abort_cmd.wqe_com, 1);
- bf_set(wqe_cqid, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
-
- /* ABTS WQE must go to the same WQ as the WQE to be aborted */
- abtsiocbp->iocb_flag |= LPFC_IO_NVME;
- abtsiocbp->vport = vport;
- abtsiocbp->wqe_cmpl = lpfc_nvme_abort_fcreq_cmpl;
- retval = lpfc_sli4_issue_wqe(phba, &phba->sli4_hba.hdwq[idx],
- abtsiocbp);
- if (retval) {
- lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME,
- "6147 Failed abts issue_wqe with status x%x "
- "for oxid x%x\n",
- retval, cmdiocb->sli4_xritag);
- lpfc_sli_release_iocbq(phba, abtsiocbp);
- return retval;
- }
-
- lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME,
- "6148 Drv Abort NVME Request Issued for "
- "ox_id x%x on reqtag x%x\n",
- cmdiocb->sli4_xritag,
- abtsiocbp->iotag);
-
- return retval;
-}
-
-/**
* lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba.
* @phba: pointer to lpfc HBA data structure.
*
@@ -13070,13 +13009,11 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
return NULL;
wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl;
- spin_lock_irqsave(&pring->ring_lock, iflags);
pring->stats.iocb_event++;
/* Look up the ELS command IOCB and create pseudo response IOCB */
cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
bf_get(lpfc_wcqe_c_request_tag, wcqe));
if (unlikely(!cmdiocbq)) {
- spin_unlock_irqrestore(&pring->ring_lock, iflags);
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
"0386 ELS complete with no corresponding "
"cmdiocb: 0x%x 0x%x 0x%x 0x%x\n",
@@ -13086,6 +13023,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
return NULL;
}
+ spin_lock_irqsave(&pring->ring_lock, iflags);
/* Put the iocb back on the txcmplq */
lpfc_sli_ringtxcmpl_put(phba, pring, cmdiocbq);
spin_unlock_irqrestore(&pring->ring_lock, iflags);
@@ -13636,7 +13574,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0390 Cannot schedule soft IRQ "
"for CQ eqcqid=%d, cqid=%d on CPU %d\n",
- cqid, cq->queue_id, smp_processor_id());
+ cqid, cq->queue_id, raw_smp_processor_id());
}
/**
@@ -13676,14 +13614,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
goto rearm_and_exit;
/* Process all the entries to the CQ */
+ cq->q_flag = 0;
cqe = lpfc_sli4_cq_get(cq);
while (cqe) {
-#if defined(CONFIG_SCSI_LPFC_DEBUG_FS) && defined(BUILD_NVME)
- if (phba->ktime_on)
- cq->isr_timestamp = ktime_get_ns();
- else
- cq->isr_timestamp = 0;
-#endif
workposted |= handler(phba, cq, cqe);
__lpfc_sli4_consume_cqe(phba, cq, cqe);
@@ -13697,6 +13630,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
consumed = 0;
}
+ if (count == LPFC_NVMET_CQ_NOTIFY)
+ cq->q_flag |= HBA_NVMET_CQ_NOTIFY;
+
cqe = lpfc_sli4_cq_get(cq);
}
if (count >= phba->cfg_cq_poll_threshold) {
@@ -13856,9 +13792,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
/* Look up the FCP command IOCB and create pseudo response IOCB */
spin_lock_irqsave(&pring->ring_lock, iflags);
pring->stats.iocb_event++;
+ spin_unlock_irqrestore(&pring->ring_lock, iflags);
cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
bf_get(lpfc_wcqe_c_request_tag, wcqe));
- spin_unlock_irqrestore(&pring->ring_lock, iflags);
if (unlikely(!cmdiocbq)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
"0374 FCP complete with no corresponding "
@@ -14012,14 +13948,14 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
goto drop;
if (fc_hdr->fh_type == FC_TYPE_FCP) {
- dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe);
+ dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe);
lpfc_nvmet_unsol_fcp_event(
- phba, idx, dma_buf,
- cq->isr_timestamp);
+ phba, idx, dma_buf, cq->isr_timestamp,
+ cq->q_flag & HBA_NVMET_CQ_NOTIFY);
return false;
}
drop:
- lpfc_in_buf_free(phba, &dma_buf->dbuf);
+ lpfc_rq_buf_free(phba, &dma_buf->hbuf);
break;
case FC_STATUS_INSUFF_BUF_FRM_DISC:
if (phba->nvmet_support) {
@@ -14181,11 +14117,17 @@ process_cq:
}
work_cq:
+#if defined(CONFIG_SCSI_LPFC_DEBUG_FS)
+ if (phba->ktime_on)
+ cq->isr_timestamp = ktime_get_ns();
+ else
+ cq->isr_timestamp = 0;
+#endif
if (!queue_work_on(cq->chann, phba->wq, &cq->irqwork))
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0363 Cannot schedule soft IRQ "
"for CQ eqcqid=%d, cqid=%d on CPU %d\n",
- cqid, cq->queue_id, smp_processor_id());
+ cqid, cq->queue_id, raw_smp_processor_id());
}
/**
@@ -14307,7 +14249,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
return IRQ_NONE;
/* Get to the EQ struct associated with this vector */
- fpeq = phba->sli4_hba.hdwq[hba_eqidx].hba_eq;
+ fpeq = phba->sli4_hba.hba_eq_hdl[hba_eqidx].eq;
if (unlikely(!fpeq))
return IRQ_NONE;
@@ -14324,7 +14266,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
eqi = phba->sli4_hba.eq_info;
icnt = this_cpu_inc_return(eqi->icnt);
- fpeq->last_cpu = smp_processor_id();
+ fpeq->last_cpu = raw_smp_processor_id();
if (icnt > LPFC_EQD_ISR_TRIGGER &&
phba->cfg_irq_chann == 1 &&
@@ -14410,6 +14352,9 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
if (!queue)
return;
+ if (!list_empty(&queue->wq_list))
+ list_del(&queue->wq_list);
+
while (!list_empty(&queue->page_list)) {
list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,
list);
@@ -14425,9 +14370,6 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
if (!list_empty(&queue->cpu_list))
list_del(&queue->cpu_list);
- if (!list_empty(&queue->wq_list))
- list_del(&queue->wq_list);
-
kfree(queue);
return;
}
@@ -14438,6 +14380,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
* @page_size: The size of a queue page
* @entry_size: The size of each queue entry for this queue.
* @entry count: The number of entries that this queue will handle.
+ * @cpu: The cpu that will primarily utilize this queue.
*
* This function allocates a queue structure and the DMAable memory used for
* the host resident queue. This function must be called before creating the
@@ -14445,28 +14388,26 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
**/
struct lpfc_queue *
lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size,
- uint32_t entry_size, uint32_t entry_count)
+ uint32_t entry_size, uint32_t entry_count, int cpu)
{
struct lpfc_queue *queue;
struct lpfc_dmabuf *dmabuf;
- int x, total_qe_count;
- void *dma_pointer;
uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+ uint16_t x, pgcnt;
if (!phba->sli4_hba.pc_sli4_params.supported)
hw_page_size = page_size;
- queue = kzalloc(sizeof(struct lpfc_queue) +
- (sizeof(union sli4_qe) * entry_count), GFP_KERNEL);
- if (!queue)
- return NULL;
- queue->page_count = (ALIGN(entry_size * entry_count,
- hw_page_size))/hw_page_size;
+ pgcnt = ALIGN(entry_size * entry_count, hw_page_size) / hw_page_size;
/* If needed, Adjust page count to match the max the adapter supports */
- if (phba->sli4_hba.pc_sli4_params.wqpcnt &&
- (queue->page_count > phba->sli4_hba.pc_sli4_params.wqpcnt))
- queue->page_count = phba->sli4_hba.pc_sli4_params.wqpcnt;
+ if (pgcnt > phba->sli4_hba.pc_sli4_params.wqpcnt)
+ pgcnt = phba->sli4_hba.pc_sli4_params.wqpcnt;
+
+ queue = kzalloc_node(sizeof(*queue) + (sizeof(void *) * pgcnt),
+ GFP_KERNEL, cpu_to_node(cpu));
+ if (!queue)
+ return NULL;
INIT_LIST_HEAD(&queue->list);
INIT_LIST_HEAD(&queue->wq_list);
@@ -14478,13 +14419,17 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size,
/* Set queue parameters now. If the system cannot provide memory
* resources, the free routine needs to know what was allocated.
*/
+ queue->page_count = pgcnt;
+ queue->q_pgs = (void **)&queue[1];
+ queue->entry_cnt_per_pg = hw_page_size / entry_size;
queue->entry_size = entry_size;
queue->entry_count = entry_count;
queue->page_size = hw_page_size;
queue->phba = phba;
- for (x = 0, total_qe_count = 0; x < queue->page_count; x++) {
- dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ for (x = 0; x < queue->page_count; x++) {
+ dmabuf = kzalloc_node(sizeof(*dmabuf), GFP_KERNEL,
+ dev_to_node(&phba->pcidev->dev));
if (!dmabuf)
goto out_fail;
dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
@@ -14496,13 +14441,8 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size,
}
dmabuf->buffer_tag = x;
list_add_tail(&dmabuf->list, &queue->page_list);
- /* initialize queue's entry array */
- dma_pointer = dmabuf->virt;
- for (; total_qe_count < entry_count &&
- dma_pointer < (hw_page_size + dmabuf->virt);
- total_qe_count++, dma_pointer += entry_size) {
- queue->qe[total_qe_count].address = dma_pointer;
- }
+ /* use lpfc_sli4_qe to index a paritcular entry in this page */
+ queue->q_pgs[x] = dmabuf->virt;
}
INIT_WORK(&queue->irqwork, lpfc_sli4_hba_process_cq);
INIT_WORK(&queue->spwork, lpfc_sli4_sp_process_cq);
@@ -14594,7 +14534,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
/* set values by EQ_DELAY register if supported */
if (phba->sli.sli_flag & LPFC_SLI_USE_EQDR) {
for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) {
- eq = phba->sli4_hba.hdwq[qidx].hba_eq;
+ eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
if (!eq)
continue;
@@ -14603,7 +14543,6 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
if (++cnt >= numq)
break;
}
-
return;
}
@@ -14631,7 +14570,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
dmult = LPFC_DMULT_MAX;
for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) {
- eq = phba->sli4_hba.hdwq[qidx].hba_eq;
+ eq = phba->sli4_hba.hba_eq_hdl[qidx].eq;
if (!eq)
continue;
eq->q_mode = usdelay;
@@ -14733,8 +14672,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0360 Unsupported EQ count. (%d)\n",
eq->entry_count);
- if (eq->entry_count < 256)
- return -EINVAL;
+ if (eq->entry_count < 256) {
+ status = -EINVAL;
+ goto out;
+ }
/* fall through - otherwise default to smallest count */
case 256:
bf_set(lpfc_eq_context_count, &eq_create->u.request.context,
@@ -14786,7 +14727,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
eq->host_index = 0;
eq->notify_interval = LPFC_EQ_NOTIFY_INTRVL;
eq->max_proc_limit = LPFC_EQ_MAX_PROC_LIMIT;
-
+out:
mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 7a1a761efdd6..467b8270f7fd 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -327,6 +327,10 @@ struct lpfc_sli {
#define LPFC_SLI_ASYNC_MBX_BLK 0x2000 /* Async mailbox is blocked */
#define LPFC_SLI_SUPPRESS_RSP 0x4000 /* Suppress RSP feature is supported */
#define LPFC_SLI_USE_EQDR 0x8000 /* EQ Delay Register is supported */
+#define LPFC_QUEUE_FREE_INIT 0x10000 /* Queue freeing is in progress */
+#define LPFC_QUEUE_FREE_WAIT 0x20000 /* Hold Queue free as it is being
+ * used outside worker thread
+ */
struct lpfc_sli_ring *sli3_ring;
@@ -427,14 +431,13 @@ struct lpfc_io_buf {
struct {
struct nvmefc_fcp_req *nvmeCmd;
uint16_t qidx;
-
-#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
- uint64_t ts_cmd_start;
- uint64_t ts_last_cmd;
- uint64_t ts_cmd_wqput;
- uint64_t ts_isr_cmpl;
- uint64_t ts_data_nvme;
-#endif
};
};
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+ uint64_t ts_cmd_start;
+ uint64_t ts_last_cmd;
+ uint64_t ts_cmd_wqput;
+ uint64_t ts_isr_cmpl;
+ uint64_t ts_data_nvme;
+#endif
};
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 40c85091c805..3aeca387b22a 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -117,21 +117,6 @@ enum lpfc_sli4_queue_subtype {
LPFC_USOL
};
-union sli4_qe {
- void *address;
- struct lpfc_eqe *eqe;
- struct lpfc_cqe *cqe;
- struct lpfc_mcqe *mcqe;
- struct lpfc_wcqe_complete *wcqe_complete;
- struct lpfc_wcqe_release *wcqe_release;
- struct sli4_wcqe_xri_aborted *wcqe_xri_aborted;
- struct lpfc_rcqe_complete *rcqe_complete;
- struct lpfc_mqe *mqe;
- union lpfc_wqe *wqe;
- union lpfc_wqe128 *wqe128;
- struct lpfc_rqe *rqe;
-};
-
/* RQ buffer list */
struct lpfc_rqb {
uint16_t entry_count; /* Current number of RQ slots */
@@ -157,6 +142,7 @@ struct lpfc_queue {
struct list_head cpu_list;
uint32_t entry_count; /* Number of entries to support on the queue */
uint32_t entry_size; /* Size of each queue entry. */
+ uint32_t entry_cnt_per_pg;
uint32_t notify_interval; /* Queue Notification Interval
* For chip->host queues (EQ, CQ, RQ):
* specifies the interval (number of
@@ -211,6 +197,8 @@ struct lpfc_queue {
#define LPFC_DB_LIST_FORMAT 0x02
uint8_t q_flag;
#define HBA_NVMET_WQFULL 0x1 /* We hit WQ Full condition for NVMET */
+#define HBA_NVMET_CQ_NOTIFY 0x1 /* LPFC_NVMET_CQ_NOTIFY CQEs this EQE */
+#define LPFC_NVMET_CQ_NOTIFY 4
void __iomem *db_regaddr;
uint16_t dpp_enable;
uint16_t dpp_id;
@@ -254,17 +242,17 @@ struct lpfc_queue {
uint16_t last_cpu; /* most recent cpu */
uint8_t qe_valid;
struct lpfc_queue *assoc_qp;
- union sli4_qe qe[1]; /* array to index entries (must be last) */
+ void **q_pgs; /* array to index entries per page */
};
struct lpfc_sli4_link {
- uint16_t speed;
+ uint32_t speed;
uint8_t duplex;
uint8_t status;
uint8_t type;
uint8_t number;
uint8_t fault;
- uint16_t logical_speed;
+ uint32_t logical_speed;
uint16_t topology;
};
@@ -464,6 +452,7 @@ struct lpfc_hba_eq_hdl {
uint32_t idx;
char handler_name[LPFC_SLI4_HANDLER_NAME_SZ];
struct lpfc_hba *phba;
+ struct lpfc_queue *eq;
};
/*BB Credit recovery value*/
@@ -526,6 +515,7 @@ struct lpfc_pc_sli4_params {
#define LPFC_WQ_SZ64_SUPPORT 1
#define LPFC_WQ_SZ128_SUPPORT 2
uint8_t wqpcnt;
+ uint8_t nvme;
};
#define LPFC_CQ_4K_PAGE_SZ 0x1
@@ -543,8 +533,9 @@ struct lpfc_sli4_lnk_info {
#define LPFC_LNK_DAT_INVAL 0
#define LPFC_LNK_DAT_VAL 1
uint8_t lnk_tp;
-#define LPFC_LNK_GE 0x0 /* FCoE */
-#define LPFC_LNK_FC 0x1 /* FC */
+#define LPFC_LNK_GE 0x0 /* FCoE */
+#define LPFC_LNK_FC 0x1 /* FC */
+#define LPFC_LNK_FC_TRUNKED 0x2 /* FC_Trunked */
uint8_t lnk_no;
uint8_t optic_state;
};
@@ -559,7 +550,10 @@ struct lpfc_vector_map_info {
uint16_t irq;
uint16_t eq;
uint16_t hdwq;
- uint16_t hyper;
+ uint16_t flag;
+#define LPFC_CPU_MAP_HYPER 0x1
+#define LPFC_CPU_MAP_UNASSIGN 0x2
+#define LPFC_CPU_FIRST_IRQ 0x4
};
#define LPFC_VECTOR_MAP_EMPTY 0xffff
@@ -856,6 +850,8 @@ struct lpfc_sli4_hba {
struct list_head lpfc_nvmet_sgl_list;
spinlock_t abts_nvmet_buf_list_lock; /* list of aborted NVMET IOs */
struct list_head lpfc_abts_nvmet_ctx_list;
+ spinlock_t t_active_list_lock; /* list of active NVMET IOs */
+ struct list_head t_active_ctx_list;
struct list_head lpfc_nvmet_io_wait_list;
struct lpfc_nvmet_ctx_info *nvmet_ctx_info;
struct lpfc_sglq **lpfc_sglq_active_list;
@@ -907,6 +903,18 @@ struct lpfc_sli4_hba {
#define lpfc_conf_trunk_port3_WORD conf_trunk
#define lpfc_conf_trunk_port3_SHIFT 3
#define lpfc_conf_trunk_port3_MASK 0x1
+#define lpfc_conf_trunk_port0_nd_WORD conf_trunk
+#define lpfc_conf_trunk_port0_nd_SHIFT 4
+#define lpfc_conf_trunk_port0_nd_MASK 0x1
+#define lpfc_conf_trunk_port1_nd_WORD conf_trunk
+#define lpfc_conf_trunk_port1_nd_SHIFT 5
+#define lpfc_conf_trunk_port1_nd_MASK 0x1
+#define lpfc_conf_trunk_port2_nd_WORD conf_trunk
+#define lpfc_conf_trunk_port2_nd_SHIFT 6
+#define lpfc_conf_trunk_port2_nd_MASK 0x1
+#define lpfc_conf_trunk_port3_nd_WORD conf_trunk
+#define lpfc_conf_trunk_port3_nd_SHIFT 7
+#define lpfc_conf_trunk_port3_nd_MASK 0x1
};
enum lpfc_sge_type {
@@ -990,8 +998,10 @@ int lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *, struct lpfcMboxq *,
uint16_t);
void lpfc_sli4_hba_reset(struct lpfc_hba *);
-struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t,
- uint32_t, uint32_t);
+struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *phba,
+ uint32_t page_size,
+ uint32_t entry_size,
+ uint32_t entry_count, int cpu);
void lpfc_sli4_queue_free(struct lpfc_queue *);
int lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint32_t);
void lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
@@ -1057,12 +1067,12 @@ void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *);
int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *);
int lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba);
int lpfc_sli4_init_vpi(struct lpfc_vport *);
-inline void lpfc_sli4_eq_clr_intr(struct lpfc_queue *);
+void lpfc_sli4_eq_clr_intr(struct lpfc_queue *);
void lpfc_sli4_write_cq_db(struct lpfc_hba *phba, struct lpfc_queue *q,
uint32_t count, bool arm);
void lpfc_sli4_write_eq_db(struct lpfc_hba *phba, struct lpfc_queue *q,
uint32_t count, bool arm);
-inline void lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q);
+void lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q);
void lpfc_sli4_if6_write_cq_db(struct lpfc_hba *phba, struct lpfc_queue *q,
uint32_t count, bool arm);
void lpfc_sli4_if6_write_eq_db(struct lpfc_hba *phba, struct lpfc_queue *q,
@@ -1079,3 +1089,8 @@ int lpfc_sli4_post_status_check(struct lpfc_hba *);
uint8_t lpfc_sli_config_mbox_subsys_get(struct lpfc_hba *, LPFC_MBOXQ_t *);
uint8_t lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_sli4_ras_dma_free(struct lpfc_hba *phba);
+static inline void *lpfc_sli4_qe(struct lpfc_queue *q, uint16_t idx)
+{
+ return q->q_pgs[idx / q->entry_cnt_per_pg] +
+ (q->entry_size * (idx % q->entry_cnt_per_pg));
+}
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 43fd693cf042..f7e93aaf1e00 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -20,7 +20,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "12.2.0.0"
+#define LPFC_DRIVER_VERSION "12.2.0.3"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
@@ -32,6 +32,6 @@
#define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright (C) 2017-2018 Broadcom. All Rights " \
+#define LPFC_COPYRIGHT "Copyright (C) 2017-2019 Broadcom. All Rights " \
"Reserved. The term \"Broadcom\" refers to Broadcom Inc. " \
"and/or its subsidiaries."
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index c8e6ae98a4a6..35d3e322d6d5 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCSI low-level driver for the 53c94 SCSI bus adaptor found
* on Power Macintosh computers, controlling the external SCSI chain.
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index ee741207fd4e..1c78bc10c790 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* mac_esp.c: ESP front-end for Macintosh Quadra systems.
*
* Adapted from jazz_esp.c and the old mac_esp.c.
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 8b4b5b1a13d7..9c5566217ef6 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -1,8 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Generic Macintosh NCR5380 driver
*
* Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
*
+ * Copyright 2019 Finn Thain
+ *
* derived in part from:
*/
/*
@@ -11,6 +14,7 @@
* Copyright 1995, Russell King
*/
+#include <linux/delay.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/ioport.h>
@@ -21,6 +25,7 @@
#include <asm/hwtest.h>
#include <asm/io.h>
+#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/setup.h>
@@ -52,7 +57,7 @@ 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);
-static int setup_use_pdma = -1;
+static int setup_use_pdma = 512;
module_param(setup_use_pdma, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
@@ -89,223 +94,318 @@ static int __init mac_scsi_setup(char *str)
__setup("mac5380=", mac_scsi_setup);
#endif /* !MODULE */
-/* Pseudo DMA asm originally by Ove Edlund */
-
-#define CP_IO_TO_MEM(s,d,n) \
-__asm__ __volatile__ \
- (" cmp.w #4,%2\n" \
- " bls 8f\n" \
- " move.w %1,%%d0\n" \
- " neg.b %%d0\n" \
- " and.w #3,%%d0\n" \
- " sub.w %%d0,%2\n" \
- " bra 2f\n" \
- " 1: move.b (%0),(%1)+\n" \
- " 2: dbf %%d0,1b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #5,%%d0\n" \
- " bra 4f\n" \
- " 3: move.l (%0),(%1)+\n" \
- "31: move.l (%0),(%1)+\n" \
- "32: move.l (%0),(%1)+\n" \
- "33: move.l (%0),(%1)+\n" \
- "34: move.l (%0),(%1)+\n" \
- "35: move.l (%0),(%1)+\n" \
- "36: move.l (%0),(%1)+\n" \
- "37: move.l (%0),(%1)+\n" \
- " 4: dbf %%d0,3b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #2,%%d0\n" \
- " and.w #7,%%d0\n" \
- " bra 6f\n" \
- " 5: move.l (%0),(%1)+\n" \
- " 6: dbf %%d0,5b\n" \
- " and.w #3,%2\n" \
- " bra 8f\n" \
- " 7: move.b (%0),(%1)+\n" \
- " 8: dbf %2,7b\n" \
- " moveq.l #0, %2\n" \
- " 9: \n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "91: moveq.l #1, %2\n" \
- " jra 9b\n" \
- "94: moveq.l #4, %2\n" \
- " jra 9b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,91b\n" \
- " .long 3b,94b\n" \
- " .long 31b,94b\n" \
- " .long 32b,94b\n" \
- " .long 33b,94b\n" \
- " .long 34b,94b\n" \
- " .long 35b,94b\n" \
- " .long 36b,94b\n" \
- " .long 37b,94b\n" \
- " .long 5b,94b\n" \
- " .long 7b,91b\n" \
- ".previous" \
- : "=a"(s), "=a"(d), "=d"(n) \
- : "0"(s), "1"(d), "2"(n) \
- : "d0")
+/*
+ * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to
+ * specify the number of bytes between the delays expected from a SCSI target.
+ * This allows the operating system to "prevent bus errors when a target fails
+ * to deliver the next byte within the processor bus error timeout period."
+ * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets
+ * so bus errors are unavoidable.
+ *
+ * If a MOVE.B instruction faults, we assume that zero bytes were transferred
+ * and simply retry. That assumption probably depends on target behaviour but
+ * seems to hold up okay. The NOP provides synchronization: without it the
+ * fault can sometimes occur after the program counter has moved past the
+ * offending instruction. Post-increment addressing can't be used.
+ */
+
+#define MOVE_BYTE(operands) \
+ asm volatile ( \
+ "1: moveb " operands " \n" \
+ "11: nop \n" \
+ " addq #1,%0 \n" \
+ " subq #1,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #1, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 11b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+/*
+ * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because
+ * the residual byte count would be uncertain. In that situation the MOVE_WORD
+ * macro clears n in the fixup section to abort the transfer.
+ */
+
+#define MOVE_WORD(operands) \
+ asm volatile ( \
+ "1: movew " operands " \n" \
+ "11: nop \n" \
+ " subq #2,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #0, %1 \n" \
+ " movel #2, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 11b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+#define MOVE_16_WORDS(operands) \
+ asm volatile ( \
+ "1: movew " operands " \n" \
+ "2: movew " operands " \n" \
+ "3: movew " operands " \n" \
+ "4: movew " operands " \n" \
+ "5: movew " operands " \n" \
+ "6: movew " operands " \n" \
+ "7: movew " operands " \n" \
+ "8: movew " operands " \n" \
+ "9: movew " operands " \n" \
+ "10: movew " operands " \n" \
+ "11: movew " operands " \n" \
+ "12: movew " operands " \n" \
+ "13: movew " operands " \n" \
+ "14: movew " operands " \n" \
+ "15: movew " operands " \n" \
+ "16: movew " operands " \n" \
+ "17: nop \n" \
+ " subl #32,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #0, %1 \n" \
+ " movel #2, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 2b,90b \n" \
+ ".long 3b,90b \n" \
+ ".long 4b,90b \n" \
+ ".long 5b,90b \n" \
+ ".long 6b,90b \n" \
+ ".long 7b,90b \n" \
+ ".long 8b,90b \n" \
+ ".long 9b,90b \n" \
+ ".long 10b,90b \n" \
+ ".long 11b,90b \n" \
+ ".long 12b,90b \n" \
+ ".long 13b,90b \n" \
+ ".long 14b,90b \n" \
+ ".long 15b,90b \n" \
+ ".long 16b,90b \n" \
+ ".long 17b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+#define MAC_PDMA_DELAY 32
+
+static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)
+{
+ unsigned char *addr = start;
+ int result = 0;
+
+ if (n >= 1) {
+ MOVE_BYTE("%3@,%0@");
+ if (result)
+ goto out;
+ }
+ if (n >= 1 && ((unsigned long)addr & 1)) {
+ MOVE_BYTE("%3@,%0@");
+ if (result)
+ goto out;
+ }
+ while (n >= 32)
+ MOVE_16_WORDS("%3@,%0@+");
+ while (n >= 2)
+ MOVE_WORD("%3@,%0@+");
+ if (result)
+ return start - addr; /* Negated to indicate uncertain length */
+ if (n == 1)
+ MOVE_BYTE("%3@,%0@");
+out:
+ return addr - start;
+}
+
+static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)
+{
+ unsigned char *addr = start;
+ int result = 0;
+
+ if (n >= 1) {
+ MOVE_BYTE("%0@,%3@");
+ if (result)
+ goto out;
+ }
+ if (n >= 1 && ((unsigned long)addr & 1)) {
+ MOVE_BYTE("%0@,%3@");
+ if (result)
+ goto out;
+ }
+ while (n >= 32)
+ MOVE_16_WORDS("%0@+,%3@");
+ while (n >= 2)
+ MOVE_WORD("%0@+,%3@");
+ if (result)
+ return start - addr; /* Negated to indicate uncertain length */
+ if (n == 1)
+ MOVE_BYTE("%0@,%3@");
+out:
+ return addr - start;
+}
+
+/* The "SCSI DMA" chip on the IIfx implements this register. */
+#define CTRL_REG 0x8
+#define CTRL_INTERRUPTS_ENABLE BIT(1)
+#define CTRL_HANDSHAKE_MODE BIT(3)
+
+static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value)
+{
+ out_be32(hostdata->io + (CTRL_REG << 4), value);
+}
static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
unsigned char *dst, int len)
{
u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
unsigned char *d = dst;
- int n = len;
- int transferred;
+ int result = 0;
+
+ hostdata->pdma_residual = len;
while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
BASR_DRQ | BASR_PHASE_MATCH,
BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
- CP_IO_TO_MEM(s, d, n);
+ int bytes;
+
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
+ CTRL_INTERRUPTS_ENABLE);
- transferred = d - dst - n;
- hostdata->pdma_residual = len - transferred;
+ bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512));
- /* No bus error. */
- if (n == 0)
- return 0;
+ if (bytes > 0) {
+ d += bytes;
+ hostdata->pdma_residual -= bytes;
+ }
+
+ if (hostdata->pdma_residual == 0)
+ goto out;
- /* Target changed phase early? */
if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
- BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
- scmd_printk(KERN_ERR, hostdata->connected,
+ BUS_AND_STATUS_REG, BASR_ACK,
+ BASR_ACK, HZ / 64) < 0)
+ scmd_printk(KERN_DEBUG, hostdata->connected,
"%s: !REQ and !ACK\n", __func__);
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
- return 0;
+ goto out;
+
+ if (bytes == 0)
+ udelay(MAC_PDMA_DELAY);
+
+ if (bytes >= 0)
+ continue;
dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
- "%s: bus error (%d/%d)\n", __func__, transferred, len);
+ "%s: bus error (%d/%d)\n", __func__, d - dst, len);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
- d = dst + transferred;
- n = len - transferred;
+ result = -1;
+ goto out;
}
scmd_printk(KERN_ERR, hostdata->connected,
"%s: phase mismatch or !DRQ\n", __func__);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
- return -1;
+ result = -1;
+out:
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
+ return result;
}
-
-#define CP_MEM_TO_IO(s,d,n) \
-__asm__ __volatile__ \
- (" cmp.w #4,%2\n" \
- " bls 8f\n" \
- " move.w %0,%%d0\n" \
- " neg.b %%d0\n" \
- " and.w #3,%%d0\n" \
- " sub.w %%d0,%2\n" \
- " bra 2f\n" \
- " 1: move.b (%0)+,(%1)\n" \
- " 2: dbf %%d0,1b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #5,%%d0\n" \
- " bra 4f\n" \
- " 3: move.l (%0)+,(%1)\n" \
- "31: move.l (%0)+,(%1)\n" \
- "32: move.l (%0)+,(%1)\n" \
- "33: move.l (%0)+,(%1)\n" \
- "34: move.l (%0)+,(%1)\n" \
- "35: move.l (%0)+,(%1)\n" \
- "36: move.l (%0)+,(%1)\n" \
- "37: move.l (%0)+,(%1)\n" \
- " 4: dbf %%d0,3b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #2,%%d0\n" \
- " and.w #7,%%d0\n" \
- " bra 6f\n" \
- " 5: move.l (%0)+,(%1)\n" \
- " 6: dbf %%d0,5b\n" \
- " and.w #3,%2\n" \
- " bra 8f\n" \
- " 7: move.b (%0)+,(%1)\n" \
- " 8: dbf %2,7b\n" \
- " moveq.l #0, %2\n" \
- " 9: \n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "91: moveq.l #1, %2\n" \
- " jra 9b\n" \
- "94: moveq.l #4, %2\n" \
- " jra 9b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,91b\n" \
- " .long 3b,94b\n" \
- " .long 31b,94b\n" \
- " .long 32b,94b\n" \
- " .long 33b,94b\n" \
- " .long 34b,94b\n" \
- " .long 35b,94b\n" \
- " .long 36b,94b\n" \
- " .long 37b,94b\n" \
- " .long 5b,94b\n" \
- " .long 7b,91b\n" \
- ".previous" \
- : "=a"(s), "=a"(d), "=d"(n) \
- : "0"(s), "1"(d), "2"(n) \
- : "d0")
-
static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
unsigned char *src, int len)
{
unsigned char *s = src;
u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
- int n = len;
- int transferred;
+ int result = 0;
+
+ hostdata->pdma_residual = len;
while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
BASR_DRQ | BASR_PHASE_MATCH,
BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
- CP_MEM_TO_IO(s, d, n);
+ int bytes;
- transferred = s - src - n;
- hostdata->pdma_residual = len - transferred;
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE |
+ CTRL_INTERRUPTS_ENABLE);
- /* Target changed phase early? */
- if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
- BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
- scmd_printk(KERN_ERR, hostdata->connected,
- "%s: !REQ and !ACK\n", __func__);
- if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
- return 0;
+ bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512));
+
+ if (bytes > 0) {
+ s += bytes;
+ hostdata->pdma_residual -= bytes;
+ }
- /* No bus error. */
- if (n == 0) {
+ if (hostdata->pdma_residual == 0) {
if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
TCR_LAST_BYTE_SENT,
- TCR_LAST_BYTE_SENT, HZ / 64) < 0)
+ TCR_LAST_BYTE_SENT,
+ HZ / 64) < 0) {
scmd_printk(KERN_ERR, hostdata->connected,
"%s: Last Byte Sent timeout\n", __func__);
- return 0;
+ result = -1;
+ }
+ goto out;
}
+ if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
+ BUS_AND_STATUS_REG, BASR_ACK,
+ BASR_ACK, HZ / 64) < 0)
+ scmd_printk(KERN_DEBUG, hostdata->connected,
+ "%s: !REQ and !ACK\n", __func__);
+ if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
+ goto out;
+
+ if (bytes == 0)
+ udelay(MAC_PDMA_DELAY);
+
+ if (bytes >= 0)
+ continue;
+
dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
- "%s: bus error (%d/%d)\n", __func__, transferred, len);
+ "%s: bus error (%d/%d)\n", __func__, s - src, len);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
- s = src + transferred;
- n = len - transferred;
+ result = -1;
+ goto out;
}
scmd_printk(KERN_ERR, hostdata->connected,
"%s: phase mismatch or !DRQ\n", __func__);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
-
- return -1;
+ result = -1;
+out:
+ if (macintosh_config->ident == MAC_MODEL_IIFX)
+ write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE);
+ return result;
}
static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
struct scsi_cmnd *cmd)
{
if (hostdata->flags & FLAG_NO_PSEUDO_DMA ||
- cmd->SCp.this_residual < 16)
+ cmd->SCp.this_residual < setup_use_pdma)
return 0;
return cmd->SCp.this_residual;
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 4862f65ec3e8..45a66048801b 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2002 LSI Logic 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Copyright (c) 2002 Red Hat, Inc. All rights reserved.
* - fixes
* - speed-ups (list handling fixes, issued_list, optimizations.)
@@ -28,7 +24,6 @@
* This driver is supported by LSI Logic, with assistance from Red Hat, Dell,
* and others. Please send updates to the mailing list
* linux-scsi@vger.kernel.org .
- *
*/
#include <linux/mm.h>
diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid
index 17419e30ffc8..2adc2afd9f91 100644
--- a/drivers/scsi/megaraid/Kconfig.megaraid
+++ b/drivers/scsi/megaraid/Kconfig.megaraid
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config MEGARAID_NEWGEN
bool "LSI Logic New Generation RAID Device Drivers"
depends on PCI && SCSI
@@ -78,6 +79,7 @@ config MEGARAID_LEGACY
config MEGARAID_SAS
tristate "LSI Logic MegaRAID SAS RAID Module"
depends on PCI && SCSI
+ select IRQ_POLL
help
Module for LSI Logic's SAS based RAID controllers.
To compile this driver as a module, choose 'm' here.
diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile
index 6e74d21227a5..12177e4cae65 100644
--- a/drivers/scsi/megaraid/Makefile
+++ b/drivers/scsi/megaraid/Makefile
@@ -3,4 +3,4 @@ obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o
obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o
obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o
megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \
- megaraid_sas_fp.o
+ megaraid_sas_fp.o megaraid_sas_debugfs.o
diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h
index e01c6f7c2cac..01a1bfb8ea2a 100644
--- a/drivers/scsi/megaraid/mbox_defs.h
+++ b/drivers/scsi/megaraid/mbox_defs.h
@@ -1,16 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
*
* Linux MegaRAID Unified device driver
*
* Copyright (c) 2003-2004 LSI Logic 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* FILE : mbox_defs.h
- *
*/
#ifndef _MRAID_MBOX_DEFS_H_
#define _MRAID_MBOX_DEFS_H_
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 1d037ed52c33..3a7596e47a88 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* FILE : mega_common.h
*
* Libaray of common routine used by all low-level megaraid drivers
diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h
index eedcbde46459..ae9c2ff7edac 100644
--- a/drivers/scsi/megaraid/megaraid_ioctl.h
+++ b/drivers/scsi/megaraid/megaraid_ioctl.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* FILE : megaraid_ioctl.h
*
* Definitions to interface with user level applications
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index f112458023ff..f6ac819e6e96 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* FILE : megaraid_mbox.c
* Version : v2.20.5.1 (Nov 16 2006)
*
@@ -38,7 +34,6 @@
* Dell PERC 4e/DC 1000 0408 1028 0002
* Dell PERC 4e/SC 1000 0408 1028 0001
*
- *
* LSI MegaRAID SCSI 320-0 1000 1960 1000 A520
* LSI MegaRAID SCSI 320-1 1000 1960 1000 0520
* LSI MegaRAID SCSI 320-2 1000 1960 1000 0518
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index e075aeb4012f..3e4347c6dab1 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* FILE : megaraid_mbox.h
*/
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index 3ce837e4b24c..59cca898f088 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* FILE : megaraid_mm.c
* Version : v2.20.2.7 (Jul 16 2006)
*
diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h
index a30e725f2d5c..bf4011590020 100644
--- a/drivers/scsi/megaraid/megaraid_mm.h
+++ b/drivers/scsi/megaraid/megaraid_mm.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2003-2004 LSI Logic 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 the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* FILE : megaraid_mm.h
*/
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 6fd57f7f0b1e..ca724fe91b8d 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
@@ -5,19 +6,6 @@
* Copyright (c) 2013-2016 Avago Technologies
* Copyright (c) 2016-2018 Broadcom Inc.
*
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* FILE: megaraid_sas.h
*
* Authors: Broadcom Inc.
@@ -33,8 +21,8 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "07.707.51.00-rc1"
-#define MEGASAS_RELDATE "February 7, 2019"
+#define MEGASAS_VERSION "07.710.06.00-rc1"
+#define MEGASAS_RELDATE "June 18, 2019"
/*
* Device IDs
@@ -64,6 +52,10 @@
#define PCI_DEVICE_ID_LSI_AERO_10E2 0x10e2
#define PCI_DEVICE_ID_LSI_AERO_10E5 0x10e5
#define PCI_DEVICE_ID_LSI_AERO_10E6 0x10e6
+#define PCI_DEVICE_ID_LSI_AERO_10E0 0x10e0
+#define PCI_DEVICE_ID_LSI_AERO_10E3 0x10e3
+#define PCI_DEVICE_ID_LSI_AERO_10E4 0x10e4
+#define PCI_DEVICE_ID_LSI_AERO_10E7 0x10e7
/*
* Intel HBA SSDIDs
@@ -135,6 +127,8 @@
#define MFI_RESET_ADAPTER 0x00000002
#define MEGAMFI_FRAME_SIZE 64
+#define MFI_STATE_FAULT_CODE 0x0FFF0000
+#define MFI_STATE_FAULT_SUBCODE 0x0000FF00
/*
* During FW init, clear pending cmds & reset state using inbound_msg_0
*
@@ -202,6 +196,7 @@ enum MFI_CMD_OP {
MFI_CMD_SMP = 0x7,
MFI_CMD_STP = 0x8,
MFI_CMD_NVME = 0x9,
+ MFI_CMD_TOOLBOX = 0xa,
MFI_CMD_OP_COUNT,
MFI_CMD_INVALID = 0xff
};
@@ -1461,7 +1456,39 @@ struct megasas_ctrl_info {
u8 reserved6[64];
- u32 rsvdForAdptOp[64];
+ struct {
+ #if defined(__BIG_ENDIAN_BITFIELD)
+ u32 reserved:19;
+ u32 support_pci_lane_margining: 1;
+ u32 support_psoc_update:1;
+ u32 support_force_personality_change:1;
+ u32 support_fde_type_mix:1;
+ u32 support_snap_dump:1;
+ u32 support_nvme_tm:1;
+ u32 support_oce_only:1;
+ u32 support_ext_mfg_vpd:1;
+ u32 support_pcie:1;
+ u32 support_cvhealth_info:1;
+ u32 support_profile_change:2;
+ u32 mr_config_ext2_supported:1;
+ #else
+ u32 mr_config_ext2_supported:1;
+ u32 support_profile_change:2;
+ u32 support_cvhealth_info:1;
+ u32 support_pcie:1;
+ u32 support_ext_mfg_vpd:1;
+ u32 support_oce_only:1;
+ u32 support_nvme_tm:1;
+ u32 support_snap_dump:1;
+ u32 support_fde_type_mix:1;
+ u32 support_force_personality_change:1;
+ u32 support_psoc_update:1;
+ u32 support_pci_lane_margining: 1;
+ u32 reserved:19;
+ #endif
+ } adapter_operations5;
+
+ u32 rsvdForAdptOp[63];
u8 reserved7[3];
@@ -1495,7 +1522,9 @@ struct megasas_ctrl_info {
#define MEGASAS_FW_BUSY 1
/* Driver's internal Logging levels*/
-#define OCR_LOGS (1 << 0)
+#define OCR_DEBUG (1 << 0)
+#define TM_DEBUG (1 << 1)
+#define LD_PD_DEBUG (1 << 2)
#define SCAN_PD_CHANNEL 0x1
#define SCAN_VD_CHANNEL 0x2
@@ -1571,6 +1600,7 @@ enum FW_BOOT_CONTEXT {
#define MFI_IO_TIMEOUT_SECS 180
#define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ)
#define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30)
+#define MEGASAS_SRIOV_MAX_RESET_TRIES_VF 1
#define MEGASAS_ROUTINE_WAIT_TIME_VF 300
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001
@@ -1595,7 +1625,10 @@ enum FW_BOOT_CONTEXT {
#define MR_CAN_HANDLE_SYNC_CACHE_OFFSET 0X01000000
+#define MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET (1 << 24)
+
#define MR_CAN_HANDLE_64_BIT_DMA_OFFSET (1 << 25)
+#define MR_INTR_COALESCING_SUPPORT_OFFSET (1 << 26)
#define MEGASAS_WATCHDOG_THREAD_INTERVAL 1000
#define MEGASAS_WAIT_FOR_NEXT_DMA_MSECS 20
@@ -1774,7 +1807,7 @@ struct megasas_init_frame {
__le32 pad_0; /*0Ch */
__le16 flags; /*10h */
- __le16 reserved_3; /*12h */
+ __le16 replyqueue_mask; /*12h */
__le32 data_xfer_len; /*14h */
__le32 queue_info_new_phys_addr_lo; /*18h */
@@ -2172,6 +2205,10 @@ struct megasas_aen_event {
struct megasas_irq_context {
struct megasas_instance *instance;
u32 MSIxIndex;
+ u32 os_irq;
+ struct irq_poll irqpoll;
+ bool irq_poll_scheduled;
+ bool irq_line_enable;
};
struct MR_DRV_SYSTEM_INFO {
@@ -2202,6 +2239,23 @@ enum MR_PD_TYPE {
#define MR_DEFAULT_NVME_MDTS_KB 128
#define MR_NVME_PAGE_SIZE_MASK 0x000000FF
+/*Aero performance parameters*/
+#define MR_HIGH_IOPS_QUEUE_COUNT 8
+#define MR_DEVICE_HIGH_IOPS_DEPTH 8
+#define MR_HIGH_IOPS_BATCH_COUNT 16
+
+enum MR_PERF_MODE {
+ MR_BALANCED_PERF_MODE = 0,
+ MR_IOPS_PERF_MODE = 1,
+ MR_LATENCY_PERF_MODE = 2,
+};
+
+#define MEGASAS_PERF_MODE_2STR(mode) \
+ ((mode) == MR_BALANCED_PERF_MODE ? "Balanced" : \
+ (mode) == MR_IOPS_PERF_MODE ? "IOPS" : \
+ (mode) == MR_LATENCY_PERF_MODE ? "Latency" : \
+ "Unknown")
+
struct megasas_instance {
unsigned int *reply_map;
@@ -2258,6 +2312,7 @@ struct megasas_instance {
u32 secure_jbod_support;
u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */
bool use_seqnum_jbod_fp; /* Added for PD sequence */
+ bool smp_affinity_enable;
spinlock_t crashdump_lock;
struct megasas_register_set __iomem *reg_set;
@@ -2275,6 +2330,7 @@ struct megasas_instance {
u16 ldio_threshold;
u16 cur_can_queue;
u32 max_sectors_per_req;
+ bool msix_load_balance;
struct megasas_aen_event *ev;
struct megasas_cmd **cmd_list;
@@ -2302,15 +2358,13 @@ struct megasas_instance {
struct pci_dev *pdev;
u32 unique_id;
u32 fw_support_ieee;
+ u32 threshold_reply_count;
atomic_t fw_outstanding;
atomic_t ldio_outstanding;
atomic_t fw_reset_no_pci_access;
- atomic_t ieee_sgl;
- atomic_t prp_sgl;
- atomic_t sge_holes_type1;
- atomic_t sge_holes_type2;
- atomic_t sge_holes_type3;
+ atomic64_t total_io_count;
+ atomic64_t high_iops_outstanding;
struct megasas_instance_template *instancet;
struct tasklet_struct isr_tasklet;
@@ -2378,8 +2432,18 @@ struct megasas_instance {
u8 task_abort_tmo;
u8 max_reset_tmo;
u8 snapdump_wait_time;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *raidmap_dump;
+#endif
u8 enable_fw_dev_list;
+ bool atomic_desc_support;
+ bool support_seqnum_jbod_fp;
+ bool support_pci_lane_margining;
+ u8 low_latency_index_start;
+ int perf_mode;
};
+
struct MR_LD_VF_MAP {
u32 size;
union MR_LD_REF ref;
@@ -2635,4 +2699,9 @@ void megasas_fusion_stop_watchdog(struct megasas_instance *instance);
void megasas_set_dma_settings(struct megasas_instance *instance,
struct megasas_dcmd_frame *dcmd,
dma_addr_t dma_addr, u32 dma_len);
+int megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
+ bool do_adp_reset,
+ int ocr_context);
+int megasas_irqpoll(struct irq_poll *irqpoll, int budget);
+void megasas_dump_fusion_io(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 293f5cf524d7..80ab9700f1de 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
@@ -5,19 +6,6 @@
* Copyright (c) 2013-2016 Avago Technologies
* Copyright (c) 2016-2018 Broadcom Inc.
*
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* Authors: Broadcom Inc.
* Sreenivas Bagalkote
* Sumant Patro
@@ -48,12 +36,14 @@
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
+#include <linux/irq_poll.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_dbg.h>
#include "megaraid_sas_fusion.h"
#include "megaraid_sas.h"
@@ -62,47 +52,59 @@
* Will be set in megasas_init_mfi if user does not provide
*/
static unsigned int max_sectors;
-module_param_named(max_sectors, max_sectors, int, 0);
+module_param_named(max_sectors, max_sectors, int, 0444);
MODULE_PARM_DESC(max_sectors,
"Maximum number of sectors per IO command");
static int msix_disable;
-module_param(msix_disable, int, S_IRUGO);
+module_param(msix_disable, int, 0444);
MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
static unsigned int msix_vectors;
-module_param(msix_vectors, int, S_IRUGO);
+module_param(msix_vectors, int, 0444);
MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW");
static int allow_vf_ioctls;
-module_param(allow_vf_ioctls, int, S_IRUGO);
+module_param(allow_vf_ioctls, int, 0444);
MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
-module_param(throttlequeuedepth, int, S_IRUGO);
+module_param(throttlequeuedepth, int, 0444);
MODULE_PARM_DESC(throttlequeuedepth,
"Adapter queue depth when throttled due to I/O timeout. Default: 16");
unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME;
-module_param(resetwaittime, int, S_IRUGO);
+module_param(resetwaittime, int, 0444);
MODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s");
int smp_affinity_enable = 1;
-module_param(smp_affinity_enable, int, S_IRUGO);
+module_param(smp_affinity_enable, int, 0444);
MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
int rdpq_enable = 1;
-module_param(rdpq_enable, int, S_IRUGO);
+module_param(rdpq_enable, int, 0444);
MODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)");
unsigned int dual_qdepth_disable;
-module_param(dual_qdepth_disable, int, S_IRUGO);
+module_param(dual_qdepth_disable, int, 0444);
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_param(scmd_timeout, int, 0444);
MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer.");
+int perf_mode = -1;
+module_param(perf_mode, int, 0444);
+MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t"
+ "0 - balanced: High iops and low latency queues are allocated &\n\t\t"
+ "interrupt coalescing is enabled only on high iops queues\n\t\t"
+ "1 - iops: High iops queues are not allocated &\n\t\t"
+ "interrupt coalescing is enabled on all queues\n\t\t"
+ "2 - latency: High iops queues are not allocated &\n\t\t"
+ "interrupt coalescing is disabled on all queues\n\t\t"
+ "default mode is 'balanced'"
+ );
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
@@ -166,6 +168,10 @@ static struct pci_device_id megasas_pci_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E2)},
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E5)},
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E6)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E7)},
{}
};
@@ -182,10 +188,17 @@ static u32 support_poll_for_event;
u32 megasas_dbg_lvl;
static u32 support_device_change;
static bool support_nvme_encapsulation;
+static bool support_pci_lane_margining;
/* define lock for aen poll */
spinlock_t poll_aen_lock;
+extern struct dentry *megasas_debugfs_root;
+extern void megasas_init_debugfs(void);
+extern void megasas_exit_debugfs(void);
+extern void megasas_setup_debugfs(struct megasas_instance *instance);
+extern void megasas_destroy_debugfs(struct megasas_instance *instance);
+
void
megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
u8 alt_status);
@@ -815,7 +828,6 @@ 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);
}
@@ -1111,8 +1123,9 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
ret = wait_event_timeout(instance->int_cmd_wait_q,
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
if (!ret) {
- dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n",
- __func__, __LINE__);
+ dev_err(&instance->pdev->dev,
+ "DCMD(opcode: 0x%x) is timed out, func:%s\n",
+ cmd->frame->dcmd.opcode, __func__);
return DCMD_TIMEOUT;
}
} else
@@ -1141,6 +1154,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd;
struct megasas_abort_frame *abort_fr;
int ret = 0;
+ u32 opcode;
cmd = megasas_get_cmd(instance);
@@ -1176,8 +1190,10 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
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, "Failed from %s %d Abort Timed out\n",
- __func__, __LINE__);
+ opcode = cmd_to_abort->frame->dcmd.opcode;
+ dev_err(&instance->pdev->dev,
+ "Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n",
+ opcode, __func__);
return DCMD_TIMEOUT;
}
} else
@@ -1931,7 +1947,6 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size)
static void megasas_set_static_target_properties(struct scsi_device *sdev,
bool is_target_prop)
{
- u16 target_index = 0;
u8 interface_type;
u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN;
u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB;
@@ -1948,8 +1963,6 @@ static void megasas_set_static_target_properties(struct scsi_device *sdev,
*/
blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
- target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
-
switch (interface_type) {
case SAS_PD:
device_qd = MEGASAS_SAS_QD;
@@ -2725,7 +2738,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
do {
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",
+ "%s:%d waiting_for_outstanding: before issue OCR. FW state = 0x%x, outstanding 0x%x\n",
__func__, __LINE__, fw_state, atomic_read(&instance->fw_outstanding));
if (i == 3)
goto kill_hba_and_failed;
@@ -2835,21 +2848,108 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
}
/**
- * megasas_dump_frame - This function will dump MPT/MFI frame
+ * megasas_dump - This function will print hexdump of provided buffer.
+ * @buf: Buffer to be dumped
+ * @sz: Size in bytes
+ * @format: Different formats of dumping e.g. format=n will
+ * cause only 'n' 32 bit words to be dumped in a single
+ * line.
*/
-static inline void
-megasas_dump_frame(void *mpi_request, int sz)
+inline void
+megasas_dump(void *buf, int sz, int format)
{
int i;
- __le32 *mfp = (__le32 *)mpi_request;
+ __le32 *buf_loc = (__le32 *)buf;
+
+ for (i = 0; i < (sz / sizeof(__le32)); i++) {
+ if ((i % format) == 0) {
+ if (i != 0)
+ printk(KERN_CONT "\n");
+ printk(KERN_CONT "%08x: ", (i * 4));
+ }
+ printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i]));
+ }
+ printk(KERN_CONT "\n");
+}
+
+/**
+ * megasas_dump_reg_set - This function will print hexdump of register set
+ * @buf: Buffer to be dumped
+ * @sz: Size in bytes
+ * @format: Different formats of dumping e.g. format=n will
+ * cause only 'n' 32 bit words to be dumped in a
+ * single line.
+ */
+inline void
+megasas_dump_reg_set(void __iomem *reg_set)
+{
+ unsigned int i, sz = 256;
+ u32 __iomem *reg = (u32 __iomem *)reg_set;
+
+ for (i = 0; i < (sz / sizeof(u32)); i++)
+ printk("%08x: %08x\n", (i * 4), readl(&reg[i]));
+}
+
+/**
+ * megasas_dump_fusion_io - This function will print key details
+ * of SCSI IO
+ * @scmd: SCSI command pointer of SCSI IO
+ */
+void
+megasas_dump_fusion_io(struct scsi_cmnd *scmd)
+{
+ struct megasas_cmd_fusion *cmd;
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+ struct megasas_instance *instance;
+
+ cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr;
+ instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+ scmd_printk(KERN_INFO, scmd,
+ "scmd: (0x%p) retries: 0x%x allowed: 0x%x\n",
+ scmd, scmd->retries, scmd->allowed);
+ scsi_print_command(scmd);
- printk(KERN_INFO "IO request frame:\n\t");
- for (i = 0; i < sz / sizeof(__le32); i++) {
- if (i && ((i % 8) == 0))
- printk("\n\t");
- printk("%08x ", le32_to_cpu(mfp[i]));
+ if (cmd) {
+ req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
+ scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n");
+ scmd_printk(KERN_INFO, scmd,
+ "RequestFlags:0x%x MSIxIndex:0x%x SMID:0x%x LMID:0x%x DevHandle:0x%x\n",
+ req_desc->SCSIIO.RequestFlags,
+ req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID,
+ req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle);
+
+ printk(KERN_INFO "IO request frame:\n");
+ megasas_dump(cmd->io_request,
+ MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8);
+ printk(KERN_INFO "Chain frame:\n");
+ megasas_dump(cmd->sg_frame,
+ instance->max_chain_frame_sz, 8);
+ }
+
+}
+
+/*
+ * megasas_dump_sys_regs - This function will dump system registers through
+ * sysfs.
+ * @reg_set: Pointer to System register set.
+ * @buf: Buffer to which output is to be written.
+ * @return: Number of bytes written to buffer.
+ */
+static inline ssize_t
+megasas_dump_sys_regs(void __iomem *reg_set, char *buf)
+{
+ unsigned int i, sz = 256;
+ int bytes_wrote = 0;
+ char *loc = (char *)buf;
+ u32 __iomem *reg = (u32 __iomem *)reg_set;
+
+ for (i = 0; i < sz / sizeof(u32); i++) {
+ bytes_wrote += snprintf(loc + bytes_wrote, PAGE_SIZE,
+ "%08x: %08x\n", (i * 4),
+ readl(&reg[i]));
}
- printk("\n");
+ return bytes_wrote;
}
/**
@@ -2863,24 +2963,20 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
instance = (struct megasas_instance *)scmd->device->host->hostdata;
scmd_printk(KERN_INFO, scmd,
- "Controller reset is requested due to IO timeout\n"
- "SCSI command pointer: (%p)\t SCSI host state: %d\t"
- " SCSI host busy: %d\t FW outstanding: %d\n",
- scmd, scmd->device->host->shost_state,
+ "OCR is requested due to IO timeout!!\n");
+
+ scmd_printk(KERN_INFO, scmd,
+ "SCSI host state: %d SCSI host busy: %d FW outstanding: %d\n",
+ scmd->device->host->shost_state,
scsi_host_busy(scmd->device->host),
atomic_read(&instance->fw_outstanding));
-
/*
* First wait for all commands to complete
*/
if (instance->adapter_type == MFI_SERIES) {
ret = megasas_generic_reset(scmd);
} else {
- struct megasas_cmd_fusion *cmd;
- cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr;
- if (cmd)
- megasas_dump_frame(cmd->io_request,
- MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE);
+ megasas_dump_fusion_io(scmd);
ret = megasas_reset_fusion(scmd->device->host,
SCSIIO_TIMEOUT_OCR);
}
@@ -3030,7 +3126,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
}
static ssize_t
-megasas_fw_crash_buffer_store(struct device *cdev,
+fw_crash_buffer_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3049,14 +3145,13 @@ megasas_fw_crash_buffer_store(struct device *cdev,
}
static ssize_t
-megasas_fw_crash_buffer_show(struct device *cdev,
+fw_crash_buffer_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;
u32 size;
- unsigned long buff_addr;
unsigned long dmachunk = CRASH_DMA_BUF_SIZE;
unsigned long src_addr;
unsigned long flags;
@@ -3073,8 +3168,6 @@ megasas_fw_crash_buffer_show(struct device *cdev,
return -EINVAL;
}
- buff_addr = (unsigned long) buf;
-
if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) {
dev_err(&instance->pdev->dev,
"Firmware crash dump offset is out of range\n");
@@ -3094,7 +3187,7 @@ megasas_fw_crash_buffer_show(struct device *cdev,
}
static ssize_t
-megasas_fw_crash_buffer_size_show(struct device *cdev,
+fw_crash_buffer_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3106,7 +3199,7 @@ megasas_fw_crash_buffer_size_show(struct device *cdev,
}
static ssize_t
-megasas_fw_crash_state_store(struct device *cdev,
+fw_crash_state_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3141,7 +3234,7 @@ megasas_fw_crash_state_store(struct device *cdev,
}
static ssize_t
-megasas_fw_crash_state_show(struct device *cdev,
+fw_crash_state_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3152,14 +3245,14 @@ megasas_fw_crash_state_show(struct device *cdev,
}
static ssize_t
-megasas_page_size_show(struct device *cdev,
+page_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
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,
+ldio_outstanding_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3169,7 +3262,7 @@ megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr
}
static ssize_t
-megasas_fw_cmds_outstanding_show(struct device *cdev,
+fw_cmds_outstanding_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3178,18 +3271,37 @@ megasas_fw_cmds_outstanding_show(struct device *cdev,
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_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,
- megasas_fw_crash_buffer_size_show, NULL);
-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);
-static DEVICE_ATTR(fw_cmds_outstanding, S_IRUGO,
- megasas_fw_cmds_outstanding_show, NULL);
+static ssize_t
+dump_system_regs_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 megasas_dump_sys_regs(instance->reg_set, buf);
+}
+
+static ssize_t
+raid_map_id_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, "%ld\n",
+ (unsigned long)instance->map_id);
+}
+
+static DEVICE_ATTR_RW(fw_crash_buffer);
+static DEVICE_ATTR_RO(fw_crash_buffer_size);
+static DEVICE_ATTR_RW(fw_crash_state);
+static DEVICE_ATTR_RO(page_size);
+static DEVICE_ATTR_RO(ldio_outstanding);
+static DEVICE_ATTR_RO(fw_cmds_outstanding);
+static DEVICE_ATTR_RO(dump_system_regs);
+static DEVICE_ATTR_RO(raid_map_id);
struct device_attribute *megaraid_host_attrs[] = {
&dev_attr_fw_crash_buffer_size,
@@ -3198,6 +3310,8 @@ struct device_attribute *megaraid_host_attrs[] = {
&dev_attr_page_size,
&dev_attr_ldio_outstanding,
&dev_attr_fw_cmds_outstanding,
+ &dev_attr_dump_system_regs,
+ &dev_attr_raid_map_id,
NULL,
};
@@ -3381,6 +3495,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
case MFI_CMD_SMP:
case MFI_CMD_STP:
case MFI_CMD_NVME:
+ case MFI_CMD_TOOLBOX:
megasas_complete_int_cmd(instance, cmd);
break;
@@ -3789,7 +3904,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
int i;
u8 max_wait;
u32 fw_state;
- u32 cur_state;
u32 abs_state, curr_abs_state;
abs_state = instance->instancet->read_fw_status_reg(instance);
@@ -3804,13 +3918,18 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
switch (fw_state) {
case MFI_STATE_FAULT:
- dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW in FAULT state!!\n");
+ dev_printk(KERN_ERR, &instance->pdev->dev,
+ "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
if (ocr) {
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_FAULT;
break;
- } else
+ } else {
+ dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+ megasas_dump_reg_set(instance->reg_set);
return -ENODEV;
+ }
case MFI_STATE_WAIT_HANDSHAKE:
/*
@@ -3830,7 +3949,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
&instance->reg_set->inbound_doorbell);
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_WAIT_HANDSHAKE;
break;
case MFI_STATE_BOOT_MESSAGE_PENDING:
@@ -3846,7 +3964,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
&instance->reg_set->inbound_doorbell);
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
break;
case MFI_STATE_OPERATIONAL:
@@ -3879,7 +3996,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
&instance->reg_set->inbound_doorbell);
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_OPERATIONAL;
break;
case MFI_STATE_UNDEFINED:
@@ -3887,37 +4003,33 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
* This state should not last for more than 2 seconds
*/
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_UNDEFINED;
break;
case MFI_STATE_BB_INIT:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_BB_INIT;
break;
case MFI_STATE_FW_INIT:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_FW_INIT;
break;
case MFI_STATE_FW_INIT_2:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_FW_INIT_2;
break;
case MFI_STATE_DEVICE_SCAN:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_DEVICE_SCAN;
break;
case MFI_STATE_FLUSH_CACHE:
max_wait = MEGASAS_RESET_WAIT_TIME;
- cur_state = MFI_STATE_FLUSH_CACHE;
break;
default:
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n",
fw_state);
+ dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+ megasas_dump_reg_set(instance->reg_set);
return -ENODEV;
}
@@ -3940,6 +4052,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
if (curr_abs_state == abs_state) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed "
"in %d secs\n", fw_state, max_wait);
+ dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n");
+ megasas_dump_reg_set(instance->reg_set);
return -ENODEV;
}
@@ -4003,23 +4117,12 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
{
int i;
u16 max_cmd;
- u32 sge_sz;
u32 frame_count;
struct megasas_cmd *cmd;
max_cmd = instance->max_mfi_cmds;
/*
- * Size of our frame is 64 bytes for MFI frame, followed by max SG
- * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer
- */
- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
- sizeof(struct megasas_sge32);
-
- if (instance->flag_ieee)
- sge_sz = sizeof(struct megasas_sge_skinny);
-
- /*
* For MFI controllers.
* max_num_sge = 60
* max_sge_sz = 16 byte (sizeof megasas_sge_skinny)
@@ -4268,8 +4371,10 @@ megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev)
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ 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);
@@ -4305,7 +4410,6 @@ megasas_get_pd_list(struct megasas_instance *instance)
struct megasas_dcmd_frame *dcmd;
struct MR_PD_LIST *ci;
struct MR_PD_ADDRESS *pd_addr;
- dma_addr_t ci_h = 0;
if (instance->pd_list_not_supported) {
dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY "
@@ -4314,7 +4418,6 @@ megasas_get_pd_list(struct megasas_instance *instance)
}
ci = instance->pd_list_buf;
- ci_h = instance->pd_list_buf_h;
cmd = megasas_get_cmd(instance);
@@ -4387,6 +4490,9 @@ megasas_get_pd_list(struct megasas_instance *instance)
case DCMD_SUCCESS:
pd_addr = ci->addr;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n",
+ __func__, le32_to_cpu(ci->count));
if ((le32_to_cpu(ci->count) >
(MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL)))
@@ -4402,6 +4508,11 @@ megasas_get_pd_list(struct megasas_instance *instance)
pd_addr->scsiDevType;
instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState =
MR_PD_STATE_SYSTEM;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "PD%d: targetID: 0x%03x deviceType:0x%x\n",
+ pd_index, le16_to_cpu(pd_addr->deviceId),
+ pd_addr->scsiDevType);
pd_addr++;
}
@@ -4505,6 +4616,10 @@ megasas_get_ld_list(struct megasas_instance *instance)
break;
case DCMD_SUCCESS:
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
+ __func__, ld_count);
+
if (ld_count > instance->fw_supported_vd_count)
break;
@@ -4514,6 +4629,10 @@ megasas_get_ld_list(struct megasas_instance *instance)
if (ci->ldList[ld_index].state != 0) {
ids = ci->ldList[ld_index].ref.targetId;
instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "LD%d: targetID: 0x%03x\n",
+ ld_index, ids);
}
}
@@ -4617,6 +4736,10 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
case DCMD_SUCCESS:
tgtid_count = le32_to_cpu(ci->count);
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n",
+ __func__, tgtid_count);
+
if ((tgtid_count > (instance->fw_supported_vd_count)))
break;
@@ -4624,6 +4747,9 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
ids = ci->targetId[ld_index];
instance->ld_ids[ids] = ci->targetId[ld_index];
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n",
+ ld_index, ci->targetId[ld_index]);
}
break;
@@ -4648,7 +4774,7 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
* Return: 0 if DCMD succeeded
* non-zero if failed
*/
-int
+static int
megasas_host_device_list_query(struct megasas_instance *instance,
bool is_probe)
{
@@ -4703,6 +4829,13 @@ megasas_host_device_list_query(struct megasas_instance *instance,
*/
count = le32_to_cpu(ci->count);
+ if (count > (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT))
+ break;
+
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev, "%s, Device count: 0x%x\n",
+ __func__, count);
+
memset(instance->local_pd_list, 0,
MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT);
@@ -4714,8 +4847,16 @@ megasas_host_device_list_query(struct megasas_instance *instance,
ci->host_device_list[i].scsi_type;
instance->local_pd_list[target_id].driveState =
MR_PD_STATE_SYSTEM;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "Device %d: PD targetID: 0x%03x deviceType:0x%x\n",
+ i, target_id, ci->host_device_list[i].scsi_type);
} else {
instance->ld_ids[target_id] = target_id;
+ if (megasas_dbg_lvl & LD_PD_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "Device %d: LD targetID: 0x%03x\n",
+ i, target_id);
}
}
@@ -4727,8 +4868,10 @@ megasas_host_device_list_query(struct megasas_instance *instance,
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ 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);
@@ -4876,8 +5019,10 @@ void megasas_get_snapdump_properties(struct megasas_instance *instance)
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ 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);
@@ -4956,6 +5101,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
le32_to_cpus((u32 *)&ci->adapterOperations2);
le32_to_cpus((u32 *)&ci->adapterOperations3);
le16_to_cpus((u16 *)&ci->adapter_operations4);
+ le32_to_cpus((u32 *)&ci->adapter_operations5);
/* Update the latest Ext VD info.
* From Init path, store current firmware details.
@@ -4963,12 +5109,14 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
* in case of Firmware upgrade without system reboot.
*/
megasas_update_ext_vd_details(instance);
- instance->use_seqnum_jbod_fp =
+ instance->support_seqnum_jbod_fp =
ci->adapterOperations3.useSeqNumJbodFP;
instance->support_morethan256jbod =
ci->adapter_operations4.support_pd_map_target_id;
instance->support_nvme_passthru =
ci->adapter_operations4.support_nvme_passthru;
+ instance->support_pci_lane_margining =
+ ci->adapter_operations5.support_pci_lane_margining;
instance->task_abort_tmo = ci->TaskAbortTO;
instance->max_reset_tmo = ci->MaxResetTO;
@@ -5000,6 +5148,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
dev_info(&instance->pdev->dev,
"FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n",
instance->task_abort_tmo, instance->max_reset_tmo);
+ dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n",
+ instance->support_seqnum_jbod_fp ? "Yes" : "No");
+ dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n",
+ instance->support_pci_lane_margining ? "Yes" : "No");
break;
@@ -5007,8 +5159,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ 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);
@@ -5275,6 +5429,25 @@ fail_alloc_cmds:
return 1;
}
+static
+void megasas_setup_irq_poll(struct megasas_instance *instance)
+{
+ struct megasas_irq_context *irq_ctx;
+ u32 count, i;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+ /* Initialize IRQ poll */
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_ctx->os_irq = pci_irq_vector(instance->pdev, i);
+ irq_ctx->irq_poll_scheduled = false;
+ irq_poll_init(&irq_ctx->irqpoll,
+ instance->threshold_reply_count,
+ megasas_irqpoll);
+ }
+}
+
/*
* megasas_setup_irqs_ioapic - register legacy interrupts.
* @instance: Adapter soft state
@@ -5299,6 +5472,8 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance)
__func__, __LINE__);
return -1;
}
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ instance->low_latency_index_start = 0;
return 0;
}
@@ -5333,6 +5508,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
&instance->irq_context[j]);
/* Retry irq register for IO_APIC*/
instance->msix_vectors = 0;
+ instance->msix_load_balance = false;
if (is_probe) {
pci_free_irq_vectors(instance->pdev);
return megasas_setup_irqs_ioapic(instance);
@@ -5341,6 +5517,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe)
}
}
}
+
return 0;
}
@@ -5353,6 +5530,16 @@ static void
megasas_destroy_irqs(struct megasas_instance *instance) {
int i;
+ int count;
+ struct megasas_irq_context *irq_ctx;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+ if (instance->adapter_type != MFI_SERIES) {
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_disable(&irq_ctx->irqpoll);
+ }
+ }
if (instance->msix_vectors)
for (i = 0; i < instance->msix_vectors; i++) {
@@ -5381,10 +5568,12 @@ megasas_setup_jbod_map(struct megasas_instance *instance)
pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
(sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1));
+ instance->use_seqnum_jbod_fp =
+ instance->support_seqnum_jbod_fp;
if (reset_devices || !fusion ||
- !instance->ctrl_info_buf->adapterOperations3.useSeqNumJbodFP) {
+ !instance->support_seqnum_jbod_fp) {
dev_info(&instance->pdev->dev,
- "Jbod map is not supported %s %d\n",
+ "JBOD sequence map is disabled %s %d\n",
__func__, __LINE__);
instance->use_seqnum_jbod_fp = false;
return;
@@ -5423,9 +5612,11 @@ skip_alloc:
static void megasas_setup_reply_map(struct megasas_instance *instance)
{
const struct cpumask *mask;
- unsigned int queue, cpu;
+ unsigned int queue, cpu, low_latency_index_start;
- for (queue = 0; queue < instance->msix_vectors; queue++) {
+ low_latency_index_start = instance->low_latency_index_start;
+
+ for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) {
mask = pci_irq_get_affinity(instance->pdev, queue);
if (!mask)
goto fallback;
@@ -5436,8 +5627,14 @@ static void megasas_setup_reply_map(struct megasas_instance *instance)
return;
fallback:
- for_each_possible_cpu(cpu)
- instance->reply_map[cpu] = cpu % instance->msix_vectors;
+ queue = low_latency_index_start;
+ for_each_possible_cpu(cpu) {
+ instance->reply_map[cpu] = queue;
+ if (queue == (instance->msix_vectors - 1))
+ queue = low_latency_index_start;
+ else
+ queue++;
+ }
}
/**
@@ -5474,6 +5671,89 @@ int megasas_get_device_list(struct megasas_instance *instance)
return SUCCESS;
}
+
+/**
+ * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPS queues
+ * @instance: Adapter soft state
+ * return: void
+ */
+static inline void
+megasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance)
+{
+ int i;
+ int local_numa_node;
+
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE) {
+ local_numa_node = dev_to_node(&instance->pdev->dev);
+
+ for (i = 0; i < instance->low_latency_index_start; i++)
+ irq_set_affinity_hint(pci_irq_vector(instance->pdev, i),
+ cpumask_of_node(local_numa_node));
+ }
+}
+
+static int
+__megasas_alloc_irq_vectors(struct megasas_instance *instance)
+{
+ int i, irq_flags;
+ struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start };
+ struct irq_affinity *descp = &desc;
+
+ irq_flags = PCI_IRQ_MSIX;
+
+ if (instance->smp_affinity_enable)
+ irq_flags |= PCI_IRQ_AFFINITY;
+ else
+ descp = NULL;
+
+ i = pci_alloc_irq_vectors_affinity(instance->pdev,
+ instance->low_latency_index_start,
+ instance->msix_vectors, irq_flags, descp);
+
+ return i;
+}
+
+/**
+ * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors
+ * @instance: Adapter soft state
+ * return: void
+ */
+static void
+megasas_alloc_irq_vectors(struct megasas_instance *instance)
+{
+ int i;
+ unsigned int num_msix_req;
+
+ i = __megasas_alloc_irq_vectors(instance);
+
+ if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+ (i != instance->msix_vectors)) {
+ if (instance->msix_vectors)
+ pci_free_irq_vectors(instance->pdev);
+ /* Disable Balanced IOPS mode and try realloc vectors */
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ instance->low_latency_index_start = 1;
+ num_msix_req = num_online_cpus() + instance->low_latency_index_start;
+
+ instance->msix_vectors = min(num_msix_req,
+ instance->msix_vectors);
+
+ i = __megasas_alloc_irq_vectors(instance);
+
+ }
+
+ dev_info(&instance->pdev->dev,
+ "requested/available msix %d/%d\n", instance->msix_vectors, i);
+
+ if (i > 0)
+ instance->msix_vectors = i;
+ else
+ instance->msix_vectors = 0;
+
+ if (instance->smp_affinity_enable)
+ megasas_set_high_iops_queue_affinity_hint(instance);
+}
+
/**
* megasas_init_fw - Initializes the FW
* @instance: Adapter soft state
@@ -5487,12 +5767,15 @@ static int megasas_init_fw(struct megasas_instance *instance)
u32 max_sectors_2, tmp_sectors, msix_enable;
u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg;
resource_size_t base_addr;
+ void *base_addr_phys;
struct megasas_ctrl_info *ctrl_info = NULL;
unsigned long bar_list;
- int i, j, loop, fw_msix_count = 0;
+ int i, j, loop;
struct IOV_111 *iovPtr;
struct fusion_context *fusion;
- bool do_adp_reset = true;
+ bool intr_coalescing;
+ unsigned int num_msix_req;
+ u16 lnksta, speed;
fusion = instance->ctrl_context;
@@ -5513,6 +5796,11 @@ static int megasas_init_fw(struct megasas_instance *instance)
goto fail_ioremap;
}
+ base_addr_phys = &base_addr;
+ dev_printk(KERN_DEBUG, &instance->pdev->dev,
+ "BAR:0x%lx BAR's base_addr(phys):%pa mapped virt_addr:0x%p\n",
+ instance->bar, base_addr_phys, instance->reg_set);
+
if (instance->adapter_type != MFI_SERIES)
instance->instancet = &megasas_instance_template_fusion;
else {
@@ -5539,29 +5827,35 @@ static int megasas_init_fw(struct megasas_instance *instance)
}
if (megasas_transition_to_ready(instance, 0)) {
- if (instance->adapter_type >= INVADER_SERIES) {
+ dev_info(&instance->pdev->dev,
+ "Failed to transition controller to ready from %s!\n",
+ __func__);
+ if (instance->adapter_type != MFI_SERIES) {
status_reg = instance->instancet->read_fw_status_reg(
instance);
- do_adp_reset = status_reg & MFI_RESET_ADAPTER;
- }
-
- if (do_adp_reset) {
+ if (status_reg & MFI_RESET_ADAPTER) {
+ if (megasas_adp_reset_wait_for_ready
+ (instance, true, 0) == FAILED)
+ goto fail_ready_state;
+ } else {
+ goto fail_ready_state;
+ }
+ } else {
atomic_set(&instance->fw_reset_no_pci_access, 1);
instance->instancet->adp_reset
(instance, instance->reg_set);
atomic_set(&instance->fw_reset_no_pci_access, 0);
- dev_info(&instance->pdev->dev,
- "FW restarted successfully from %s!\n",
- __func__);
/*waiting for about 30 second before retry*/
ssleep(30);
if (megasas_transition_to_ready(instance, 0))
goto fail_ready_state;
- } else {
- goto fail_ready_state;
}
+
+ dev_info(&instance->pdev->dev,
+ "FW restarted successfully from %s!\n",
+ __func__);
}
megasas_init_ctrl_params(instance);
@@ -5586,11 +5880,21 @@ static int megasas_init_fw(struct megasas_instance *instance)
MR_MAX_RAID_MAP_SIZE_MASK);
}
+ switch (instance->adapter_type) {
+ case VENTURA_SERIES:
+ fusion->pcie_bw_limitation = true;
+ break;
+ case AERO_SERIES:
+ fusion->r56_div_offload = true;
+ break;
+ default:
+ break;
+ }
+
/* Check if MSI-X is supported while in ready state */
msix_enable = (instance->instancet->read_fw_status_reg(instance) &
0x4000000) >> 0x1a;
if (msix_enable && !msix_disable) {
- int irq_flags = PCI_IRQ_MSIX;
scratch_pad_1 = megasas_readl
(instance, &instance->reg_set->outbound_scratch_pad_1);
@@ -5600,7 +5904,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
/* Thunderbolt Series*/
instance->msix_vectors = (scratch_pad_1
& MR_MAX_REPLY_QUEUES_OFFSET) + 1;
- fw_msix_count = instance->msix_vectors;
} else {
instance->msix_vectors = ((scratch_pad_1
& MR_MAX_REPLY_QUEUES_EXT_OFFSET)
@@ -5629,7 +5932,12 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (rdpq_enable)
instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ?
1 : 0;
- fw_msix_count = instance->msix_vectors;
+
+ if (!instance->msix_combined) {
+ instance->msix_load_balance = true;
+ instance->smp_affinity_enable = false;
+ }
+
/* Save 1-15 reply post index address to local memory
* Index 0 is already saved from reg offset
* MPI2_REPLY_POST_HOST_INDEX_OFFSET
@@ -5642,22 +5950,91 @@ static int megasas_init_fw(struct megasas_instance *instance)
+ (loop * 0x10));
}
}
+
+ dev_info(&instance->pdev->dev,
+ "firmware supports msix\t: (%d)",
+ instance->msix_vectors);
if (msix_vectors)
instance->msix_vectors = min(msix_vectors,
instance->msix_vectors);
} else /* MFI adapters */
instance->msix_vectors = 1;
- /* Don't bother allocating more MSI-X vectors than cpus */
- instance->msix_vectors = min(instance->msix_vectors,
- (unsigned int)num_online_cpus());
- if (smp_affinity_enable)
- irq_flags |= PCI_IRQ_AFFINITY;
- i = pci_alloc_irq_vectors(instance->pdev, 1,
- instance->msix_vectors, irq_flags);
- if (i > 0)
- instance->msix_vectors = i;
+
+
+ /*
+ * For Aero (if some conditions are met), driver will configure a
+ * few additional reply queues with interrupt coalescing enabled.
+ * These queues with interrupt coalescing enabled are called
+ * High IOPS queues and rest of reply queues (based on number of
+ * logical CPUs) are termed as Low latency queues.
+ *
+ * Total Number of reply queues = High IOPS queues + low latency queues
+ *
+ * For rest of fusion adapters, 1 additional reply queue will be
+ * reserved for management commands, rest of reply queues
+ * (based on number of logical CPUs) will be used for IOs and
+ * referenced as IO queues.
+ * Total Number of reply queues = 1 + IO queues
+ *
+ * MFI adapters supports single MSI-x so single reply queue
+ * will be used for IO and management commands.
+ */
+
+ intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
+ true : false;
+ if (intr_coalescing &&
+ (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) &&
+ (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES))
+ instance->perf_mode = MR_BALANCED_PERF_MODE;
else
- instance->msix_vectors = 0;
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+
+
+ if (instance->adapter_type == AERO_SERIES) {
+ pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta);
+ speed = lnksta & PCI_EXP_LNKSTA_CLS;
+
+ /*
+ * For Aero, if PCIe link speed is <16 GT/s, then driver should operate
+ * in latency perf mode and enable R1 PCI bandwidth algorithm
+ */
+ if (speed < 0x4) {
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+ fusion->pcie_bw_limitation = true;
+ }
+
+ /*
+ * Performance mode settings provided through module parameter-perf_mode will
+ * take affect only for:
+ * 1. Aero family of adapters.
+ * 2. When user sets module parameter- perf_mode in range of 0-2.
+ */
+ if ((perf_mode >= MR_BALANCED_PERF_MODE) &&
+ (perf_mode <= MR_LATENCY_PERF_MODE))
+ instance->perf_mode = perf_mode;
+ /*
+ * If intr coalescing is not supported by controller FW, then IOPS
+ * and Balanced modes are not feasible.
+ */
+ if (!intr_coalescing)
+ instance->perf_mode = MR_LATENCY_PERF_MODE;
+
+ }
+
+ if (instance->perf_mode == MR_BALANCED_PERF_MODE)
+ instance->low_latency_index_start =
+ MR_HIGH_IOPS_QUEUE_COUNT;
+ else
+ instance->low_latency_index_start = 1;
+
+ num_msix_req = num_online_cpus() + instance->low_latency_index_start;
+
+ instance->msix_vectors = min(num_msix_req,
+ instance->msix_vectors);
+
+ megasas_alloc_irq_vectors(instance);
+ if (!instance->msix_vectors)
+ instance->msix_load_balance = false;
}
/*
* MSI-X host index 0 is common for all adapter.
@@ -5682,8 +6059,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
megasas_setup_reply_map(instance);
dev_info(&instance->pdev->dev,
- "firmware supports msix\t: (%d)", fw_msix_count);
- 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,
@@ -5720,6 +6095,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
megasas_setup_irqs_ioapic(instance))
goto fail_init_adapter;
+ if (instance->adapter_type != MFI_SERIES)
+ megasas_setup_irq_poll(instance);
+
instance->instancet->enable_intr(instance);
dev_info(&instance->pdev->dev, "INIT adapter done\n");
@@ -5846,8 +6224,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->UnevenSpanSupport ? "yes" : "no");
dev_info(&instance->pdev->dev, "firmware crash dump : %s\n",
instance->crash_dump_drv_support ? "yes" : "no");
- dev_info(&instance->pdev->dev, "jbod sync map : %s\n",
- instance->use_seqnum_jbod_fp ? "yes" : "no");
+ dev_info(&instance->pdev->dev, "JBOD sequence map : %s\n",
+ instance->use_seqnum_jbod_fp ? "enabled" : "disabled");
instance->max_sectors_per_req = instance->max_num_sge *
SGE_BUFFER_SIZE / 512;
@@ -6210,8 +6588,10 @@ megasas_get_target_prop(struct megasas_instance *instance,
switch (dcmd_timeout_ocr_possible(instance)) {
case INITIATE_OCR:
cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+ 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);
@@ -6761,6 +7141,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
INIT_LIST_HEAD(&instance->internal_reset_pending_q);
atomic_set(&instance->fw_outstanding, 0);
+ atomic64_set(&instance->total_io_count, 0);
init_waitqueue_head(&instance->int_cmd_wait_q);
init_waitqueue_head(&instance->abort_cmd_wait_q);
@@ -6783,6 +7164,8 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance)
instance->last_time = 0;
instance->disableOnlineCtrlReset = 1;
instance->UnevenSpanSupport = 0;
+ instance->smp_affinity_enable = smp_affinity_enable ? true : false;
+ instance->msix_load_balance = false;
if (instance->adapter_type != MFI_SERIES)
INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
@@ -6804,6 +7187,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
u16 control = 0;
switch (pdev->device) {
+ case PCI_DEVICE_ID_LSI_AERO_10E0:
+ case PCI_DEVICE_ID_LSI_AERO_10E3:
+ case PCI_DEVICE_ID_LSI_AERO_10E4:
+ case PCI_DEVICE_ID_LSI_AERO_10E7:
+ dev_err(&pdev->dev, "Adapter is in non secure mode\n");
+ return 1;
case PCI_DEVICE_ID_LSI_AERO_10E1:
case PCI_DEVICE_ID_LSI_AERO_10E5:
dev_info(&pdev->dev, "Adapter is in configurable secure mode\n");
@@ -6923,6 +7312,8 @@ static int megasas_probe_one(struct pci_dev *pdev,
goto fail_start_aen;
}
+ megasas_setup_debugfs(instance);
+
/* Get current SR-IOV LD/VF affiliation */
if (instance->requestorId)
megasas_get_ld_vf_affiliation(instance, 1);
@@ -7054,13 +7445,17 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
static int
megasas_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct Scsi_Host *host;
struct megasas_instance *instance;
instance = pci_get_drvdata(pdev);
- host = instance->host;
+
+ if (!instance)
+ return 0;
+
instance->unload = 1;
+ dev_info(&pdev->dev, "%s is called\n", __func__);
+
/* Shutdown SR-IOV heartbeat timer */
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
del_timer_sync(&instance->sriov_heartbeat_timer);
@@ -7110,11 +7505,16 @@ megasas_resume(struct pci_dev *pdev)
int irq_flags = PCI_IRQ_LEGACY;
instance = pci_get_drvdata(pdev);
+
+ if (!instance)
+ return 0;
+
host = instance->host;
pci_set_power_state(pdev, PCI_D0);
pci_enable_wake(pdev, PCI_D0, 0);
pci_restore_state(pdev);
+ dev_info(&pdev->dev, "%s is called\n", __func__);
/*
* PCI prepping: enable device set bus mastering and dma mask
*/
@@ -7146,7 +7546,7 @@ megasas_resume(struct pci_dev *pdev)
/* Now re-enable MSI-X */
if (instance->msix_vectors) {
irq_flags = PCI_IRQ_MSIX;
- if (smp_affinity_enable)
+ if (instance->smp_affinity_enable)
irq_flags |= PCI_IRQ_AFFINITY;
}
rval = pci_alloc_irq_vectors(instance->pdev, 1,
@@ -7184,6 +7584,9 @@ megasas_resume(struct pci_dev *pdev)
megasas_setup_irqs_ioapic(instance))
goto fail_init_mfi;
+ if (instance->adapter_type != MFI_SERIES)
+ megasas_setup_irq_poll(instance);
+
/* Re-launch SR-IOV heartbeat timer */
if (instance->requestorId) {
if (!megasas_sriov_start_heartbeat(instance, 0))
@@ -7274,6 +7677,10 @@ static void megasas_detach_one(struct pci_dev *pdev)
u32 pd_seq_map_sz;
instance = pci_get_drvdata(pdev);
+
+ if (!instance)
+ return;
+
host = instance->host;
fusion = instance->ctrl_context;
@@ -7387,6 +7794,8 @@ skip_firing_dcmds:
megasas_free_ctrl_mem(instance);
+ megasas_destroy_debugfs(instance);
+
scsi_host_put(host);
pci_disable_device(pdev);
@@ -7400,6 +7809,9 @@ static void megasas_shutdown(struct pci_dev *pdev)
{
struct megasas_instance *instance = pci_get_drvdata(pdev);
+ if (!instance)
+ return;
+
instance->unload = 1;
if (megasas_wait_for_adapter_operational(instance))
@@ -7545,7 +7957,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
if ((ioc->frame.hdr.cmd >= MFI_CMD_OP_COUNT) ||
((ioc->frame.hdr.cmd == MFI_CMD_NVME) &&
- !instance->support_nvme_passthru)) {
+ !instance->support_nvme_passthru) ||
+ ((ioc->frame.hdr.cmd == MFI_CMD_TOOLBOX) &&
+ !instance->support_pci_lane_margining)) {
dev_err(&instance->pdev->dev,
"Received invalid ioctl command 0x%x\n",
ioc->frame.hdr.cmd);
@@ -7581,10 +7995,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
if (opcode == MR_DCMD_CTRL_SHUTDOWN) {
+ mutex_lock(&instance->reset_mutex);
if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) {
megasas_return_cmd(instance, cmd);
+ mutex_unlock(&instance->reset_mutex);
return -1;
}
+ mutex_unlock(&instance->reset_mutex);
}
if (opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) {
@@ -8026,6 +8443,14 @@ support_nvme_encapsulation_show(struct device_driver *dd, char *buf)
static DRIVER_ATTR_RO(support_nvme_encapsulation);
+static ssize_t
+support_pci_lane_margining_show(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf, "%u\n", support_pci_lane_margining);
+}
+
+static DRIVER_ATTR_RO(support_pci_lane_margining);
+
static inline void megasas_remove_scsi_device(struct scsi_device *sdev)
{
sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n");
@@ -8174,7 +8599,7 @@ megasas_aen_polling(struct work_struct *work)
struct megasas_instance *instance = ev->instance;
union megasas_evt_class_locale class_locale;
int event_type = 0;
- u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME;
+ u32 seq_num;
int error;
u8 dcmd_ret = DCMD_SUCCESS;
@@ -8184,10 +8609,6 @@ megasas_aen_polling(struct work_struct *work)
return;
}
- /* Adjust event workqueue thread wait time for VF mode */
- if (instance->requestorId)
- wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF;
-
/* Don't run the event workqueue thread if OCR is running */
mutex_lock(&instance->reset_mutex);
@@ -8299,6 +8720,7 @@ static int __init megasas_init(void)
support_poll_for_event = 2;
support_device_change = 1;
support_nvme_encapsulation = true;
+ support_pci_lane_margining = true;
memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
@@ -8314,6 +8736,8 @@ static int __init megasas_init(void)
megasas_mgmt_majorno = rval;
+ megasas_init_debugfs();
+
/*
* Register ourselves as PCI hotplug module
*/
@@ -8353,8 +8777,17 @@ static int __init megasas_init(void)
if (rval)
goto err_dcf_support_nvme_encapsulation;
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_support_pci_lane_margining);
+ if (rval)
+ goto err_dcf_support_pci_lane_margining;
+
return rval;
+err_dcf_support_pci_lane_margining:
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_nvme_encapsulation);
+
err_dcf_support_nvme_encapsulation:
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_support_device_change);
@@ -8373,6 +8806,7 @@ err_dcf_rel_date:
err_dcf_attr_ver:
pci_unregister_driver(&megasas_pci_driver);
err_pcidrv:
+ megasas_exit_debugfs();
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
return rval;
}
@@ -8393,8 +8827,11 @@ static void __exit megasas_exit(void)
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_support_nvme_encapsulation);
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_pci_lane_margining);
pci_unregister_driver(&megasas_pci_driver);
+ megasas_exit_debugfs();
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_debugfs.c b/drivers/scsi/megaraid/megaraid_sas_debugfs.c
new file mode 100644
index 000000000000..c69760775efa
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_sas_debugfs.c
@@ -0,0 +1,179 @@
+/*
+ * Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * Copyright (c) 2003-2018 LSI Corporation.
+ * Copyright (c) 2003-2018 Avago Technologies.
+ * Copyright (c) 2003-2018 Broadcom Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Broadcom Inc.
+ * Kashyap Desai <kashyap.desai@broadcom.com>
+ * Sumit Saxena <sumit.saxena@broadcom.com>
+ * Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
+ *
+ * Send feedback to: megaraidlinux.pdl@broadcom.com
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/compat.h>
+#include <linux/irq_poll.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "megaraid_sas_fusion.h"
+#include "megaraid_sas.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+struct dentry *megasas_debugfs_root;
+
+static ssize_t
+megasas_debugfs_read(struct file *filp, char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+{
+ struct megasas_debugfs_buffer *debug = filp->private_data;
+
+ if (!debug || !debug->buf)
+ return 0;
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, debug->buf, debug->len);
+}
+
+static int
+megasas_debugfs_raidmap_open(struct inode *inode, struct file *file)
+{
+ struct megasas_instance *instance = inode->i_private;
+ struct megasas_debugfs_buffer *debug;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ debug = kzalloc(sizeof(struct megasas_debugfs_buffer), GFP_KERNEL);
+ if (!debug)
+ return -ENOMEM;
+
+ debug->buf = (void *)fusion->ld_drv_map[(instance->map_id & 1)];
+ debug->len = fusion->drv_map_sz;
+ file->private_data = debug;
+
+ return 0;
+}
+
+static int
+megasas_debugfs_release(struct inode *inode, struct file *file)
+{
+ struct megasas_debug_buffer *debug = file->private_data;
+
+ if (!debug)
+ return 0;
+
+ file->private_data = NULL;
+ kfree(debug);
+ return 0;
+}
+
+static const struct file_operations megasas_debugfs_raidmap_fops = {
+ .owner = THIS_MODULE,
+ .open = megasas_debugfs_raidmap_open,
+ .read = megasas_debugfs_read,
+ .release = megasas_debugfs_release,
+};
+
+/*
+ * megasas_init_debugfs : Create debugfs root for megaraid_sas driver
+ */
+void megasas_init_debugfs(void)
+{
+ megasas_debugfs_root = debugfs_create_dir("megaraid_sas", NULL);
+ if (!megasas_debugfs_root)
+ pr_info("Cannot create debugfs root\n");
+}
+
+/*
+ * megasas_exit_debugfs : Remove debugfs root for megaraid_sas driver
+ */
+void megasas_exit_debugfs(void)
+{
+ debugfs_remove_recursive(megasas_debugfs_root);
+}
+
+/*
+ * megasas_setup_debugfs : Setup debugfs per Fusion adapter
+ * instance: Soft instance of adapter
+ */
+void
+megasas_setup_debugfs(struct megasas_instance *instance)
+{
+ char name[64];
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
+
+ if (fusion) {
+ snprintf(name, sizeof(name),
+ "scsi_host%d", instance->host->host_no);
+ if (!instance->debugfs_root) {
+ instance->debugfs_root =
+ debugfs_create_dir(name, megasas_debugfs_root);
+ if (!instance->debugfs_root) {
+ dev_err(&instance->pdev->dev,
+ "Cannot create per adapter debugfs directory\n");
+ return;
+ }
+ }
+
+ snprintf(name, sizeof(name), "raidmap_dump");
+ instance->raidmap_dump =
+ debugfs_create_file(name, S_IRUGO,
+ instance->debugfs_root, instance,
+ &megasas_debugfs_raidmap_fops);
+ if (!instance->raidmap_dump) {
+ dev_err(&instance->pdev->dev,
+ "Cannot create raidmap debugfs file\n");
+ debugfs_remove(instance->debugfs_root);
+ return;
+ }
+ }
+
+}
+
+/*
+ * megasas_destroy_debugfs : Destroy debugfs per Fusion adapter
+ * instance: Soft instance of adapter
+ */
+void megasas_destroy_debugfs(struct megasas_instance *instance)
+{
+ debugfs_remove_recursive(instance->debugfs_root);
+}
+
+#else
+void megasas_init_debugfs(void)
+{
+}
+void megasas_exit_debugfs(void)
+{
+}
+void megasas_setup_debugfs(struct megasas_instance *instance)
+{
+}
+void megasas_destroy_debugfs(struct megasas_instance *instance)
+{
+}
+#endif /*CONFIG_DEBUG_FS*/
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 87c2c0472c8f..50b8c1b12767 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
@@ -5,19 +6,6 @@
* Copyright (c) 2013-2016 Avago Technologies
* Copyright (c) 2016-2018 Broadcom Inc.
*
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* FILE: megaraid_sas_fp.c
*
* Authors: Broadcom Inc.
@@ -45,6 +33,7 @@
#include <linux/compat.h>
#include <linux/blkdev.h>
#include <linux/poll.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -57,7 +46,7 @@
#define LB_PENDING_CMDS_DEFAULT 4
static unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT;
-module_param(lb_pending_cmds, int, S_IRUGO);
+module_param(lb_pending_cmds, int, 0444);
MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding "
"threshold. Valid Values are 1-128. Default: 4");
@@ -901,6 +890,77 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
}
/*
+ * mr_get_phy_params_r56_rmw - Calculate parameters for R56 CTIO write operation
+ * @instance: Adapter soft state
+ * @ld: LD index
+ * @stripNo: Strip Number
+ * @io_info: IO info structure pointer
+ * pRAID_Context: RAID context pointer
+ * map: RAID map pointer
+ *
+ * This routine calculates the logical arm, data Arm, row number and parity arm
+ * for R56 CTIO write operation.
+ */
+static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,
+ u32 ld, u64 stripNo,
+ struct IO_REQUEST_INFO *io_info,
+ struct RAID_CONTEXT_G35 *pRAID_Context,
+ struct MR_DRV_RAID_MAP_ALL *map)
+{
+ struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
+ u8 span, dataArms, arms, dataArm, logArm;
+ s8 rightmostParityArm, PParityArm;
+ u64 rowNum;
+ u64 *pdBlock = &io_info->pdBlock;
+
+ dataArms = raid->rowDataSize;
+ arms = raid->rowSize;
+
+ rowNum = mega_div64_32(stripNo, dataArms);
+ /* parity disk arm, first arm is 0 */
+ rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms);
+
+ /* logical arm within row */
+ logArm = mega_mod64(stripNo, dataArms);
+ /* physical arm for data */
+ dataArm = mega_mod64((rightmostParityArm + 1 + logArm), arms);
+
+ if (raid->spanDepth == 1) {
+ span = 0;
+ } else {
+ span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map);
+ if (span == SPAN_INVALID)
+ return;
+ }
+
+ if (raid->level == 6) {
+ /* P Parity arm, note this can go negative adjust if negative */
+ PParityArm = (arms - 2) - mega_mod64(rowNum, arms);
+
+ if (PParityArm < 0)
+ PParityArm += arms;
+
+ /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */
+ pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm;
+ pRAID_Context->flow_specific.r56_arm_map |=
+ (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT);
+ } else {
+ pRAID_Context->flow_specific.r56_arm_map |=
+ (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT);
+ }
+
+ pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum);
+ pRAID_Context->flow_specific.r56_arm_map |=
+ (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT);
+ cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map);
+ pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm;
+ pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD <<
+ MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
+
+ return;
+}
+
+/*
******************************************************************************
*
* MR_BuildRaidContext function
@@ -966,6 +1026,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
stripSize = 1 << raid->stripeShift;
stripe_mask = stripSize-1;
+ io_info->data_arms = raid->rowDataSize;
/*
* calculate starting row and stripe, and number of strips and rows
@@ -1107,6 +1168,13 @@ MR_BuildRaidContext(struct megasas_instance *instance,
/* save pointer to raid->LUN array */
*raidLUN = raid->LUN;
+ /* Aero R5/6 Division Offload for WRITE */
+ if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) {
+ mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info,
+ (struct RAID_CONTEXT_G35 *)pRAID_Context,
+ map);
+ return true;
+ }
/*Get Phy Params only if FP capable, or else leave it to MR firmware
to do the calculation.*/
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 1d17128030cd..a32b3f0fcd15 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
@@ -5,19 +6,6 @@
* Copyright (c) 2013-2016 Avago Technologies
* Copyright (c) 2016-2018 Broadcom Inc.
*
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* FILE: megaraid_sas_fusion.c
*
* Authors: Broadcom Inc.
@@ -47,6 +35,7 @@
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -99,6 +88,62 @@ extern u32 megasas_readl(struct megasas_instance *instance,
const volatile void __iomem *addr);
/**
+ * megasas_adp_reset_wait_for_ready - initiate chip reset and wait for
+ * controller to come to ready state
+ * @instance - adapter's soft state
+ * @do_adp_reset - If true, do a chip reset
+ * @ocr_context - If called from OCR context this will
+ * be set to 1, else 0
+ *
+ * This function initates a chip reset followed by a wait for controller to
+ * transition to ready state.
+ * During this, driver will block all access to PCI config space from userspace
+ */
+int
+megasas_adp_reset_wait_for_ready(struct megasas_instance *instance,
+ bool do_adp_reset,
+ int ocr_context)
+{
+ int ret = FAILED;
+
+ /*
+ * Block access to PCI config space from userspace
+ * when diag reset is initiated from driver
+ */
+ if (megasas_dbg_lvl & OCR_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "Block access to PCI config space %s %d\n",
+ __func__, __LINE__);
+
+ pci_cfg_access_lock(instance->pdev);
+
+ if (do_adp_reset) {
+ if (instance->instancet->adp_reset
+ (instance, instance->reg_set))
+ goto out;
+ }
+
+ /* Wait for FW to become ready */
+ if (megasas_transition_to_ready(instance, ocr_context)) {
+ dev_warn(&instance->pdev->dev,
+ "Failed to transition controller to ready for scsi%d.\n",
+ instance->host->host_no);
+ goto out;
+ }
+
+ ret = SUCCESS;
+out:
+ if (megasas_dbg_lvl & OCR_DEBUG)
+ dev_info(&instance->pdev->dev,
+ "Unlock access to PCI config space %s %d\n",
+ __func__, __LINE__);
+
+ pci_cfg_access_unlock(instance->pdev);
+
+ return ret;
+}
+
+/**
* megasas_check_same_4gb_region - check if allocation
* crosses same 4GB boundary or not
* @instance - adapter's soft instance
@@ -145,7 +190,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance)
writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
/* Dummy readl to force pci flush */
- readl(&regs->outbound_intr_mask);
+ dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
+ __func__, readl(&regs->outbound_intr_mask));
}
/**
@@ -156,14 +202,14 @@ void
megasas_disable_intr_fusion(struct megasas_instance *instance)
{
u32 mask = 0xFFFFFFFF;
- u32 status;
struct megasas_register_set __iomem *regs;
regs = instance->reg_set;
instance->mask_interrupts = 1;
writel(mask, &regs->outbound_intr_mask);
/* Dummy readl to force pci flush */
- status = readl(&regs->outbound_intr_mask);
+ dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n",
+ __func__, readl(&regs->outbound_intr_mask));
}
int
@@ -219,21 +265,17 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
}
/**
- * megasas_fire_cmd_fusion - Sends command to the FW
- * @instance: Adapter soft state
- * @req_desc: 64bit Request descriptor
- *
- * Perform PCI Write.
+ * megasas_write_64bit_req_desc - PCI writes 64bit request descriptor
+ * @instance: Adapter soft state
+ * @req_desc: 64bit Request descriptor
*/
-
static void
-megasas_fire_cmd_fusion(struct megasas_instance *instance,
+megasas_write_64bit_req_desc(struct megasas_instance *instance,
union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
{
#if defined(writeq) && defined(CONFIG_64BIT)
u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
le32_to_cpu(req_desc->u.low));
-
writeq(req_data, &instance->reg_set->inbound_low_queue_port);
#else
unsigned long flags;
@@ -242,12 +284,30 @@ 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_fire_cmd_fusion - Sends command to the FW
+ * @instance: Adapter soft state
+ * @req_desc: 32bit or 64bit Request descriptor
+ *
+ * Perform PCI Write. AERO SERIES supports 32 bit Descriptor.
+ * Prior to AERO_SERIES support 64 bit Descriptor.
+ */
+static void
+megasas_fire_cmd_fusion(struct megasas_instance *instance,
+ union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
+{
+ if (instance->atomic_desc_support)
+ writel(le32_to_cpu(req_desc->u.low),
+ &instance->reg_set->inbound_single_queue_port);
+ else
+ megasas_write_64bit_req_desc(instance, req_desc);
+}
+
+/**
* 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
@@ -937,6 +997,7 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
{
int i;
struct megasas_header *frame_hdr = &cmd->frame->hdr;
+ u32 status_reg;
u32 msecs = seconds * 1000;
@@ -946,6 +1007,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) {
rmb();
msleep(20);
+ if (!(i % 5000)) {
+ status_reg = instance->instancet->read_fw_status_reg(instance)
+ & MFI_STATE_MASK;
+ if (status_reg == MFI_STATE_FAULT)
+ break;
+ }
}
if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
@@ -979,6 +1046,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
u32 scratch_pad_1;
ktime_t time;
bool cur_fw_64bit_dma_capable;
+ bool cur_intr_coalescing;
fusion = instance->ctrl_context;
@@ -1012,6 +1080,16 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
goto fail_fw_init;
}
+ cur_intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ?
+ true : false;
+
+ if ((instance->low_latency_index_start ==
+ MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing)
+ instance->perf_mode = MR_BALANCED_PERF_MODE;
+
+ dev_info(&instance->pdev->dev, "Performance mode :%s\n",
+ MEGASAS_PERF_MODE_2STR(instance->perf_mode));
+
instance->fw_sync_cache_support = (scratch_pad_1 &
MR_CAN_HANDLE_SYNC_CACHE_OFFSET) ? 1 : 0;
dev_info(&instance->pdev->dev, "FW supports sync cache\t: %s\n",
@@ -1096,6 +1174,22 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
cpu_to_le32(lower_32_bits(ioc_init_handle));
init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
+ /*
+ * Each bit in replyqueue_mask represents one group of MSI-x vectors
+ * (each group has 8 vectors)
+ */
+ switch (instance->perf_mode) {
+ case MR_BALANCED_PERF_MODE:
+ init_frame->replyqueue_mask =
+ cpu_to_le16(~(~0 << instance->low_latency_index_start/8));
+ break;
+ case MR_IOPS_PERF_MODE:
+ init_frame->replyqueue_mask =
+ cpu_to_le16(~(~0 << instance->msix_vectors/8));
+ break;
+ }
+
+
req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr));
req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr));
req_desc.MFAIo.RequestFlags =
@@ -1114,7 +1208,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
break;
}
- megasas_fire_cmd_fusion(instance, &req_desc);
+ /* For AERO also, IOC_INIT requires 64 bit descriptor write */
+ megasas_write_64bit_req_desc(instance, &req_desc);
wait_and_poll(instance, cmd, MFI_IO_TIMEOUT_SECS);
@@ -1124,6 +1219,17 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
goto fail_fw_init;
}
+ if (instance->adapter_type >= AERO_SERIES) {
+ scratch_pad_1 = megasas_readl
+ (instance, &instance->reg_set->outbound_scratch_pad_1);
+
+ instance->atomic_desc_support =
+ (scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0;
+
+ dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n",
+ instance->atomic_desc_support ? "Yes" : "No");
+ }
+
return 0;
fail_fw_init:
@@ -1146,7 +1252,7 @@ fail_fw_init:
int
megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
int ret = 0;
- u32 pd_seq_map_sz;
+ size_t pd_seq_map_sz;
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
struct fusion_context *fusion = instance->ctrl_context;
@@ -1155,9 +1261,7 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
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));
+ pd_seq_map_sz = struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES - 1);
cmd = megasas_get_cmd(instance);
if (!cmd) {
@@ -1638,6 +1742,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
struct fusion_context *fusion;
u32 scratch_pad_1;
int i = 0, count;
+ u32 status_reg;
fusion = instance->ctrl_context;
@@ -1720,8 +1825,21 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
if (megasas_alloc_cmds_fusion(instance))
goto fail_alloc_cmds;
- if (megasas_ioc_init_fusion(instance))
- goto fail_ioc_init;
+ if (megasas_ioc_init_fusion(instance)) {
+ status_reg = instance->instancet->read_fw_status_reg(instance);
+ if (((status_reg & MFI_STATE_MASK) == MFI_STATE_FAULT) &&
+ (status_reg & MFI_RESET_ADAPTER)) {
+ /* Do a chip reset and then retry IOC INIT once */
+ if (megasas_adp_reset_wait_for_ready
+ (instance, true, 0) == FAILED)
+ goto fail_ioc_init;
+
+ if (megasas_ioc_init_fusion(instance))
+ goto fail_ioc_init;
+ } else {
+ goto fail_ioc_init;
+ }
+ }
megasas_display_intel_branding(instance);
if (megasas_get_ctrl_info(instance)) {
@@ -1733,6 +1851,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
instance->flag_ieee = 1;
instance->r1_ldio_hint_default = MR_R1_LDIO_PIGGYBACK_DEFAULT;
+ instance->threshold_reply_count = instance->max_fw_cmds / 4;
fusion->fast_path_io = 0;
if (megasas_allocate_raid_maps(instance))
@@ -1983,7 +2102,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
mega_mod64(sg_dma_address(sg_scmd),
mr_nvme_pg_size)) {
build_prp = false;
- atomic_inc(&instance->sge_holes_type1);
break;
}
}
@@ -1993,7 +2111,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
sg_dma_len(sg_scmd)),
mr_nvme_pg_size))) {
build_prp = false;
- atomic_inc(&instance->sge_holes_type2);
break;
}
}
@@ -2002,7 +2119,6 @@ megasas_is_prp_possible(struct megasas_instance *instance,
if (mega_mod64(sg_dma_address(sg_scmd),
mr_nvme_pg_size)) {
build_prp = false;
- atomic_inc(&instance->sge_holes_type3);
break;
}
}
@@ -2135,7 +2251,6 @@ megasas_make_prp_nvme(struct megasas_instance *instance, struct scsi_cmnd *scmd,
main_chain_element->Length =
cpu_to_le32(num_prp_in_chain * sizeof(u64));
- atomic_inc(&instance->prp_sgl);
return build_prp;
}
@@ -2210,7 +2325,6 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
memset(sgl_ptr, 0, instance->max_chain_frame_sz);
}
}
- atomic_inc(&instance->ieee_sgl);
}
/**
@@ -2522,9 +2636,10 @@ static void megasas_stream_detect(struct megasas_instance *instance,
*
*/
static void
-megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context,
- struct MR_LD_RAID *raid, bool fp_possible,
- u8 is_read, u32 scsi_buff_len)
+megasas_set_raidflag_cpu_affinity(struct fusion_context *fusion,
+ union RAID_CONTEXT_UNION *praid_context,
+ struct MR_LD_RAID *raid, bool fp_possible,
+ u8 is_read, u32 scsi_buff_len)
{
u8 cpu_sel = MR_RAID_CTX_CPUSEL_0;
struct RAID_CONTEXT_G35 *rctx_g35;
@@ -2582,11 +2697,11 @@ megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context,
* vs MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS.
* IO Subtype is not bitmap.
*/
- if ((raid->level == 1) && (!is_read)) {
- if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
- praid_context->raid_context_g35.raid_flags =
- (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
- << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
+ if ((fusion->pcie_bw_limitation) && (raid->level == 1) && (!is_read) &&
+ (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)) {
+ praid_context->raid_context_g35.raid_flags =
+ (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
+ << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
}
}
@@ -2692,6 +2807,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
scsi_buff_len = scsi_bufflen(scp);
io_request->DataLength = cpu_to_le32(scsi_buff_len);
+ io_info.data_arms = 1;
if (scp->sc_data_direction == DMA_FROM_DEVICE)
io_info.isRead = 1;
@@ -2711,8 +2827,19 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
fp_possible = (io_info.fpOkForIo > 0) ? true : false;
}
- cmd->request_desc->SCSIIO.MSIxIndex =
- instance->reply_map[raw_smp_processor_id()];
+ if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+ atomic_read(&scp->device->device_busy) >
+ (io_info.data_arms * MR_DEVICE_HIGH_IOPS_DEPTH))
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
+ MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
+ else if (instance->msix_load_balance)
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
+ instance->msix_vectors));
+ else
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ instance->reply_map[raw_smp_processor_id()];
if (instance->adapter_type >= VENTURA_SERIES) {
/* FP for Optimal raid level 1.
@@ -2730,8 +2857,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
(instance->host->can_queue)) {
fp_possible = false;
atomic_dec(&instance->fw_outstanding);
- } else if ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
- (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0)) {
+ } else if (fusion->pcie_bw_limitation &&
+ ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
+ (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0))) {
fp_possible = false;
atomic_dec(&instance->fw_outstanding);
if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
@@ -2756,7 +2884,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
/* If raid is NULL, set CPU affinity to default CPU0 */
if (raid)
- megasas_set_raidflag_cpu_affinity(&io_request->RaidContext,
+ megasas_set_raidflag_cpu_affinity(fusion, &io_request->RaidContext,
raid, fp_possible, io_info.isRead,
scsi_buff_len);
else
@@ -2772,10 +2900,6 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
(MPI2_REQ_DESCRIPT_FLAGS_FP_IO
<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
if (instance->adapter_type == INVADER_SERIES) {
- if (rctx->reg_lock_flags == REGION_TYPE_UNUSED)
- cmd->request_desc->SCSIIO.RequestFlags =
- (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
- MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
rctx->type = MPI2_TYPE_CUDA;
rctx->nseg = 0x1;
io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
@@ -2983,50 +3107,71 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
<< MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
/* 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
- */
- /* More than 256 PD/JBOD support for Ventura */
- if (instance->support_morethan256jbod)
- pRAID_Context->virtual_disk_tgt_id =
- pd_sync->seq[pd_index].pd_target_id;
- else
- pRAID_Context->virtual_disk_tgt_id =
- cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
- pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum;
- io_request->DevHandle = pd_sync->seq[pd_index].devHandle;
- if (instance->adapter_type >= VENTURA_SERIES) {
- io_request->RaidContext.raid_context_g35.routing_flags |=
- (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
- io_request->RaidContext.raid_context_g35.nseg_type |=
- (1 << RAID_CONTEXT_NSEG_SHIFT);
- io_request->RaidContext.raid_context_g35.nseg_type |=
- (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
+ if (instance->support_seqnum_jbod_fp) {
+ if (instance->use_seqnum_jbod_fp &&
+ instance->pd_list[pd_index].driveType == TYPE_DISK) {
+
+ /* More than 256 PD/JBOD support for Ventura */
+ if (instance->support_morethan256jbod)
+ pRAID_Context->virtual_disk_tgt_id =
+ pd_sync->seq[pd_index].pd_target_id;
+ else
+ pRAID_Context->virtual_disk_tgt_id =
+ cpu_to_le16(device_id +
+ (MAX_PHYSICAL_DEVICES - 1));
+ pRAID_Context->config_seq_num =
+ pd_sync->seq[pd_index].seqNum;
+ io_request->DevHandle =
+ pd_sync->seq[pd_index].devHandle;
+ if (instance->adapter_type >= VENTURA_SERIES) {
+ io_request->RaidContext.raid_context_g35.routing_flags |=
+ (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
+ io_request->RaidContext.raid_context_g35.nseg_type |=
+ (1 << RAID_CONTEXT_NSEG_SHIFT);
+ io_request->RaidContext.raid_context_g35.nseg_type |=
+ (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
+ } else {
+ pRAID_Context->type = MPI2_TYPE_CUDA;
+ pRAID_Context->nseg = 0x1;
+ pRAID_Context->reg_lock_flags |=
+ (MR_RL_FLAGS_SEQ_NUM_ENABLE |
+ MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+ }
} else {
- pRAID_Context->type = MPI2_TYPE_CUDA;
- pRAID_Context->nseg = 0x1;
- pRAID_Context->reg_lock_flags |=
- (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+ pRAID_Context->virtual_disk_tgt_id =
+ cpu_to_le16(device_id +
+ (MAX_PHYSICAL_DEVICES - 1));
+ pRAID_Context->config_seq_num = 0;
+ io_request->DevHandle = cpu_to_le16(0xFFFF);
}
- } else if (fusion->fast_path_io) {
- pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
- pRAID_Context->config_seq_num = 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->virtual_disk_tgt_id = cpu_to_le16(device_id);
pRAID_Context->config_seq_num = 0;
- io_request->DevHandle = cpu_to_le16(0xFFFF);
+
+ if (fusion->fast_path_io) {
+ local_map_ptr =
+ fusion->ld_drv_map[(instance->map_id & 1)];
+ io_request->DevHandle =
+ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ } else {
+ io_request->DevHandle = cpu_to_le16(0xFFFF);
+ }
}
cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
- cmd->request_desc->SCSIIO.MSIxIndex =
- instance->reply_map[raw_smp_processor_id()];
+ if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
+ atomic_read(&scmd->device->device_busy) > MR_DEVICE_HIGH_IOPS_DEPTH)
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
+ MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
+ else if (instance->msix_load_balance)
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ (mega_mod64(atomic64_add_return(1, &instance->total_io_count),
+ instance->msix_vectors));
+ else
+ cmd->request_desc->SCSIIO.MSIxIndex =
+ instance->reply_map[raw_smp_processor_id()];
if (!fp_possible) {
/* system pd firmware path */
@@ -3206,9 +3351,9 @@ void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle;
r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle;
r1_cmd->r1_alt_dev_handle = cmd->io_request->DevHandle;
- cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
+ cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid =
cpu_to_le16(r1_cmd->index);
- r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
+ r1_cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid =
cpu_to_le16(cmd->index);
/*MSIxIndex of both commands request descriptors should be same*/
r1_cmd->request_desc->SCSIIO.MSIxIndex =
@@ -3326,7 +3471,7 @@ megasas_complete_r1_command(struct megasas_instance *instance,
rctx_g35 = &cmd->io_request->RaidContext.raid_context_g35;
fusion = instance->ctrl_context;
- peer_smid = le16_to_cpu(rctx_g35->smid.peer_smid);
+ peer_smid = le16_to_cpu(rctx_g35->flow_specific.peer_smid);
r1_cmd = fusion->cmd_list[peer_smid - 1];
scmd_local = cmd->scmd;
@@ -3366,7 +3511,8 @@ megasas_complete_r1_command(struct megasas_instance *instance,
* Completes all commands that is in reply descriptor queue
*/
int
-complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
+complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
+ struct megasas_irq_context *irq_context)
{
union MPI2_REPLY_DESCRIPTORS_UNION *desc;
struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc;
@@ -3499,7 +3645,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
* number of reply counts and still there are more replies in reply queue
* pending to be completed
*/
- if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
+ if (threshold_reply_count >= instance->threshold_reply_count) {
if (instance->msix_combined)
writel(((MSIxIndex & 0x7) << 24) |
fusion->last_reply_idx[MSIxIndex],
@@ -3509,23 +3655,46 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
fusion->last_reply_idx[MSIxIndex],
instance->reply_post_host_index_addr[0]);
threshold_reply_count = 0;
+ if (irq_context) {
+ if (!irq_context->irq_poll_scheduled) {
+ irq_context->irq_poll_scheduled = true;
+ irq_context->irq_line_enable = true;
+ irq_poll_sched(&irq_context->irqpoll);
+ }
+ return num_completed;
+ }
}
}
- if (!num_completed)
- return IRQ_NONE;
+ if (num_completed) {
+ wmb();
+ if (instance->msix_combined)
+ writel(((MSIxIndex & 0x7) << 24) |
+ fusion->last_reply_idx[MSIxIndex],
+ instance->reply_post_host_index_addr[MSIxIndex/8]);
+ else
+ writel((MSIxIndex << 24) |
+ fusion->last_reply_idx[MSIxIndex],
+ instance->reply_post_host_index_addr[0]);
+ megasas_check_and_restore_queue_depth(instance);
+ }
+ return num_completed;
+}
- wmb();
- if (instance->msix_combined)
- writel(((MSIxIndex & 0x7) << 24) |
- fusion->last_reply_idx[MSIxIndex],
- instance->reply_post_host_index_addr[MSIxIndex/8]);
- else
- writel((MSIxIndex << 24) |
- fusion->last_reply_idx[MSIxIndex],
- instance->reply_post_host_index_addr[0]);
- megasas_check_and_restore_queue_depth(instance);
- return IRQ_HANDLED;
+/**
+ * megasas_enable_irq_poll() - enable irqpoll
+ */
+static void megasas_enable_irq_poll(struct megasas_instance *instance)
+{
+ u32 count, i;
+ struct megasas_irq_context *irq_ctx;
+
+ count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+ for (i = 0; i < count; i++) {
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_enable(&irq_ctx->irqpoll);
+ }
}
/**
@@ -3537,11 +3706,51 @@ void megasas_sync_irqs(unsigned long instance_addr)
u32 count, i;
struct megasas_instance *instance =
(struct megasas_instance *)instance_addr;
+ struct megasas_irq_context *irq_ctx;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
- for (i = 0; i < count; i++)
+ for (i = 0; i < count; i++) {
synchronize_irq(pci_irq_vector(instance->pdev, i));
+ irq_ctx = &instance->irq_context[i];
+ irq_poll_disable(&irq_ctx->irqpoll);
+ if (irq_ctx->irq_poll_scheduled) {
+ irq_ctx->irq_poll_scheduled = false;
+ enable_irq(irq_ctx->os_irq);
+ }
+ }
+}
+
+/**
+ * megasas_irqpoll() - process a queue for completed reply descriptors
+ * @irqpoll: IRQ poll structure associated with queue to poll.
+ * @budget: Threshold of reply descriptors to process per poll.
+ *
+ * Return: The number of entries processed.
+ */
+
+int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
+{
+ struct megasas_irq_context *irq_ctx;
+ struct megasas_instance *instance;
+ int num_entries;
+
+ irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll);
+ instance = irq_ctx->instance;
+
+ if (irq_ctx->irq_line_enable) {
+ disable_irq(irq_ctx->os_irq);
+ irq_ctx->irq_line_enable = false;
+ }
+
+ num_entries = complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
+ if (num_entries < budget) {
+ irq_poll_complete(irqpoll);
+ irq_ctx->irq_poll_scheduled = false;
+ enable_irq(irq_ctx->os_irq);
+ }
+
+ return num_entries;
}
/**
@@ -3564,7 +3773,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
return;
for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++)
- complete_cmd_fusion(instance, MSIxIndex);
+ complete_cmd_fusion(instance, MSIxIndex, NULL);
}
/**
@@ -3579,6 +3788,11 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
if (instance->mask_interrupts)
return IRQ_NONE;
+#if defined(ENABLE_IRQ_POLL)
+ if (irq_context->irq_poll_scheduled)
+ return IRQ_HANDLED;
+#endif
+
if (!instance->msix_vectors) {
mfiStatus = instance->instancet->clear_intr(instance);
if (!mfiStatus)
@@ -3591,7 +3805,8 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
return IRQ_HANDLED;
}
- return complete_cmd_fusion(instance, irq_context->MSIxIndex);
+ return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context)
+ ? IRQ_HANDLED : IRQ_NONE;
}
/**
@@ -3856,7 +4071,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
static inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
{
int j;
- u32 fw_state;
+ u32 fw_state, abs_state;
if (!instance->disableOnlineCtrlReset) {
dev_info(&instance->pdev->dev, "Trigger snap dump\n");
@@ -3866,11 +4081,13 @@ static inline void megasas_trigger_snap_dump(struct megasas_instance *instance)
}
for (j = 0; j < instance->snapdump_wait_time; j++) {
- fw_state = instance->instancet->read_fw_status_reg(instance) &
- MFI_STATE_MASK;
+ abs_state = instance->instancet->read_fw_status_reg(instance);
+ fw_state = abs_state & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
- dev_err(&instance->pdev->dev,
- "Found FW in FAULT state, after snap dump trigger\n");
+ dev_printk(KERN_ERR, &instance->pdev->dev,
+ "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
return;
}
msleep(1000);
@@ -3882,7 +4099,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
int reason, int *convert)
{
int i, outstanding, retval = 0, hb_seconds_missed = 0;
- u32 fw_state;
+ u32 fw_state, abs_state;
u32 waittime_for_io_completion;
waittime_for_io_completion =
@@ -3901,12 +4118,13 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
for (i = 0; i < waittime_for_io_completion; i++) {
/* Check if firmware is in fault state */
- fw_state = instance->instancet->read_fw_status_reg(instance) &
- MFI_STATE_MASK;
+ abs_state = instance->instancet->read_fw_status_reg(instance);
+ fw_state = abs_state & MFI_STATE_MASK;
if (fw_state == MFI_STATE_FAULT) {
- dev_warn(&instance->pdev->dev, "Found FW in FAULT state,"
- " will reset adapter scsi%d.\n",
- instance->host->host_no);
+ dev_printk(KERN_ERR, &instance->pdev->dev,
+ "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n",
+ abs_state & MFI_STATE_FAULT_CODE,
+ abs_state & MFI_STATE_FAULT_SUBCODE, __func__);
megasas_complete_cmd_dpc_fusion((unsigned long)instance);
if (instance->requestorId && reason) {
dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT"
@@ -4055,6 +4273,13 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
}
break;
+ case MFI_CMD_TOOLBOX:
+ if (!instance->support_pci_lane_margining) {
+ cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD;
+ result = COMPLETE_CMD;
+ }
+
+ break;
default:
break;
}
@@ -4278,6 +4503,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
instance->instancet->disable_intr(instance);
megasas_sync_irqs((unsigned long)instance);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
if (scsi_lookup->scmd == NULL)
break;
}
@@ -4291,6 +4517,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
megasas_sync_irqs((unsigned long)instance);
rc = megasas_track_scsiio(instance, id, channel);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
break;
case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
@@ -4389,9 +4616,6 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
instance = (struct megasas_instance *)scmd->device->host->hostdata;
- scmd_printk(KERN_INFO, scmd, "task abort called for scmd(%p)\n", scmd);
- scsi_print_command(scmd);
-
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);
@@ -4419,7 +4643,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
if (!smid) {
ret = SUCCESS;
scmd_printk(KERN_NOTICE, scmd, "Command for which abort is"
- " issued is not found in oustanding commands\n");
+ " issued is not found in outstanding commands\n");
mutex_unlock(&instance->reset_mutex);
goto out;
}
@@ -4434,7 +4658,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
goto out;
}
sdev_printk(KERN_INFO, scmd->device,
- "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n",
+ "attempting task abort! scmd(0x%p) tm_dev_handle 0x%x\n",
scmd, devhandle);
mr_device_priv_data->tm_busy = 1;
@@ -4445,9 +4669,12 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
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",
+ scmd_printk(KERN_INFO, scmd, "task abort %s!! scmd(0x%p)\n",
((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+out:
+ scsi_print_command(scmd);
+ if (megasas_dbg_lvl & TM_DEBUG)
+ megasas_dump_fusion_io(scmd);
return ret;
}
@@ -4470,9 +4697,6 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
instance = (struct megasas_instance *)scmd->device->host->hostdata;
- sdev_printk(KERN_INFO, scmd->device,
- "target reset called for scmd(%p)\n", scmd);
-
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);
@@ -4481,8 +4705,8 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
}
if (!mr_device_priv_data) {
- sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
- "scmd(%p)\n", scmd);
+ sdev_printk(KERN_INFO, scmd->device,
+ "device been deleted! scmd: (0x%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
ret = SUCCESS;
goto out;
@@ -4505,7 +4729,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
}
sdev_printk(KERN_INFO, scmd->device,
- "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n",
+ "attempting target reset! scmd(0x%p) tm_dev_handle: 0x%x\n",
scmd, devhandle);
mr_device_priv_data->tm_busy = 1;
ret = megasas_issue_tm(instance, devhandle,
@@ -4514,10 +4738,10 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
mr_device_priv_data);
mr_device_priv_data->tm_busy = 0;
mutex_unlock(&instance->reset_mutex);
-out:
- scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n",
+ scmd_printk(KERN_NOTICE, scmd, "target reset %s!!\n",
(ret == SUCCESS) ? "SUCCESS" : "FAILED");
+out:
return ret;
}
@@ -4562,12 +4786,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
struct megasas_instance *instance;
struct megasas_cmd_fusion *cmd_fusion, *r1_cmd;
struct fusion_context *fusion;
- u32 abs_state, status_reg, reset_adapter;
+ u32 abs_state, status_reg, reset_adapter, fpio_count = 0;
u32 io_timeout_in_crash_mode = 0;
struct scsi_cmnd *scmd_local = NULL;
struct scsi_device *sdev;
int ret_target_prop = DCMD_FAILED;
bool is_target_prop = false;
+ bool do_adp_reset = true;
+ int max_reset_tries = MEGASAS_FUSION_MAX_RESET_TRIES;
instance = (struct megasas_instance *)shost->hostdata;
fusion = instance->ctrl_context;
@@ -4634,7 +4860,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
if (convert)
reason = 0;
- if (megasas_dbg_lvl & OCR_LOGS)
+ if (megasas_dbg_lvl & OCR_DEBUG)
dev_info(&instance->pdev->dev, "\nPending SCSI commands:\n");
/* Now return commands back to the OS */
@@ -4647,13 +4873,17 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
}
scmd_local = cmd_fusion->scmd;
if (cmd_fusion->scmd) {
- if (megasas_dbg_lvl & OCR_LOGS) {
+ if (megasas_dbg_lvl & OCR_DEBUG) {
sdev_printk(KERN_INFO,
cmd_fusion->scmd->device, "SMID: 0x%x\n",
cmd_fusion->index);
- scsi_print_command(cmd_fusion->scmd);
+ megasas_dump_fusion_io(cmd_fusion->scmd);
}
+ if (cmd_fusion->io_request->Function ==
+ MPI2_FUNCTION_SCSI_IO_REQUEST)
+ fpio_count++;
+
scmd_local->result =
megasas_check_mpio_paths(instance,
scmd_local);
@@ -4666,6 +4896,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
}
}
+ dev_info(&instance->pdev->dev, "Outstanding fastpath IOs: %d\n",
+ fpio_count);
+
atomic_set(&instance->fw_outstanding, 0);
status_reg = instance->instancet->read_fw_status_reg(instance);
@@ -4677,52 +4910,45 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
dev_warn(&instance->pdev->dev, "Reset not supported"
", killing adapter scsi%d.\n",
instance->host->host_no);
- megaraid_sas_kill_hba(instance);
- instance->skip_heartbeat_timer_del = 1;
- retval = FAILED;
- goto out;
+ goto kill_hba;
}
/* Let SR-IOV VF & PF sync up if there was a HB failure */
if (instance->requestorId && !reason) {
msleep(MEGASAS_OCR_SETTLE_TIME_VF);
- goto transition_to_ready;
+ do_adp_reset = false;
+ max_reset_tries = MEGASAS_SRIOV_MAX_RESET_TRIES_VF;
}
/* Now try to reset the chip */
- for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
-
- if (instance->instancet->adp_reset
- (instance, instance->reg_set))
+ for (i = 0; i < max_reset_tries; i++) {
+ /*
+ * Do adp reset and wait for
+ * controller to transition to ready
+ */
+ if (megasas_adp_reset_wait_for_ready(instance,
+ do_adp_reset, 1) == FAILED)
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);
- if (instance->requestorId && !reason)
- goto fail_kill_adapter;
- else
- continue;
+ continue;
}
megasas_reset_reply_desc(instance);
megasas_fusion_update_can_queue(instance, OCR_CONTEXT);
if (megasas_ioc_init_fusion(instance)) {
- if (instance->requestorId && !reason)
- goto fail_kill_adapter;
- else
- continue;
+ continue;
}
if (megasas_get_ctrl_info(instance)) {
dev_info(&instance->pdev->dev,
"Failed from %s %d\n",
__func__, __LINE__);
- megaraid_sas_kill_hba(instance);
- retval = FAILED;
- goto out;
+ goto kill_hba;
}
megasas_refire_mgmt_cmd(instance);
@@ -4751,7 +4977,7 @@ transition_to_ready:
clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags);
instance->instancet->enable_intr(instance);
-
+ megasas_enable_irq_poll(instance);
shost_for_each_device(sdev, shost) {
if ((instance->tgt_prop) &&
(instance->nvme_page_size))
@@ -4763,9 +4989,9 @@ transition_to_ready:
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
- dev_info(&instance->pdev->dev, "Interrupts are enabled and"
- " controller is OPERATIONAL for scsi:%d\n",
- instance->host->host_no);
+ dev_info(&instance->pdev->dev,
+ "Adapter is OPERATIONAL for scsi:%d\n",
+ instance->host->host_no);
/* Restart SR-IOV heartbeat */
if (instance->requestorId) {
@@ -4799,13 +5025,10 @@ transition_to_ready:
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);
- megaraid_sas_kill_hba(instance);
- instance->skip_heartbeat_timer_del = 1;
- retval = FAILED;
+ goto kill_hba;
} else {
/* For VF: Restart HB timer if we didn't OCR */
if (instance->requestorId) {
@@ -4813,8 +5036,15 @@ fail_kill_adapter:
}
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
instance->instancet->enable_intr(instance);
+ megasas_enable_irq_poll(instance);
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
+ goto out;
}
+kill_hba:
+ megaraid_sas_kill_hba(instance);
+ megasas_enable_irq_poll(instance);
+ instance->skip_heartbeat_timer_del = 1;
+ retval = FAILED;
out:
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
mutex_unlock(&instance->reset_mutex);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 1481bf029490..c013c80fe4e6 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
@@ -5,19 +6,6 @@
* Copyright (c) 2013-2016 Avago Technologies
* Copyright (c) 2016-2018 Broadcom Inc.
*
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
* FILE: megaraid_sas_fusion.h
*
* Authors: Broadcom Inc.
@@ -87,7 +75,8 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
MR_RAID_FLAGS_IO_SUB_TYPE_RMW_P = 3,
MR_RAID_FLAGS_IO_SUB_TYPE_RMW_Q = 4,
MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS = 6,
- MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7
+ MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7,
+ MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD = 8
};
/*
@@ -100,7 +89,6 @@ 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 RAID_1_PEER_CMDS 2
#define JBOD_MAPS_COUNT 2
#define MEGASAS_REDUCE_QD_COUNT 64
@@ -152,12 +140,15 @@ struct RAID_CONTEXT_G35 {
u16 timeout_value; /* 0x02 -0x03 */
u16 routing_flags; // 0x04 -0x05 routing flags
u16 virtual_disk_tgt_id; /* 0x06 -0x07 */
- u64 reg_lock_row_lba; /* 0x08 - 0x0F */
+ __le64 reg_lock_row_lba; /* 0x08 - 0x0F */
u32 reg_lock_length; /* 0x10 - 0x13 */
- union {
- u16 next_lmid; /* 0x14 - 0x15 */
- u16 peer_smid; /* used for the raid 1/10 fp writes */
- } smid;
+ union { // flow specific
+ u16 rmw_op_index; /* 0x14 - 0x15, R5/6 RMW: rmw operation index*/
+ u16 peer_smid; /* 0x14 - 0x15, R1 Write: peer smid*/
+ u16 r56_arm_map; /* 0x14 - 0x15, Unused [15], LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */
+
+ } flow_specific;
+
u8 ex_status; /* 0x16 : OUT */
u8 status; /* 0x17 status */
u8 raid_flags; /* 0x18 resvd[7:6], ioSubType[5:4],
@@ -248,6 +239,13 @@ union RAID_CONTEXT_UNION {
#define RAID_CTX_SPANARM_SPAN_SHIFT (5)
#define RAID_CTX_SPANARM_SPAN_MASK (0xE0)
+/* LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */
+#define RAID_CTX_R56_Q_ARM_MASK (0x1F)
+#define RAID_CTX_R56_P_ARM_SHIFT (5)
+#define RAID_CTX_R56_P_ARM_MASK (0x3E0)
+#define RAID_CTX_R56_LOG_ARM_SHIFT (10)
+#define RAID_CTX_R56_LOG_ARM_MASK (0x7C00)
+
/* number of bits per index in U32 TrackStream */
#define BITS_PER_INDEX_STREAM 4
#define INVALID_STREAM_NUM 16
@@ -952,6 +950,7 @@ struct IO_REQUEST_INFO {
u8 pd_after_lb;
u16 r1_alt_dev_handle; /* raid 1/10 only */
bool ra_capable;
+ u8 data_arms;
};
struct MR_LD_TARGET_SYNC {
@@ -1336,7 +1335,8 @@ struct fusion_context {
dma_addr_t ioc_init_request_phys;
struct MPI2_IOC_INIT_REQUEST *ioc_init_request;
struct megasas_cmd *ioc_init_cmd;
-
+ bool pcie_bw_limitation;
+ bool r56_div_offload;
};
union desc_value {
@@ -1361,6 +1361,11 @@ struct MR_SNAPDUMP_PROPERTIES {
u8 reserved[12];
};
+struct megasas_debugfs_buffer {
+ void *buf;
+ u32 len;
+};
+
void megasas_free_cmds_fusion(struct megasas_instance *instance);
int megasas_ioc_init_fusion(struct megasas_instance *instance);
u8 megasas_get_map_info(struct megasas_instance *instance);
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index c9dc7740e9e7..74fb50644678 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware)
* bus adaptor found on Power Macintosh computers.
diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig
index b736dbc80485..a072187875df 100644
--- a/drivers/scsi/mpt3sas/Kconfig
+++ b/drivers/scsi/mpt3sas/Kconfig
@@ -45,6 +45,7 @@ config SCSI_MPT3SAS
depends on PCI && SCSI
select SCSI_SAS_ATTRS
select RAID_ATTRS
+ select IRQ_POLL
---help---
This driver supports PCI-Express SAS 12Gb/s Host Adapters.
diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
index a2f4a55c51be..167d79d145ca 100644
--- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
@@ -1398,7 +1398,7 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_1 {
U8 PCIBusNum; /*0x0E */
U8 PCIDomainSegment; /*0x0F */
U32 Reserved1; /*0x10 */
- U32 Reserved2; /*0x14 */
+ U32 ProductSpecific; /* 0x14 */
} MPI2_CONFIG_PAGE_IOC_1,
*PTR_MPI2_CONFIG_PAGE_IOC_1,
Mpi2IOCPage1_t, *pMpi2IOCPage1_t;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 1d8c584ec1e9..684662888792 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -74,30 +74,55 @@ static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
#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_param(max_queue_depth, int, 0444);
MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
static int max_sgl_entries = -1;
-module_param(max_sgl_entries, int, 0);
+module_param(max_sgl_entries, int, 0444);
MODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
static int msix_disable = -1;
-module_param(msix_disable, int, 0);
+module_param(msix_disable, int, 0444);
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_param(smp_affinity_enable, int, 0444);
MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)");
static int max_msix_vectors = -1;
-module_param(max_msix_vectors, int, 0);
+module_param(max_msix_vectors, int, 0444);
MODULE_PARM_DESC(max_msix_vectors,
" max msix vectors");
+static int irqpoll_weight = -1;
+module_param(irqpoll_weight, int, 0444);
+MODULE_PARM_DESC(irqpoll_weight,
+ "irq poll weight (default= one fourth of HBA queue depth)");
+
static int mpt3sas_fwfault_debug;
MODULE_PARM_DESC(mpt3sas_fwfault_debug,
" enable detection of firmware fault and halt firmware - (default=0)");
+static int perf_mode = -1;
+module_param(perf_mode, int, 0444);
+MODULE_PARM_DESC(perf_mode,
+ "Performance mode (only for Aero/Sea Generation), options:\n\t\t"
+ "0 - balanced: high iops mode is enabled &\n\t\t"
+ "interrupt coalescing is enabled only on high iops queues,\n\t\t"
+ "1 - iops: high iops mode is disabled &\n\t\t"
+ "interrupt coalescing is enabled on all queues,\n\t\t"
+ "2 - latency: high iops mode is disabled &\n\t\t"
+ "interrupt coalescing is enabled on all queues with timeout value 0xA,\n"
+ "\t\tdefault - default perf_mode is 'balanced'"
+ );
+
+enum mpt3sas_perf_mode {
+ MPT_PERF_MODE_DEFAULT = -1,
+ MPT_PERF_MODE_BALANCED = 0,
+ MPT_PERF_MODE_IOPS = 1,
+ MPT_PERF_MODE_LATENCY = 2,
+};
+
static int
_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc);
@@ -1277,7 +1302,7 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
ack_request->EventContext = mpi_reply->EventContext;
ack_request->VF_ID = 0; /* TODO */
ack_request->VP_ID = 0;
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
out:
@@ -1382,20 +1407,30 @@ union reply_descriptor {
} u;
};
+static u32 base_mod64(u64 dividend, u32 divisor)
+{
+ u32 remainder;
+
+ if (!divisor)
+ pr_err("mpt3sas: DIVISOR is zero, in div fn\n");
+ remainder = do_div(dividend, divisor);
+ return remainder;
+}
+
/**
- * _base_interrupt - MPT adapter (IOC) specific interrupt handler.
- * @irq: irq number (not used)
- * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ * _base_process_reply_queue - Process reply descriptors from reply
+ * descriptor post queue.
+ * @reply_q: per IRQ's reply queue object.
*
- * Return: IRQ_HANDLED if processed, else IRQ_NONE.
+ * Return: number of reply descriptors processed from reply
+ * descriptor queue.
*/
-static irqreturn_t
-_base_interrupt(int irq, void *bus_id)
+static int
+_base_process_reply_queue(struct adapter_reply_queue *reply_q)
{
- struct adapter_reply_queue *reply_q = bus_id;
union reply_descriptor rd;
- u32 completed_cmds;
- u8 request_desript_type;
+ u64 completed_cmds;
+ u8 request_descript_type;
u16 smid;
u8 cb_idx;
u32 reply;
@@ -1404,21 +1439,18 @@ _base_interrupt(int irq, void *bus_id)
Mpi2ReplyDescriptorsUnion_t *rpf;
u8 rc;
- if (ioc->mask_interrupts)
- return IRQ_NONE;
-
+ completed_cmds = 0;
if (!atomic_add_unless(&reply_q->busy, 1, 1))
- return IRQ_NONE;
+ return completed_cmds;
rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index];
- request_desript_type = rpf->Default.ReplyFlags
+ request_descript_type = rpf->Default.ReplyFlags
& MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
- if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
+ if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
atomic_dec(&reply_q->busy);
- return IRQ_NONE;
+ return completed_cmds;
}
- completed_cmds = 0;
cb_idx = 0xFF;
do {
rd.word = le64_to_cpu(rpf->Words);
@@ -1426,11 +1458,11 @@ _base_interrupt(int irq, void *bus_id)
goto out;
reply = 0;
smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
- if (request_desript_type ==
+ if (request_descript_type ==
MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS ||
- request_desript_type ==
+ request_descript_type ==
MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS ||
- request_desript_type ==
+ request_descript_type ==
MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS) {
cb_idx = _base_get_cb_idx(ioc, smid);
if ((likely(cb_idx < MPT_MAX_CALLBACKS)) &&
@@ -1440,7 +1472,7 @@ _base_interrupt(int irq, void *bus_id)
if (rc)
mpt3sas_base_free_smid(ioc, smid);
}
- } else if (request_desript_type ==
+ } else if (request_descript_type ==
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
reply = le32_to_cpu(
rpf->AddressReply.ReplyFrameAddress);
@@ -1486,7 +1518,7 @@ _base_interrupt(int irq, void *bus_id)
(reply_q->reply_post_host_index ==
(ioc->reply_post_queue_depth - 1)) ? 0 :
reply_q->reply_post_host_index + 1;
- request_desript_type =
+ request_descript_type =
reply_q->reply_post_free[reply_q->reply_post_host_index].
Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
completed_cmds++;
@@ -1495,7 +1527,7 @@ _base_interrupt(int irq, void *bus_id)
* So that FW can find enough entries to post the Reply
* Descriptors in the reply descriptor post queue.
*/
- if (completed_cmds > ioc->hba_queue_depth/3) {
+ if (!base_mod64(completed_cmds, ioc->thresh_hold)) {
if (ioc->combined_reply_queue) {
writel(reply_q->reply_post_host_index |
((msix_index & 7) <<
@@ -1507,9 +1539,14 @@ _base_interrupt(int irq, void *bus_id)
MPI2_RPHI_MSIX_INDEX_SHIFT),
&ioc->chip->ReplyPostHostIndex);
}
- completed_cmds = 1;
+ if (!reply_q->irq_poll_scheduled) {
+ reply_q->irq_poll_scheduled = true;
+ irq_poll_sched(&reply_q->irqpoll);
+ }
+ atomic_dec(&reply_q->busy);
+ return completed_cmds;
}
- if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+ if (request_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
goto out;
if (!reply_q->reply_post_host_index)
rpf = reply_q->reply_post_free;
@@ -1521,14 +1558,14 @@ _base_interrupt(int irq, void *bus_id)
if (!completed_cmds) {
atomic_dec(&reply_q->busy);
- return IRQ_NONE;
+ return completed_cmds;
}
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;
+ return completed_cmds;
}
/* Update Reply Post Host Index.
@@ -1555,7 +1592,82 @@ _base_interrupt(int irq, void *bus_id)
MPI2_RPHI_MSIX_INDEX_SHIFT),
&ioc->chip->ReplyPostHostIndex);
atomic_dec(&reply_q->busy);
- return IRQ_HANDLED;
+ return completed_cmds;
+}
+
+/**
+ * _base_interrupt - MPT adapter (IOC) specific interrupt handler.
+ * @irq: irq number (not used)
+ * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
+ *
+ * Return: IRQ_HANDLED if processed, else IRQ_NONE.
+ */
+static irqreturn_t
+_base_interrupt(int irq, void *bus_id)
+{
+ struct adapter_reply_queue *reply_q = bus_id;
+ struct MPT3SAS_ADAPTER *ioc = reply_q->ioc;
+
+ if (ioc->mask_interrupts)
+ return IRQ_NONE;
+ if (reply_q->irq_poll_scheduled)
+ return IRQ_HANDLED;
+ return ((_base_process_reply_queue(reply_q) > 0) ?
+ IRQ_HANDLED : IRQ_NONE);
+}
+
+/**
+ * _base_irqpoll - IRQ poll callback handler
+ * @irqpoll - irq_poll object
+ * @budget - irq poll weight
+ *
+ * returns number of reply descriptors processed
+ */
+static int
+_base_irqpoll(struct irq_poll *irqpoll, int budget)
+{
+ struct adapter_reply_queue *reply_q;
+ int num_entries = 0;
+
+ reply_q = container_of(irqpoll, struct adapter_reply_queue,
+ irqpoll);
+ if (reply_q->irq_line_enable) {
+ disable_irq(reply_q->os_irq);
+ reply_q->irq_line_enable = false;
+ }
+ num_entries = _base_process_reply_queue(reply_q);
+ if (num_entries < budget) {
+ irq_poll_complete(irqpoll);
+ reply_q->irq_poll_scheduled = false;
+ reply_q->irq_line_enable = true;
+ enable_irq(reply_q->os_irq);
+ }
+
+ return num_entries;
+}
+
+/**
+ * _base_init_irqpolls - initliaze IRQ polls
+ * @ioc: per adapter object
+ *
+ * returns nothing
+ */
+static void
+_base_init_irqpolls(struct MPT3SAS_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) {
+ irq_poll_init(&reply_q->irqpoll,
+ ioc->hba_queue_depth/4, _base_irqpoll);
+ reply_q->irq_poll_scheduled = false;
+ reply_q->irq_line_enable = true;
+ reply_q->os_irq = pci_irq_vector(ioc->pdev,
+ reply_q->msix_index);
+ }
}
/**
@@ -1596,6 +1708,17 @@ mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc)
/* TMs are on msix_index == 0 */
if (reply_q->msix_index == 0)
continue;
+ if (reply_q->irq_poll_scheduled) {
+ /* Calling irq_poll_disable will wait for any pending
+ * callbacks to have completed.
+ */
+ irq_poll_disable(&reply_q->irqpoll);
+ irq_poll_enable(&reply_q->irqpoll);
+ reply_q->irq_poll_scheduled = false;
+ reply_q->irq_line_enable = true;
+ enable_irq(reply_q->os_irq);
+ continue;
+ }
synchronize_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index));
}
}
@@ -2690,6 +2813,9 @@ _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);
+ if (ioc->smp_affinity_enable)
+ irq_set_affinity_hint(pci_irq_vector(ioc->pdev,
+ reply_q->msix_index), NULL);
free_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index),
reply_q);
kfree(reply_q);
@@ -2754,10 +2880,14 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
{
unsigned int cpu, nr_cpus, nr_msix, index = 0;
struct adapter_reply_queue *reply_q;
+ int local_numa_node;
if (!_base_is_controller_msix_enabled(ioc))
return;
+ if (ioc->msix_load_balance)
+ return;
+
memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz);
nr_cpus = num_online_cpus();
@@ -2766,14 +2896,33 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
if (!nr_msix)
return;
- if (smp_affinity_enable) {
+ if (ioc->smp_affinity_enable) {
+
+ /*
+ * set irq affinity to local numa node for those irqs
+ * corresponding to high iops queues.
+ */
+ if (ioc->high_iops_queues) {
+ local_numa_node = dev_to_node(&ioc->pdev->dev);
+ for (index = 0; index < ioc->high_iops_queues;
+ index++) {
+ irq_set_affinity_hint(pci_irq_vector(ioc->pdev,
+ index), cpumask_of_node(local_numa_node));
+ }
+ }
+
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
- const cpumask_t *mask = pci_irq_get_affinity(ioc->pdev,
- reply_q->msix_index);
+ const cpumask_t *mask;
+
+ if (reply_q->msix_index < ioc->high_iops_queues)
+ continue;
+
+ mask = pci_irq_get_affinity(ioc->pdev,
+ reply_q->msix_index);
if (!mask) {
ioc_warn(ioc, "no affinity for msi %x\n",
reply_q->msix_index);
- continue;
+ goto fall_back;
}
for_each_cpu_and(cpu, mask, cpu_online_mask) {
@@ -2784,12 +2933,18 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
}
return;
}
+
+fall_back:
cpu = cpumask_first(cpu_online_mask);
+ nr_msix -= ioc->high_iops_queues;
+ index = 0;
list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-
unsigned int i, group = nr_cpus / nr_msix;
+ if (reply_q->msix_index < ioc->high_iops_queues)
+ continue;
+
if (cpu >= nr_cpus)
break;
@@ -2805,6 +2960,52 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
}
/**
+ * _base_check_and_enable_high_iops_queues - enable high iops mode
+ * @ ioc - per adapter object
+ * @ hba_msix_vector_count - msix vectors supported by HBA
+ *
+ * Enable high iops queues only if
+ * - HBA is a SEA/AERO controller and
+ * - MSI-Xs vector supported by the HBA is 128 and
+ * - total CPU count in the system >=16 and
+ * - loaded driver with default max_msix_vectors module parameter and
+ * - system booted in non kdump mode
+ *
+ * returns nothing.
+ */
+static void
+_base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc,
+ int hba_msix_vector_count)
+{
+ u16 lnksta, speed;
+
+ if (perf_mode == MPT_PERF_MODE_IOPS ||
+ perf_mode == MPT_PERF_MODE_LATENCY) {
+ ioc->high_iops_queues = 0;
+ return;
+ }
+
+ if (perf_mode == MPT_PERF_MODE_DEFAULT) {
+
+ pcie_capability_read_word(ioc->pdev, PCI_EXP_LNKSTA, &lnksta);
+ speed = lnksta & PCI_EXP_LNKSTA_CLS;
+
+ if (speed < 0x4) {
+ ioc->high_iops_queues = 0;
+ return;
+ }
+ }
+
+ if (!reset_devices && ioc->is_aero_ioc &&
+ hba_msix_vector_count == MPT3SAS_GEN35_MAX_MSIX_QUEUES &&
+ num_online_cpus() >= MPT3SAS_HIGH_IOPS_REPLY_QUEUES &&
+ max_msix_vectors == -1)
+ ioc->high_iops_queues = MPT3SAS_HIGH_IOPS_REPLY_QUEUES;
+ else
+ ioc->high_iops_queues = 0;
+}
+
+/**
* _base_disable_msix - disables msix
* @ioc: per adapter object
*
@@ -2814,11 +3015,38 @@ _base_disable_msix(struct MPT3SAS_ADAPTER *ioc)
{
if (!ioc->msix_enable)
return;
- pci_disable_msix(ioc->pdev);
+ pci_free_irq_vectors(ioc->pdev);
ioc->msix_enable = 0;
}
/**
+ * _base_alloc_irq_vectors - allocate msix vectors
+ * @ioc: per adapter object
+ *
+ */
+static int
+_base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc)
+{
+ int i, irq_flags = PCI_IRQ_MSIX;
+ struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues };
+ struct irq_affinity *descp = &desc;
+
+ if (ioc->smp_affinity_enable)
+ irq_flags |= PCI_IRQ_AFFINITY;
+ else
+ descp = NULL;
+
+ ioc_info(ioc, " %d %d\n", ioc->high_iops_queues,
+ ioc->msix_vector_count);
+
+ i = pci_alloc_irq_vectors_affinity(ioc->pdev,
+ ioc->high_iops_queues,
+ ioc->msix_vector_count, irq_flags, descp);
+
+ return i;
+}
+
+/**
* _base_enable_msix - enables msix, failback to io_apic
* @ioc: per adapter object
*
@@ -2829,7 +3057,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
int r;
int i, local_max_msix_vectors;
u8 try_msix = 0;
- unsigned int irq_flags = PCI_IRQ_MSIX;
+
+ ioc->msix_load_balance = false;
if (msix_disable == -1 || msix_disable == 0)
try_msix = 1;
@@ -2840,12 +3069,16 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
if (_base_check_enable_msix(ioc) != 0)
goto try_ioapic;
- ioc->reply_queue_count = min_t(int, ioc->cpu_count,
+ ioc_info(ioc, "MSI-X vectors supported: %d\n", ioc->msix_vector_count);
+ pr_info("\t no of cores: %d, max_msix_vectors: %d\n",
+ ioc->cpu_count, max_msix_vectors);
+ if (ioc->is_aero_ioc)
+ _base_check_and_enable_high_iops_queues(ioc,
+ ioc->msix_vector_count);
+ ioc->reply_queue_count =
+ min_t(int, ioc->cpu_count + ioc->high_iops_queues,
ioc->msix_vector_count);
- ioc_info(ioc, "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n",
- ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors);
-
if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
local_max_msix_vectors = (reset_devices) ? 1 : 8;
else
@@ -2857,14 +3090,23 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
else if (local_max_msix_vectors == 0)
goto try_ioapic;
- if (ioc->msix_vector_count < ioc->cpu_count)
- smp_affinity_enable = 0;
+ /*
+ * Enable msix_load_balance only if combined reply queue mode is
+ * disabled on SAS3 & above generation HBA devices.
+ */
+ if (!ioc->combined_reply_queue &&
+ ioc->hba_mpi_version_belonged != MPI2_VERSION) {
+ ioc->msix_load_balance = true;
+ }
- if (smp_affinity_enable)
- irq_flags |= PCI_IRQ_AFFINITY;
+ /*
+ * smp affinity setting is not need when msix load balance
+ * is enabled.
+ */
+ if (ioc->msix_load_balance)
+ ioc->smp_affinity_enable = 0;
- r = pci_alloc_irq_vectors(ioc->pdev, 1, ioc->reply_queue_count,
- irq_flags);
+ r = _base_alloc_irq_vectors(ioc);
if (r < 0) {
dfailprintk(ioc,
ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n",
@@ -2883,11 +3125,15 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
}
}
+ ioc_info(ioc, "High IOPs queues : %s\n",
+ ioc->high_iops_queues ? "enabled" : "disabled");
+
return 0;
/* failback to io_apic interrupt routing */
try_ioapic:
-
+ ioc->high_iops_queues = 0;
+ ioc_info(ioc, "High IOPs queues : disabled\n");
ioc->reply_queue_count = 1;
r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY);
if (r < 0) {
@@ -3015,6 +3261,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
if (r)
goto out_fail;
+ if (!ioc->is_driver_loading)
+ _base_init_irqpolls(ioc);
/* Use the Combined reply queue feature only for SAS3 C0 & higher
* revision HBAs and also only when reply queue count is greater than 8
*/
@@ -3155,13 +3403,58 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr)
return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
}
+/**
+ * _base_get_msix_index - get the msix index
+ * @ioc: per adapter object
+ * @scmd: scsi_cmnd object
+ *
+ * returns msix index of general reply queues,
+ * i.e. reply queue on which IO request's reply
+ * should be posted by the HBA firmware.
+ */
static inline u8
-_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc)
+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_cmnd *scmd)
{
+ /* Enables reply_queue load balancing */
+ if (ioc->msix_load_balance)
+ return ioc->reply_queue_count ?
+ base_mod64(atomic64_add_return(1,
+ &ioc->total_io_cnt), ioc->reply_queue_count) : 0;
+
return ioc->cpu_msix_table[raw_smp_processor_id()];
}
/**
+ * _base_get_high_iops_msix_index - get the msix index of
+ * high iops queues
+ * @ioc: per adapter object
+ * @scmd: scsi_cmnd object
+ *
+ * Returns: msix index of high iops reply queues.
+ * i.e. high iops reply queue on which IO request's
+ * reply should be posted by the HBA firmware.
+ */
+static inline u8
+_base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_cmnd *scmd)
+{
+ /**
+ * Round robin the IO interrupts among the high iops
+ * reply queues in terms of batch count 16 when outstanding
+ * IOs on the target device is >=8.
+ */
+ if (atomic_read(&scmd->device->device_busy) >
+ MPT3SAS_DEVICE_HIGH_IOPS_DEPTH)
+ return base_mod64((
+ atomic64_add_return(1, &ioc->high_iops_outstanding) /
+ MPT3SAS_HIGH_IOPS_BATCH_COUNT),
+ MPT3SAS_HIGH_IOPS_REPLY_QUEUES);
+
+ return _base_get_msix_index(ioc, scmd);
+}
+
+/**
* mpt3sas_base_get_smid - obtain a free smid from internal queue
* @ioc: per adapter object
* @cb_idx: callback index
@@ -3209,8 +3502,8 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
smid = tag + 1;
request->cb_idx = cb_idx;
- request->msix_io = _base_get_msix_index(ioc);
request->smid = smid;
+ request->scmd = scmd;
INIT_LIST_HEAD(&request->chain_list);
return smid;
}
@@ -3264,6 +3557,7 @@ void mpt3sas_base_clear_st(struct MPT3SAS_ADAPTER *ioc,
return;
st->cb_idx = 0xFF;
st->direct_io = 0;
+ st->scmd = NULL;
atomic_set(&ioc->chain_lookup[st->smid - 1].chain_offset, 0);
st->smid = 0;
}
@@ -3333,7 +3627,6 @@ _base_mpi_ep_writeq(__u64 b, volatile void __iomem *addr,
spin_lock_irqsave(writeq_lock, flags);
__raw_writel((u32)(b), addr);
__raw_writel((u32)(b >> 32), (addr + 4));
- mmiowb();
spin_unlock_irqrestore(writeq_lock, flags);
}
@@ -3364,13 +3657,37 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
#endif
/**
+ * _base_set_and_get_msix_index - get the msix index and assign to msix_io
+ * variable of scsi tracker
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * returns msix index.
+ */
+static u8
+_base_set_and_get_msix_index(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+ struct scsiio_tracker *st = NULL;
+
+ if (smid < ioc->hi_priority_smid)
+ st = _get_st_from_smid(ioc, smid);
+
+ if (st == NULL)
+ return _base_get_msix_index(ioc, NULL);
+
+ st->msix_io = ioc->get_msix_index_for_smlio(ioc, st->scmd);
+ return st->msix_io;
+}
+
+/**
* _base_put_smid_mpi_ep_scsi_io - send SCSI_IO request to firmware
* @ioc: per adapter object
* @smid: system request message index
* @handle: device handle
*/
static void
-_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
+_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc,
+ u16 smid, u16 handle)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
@@ -3383,7 +3700,7 @@ _base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
_base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp,
ioc->request_sz);
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
- descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
descriptor.SCSIIO.LMID = 0;
@@ -3405,7 +3722,7 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
- descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
descriptor.SCSIIO.LMID = 0;
@@ -3414,13 +3731,13 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
}
/**
- * mpt3sas_base_put_smid_fast_path - send fast path request to firmware
+ * _base_put_smid_fast_path - send fast path request to firmware
* @ioc: per adapter object
* @smid: system request message index
* @handle: device handle
*/
-void
-mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+static void
+_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 handle)
{
Mpi2RequestDescriptorUnion_t descriptor;
@@ -3428,7 +3745,7 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
descriptor.SCSIIO.RequestFlags =
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
- descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
descriptor.SCSIIO.LMID = 0;
@@ -3437,13 +3754,13 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
}
/**
- * mpt3sas_base_put_smid_hi_priority - send Task Management request to firmware
+ * _base_put_smid_hi_priority - send Task Management 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.
*/
-void
-mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+static void
+_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 msix_task)
{
Mpi2RequestDescriptorUnion_t descriptor;
@@ -3492,7 +3809,7 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
descriptor.Default.RequestFlags =
MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
- descriptor.Default.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.Default.SMID = cpu_to_le16(smid);
descriptor.Default.LMID = 0;
descriptor.Default.DescriptorTypeDependent = 0;
@@ -3501,12 +3818,12 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
/**
- * mpt3sas_base_put_smid_default - Default, primarily used for config pages
+ * _base_put_smid_default - Default, primarily used for config pages
* @ioc: per adapter object
* @smid: system request message index
*/
-void
-mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+static void
+_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
{
Mpi2RequestDescriptorUnion_t descriptor;
void *mpi_req_iomem;
@@ -3524,7 +3841,7 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
request = (u64 *)&descriptor;
descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- descriptor.Default.MSIxIndex = _base_get_msix_index(ioc);
+ descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.Default.SMID = cpu_to_le16(smid);
descriptor.Default.LMID = 0;
descriptor.Default.DescriptorTypeDependent = 0;
@@ -3538,6 +3855,95 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
/**
+ * _base_put_smid_scsi_io_atomic - send SCSI_IO request to firmware using
+ * Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle, unused in this function, for function type match
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+ u16 handle)
+{
+ Mpi26AtomicRequestDescriptor_t descriptor;
+ u32 *request = (u32 *)&descriptor;
+
+ descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+ descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+ descriptor.SMID = cpu_to_le16(smid);
+
+ writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_fast_path_atomic - send fast path request to firmware
+ * using Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @handle: device handle, unused in this function, for function type match
+ * Return nothing
+ */
+static void
+_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+ u16 handle)
+{
+ Mpi26AtomicRequestDescriptor_t descriptor;
+ u32 *request = (u32 *)&descriptor;
+
+ descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
+ descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+ descriptor.SMID = cpu_to_le16(smid);
+
+ writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_hi_priority_atomic - send Task Management request to
+ * firmware using Atomic Request Descriptor
+ * @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.
+ */
+static void
+_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+ u16 msix_task)
+{
+ Mpi26AtomicRequestDescriptor_t descriptor;
+ u32 *request = (u32 *)&descriptor;
+
+ descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
+ descriptor.MSIxIndex = msix_task;
+ descriptor.SMID = cpu_to_le16(smid);
+
+ writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
+ * _base_put_smid_default - Default, primarily used for config pages
+ * use Atomic Request Descriptor
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+ Mpi26AtomicRequestDescriptor_t descriptor;
+ u32 *request = (u32 *)&descriptor;
+
+ descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
+ descriptor.SMID = cpu_to_le16(smid);
+
+ writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+}
+
+/**
* _base_display_OEMs_branding - Display branding string
* @ioc: per adapter object
*/
@@ -3837,7 +4243,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
ioc->build_sg(ioc, &mpi_request->SGL, 0, 0, fwpkg_data_dma,
data_length);
init_completion(&ioc->base_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
/* Wait for 15 seconds */
wait_for_completion_timeout(&ioc->base_cmds.done,
FW_IMG_HDR_READ_TIMEOUT*HZ);
@@ -4077,6 +4483,71 @@ out:
}
/**
+ * _base_update_ioc_page1_inlinewith_perf_mode - Update IOC Page1 fields
+ * according to performance mode.
+ * @ioc : per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc)
+{
+ Mpi2IOCPage1_t ioc_pg1;
+ Mpi2ConfigReply_t mpi_reply;
+
+ mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy);
+ memcpy(&ioc_pg1, &ioc->ioc_pg1_copy, sizeof(Mpi2IOCPage1_t));
+
+ switch (perf_mode) {
+ case MPT_PERF_MODE_DEFAULT:
+ case MPT_PERF_MODE_BALANCED:
+ if (ioc->high_iops_queues) {
+ ioc_info(ioc,
+ "Enable interrupt coalescing only for first\t"
+ "%d reply queues\n",
+ MPT3SAS_HIGH_IOPS_REPLY_QUEUES);
+ /*
+ * If 31st bit is zero then interrupt coalescing is
+ * enabled for all reply descriptor post queues.
+ * If 31st bit is set to one then user can
+ * enable/disable interrupt coalescing on per reply
+ * descriptor post queue group(8) basis. So to enable
+ * interrupt coalescing only on first reply descriptor
+ * post queue group 31st bit and zero th bit is enabled.
+ */
+ ioc_pg1.ProductSpecific = cpu_to_le32(0x80000000 |
+ ((1 << MPT3SAS_HIGH_IOPS_REPLY_QUEUES/8) - 1));
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ ioc_info(ioc, "performance mode: balanced\n");
+ return;
+ }
+ /* Fall through */
+ case MPT_PERF_MODE_LATENCY:
+ /*
+ * Enable interrupt coalescing on all reply queues
+ * with timeout value 0xA
+ */
+ ioc_pg1.CoalescingTimeout = cpu_to_le32(0xa);
+ ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING);
+ ioc_pg1.ProductSpecific = 0;
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ ioc_info(ioc, "performance mode: latency\n");
+ break;
+ case MPT_PERF_MODE_IOPS:
+ /*
+ * Enable interrupt coalescing on all reply queues.
+ */
+ ioc_info(ioc,
+ "performance mode: iops with coalescing timeout: 0x%x\n",
+ le32_to_cpu(ioc_pg1.CoalescingTimeout));
+ ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING);
+ ioc_pg1.ProductSpecific = 0;
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1);
+ break;
+ }
+}
+
+/**
* _base_static_config_pages - static start of day config pages
* @ioc: per adapter object
*/
@@ -4143,6 +4614,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
if (ioc->iounit_pg8.NumSensors)
ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
+ if (ioc->is_aero_ioc)
+ _base_update_ioc_page1_inlinewith_perf_mode(ioc);
}
/**
@@ -5316,7 +5789,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
ioc->ioc_link_reset_in_progress = 1;
init_completion(&ioc->base_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
@@ -5395,7 +5868,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
ioc->base_cmds.smid = smid;
memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
init_completion(&ioc->base_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -5578,6 +6051,9 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
if ((facts->IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices))
ioc->rdpq_array_capable = 1;
+ if ((facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
+ && ioc->is_aero_ioc)
+ ioc->atomic_desc_capable = 1;
facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
facts->IOCRequestFrameSize =
le16_to_cpu(mpi_reply.IOCRequestFrameSize);
@@ -5799,7 +6275,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
init_completion(&ioc->port_enable_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ);
if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) {
ioc_err(ioc, "%s: timeout\n", __func__);
@@ -5858,7 +6334,7 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc)
memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
return 0;
}
@@ -5974,7 +6450,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
mpi_request->EventMasks[i] =
cpu_to_le32(ioc->event_masks[i]);
init_completion(&ioc->base_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
ioc_err(ioc, "%s: timeout\n", __func__);
@@ -6434,6 +6910,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
}
}
+ ioc->smp_affinity_enable = smp_affinity_enable;
+
ioc->rdpq_array_enable_assigned = 0;
ioc->dma_mask = 0;
if (ioc->is_aero_ioc)
@@ -6454,6 +6932,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
ioc->build_sg_scmd = &_base_build_sg_scmd;
ioc->build_sg = &_base_build_sg;
ioc->build_zero_len_sge = &_base_build_zero_len_sge;
+ ioc->get_msix_index_for_smlio = &_base_get_msix_index;
break;
case MPI25_VERSION:
case MPI26_VERSION:
@@ -6468,15 +6947,30 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
ioc->build_nvme_prp = &_base_build_nvme_prp;
ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
-
+ if (ioc->high_iops_queues)
+ ioc->get_msix_index_for_smlio =
+ &_base_get_high_iops_msix_index;
+ else
+ ioc->get_msix_index_for_smlio = &_base_get_msix_index;
break;
}
-
- if (ioc->is_mcpu_endpoint)
- ioc->put_smid_scsi_io = &_base_put_smid_mpi_ep_scsi_io;
- else
- ioc->put_smid_scsi_io = &_base_put_smid_scsi_io;
-
+ if (ioc->atomic_desc_capable) {
+ ioc->put_smid_default = &_base_put_smid_default_atomic;
+ ioc->put_smid_scsi_io = &_base_put_smid_scsi_io_atomic;
+ ioc->put_smid_fast_path =
+ &_base_put_smid_fast_path_atomic;
+ ioc->put_smid_hi_priority =
+ &_base_put_smid_hi_priority_atomic;
+ } else {
+ ioc->put_smid_default = &_base_put_smid_default;
+ ioc->put_smid_fast_path = &_base_put_smid_fast_path;
+ ioc->put_smid_hi_priority = &_base_put_smid_hi_priority;
+ if (ioc->is_mcpu_endpoint)
+ ioc->put_smid_scsi_io =
+ &_base_put_smid_mpi_ep_scsi_io;
+ else
+ ioc->put_smid_scsi_io = &_base_put_smid_scsi_io;
+ }
/*
* These function pointers for other requests that don't
* the require IEEE scatter gather elements.
@@ -6507,6 +7001,12 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
if (r)
goto out_free_resources;
+ if (irqpoll_weight > 0)
+ ioc->thresh_hold = irqpoll_weight;
+ else
+ ioc->thresh_hold = ioc->hba_queue_depth/4;
+
+ _base_init_irqpolls(ioc);
init_waitqueue_head(&ioc->reset_wq);
/* allocate memory pd handle bitmask list */
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 19158cb59101..6afbdb044310 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -67,6 +67,7 @@
#include <scsi/scsi_eh.h>
#include <linux/pci.h>
#include <linux/poll.h>
+#include <linux/irq_poll.h>
#include "mpt3sas_debug.h"
#include "mpt3sas_trigger_diag.h"
@@ -75,9 +76,9 @@
#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 "27.102.00.00"
-#define MPT3SAS_MAJOR_VERSION 27
-#define MPT3SAS_MINOR_VERSION 102
+#define MPT3SAS_DRIVER_VERSION "29.100.00.00"
+#define MPT3SAS_MAJOR_VERSION 29
+#define MPT3SAS_MINOR_VERSION 100
#define MPT3SAS_BUILD_VERSION 0
#define MPT3SAS_RELEASE_VERSION 00
@@ -354,6 +355,12 @@ struct mpt3sas_nvme_cmd {
#define VIRTUAL_IO_FAILED_RETRY (0x32010081)
+/* High IOPs definitions */
+#define MPT3SAS_DEVICE_HIGH_IOPS_DEPTH 8
+#define MPT3SAS_HIGH_IOPS_REPLY_QUEUES 8
+#define MPT3SAS_HIGH_IOPS_BATCH_COUNT 16
+#define MPT3SAS_GEN35_MAX_MSIX_QUEUES 128
+
/* OEM Specific Flags will come from OEM specific header files */
struct Mpi2ManufacturingPage10_t {
MPI2_CONFIG_PAGE_HEADER Header; /* 00h */
@@ -823,6 +830,7 @@ struct chain_lookup {
*/
struct scsiio_tracker {
u16 smid;
+ struct scsi_cmnd *scmd;
u8 cb_idx;
u8 direct_io;
struct pcie_sg_list pcie_sg_list;
@@ -882,6 +890,9 @@ struct _event_ack_list {
* @reply_post_free: reply post base virt address
* @name: the name registered to request_irq()
* @busy: isr is actively processing replies on another cpu
+ * @os_irq: irq number
+ * @irqpoll: irq_poll object
+ * @irq_poll_scheduled: Tells whether irq poll is scheduled or not
* @list: this list
*/
struct adapter_reply_queue {
@@ -891,6 +902,10 @@ struct adapter_reply_queue {
Mpi2ReplyDescriptorsUnion_t *reply_post_free;
char name[MPT_NAME_LENGTH];
atomic_t busy;
+ u32 os_irq;
+ struct irq_poll irqpoll;
+ bool irq_poll_scheduled;
+ bool irq_line_enable;
struct list_head list;
};
@@ -916,6 +931,12 @@ typedef void (*PUT_SMID_IO_FP_HIP) (struct MPT3SAS_ADAPTER *ioc, u16 smid,
u16 funcdep);
typedef void (*PUT_SMID_DEFAULT) (struct MPT3SAS_ADAPTER *ioc, u16 smid);
typedef u32 (*BASE_READ_REG) (const volatile void __iomem *addr);
+/*
+ * To get high iops reply queue's msix index when high iops mode is enabled
+ * else get the msix index of general reply queues.
+ */
+typedef u8 (*GET_MSIX_INDEX) (struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_cmnd *scmd);
/* IOC Facts and Port Facts converted from little endian to cpu */
union mpi3_version_union {
@@ -1016,7 +1037,14 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @msix_vector_count: number msix vectors
* @cpu_msix_table: table for mapping cpus to msix index
* @cpu_msix_table_sz: table size
+ * @total_io_cnt: Gives total IO count, used to load balance the interrupts
+ * @high_iops_outstanding: used to load balance the interrupts
+ * within high iops reply queues
+ * @msix_load_balance: Enables load balancing of interrupts across
+ * the multiple MSIXs
* @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands
+ * @thresh_hold: Max number of reply descriptors processed
+ * before updating Host Index
* @scsi_io_cb_idx: shost generated commands
* @tm_cb_idx: task management commands
* @scsih_cb_idx: scsih internal commands
@@ -1134,6 +1162,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* 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.
+ * @atomic_desc_capable: Atomic Request Descriptor support.
+ * @GET_MSIX_INDEX: Get the msix index of high iops queues.
*/
struct MPT3SAS_ADAPTER {
struct list_head list;
@@ -1192,6 +1222,11 @@ struct MPT3SAS_ADAPTER {
u32 ioc_reset_count;
MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
u32 non_operational_loop;
+ atomic64_t total_io_cnt;
+ atomic64_t high_iops_outstanding;
+ bool msix_load_balance;
+ u16 thresh_hold;
+ u8 high_iops_queues;
/* internal commands, callback index */
u8 scsi_io_cb_idx;
@@ -1251,6 +1286,7 @@ struct MPT3SAS_ADAPTER {
Mpi2IOUnitPage0_t iounit_pg0;
Mpi2IOUnitPage1_t iounit_pg1;
Mpi2IOUnitPage8_t iounit_pg8;
+ Mpi2IOCPage1_t ioc_pg1_copy;
struct _boot_device req_boot_device;
struct _boot_device req_alt_boot_device;
@@ -1369,6 +1405,7 @@ struct MPT3SAS_ADAPTER {
u8 combined_reply_queue;
u8 combined_reply_index_count;
+ u8 smp_affinity_enable;
/* reply post register index */
resource_size_t **replyPostRegisterIndex;
@@ -1396,6 +1433,7 @@ struct MPT3SAS_ADAPTER {
u8 hide_drives;
spinlock_t diag_trigger_lock;
u8 diag_trigger_active;
+ u8 atomic_desc_capable;
BASE_READ_REG base_readl;
struct SL_WH_MASTER_TRIGGER_T diag_trigger_master;
struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event;
@@ -1406,7 +1444,10 @@ struct MPT3SAS_ADAPTER {
u8 is_gen35_ioc;
u8 is_aero_ioc;
PUT_SMID_IO_FP_HIP put_smid_scsi_io;
-
+ PUT_SMID_IO_FP_HIP put_smid_fast_path;
+ PUT_SMID_IO_FP_HIP put_smid_hi_priority;
+ PUT_SMID_DEFAULT put_smid_default;
+ GET_MSIX_INDEX get_msix_index_for_smlio;
};
typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
@@ -1595,6 +1636,10 @@ int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
int mpt3sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page,
u16 sz);
+int mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2IOCPage1_t *config_page);
+int mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2IOCPage1_t *config_page);
int mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOCPage8_t *config_page);
int mpt3sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc,
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index fb0a17252f86..14a1a2793dd5 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -380,7 +380,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
_config_display_some_debug(ioc, smid, "config_request", NULL);
init_completion(&ioc->config_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
mpt3sas_base_check_cmd_timeout(ioc,
@@ -949,6 +949,77 @@ mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc,
out:
return r;
}
+/**
+ * mpt3sas_config_get_ioc_pg1 - obtain ioc page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_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 = 1;
+ mpi_request.Header.PageVersion = MPI2_IOCPAGE8_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,
+ sizeof(*config_page));
+ out:
+ return r;
+}
+
+/**
+ * mpt3sas_config_set_ioc_pg1 - modify ioc page 1
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_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 = 1;
+ mpi_request.Header.PageVersion = MPI2_IOCPAGE8_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_WRITE_CURRENT;
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+ sizeof(*config_page));
+ out:
+ return r;
+}
/**
* mpt3sas_config_get_sas_device_pg0 - obtain sas device page 0
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index b2bb47c14d35..d4ecfbbe738c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -822,7 +822,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
ioc->put_smid_scsi_io(ioc, smid, device_handle);
else
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_SCSI_TASK_MGMT:
@@ -859,7 +859,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, 0);
+ ioc->put_smid_hi_priority(ioc, smid, 0);
break;
}
case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -890,7 +890,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
}
ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
data_in_sz);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_SATA_PASSTHROUGH:
@@ -905,7 +905,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
}
ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
data_in_sz);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_FW_DOWNLOAD:
@@ -913,7 +913,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
{
ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
data_in_sz);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_TOOLBOX:
@@ -928,7 +928,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
data_in_dma, data_in_sz);
}
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
@@ -948,7 +948,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
default:
ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
data_in_dma, data_in_sz);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
break;
}
@@ -1576,7 +1576,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
cpu_to_le32(ioc->product_specific[buffer_type][i]);
init_completion(&ioc->ctl_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -1903,7 +1903,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
mpi_request->VP_ID = 0;
init_completion(&ioc->ctl_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -2151,7 +2151,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
mpi_request->VP_ID = 0;
init_completion(&ioc->ctl_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -2319,6 +2319,10 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
break;
}
+ if (karg.hdr.ioc_number != ioctl_header.ioc_number) {
+ ret = -EINVAL;
+ break;
+ }
if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) {
uarg = arg;
ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);
@@ -2453,7 +2457,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
/* scsi host attributes */
/**
- * _ctl_version_fw_show - firmware version
+ * version_fw_show - firmware version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2461,7 +2465,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
+version_fw_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2473,10 +2477,10 @@ _ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
(ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
ioc->facts.FWVersion.Word & 0x000000FF);
}
-static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
+static DEVICE_ATTR_RO(version_fw);
/**
- * _ctl_version_bios_show - bios version
+ * version_bios_show - bios version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2484,7 +2488,7 @@ static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
+version_bios_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2498,10 +2502,10 @@ _ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
(version & 0x0000FF00) >> 8,
version & 0x000000FF);
}
-static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
+static DEVICE_ATTR_RO(version_bios);
/**
- * _ctl_version_mpi_show - MPI (message passing interface) version
+ * version_mpi_show - MPI (message passing interface) version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2509,7 +2513,7 @@ static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
+version_mpi_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2518,10 +2522,10 @@ _ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
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);
+static DEVICE_ATTR_RO(version_mpi);
/**
- * _ctl_version_product_show - product name
+ * version_product_show - product name
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2529,7 +2533,7 @@ static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
+version_product_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2537,10 +2541,10 @@ _ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName);
}
-static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL);
+static DEVICE_ATTR_RO(version_product);
/**
- * _ctl_version_nvdata_persistent_show - ndvata persistent version
+ * version_nvdata_persistent_show - ndvata persistent version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2548,7 +2552,7 @@ static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_nvdata_persistent_show(struct device *cdev,
+version_nvdata_persistent_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2557,11 +2561,10 @@ _ctl_version_nvdata_persistent_show(struct device *cdev,
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);
+static DEVICE_ATTR_RO(version_nvdata_persistent);
/**
- * _ctl_version_nvdata_default_show - nvdata default version
+ * version_nvdata_default_show - nvdata default version
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2569,7 +2572,7 @@ static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute
+version_nvdata_default_show(struct device *cdev, struct device_attribute
*attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2578,11 +2581,10 @@ _ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute
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);
+static DEVICE_ATTR_RO(version_nvdata_default);
/**
- * _ctl_board_name_show - board name
+ * board_name_show - board name
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2590,7 +2592,7 @@ static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
+board_name_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2598,10 +2600,10 @@ _ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName);
}
-static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
+static DEVICE_ATTR_RO(board_name);
/**
- * _ctl_board_assembly_show - board assembly name
+ * board_assembly_show - board assembly name
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2609,7 +2611,7 @@ static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
+board_assembly_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2617,10 +2619,10 @@ _ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly);
}
-static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL);
+static DEVICE_ATTR_RO(board_assembly);
/**
- * _ctl_board_tracer_show - board tracer number
+ * board_tracer_show - board tracer number
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2628,7 +2630,7 @@ static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
+board_tracer_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2636,10 +2638,10 @@ _ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber);
}
-static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL);
+static DEVICE_ATTR_RO(board_tracer);
/**
- * _ctl_io_delay_show - io missing delay
+ * io_delay_show - io missing delay
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2650,7 +2652,7 @@ static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
+io_delay_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2658,10 +2660,10 @@ _ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
}
-static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL);
+static DEVICE_ATTR_RO(io_delay);
/**
- * _ctl_device_delay_show - device missing delay
+ * device_delay_show - device missing delay
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2672,7 +2674,7 @@ static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
+device_delay_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2680,10 +2682,10 @@ _ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
}
-static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL);
+static DEVICE_ATTR_RO(device_delay);
/**
- * _ctl_fw_queue_depth_show - global credits
+ * fw_queue_depth_show - global credits
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2693,7 +2695,7 @@ static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
+fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2701,10 +2703,10 @@ _ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit);
}
-static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL);
+static DEVICE_ATTR_RO(fw_queue_depth);
/**
- * _ctl_sas_address_show - sas address
+ * sas_address_show - sas address
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2714,7 +2716,7 @@ static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
+host_sas_address_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
@@ -2724,11 +2726,10 @@ _ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
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);
+static DEVICE_ATTR_RO(host_sas_address);
/**
- * _ctl_logging_level_show - logging level
+ * logging_level_show - logging level
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2736,7 +2737,7 @@ static DEVICE_ATTR(host_sas_address, S_IRUGO,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
+logging_level_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2745,7 +2746,7 @@ _ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level);
}
static ssize_t
-_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
+logging_level_store(struct device *cdev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2760,11 +2761,10 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
ioc->logging_level);
return strlen(buf);
}
-static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show,
- _ctl_logging_level_store);
+static DEVICE_ATTR_RW(logging_level);
/**
- * _ctl_fwfault_debug_show - show/store fwfault_debug
+ * fwfault_debug_show - show/store fwfault_debug
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2773,7 +2773,7 @@ static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
+fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2782,7 +2782,7 @@ _ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug);
}
static ssize_t
-_ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
+fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2797,11 +2797,10 @@ _ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr,
ioc->fwfault_debug);
return strlen(buf);
}
-static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
- _ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
+static DEVICE_ATTR_RW(fwfault_debug);
/**
- * _ctl_ioc_reset_count_show - ioc reset count
+ * ioc_reset_count_show - ioc reset count
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2811,7 +2810,7 @@ static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
+ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2819,10 +2818,10 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count);
}
-static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL);
+static DEVICE_ATTR_RO(ioc_reset_count);
/**
- * _ctl_ioc_reply_queue_count_show - number of reply queues
+ * reply_queue_count_show - number of reply queues
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2832,7 +2831,7 @@ static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_ioc_reply_queue_count_show(struct device *cdev,
+reply_queue_count_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
u8 reply_queue_count;
@@ -2847,11 +2846,10 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev,
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);
+static DEVICE_ATTR_RO(reply_queue_count);
/**
- * _ctl_BRM_status_show - Backup Rail Monitor Status
+ * BRM_status_show - Backup Rail Monitor Status
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2861,7 +2859,7 @@ static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show,
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
+BRM_status_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2923,7 +2921,7 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
mutex_unlock(&ioc->pci_access_mutex);
return rc;
}
-static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
+static DEVICE_ATTR_RO(BRM_status);
struct DIAG_BUFFER_START {
__le32 Size;
@@ -2936,7 +2934,7 @@ struct DIAG_BUFFER_START {
};
/**
- * _ctl_host_trace_buffer_size_show - host buffer size (trace only)
+ * host_trace_buffer_size_show - host buffer size (trace only)
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2944,7 +2942,7 @@ struct DIAG_BUFFER_START {
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_host_trace_buffer_size_show(struct device *cdev,
+host_trace_buffer_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -2976,11 +2974,10 @@ _ctl_host_trace_buffer_size_show(struct device *cdev,
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);
+static DEVICE_ATTR_RO(host_trace_buffer_size);
/**
- * _ctl_host_trace_buffer_show - firmware ring buffer (trace only)
+ * host_trace_buffer_show - firmware ring buffer (trace only)
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -2992,7 +2989,7 @@ static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
* 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,
+host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3024,7 +3021,7 @@ _ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
}
static ssize_t
-_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
+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);
@@ -3037,14 +3034,13 @@ _ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
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);
+static DEVICE_ATTR_RW(host_trace_buffer);
/*****************************************/
/**
- * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only)
+ * host_trace_buffer_enable_show - firmware ring buffer (trace only)
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3054,7 +3050,7 @@ static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
* This is a mechnism to post/release host_trace_buffers
*/
static ssize_t
-_ctl_host_trace_buffer_enable_show(struct device *cdev,
+host_trace_buffer_enable_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3072,7 +3068,7 @@ _ctl_host_trace_buffer_enable_show(struct device *cdev,
}
static ssize_t
-_ctl_host_trace_buffer_enable_store(struct device *cdev,
+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);
@@ -3122,14 +3118,12 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev,
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);
+static DEVICE_ATTR_RW(host_trace_buffer_enable);
/*********** diagnostic trigger suppport *********************************/
/**
- * _ctl_diag_trigger_master_show - show the diag_trigger_master attribute
+ * diag_trigger_master_show - show the diag_trigger_master attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3137,7 +3131,7 @@ static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_master_show(struct device *cdev,
+diag_trigger_master_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
@@ -3154,7 +3148,7 @@ _ctl_diag_trigger_master_show(struct device *cdev,
}
/**
- * _ctl_diag_trigger_master_store - store the diag_trigger_master attribute
+ * diag_trigger_master_store - store the diag_trigger_master attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3163,7 +3157,7 @@ _ctl_diag_trigger_master_show(struct device *cdev,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_master_store(struct device *cdev,
+diag_trigger_master_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -3182,12 +3176,11 @@ _ctl_diag_trigger_master_store(struct device *cdev,
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
return rc;
}
-static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR,
- _ctl_diag_trigger_master_show, _ctl_diag_trigger_master_store);
+static DEVICE_ATTR_RW(diag_trigger_master);
/**
- * _ctl_diag_trigger_event_show - show the diag_trigger_event attribute
+ * diag_trigger_event_show - show the diag_trigger_event attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3195,7 +3188,7 @@ static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_event_show(struct device *cdev,
+diag_trigger_event_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3211,7 +3204,7 @@ _ctl_diag_trigger_event_show(struct device *cdev,
}
/**
- * _ctl_diag_trigger_event_store - store the diag_trigger_event attribute
+ * diag_trigger_event_store - store the diag_trigger_event attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3220,7 +3213,7 @@ _ctl_diag_trigger_event_show(struct device *cdev,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_event_store(struct device *cdev,
+diag_trigger_event_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -3239,12 +3232,11 @@ _ctl_diag_trigger_event_store(struct device *cdev,
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
return sz;
}
-static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR,
- _ctl_diag_trigger_event_show, _ctl_diag_trigger_event_store);
+static DEVICE_ATTR_RW(diag_trigger_event);
/**
- * _ctl_diag_trigger_scsi_show - show the diag_trigger_scsi attribute
+ * diag_trigger_scsi_show - show the diag_trigger_scsi attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3252,7 +3244,7 @@ static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_scsi_show(struct device *cdev,
+diag_trigger_scsi_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3268,7 +3260,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev,
}
/**
- * _ctl_diag_trigger_scsi_store - store the diag_trigger_scsi attribute
+ * diag_trigger_scsi_store - store the diag_trigger_scsi attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3277,7 +3269,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_scsi_store(struct device *cdev,
+diag_trigger_scsi_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3295,12 +3287,11 @@ _ctl_diag_trigger_scsi_store(struct device *cdev,
spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags);
return sz;
}
-static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR,
- _ctl_diag_trigger_scsi_show, _ctl_diag_trigger_scsi_store);
+static DEVICE_ATTR_RW(diag_trigger_scsi);
/**
- * _ctl_diag_trigger_scsi_show - show the diag_trigger_mpi attribute
+ * diag_trigger_scsi_show - show the diag_trigger_mpi attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3308,7 +3299,7 @@ static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_mpi_show(struct device *cdev,
+diag_trigger_mpi_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3324,7 +3315,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev,
}
/**
- * _ctl_diag_trigger_mpi_store - store the diag_trigger_mpi attribute
+ * diag_trigger_mpi_store - store the diag_trigger_mpi attribute
* @cdev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3333,7 +3324,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev,
* A sysfs 'read/write' shost attribute.
*/
static ssize_t
-_ctl_diag_trigger_mpi_store(struct device *cdev,
+diag_trigger_mpi_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3352,8 +3343,7 @@ _ctl_diag_trigger_mpi_store(struct device *cdev,
return sz;
}
-static DEVICE_ATTR(diag_trigger_mpi, S_IRUGO | S_IWUSR,
- _ctl_diag_trigger_mpi_show, _ctl_diag_trigger_mpi_store);
+static DEVICE_ATTR_RW(diag_trigger_mpi);
/*********** diagnostic trigger suppport *** END ****************************/
@@ -3391,7 +3381,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
/* device attributes */
/**
- * _ctl_device_sas_address_show - sas address
+ * sas_address_show - sas address
* @dev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3401,7 +3391,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
+sas_address_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -3410,10 +3400,10 @@ _ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
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);
+static DEVICE_ATTR_RO(sas_address);
/**
- * _ctl_device_handle_show - device handle
+ * sas_device_handle_show - device handle
* @dev: pointer to embedded class device
* @attr: ?
* @buf: the buffer returned
@@ -3423,7 +3413,7 @@ static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL);
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
-_ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
+sas_device_handle_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -3432,10 +3422,10 @@ _ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
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);
+static DEVICE_ATTR_RO(sas_device_handle);
/**
- * _ctl_device_ncq_io_prio_show - send prioritized io commands to device
+ * sas_ncq_io_prio_show - send prioritized io commands to device
* @dev: pointer to embedded device
* @attr: ?
* @buf: the buffer returned
@@ -3443,7 +3433,7 @@ static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
* A sysfs 'read/write' sdev attribute, only works with SATA
*/
static ssize_t
-_ctl_device_ncq_prio_enable_show(struct device *dev,
+sas_ncq_prio_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
@@ -3454,7 +3444,7 @@ _ctl_device_ncq_prio_enable_show(struct device *dev,
}
static ssize_t
-_ctl_device_ncq_prio_enable_store(struct device *dev,
+sas_ncq_prio_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -3471,9 +3461,7 @@ _ctl_device_ncq_prio_enable_store(struct device *dev,
sas_device_priv_data->ncq_prio_enable = ncq_prio_enable;
return strlen(buf);
}
-static DEVICE_ATTR(sas_ncq_prio_enable, S_IRUGO | S_IWUSR,
- _ctl_device_ncq_prio_enable_show,
- _ctl_device_ncq_prio_enable_store);
+static DEVICE_ATTR_RW(sas_ncq_prio_enable);
struct device_attribute *mpt3sas_dev_attrs[] = {
&dev_attr_sas_address,
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 1ccfbc7eebe0..27c731a3fb49 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -113,22 +113,22 @@ MODULE_PARM_DESC(logging_level,
static ushort max_sectors = 0xFFFF;
-module_param(max_sectors, ushort, 0);
+module_param(max_sectors, ushort, 0444);
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_param_array(missing_delay, int, NULL, 0444);
MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
#define MPT3SAS_MAX_LUN (16895)
static u64 max_lun = MPT3SAS_MAX_LUN;
-module_param(max_lun, ullong, 0);
+module_param(max_lun, ullong, 0444);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
static ushort hbas_to_enumerate;
-module_param(hbas_to_enumerate, ushort, 0);
+module_param(hbas_to_enumerate, ushort, 0444);
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 \
@@ -142,17 +142,17 @@ MODULE_PARM_DESC(hbas_to_enumerate,
* Either bit can be set, or both
*/
static int diag_buffer_enable = -1;
-module_param(diag_buffer_enable, int, 0);
+module_param(diag_buffer_enable, int, 0444);
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_param(disable_discovery, int, 0444);
MODULE_PARM_DESC(disable_discovery, " disable discovery ");
/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */
static int prot_mask = -1;
-module_param(prot_mask, int, 0);
+module_param(prot_mask, int, 0444);
MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 ");
@@ -2685,7 +2685,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
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, msix_task);
+ ioc->put_smid_hi_priority(ioc, smid, msix_task);
wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
if (mpt3sas_base_check_cmd_timeout(ioc,
@@ -3659,7 +3659,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
mpi_request->MsgFlags = tr_method;
set_bit(handle, ioc->device_remove_in_progress);
- mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
+ ioc->put_smid_hi_priority(ioc, smid, 0);
mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
out:
@@ -3755,7 +3755,7 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
mpi_request->DevHandle = mpi_request_tm->DevHandle;
- mpt3sas_base_put_smid_default(ioc, smid_sas_ctrl);
+ ioc->put_smid_default(ioc, smid_sas_ctrl);
return _scsih_check_for_pending_tm(ioc, smid);
}
@@ -3881,7 +3881,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, 0);
+ ioc->put_smid_hi_priority(ioc, smid, 0);
}
/**
@@ -3970,7 +3970,7 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, U16 event,
ack_request->EventContext = event_context;
ack_request->VF_ID = 0; /* TODO */
ack_request->VP_ID = 0;
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
}
/**
@@ -4026,7 +4026,7 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
mpi_request->DevHandle = cpu_to_le16(handle);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
}
/**
@@ -4734,12 +4734,12 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
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);
+ ioc->put_smid_fast_path(ioc, smid, handle);
} else
ioc->put_smid_scsi_io(ioc, smid,
le16_to_cpu(mpi_request->DevHandle));
} else
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
return 0;
out:
@@ -5210,6 +5210,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
((ioc_status & MPI2_IOCSTATUS_MASK)
!= MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
st->direct_io = 0;
+ st->scmd = scmd;
memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
mpi_request->DevHandle =
cpu_to_le16(sas_device_priv_data->sas_target->handle);
@@ -7601,7 +7602,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
handle, phys_disk_num));
init_completion(&ioc->scsih_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -9633,7 +9634,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
if (!ioc->hide_ir_msg)
ioc_info(ioc, "IR shutdown (sending)\n");
init_completion(&ioc->scsih_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -9670,6 +9671,7 @@ static void scsih_remove(struct pci_dev *pdev)
struct _pcie_device *pcie_device, *pcienext;
struct workqueue_struct *wq;
unsigned long flags;
+ Mpi2ConfigReply_t mpi_reply;
ioc->remove_host = 1;
@@ -9684,7 +9686,13 @@ static void scsih_remove(struct pci_dev *pdev)
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
if (wq)
destroy_workqueue(wq);
-
+ /*
+ * Copy back the unmodified ioc page1. so that on next driver load,
+ * current modified changes on ioc page1 won't take effect.
+ */
+ if (ioc->is_aero_ioc)
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply,
+ &ioc->ioc_pg1_copy);
/* release all the volumes */
_scsih_ir_shutdown(ioc);
sas_remove_host(shost);
@@ -9747,6 +9755,7 @@ scsih_shutdown(struct pci_dev *pdev)
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
struct workqueue_struct *wq;
unsigned long flags;
+ Mpi2ConfigReply_t mpi_reply;
ioc->remove_host = 1;
@@ -9761,6 +9770,13 @@ scsih_shutdown(struct pci_dev *pdev)
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
if (wq)
destroy_workqueue(wq);
+ /*
+ * Copy back the unmodified ioc page1 so that on next driver load,
+ * current modified changes on ioc page1 won't take effect.
+ */
+ if (ioc->is_aero_ioc)
+ mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply,
+ &ioc->ioc_pg1_copy);
_scsih_ir_shutdown(ioc);
mpt3sas_base_detach(ioc);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index 60ae2d0feb2b..5324662751bf 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -367,7 +367,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n",
(u64)sas_address));
init_completion(&ioc->transport_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1139,7 +1139,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
(u64)phy->identify.sas_address,
phy->number));
init_completion(&ioc->transport_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1434,7 +1434,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
(u64)phy->identify.sas_address,
phy->number, phy_operation));
init_completion(&ioc->transport_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1911,7 +1911,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
ioc_info(ioc, "%s: sending smp request\n", __func__));
init_completion(&ioc->transport_cmds.done);
- mpt3sas_base_put_smid_default(ioc, smid);
+ ioc->put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c
index 050c8c39d7ed..21d638299ab8 100644
--- a/drivers/scsi/mvme16x_scsi.c
+++ b/drivers/scsi/mvme16x_scsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
*
diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig
index 78f7e20a0c1c..79812b80743b 100644
--- a/drivers/scsi/mvsas/Kconfig
+++ b/drivers/scsi/mvsas/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver.
#
@@ -5,25 +6,6 @@
# Copyright 2008 Marvell. <kewei@marvell.com>
# Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
#
-# This file is licensed under GPLv2.
-#
-# This file is part of the 88SE64XX/88SE94XX driver.
-#
-# The 88SE64XX/88SE94XX driver 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; version 2 of the
-# License.
-#
-# The 88SE64XX/88SE94XX driver 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.
-#
-# You should have received a copy of the GNU General Public License
-# along with 88SE64XX/88SE94XX Driver; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-#
-#
config SCSI_MVSAS
tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support"
diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile
index 87b231a5bd5e..75849258e898 100644
--- a/drivers/scsi/mvsas/Makefile
+++ b/drivers/scsi/mvsas/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for Marvell 88SE64xx/88SE84xx SAS/SATA driver.
#
@@ -5,22 +6,6 @@
# Copyright 2008 Marvell. <kewei@marvell.com>
# Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
#
-# This file is licensed under GPLv2.
-#
-# 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; version 2 of the
-# License.
-#
-# 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.
-#
-# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-# USA
ccflags-$(CONFIG_SCSI_MVSAS_DEBUG) := -DMV_DEBUG
diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c
index b757d389e32f..1f2b61de8c63 100644
--- a/drivers/scsi/mvsas/mv_64xx.c
+++ b/drivers/scsi/mvsas/mv_64xx.c
@@ -1,26 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell 88SE64xx hardware specific
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "mv_sas.h"
@@ -678,7 +662,8 @@ static u32 mvs_64xx_spi_read_data(struct mvs_info *mvi)
static void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data)
{
void __iomem *regs = mvi->regs_ex;
- iow32(SPI_DATA_REG_64XX, data);
+
+ iow32(SPI_DATA_REG_64XX, data);
}
diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h
index 545889bd9753..c25a5dfe7889 100644
--- a/drivers/scsi/mvsas/mv_64xx.h
+++ b/drivers/scsi/mvsas/mv_64xx.h
@@ -1,26 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Marvell 88SE64xx hardware specific head file
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#ifndef _MVS64XX_REG_H_
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
index eb5471bc7263..fc0b8eb68204 100644
--- a/drivers/scsi/mvsas/mv_94xx.c
+++ b/drivers/scsi/mvsas/mv_94xx.c
@@ -1,26 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell 88SE94xx hardware specific
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "mv_sas.h"
@@ -946,7 +930,8 @@ static u32 mvs_94xx_spi_read_data(struct mvs_info *mvi)
static void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data)
{
void __iomem *regs = mvi->regs_ex - 0x10200;
- mw32(SPI_RD_DATA_REG_94XX, data);
+
+ mw32(SPI_RD_DATA_REG_94XX, data);
}
diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h
index 578960803a00..a243182c1345 100644
--- a/drivers/scsi/mvsas/mv_94xx.h
+++ b/drivers/scsi/mvsas/mv_94xx.h
@@ -1,26 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Marvell 88SE94xx hardware specific head file
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#ifndef _MVS94XX_REG_H_
diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h
index 8c4479ab49e8..0e7366fafca9 100644
--- a/drivers/scsi/mvsas/mv_chips.h
+++ b/drivers/scsi/mvsas/mv_chips.h
@@ -1,26 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Marvell 88SE64xx/88SE94xx register IO interface
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h
index f5451940d289..199ab49aa047 100644
--- a/drivers/scsi/mvsas/mv_defs.h
+++ b/drivers/scsi/mvsas/mv_defs.h
@@ -1,26 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Marvell 88SE64xx/88SE94xx const head file
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#ifndef _MV_DEFS_H_
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 030d911ee374..da719b0694dc 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -1,26 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell 88SE64xx/88SE94xx pci init
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 311d23c727ce..3e0b8ebe257f 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1,26 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell 88SE64xx/88SE94xx main function
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include "mv_sas.h"
@@ -1209,7 +1193,7 @@ static int mvs_dev_found_notify(struct domain_device *dev, int lock)
mvi_device->dev_type = dev->dev_type;
mvi_device->mvi_info = mvi;
mvi_device->sas_device = dev;
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
int phy_id;
u8 phy_num = parent_dev->ex_dev.num_phys;
struct ex_phy *phy;
@@ -1422,7 +1406,7 @@ int mvs_I_T_nexus_reset(struct domain_device *dev)
{
unsigned long flags;
int rc = TMF_RESP_FUNC_FAILED;
- struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
+ struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev;
struct mvs_info *mvi = mvi_dev->mvi_info;
if (mvi_dev->dev_status != MVS_DEV_EH)
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index 080676c1c9e5..519edc796691 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -1,26 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Marvell 88SE64xx/88SE94xx main function head file
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#ifndef _MV_SAS_H_
@@ -66,9 +50,6 @@ extern struct mvs_info *tgt_mvi;
extern const struct mvs_dispatch mvs_64xx_dispatch;
extern const struct mvs_dispatch mvs_94xx_dispatch;
-#define DEV_IS_EXPANDER(type) \
- ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
-
#define bit(n) ((u64)1 << n)
#define for_each_phy(__lseq_mask, __mc, __lseq) \
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 3df02691a092..8906aceda4c4 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -1,24 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell UMI driver
*
* Copyright 2011 Marvell. <jyli@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#include <linux/kernel.h>
@@ -211,23 +195,22 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd,
unsigned int sgnum = scsi_sg_count(scmd);
dma_addr_t busaddr;
- sg = scsi_sglist(scmd);
- *sg_count = dma_map_sg(&mhba->pdev->dev, sg, sgnum,
+ *sg_count = dma_map_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum,
scmd->sc_data_direction);
if (*sg_count > mhba->max_sge) {
dev_err(&mhba->pdev->dev,
"sg count[0x%x] is bigger than max sg[0x%x].\n",
*sg_count, mhba->max_sge);
- dma_unmap_sg(&mhba->pdev->dev, sg, sgnum,
+ dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum,
scmd->sc_data_direction);
return -1;
}
- for (i = 0; i < *sg_count; i++) {
- busaddr = sg_dma_address(&sg[i]);
+ scsi_for_each_sg(scmd, sg, *sg_count, i) {
+ busaddr = sg_dma_address(sg);
m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr));
m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr));
m_sg->flags = 0;
- sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(&sg[i])));
+ sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(sg)));
if ((i + 1) == *sg_count)
m_sg->flags |= 1U << mhba->eot_flag;
@@ -752,7 +735,7 @@ static int mvumi_issue_blocked_cmd(struct mvumi_hba *mhba,
spin_lock_irqsave(mhba->shost->host_lock, flags);
atomic_dec(&cmd->sync_cmd);
if (mhba->tag_cmd[cmd->frame->tag]) {
- mhba->tag_cmd[cmd->frame->tag] = 0;
+ mhba->tag_cmd[cmd->frame->tag] = NULL;
dev_warn(&mhba->pdev->dev, "TIMEOUT:release tag [%d]\n",
cmd->frame->tag);
tag_release_one(mhba, &mhba->tag_pool, cmd->frame->tag);
@@ -1794,7 +1777,7 @@ static void mvumi_handle_clob(struct mvumi_hba *mhba)
cmd = mhba->tag_cmd[ob_frame->tag];
atomic_dec(&mhba->fw_outstanding);
- mhba->tag_cmd[ob_frame->tag] = 0;
+ mhba->tag_cmd[ob_frame->tag] = NULL;
tag_release_one(mhba, &mhba->tag_pool, ob_frame->tag);
if (cmd->scmd)
mvumi_complete_cmd(mhba, cmd, ob_frame);
@@ -2139,7 +2122,7 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd)
spin_lock_irqsave(mhba->shost->host_lock, flags);
if (mhba->tag_cmd[cmd->frame->tag]) {
- mhba->tag_cmd[cmd->frame->tag] = 0;
+ mhba->tag_cmd[cmd->frame->tag] = NULL;
tag_release_one(mhba, &mhba->tag_pool, cmd->frame->tag);
}
if (!list_empty(&cmd->queue_pointer))
diff --git a/drivers/scsi/mvumi.h b/drivers/scsi/mvumi.h
index 41f168702ac7..ec8cc2207536 100644
--- a/drivers/scsi/mvumi.h
+++ b/drivers/scsi/mvumi.h
@@ -1,24 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Marvell UMI head file
*
* Copyright 2011 Marvell. <jyli@marvell.com>
- *
- * This file is licensed under GPLv2.
- *
- * 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; version 2 of the
- * License.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
*/
#ifndef MVUMI_H
diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c
index b8d54ef8cf6d..eb0dd566330a 100644
--- a/drivers/scsi/myrs.c
+++ b/drivers/scsi/myrs.c
@@ -818,7 +818,7 @@ static void myrs_log_event(struct myrs_hba *cs, struct myrs_event *ev)
unsigned char ev_type, *ev_msg;
struct Scsi_Host *shost = cs->host;
struct scsi_device *sdev;
- struct scsi_sense_hdr sshdr;
+ struct scsi_sense_hdr sshdr = {0};
unsigned char sense_info[4];
unsigned char cmd_specific[4];
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 1a236a3dfd51..e6a95498ac0d 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/******************************************************************************
** Device driver for the PCI-SCSI NCR538XX controller family.
**
** Copyright (C) 1994 Wolfgang Stanglmeier
**
-** 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.
-**
-** 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., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
**
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 02901c54b08b..8326f5f01e07 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -1,22 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/******************************************************************************
** Device driver for the PCI-SCSI NCR538XX controller family.
**
** Copyright (C) 1994 Wolfgang Stanglmeier
** Copyright (C) 1998-2001 Gerard Roudier <groudier@free.fr>
**
-** 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.
-**
-** 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., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
**
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index da4d6e1106c4..70db79254155 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -1,20 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver
* Copyright (C) 2001, 2002, 2003
* YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
* GOTO Masanori <gotom@debian.or.jp>, <gotom@debian.org>
*
- * 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, 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.
- *
- *
* Revision History:
* 1.0: Initial Release.
* 1.1: Add /proc SDTR status.
diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
index c0221829069c..ab0726c070f7 100644
--- a/drivers/scsi/nsp32.h
+++ b/drivers/scsi/nsp32.h
@@ -1,16 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver
* Basic data header
- *
- * 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, 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.
*/
#ifndef _NSP32_H
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
deleted file mode 100644
index be3c73ebbfde..000000000000
--- a/drivers/scsi/osst.c
+++ /dev/null
@@ -1,6101 +0,0 @@
-/*
- SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
- file Documentation/scsi/st.txt for more information.
-
- History:
-
- OnStream SCSI Tape support (osst) cloned from st.c by
- Willem Riede (osst@riede.org) Feb 2000
- Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000
-
- Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
- Contribution and ideas from several people including (in alphabetical
- order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
- Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
-
- Copyright 1992 - 2002 Kai Makisara / 2000 - 2006 Willem Riede
- email osst@riede.org
-
- $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $
-
- Microscopic alterations - Rik Ling, 2000/12/21
- Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
- Some small formal changes - aeb, 950809
-*/
-
-static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $";
-static const char * osst_version = "0.99.4";
-
-/* The "failure to reconnect" firmware bug */
-#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
-#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/
-#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched/signal.h>
-#include <linux/proc_fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/mtio.h>
-#include <linux/ioctl.h>
-#include <linux/fcntl.h>
-#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
-#include <linux/blkdev.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <asm/dma.h>
-
-/* The driver prints some debugging information on the console if DEBUG
- is defined and non-zero. */
-#define DEBUG 0
-
-/* The message level for the debug messages is currently set to KERN_NOTICE
- so that people can easily see the messages. Later when the debugging messages
- in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
-#define OSST_DEB_MSG KERN_NOTICE
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_driver.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_ioctl.h>
-
-#define ST_KILOBYTE 1024
-
-#include "st.h"
-#include "osst.h"
-#include "osst_options.h"
-#include "osst_detect.h"
-
-static DEFINE_MUTEX(osst_int_mutex);
-static int max_dev = 0;
-static int write_threshold_kbs = 0;
-static int max_sg_segs = 0;
-
-#ifdef MODULE
-MODULE_AUTHOR("Willem Riede");
-MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
-MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
-
-module_param(max_dev, int, 0444);
-MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
-
-module_param(write_threshold_kbs, int, 0644);
-MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
-
-module_param(max_sg_segs, int, 0644);
-MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
-#else
-static struct osst_dev_parm {
- char *name;
- int *val;
-} parms[] __initdata = {
- { "max_dev", &max_dev },
- { "write_threshold_kbs", &write_threshold_kbs },
- { "max_sg_segs", &max_sg_segs }
-};
-#endif
-
-/* Some default definitions have been moved to osst_options.h */
-#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
-#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
-
-/* The buffer size should fit into the 24 bits for length in the
- 6-byte SCSI read and write commands. */
-#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
-#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
-#endif
-
-#if DEBUG
-static int debugging = 1;
-/* uncomment define below to test error recovery */
-// #define OSST_INJECT_ERRORS 1
-#endif
-
-/* Do not retry! The drive firmware already retries when appropriate,
- and when it tries to tell us something, we had better listen... */
-#define MAX_RETRIES 0
-
-#define NO_TAPE NOT_READY
-
-#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
-#define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
-#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
-
-#define OSST_TIMEOUT (200 * HZ)
-#define OSST_LONG_TIMEOUT (1800 * HZ)
-
-#define TAPE_NR(x) (iminor(x) & ((1 << ST_MODE_SHIFT)-1))
-#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
-#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
-#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
-
-/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
- 24 bits) */
-#define SET_DENS_AND_BLK 0x10001
-
-static int osst_buffer_size = OSST_BUFFER_SIZE;
-static int osst_write_threshold = OSST_WRITE_THRESHOLD;
-static int osst_max_sg_segs = OSST_MAX_SG;
-static int osst_max_dev = OSST_MAX_TAPES;
-static int osst_nr_dev;
-
-static struct osst_tape **os_scsi_tapes = NULL;
-static DEFINE_RWLOCK(os_scsi_tapes_lock);
-
-static int modes_defined = 0;
-
-static struct osst_buffer *new_tape_buffer(int, int, int);
-static int enlarge_buffer(struct osst_buffer *, int);
-static void normalize_buffer(struct osst_buffer *);
-static int append_to_buffer(const char __user *, struct osst_buffer *, int);
-static int from_buffer(struct osst_buffer *, char __user *, int);
-static int osst_zero_buffer_tail(struct osst_buffer *);
-static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *);
-static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *);
-
-static int osst_probe(struct device *);
-static int osst_remove(struct device *);
-
-static struct scsi_driver osst_template = {
- .gendrv = {
- .name = "osst",
- .owner = THIS_MODULE,
- .probe = osst_probe,
- .remove = osst_remove,
- }
-};
-
-static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt,
- unsigned int cmd_in, unsigned long arg);
-
-static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip);
-
-static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt);
-
-static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt);
-
-static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending);
-
-static inline char *tape_name(struct osst_tape *tape)
-{
- return tape->drive->disk_name;
-}
-
-/* Routines that handle the interaction with mid-layer SCSI routines */
-
-
-/* Normalize Sense */
-static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s)
-{
- const u8 *ucp;
- const u8 *sense = SRpnt->sense;
-
- s->have_sense = scsi_normalize_sense(SRpnt->sense,
- SCSI_SENSE_BUFFERSIZE, &s->sense_hdr);
- s->flags = 0;
-
- if (s->have_sense) {
- s->deferred = 0;
- s->remainder_valid =
- scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
- switch (sense[0] & 0x7f) {
- case 0x71:
- s->deferred = 1;
- case 0x70:
- s->fixed_format = 1;
- s->flags = sense[2] & 0xe0;
- break;
- case 0x73:
- s->deferred = 1;
- case 0x72:
- s->fixed_format = 0;
- ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
- s->flags = ucp ? (ucp[3] & 0xe0) : 0;
- break;
- }
- }
-}
-
-/* Convert the result to success code */
-static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
-{
- char *name = tape_name(STp);
- int result = SRpnt->result;
- u8 * sense = SRpnt->sense, scode;
-#if DEBUG
- const char *stp;
-#endif
- struct st_cmdstatus *cmdstatp;
-
- if (!result)
- return 0;
-
- cmdstatp = &STp->buffer->cmdstat;
- osst_analyze_sense(SRpnt, cmdstatp);
-
- if (cmdstatp->have_sense)
- scode = STp->buffer->cmdstat.sense_hdr.sense_key;
- else
- scode = 0;
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n",
- name, result,
- SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
- SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
- if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
- name, scode, sense[12], sense[13]);
- if (cmdstatp->have_sense)
- __scsi_print_sense(STp->device, name,
- SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
- }
- else
-#endif
- if (cmdstatp->have_sense && (
- scode != NO_SENSE &&
- scode != RECOVERED_ERROR &&
-/* scode != UNIT_ATTENTION && */
- scode != BLANK_CHECK &&
- scode != VOLUME_OVERFLOW &&
- SRpnt->cmd[0] != MODE_SENSE &&
- SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
- if (cmdstatp->have_sense) {
- printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
- __scsi_print_sense(STp->device, name,
- SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
- }
- else {
- static int notyetprinted = 1;
-
- printk(KERN_WARNING
- "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n",
- name, result, driver_byte(result),
- host_byte(result));
- if (notyetprinted) {
- notyetprinted = 0;
- printk(KERN_INFO
- "%s:I: This warning may be caused by your scsi controller,\n", name);
- printk(KERN_INFO
- "%s:I: it has been reported with some Buslogic cards.\n", name);
- }
- }
- }
- STp->pos_unknown |= STp->device->was_reset;
-
- if (cmdstatp->have_sense && scode == RECOVERED_ERROR) {
- STp->recover_count++;
- STp->recover_erreg++;
-#if DEBUG
- if (debugging) {
- if (SRpnt->cmd[0] == READ_6)
- stp = "read";
- else if (SRpnt->cmd[0] == WRITE_6)
- stp = "write";
- else
- stp = "ioctl";
- printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
- STp->recover_count);
- }
-#endif
- if ((sense[2] & 0xe0) == 0)
- return 0;
- }
- return (-EIO);
-}
-
-
-/* Wakeup from interrupt */
-static void osst_end_async(struct request *req, blk_status_t status)
-{
- struct scsi_request *rq = scsi_req(req);
- struct osst_request *SRpnt = req->end_io_data;
- struct osst_tape *STp = SRpnt->stp;
- struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
-
- STp->buffer->cmdstat.midlevel_result = SRpnt->result = rq->result;
-#if DEBUG
- STp->write_pending = 0;
-#endif
- if (rq->sense_len)
- memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE);
- if (SRpnt->waiting)
- complete(SRpnt->waiting);
-
- if (SRpnt->bio) {
- kfree(mdata->pages);
- blk_rq_unmap_user(SRpnt->bio);
- }
-
- blk_put_request(req);
-}
-
-/* osst_request memory management */
-static struct osst_request *osst_allocate_request(void)
-{
- return kzalloc(sizeof(struct osst_request), GFP_KERNEL);
-}
-
-static void osst_release_request(struct osst_request *streq)
-{
- kfree(streq);
-}
-
-static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
- int cmd_len, int data_direction, void *buffer, unsigned bufflen,
- int use_sg, int timeout, int retries)
-{
- struct request *req;
- struct scsi_request *rq;
- struct page **pages = NULL;
- struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
-
- int err = 0;
- int write = (data_direction == DMA_TO_DEVICE);
-
- req = blk_get_request(SRpnt->stp->device->request_queue,
- write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0);
- if (IS_ERR(req))
- return DRIVER_ERROR << 24;
-
- rq = scsi_req(req);
- req->rq_flags |= RQF_QUIET;
-
- SRpnt->bio = NULL;
-
- if (use_sg) {
- struct scatterlist *sg, *sgl = (struct scatterlist *)buffer;
- int i;
-
- pages = kcalloc(use_sg, sizeof(struct page *), GFP_KERNEL);
- if (!pages)
- goto free_req;
-
- for_each_sg(sgl, sg, use_sg, i)
- pages[i] = sg_page(sg);
-
- mdata->null_mapped = 1;
-
- mdata->page_order = get_order(sgl[0].length);
- mdata->nr_entries =
- DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order);
- mdata->offset = 0;
-
- err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL);
- if (err) {
- kfree(pages);
- goto free_req;
- }
- SRpnt->bio = req->bio;
- mdata->pages = pages;
-
- } else if (bufflen) {
- err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL);
- if (err)
- goto free_req;
- }
-
- rq->cmd_len = cmd_len;
- memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
- memcpy(rq->cmd, cmd, rq->cmd_len);
- req->timeout = timeout;
- rq->retries = retries;
- req->end_io_data = SRpnt;
-
- blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async);
- return 0;
-free_req:
- blk_put_request(req);
- return DRIVER_ERROR << 24;
-}
-
-/* Do the scsi command. Waits until command performed if do_wait is true.
- Otherwise osst_write_behind_check() is used to check that the command
- has finished. */
-static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp,
- unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
-{
- unsigned char *bp;
- unsigned short use_sg;
-#ifdef OSST_INJECT_ERRORS
- static int inject = 0;
- static int repeat = 0;
-#endif
- struct completion *waiting;
-
- /* if async, make sure there's no command outstanding */
- if (!do_wait && ((STp->buffer)->last_SRpnt)) {
- printk(KERN_ERR "%s: Async command already active.\n",
- tape_name(STp));
- if (signal_pending(current))
- (STp->buffer)->syscall_result = (-EINTR);
- else
- (STp->buffer)->syscall_result = (-EBUSY);
- return NULL;
- }
-
- if (SRpnt == NULL) {
- SRpnt = osst_allocate_request();
- if (SRpnt == NULL) {
- printk(KERN_ERR "%s: Can't allocate SCSI request.\n",
- tape_name(STp));
- if (signal_pending(current))
- (STp->buffer)->syscall_result = (-EINTR);
- else
- (STp->buffer)->syscall_result = (-EBUSY);
- return NULL;
- }
- SRpnt->stp = STp;
- }
-
- /* If async IO, set last_SRpnt. This ptr tells write_behind_check
- which IO is outstanding. It's nulled out when the IO completes. */
- if (!do_wait)
- (STp->buffer)->last_SRpnt = SRpnt;
-
- waiting = &STp->wait;
- init_completion(waiting);
- SRpnt->waiting = waiting;
-
- use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0;
- if (use_sg) {
- bp = (char *)&(STp->buffer->sg[0]);
- if (STp->buffer->sg_segs < use_sg)
- use_sg = STp->buffer->sg_segs;
- }
- else
- bp = (STp->buffer)->b_data;
-
- memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
- STp->buffer->cmdstat.have_sense = 0;
- STp->buffer->syscall_result = 0;
-
- if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes,
- use_sg, timeout, retries))
- /* could not allocate the buffer or request was too large */
- (STp->buffer)->syscall_result = (-EBUSY);
- else if (do_wait) {
- wait_for_completion(waiting);
- SRpnt->waiting = NULL;
- STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
-#ifdef OSST_INJECT_ERRORS
- if (STp->buffer->syscall_result == 0 &&
- cmd[0] == READ_6 &&
- cmd[4] &&
- ( (++ inject % 83) == 29 ||
- (STp->first_frame_position == 240
- /* or STp->read_error_frame to fail again on the block calculated above */ &&
- ++repeat < 3))) {
- printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
- STp->buffer->last_result_fatal = 1;
- }
-#endif
- }
- return SRpnt;
-}
-
-
-/* Handle the write-behind checking (downs the semaphore) */
-static void osst_write_behind_check(struct osst_tape *STp)
-{
- struct osst_buffer * STbuffer;
-
- STbuffer = STp->buffer;
-
-#if DEBUG
- if (STp->write_pending)
- STp->nbr_waits++;
- else
- STp->nbr_finished++;
-#endif
- wait_for_completion(&(STp->wait));
- STp->buffer->last_SRpnt->waiting = NULL;
-
- STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
-
- if (STp->buffer->syscall_result)
- STp->buffer->syscall_result =
- osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1);
- else
- STp->first_frame_position++;
-
- osst_release_request(STp->buffer->last_SRpnt);
-
- if (STbuffer->writing < STbuffer->buffer_bytes)
- printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
-
- STbuffer->last_SRpnt = NULL;
- STbuffer->buffer_bytes -= STbuffer->writing;
- STbuffer->writing = 0;
-
- return;
-}
-
-
-
-/* Onstream specific Routines */
-/*
- * Initialize the OnStream AUX
- */
-static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number,
- int logical_blk_num, int blk_sz, int blk_cnt)
-{
- os_aux_t *aux = STp->buffer->aux;
- os_partition_t *par = &aux->partition;
- os_dat_t *dat = &aux->dat;
-
- if (STp->raw) return;
-
- memset(aux, 0, sizeof(*aux));
- aux->format_id = htonl(0);
- memcpy(aux->application_sig, "LIN4", 4);
- aux->hdwr = htonl(0);
- aux->frame_type = frame_type;
-
- switch (frame_type) {
- case OS_FRAME_TYPE_HEADER:
- aux->update_frame_cntr = htonl(STp->update_frame_cntr);
- par->partition_num = OS_CONFIG_PARTITION;
- par->par_desc_ver = OS_PARTITION_VERSION;
- par->wrt_pass_cntr = htons(0xffff);
- /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
- par->first_frame_ppos = htonl(0);
- par->last_frame_ppos = htonl(0xbb7);
- aux->frame_seq_num = htonl(0);
- aux->logical_blk_num_high = htonl(0);
- aux->logical_blk_num = htonl(0);
- aux->next_mark_ppos = htonl(STp->first_mark_ppos);
- break;
- case OS_FRAME_TYPE_DATA:
- case OS_FRAME_TYPE_MARKER:
- dat->dat_sz = 8;
- dat->reserved1 = 0;
- dat->entry_cnt = 1;
- dat->reserved3 = 0;
- dat->dat_list[0].blk_sz = htonl(blk_sz);
- dat->dat_list[0].blk_cnt = htons(blk_cnt);
- dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER?
- OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
- dat->dat_list[0].reserved = 0;
- case OS_FRAME_TYPE_EOD:
- aux->update_frame_cntr = htonl(0);
- par->partition_num = OS_DATA_PARTITION;
- par->par_desc_ver = OS_PARTITION_VERSION;
- par->wrt_pass_cntr = htons(STp->wrt_pass_cntr);
- par->first_frame_ppos = htonl(STp->first_data_ppos);
- par->last_frame_ppos = htonl(STp->capacity);
- aux->frame_seq_num = htonl(frame_seq_number);
- aux->logical_blk_num_high = htonl(0);
- aux->logical_blk_num = htonl(logical_blk_num);
- break;
- default: ; /* probably FILL */
- }
- aux->filemark_cnt = htonl(STp->filemark_cnt);
- aux->phys_fm = htonl(0xffffffff);
- aux->last_mark_ppos = htonl(STp->last_mark_ppos);
- aux->last_mark_lbn = htonl(STp->last_mark_lbn);
-}
-
-/*
- * Verify that we have the correct tape frame
- */
-static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet)
-{
- char * name = tape_name(STp);
- os_aux_t * aux = STp->buffer->aux;
- os_partition_t * par = &(aux->partition);
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- unsigned int blk_cnt, blk_sz, i;
-
- if (STp->raw) {
- if (STp->buffer->syscall_result) {
- for (i=0; i < STp->buffer->sg_segs; i++)
- memset(page_address(sg_page(&STp->buffer->sg[i])),
- 0, STp->buffer->sg[i].length);
- strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
- } else
- STp->buffer->buffer_bytes = OS_FRAME_SIZE;
- return 1;
- }
- if (STp->buffer->syscall_result) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
-#endif
- return 0;
- }
- if (ntohl(aux->format_id) != 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
-#endif
- goto err_out;
- }
- if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
- (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
-#endif
- goto err_out;
- }
- if (par->partition_num != OS_DATA_PARTITION) {
- if (!STp->linux_media || STp->linux_media_version != 2) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
- name, par->partition_num);
-#endif
- goto err_out;
- }
- }
- if (par->par_desc_ver != OS_PARTITION_VERSION) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
-#endif
- goto err_out;
- }
- if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n",
- name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
-#endif
- goto err_out;
- }
- if (aux->frame_type != OS_FRAME_TYPE_DATA &&
- aux->frame_type != OS_FRAME_TYPE_EOD &&
- aux->frame_type != OS_FRAME_TYPE_MARKER) {
- if (!quiet) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
-#endif
- }
- goto err_out;
- }
- if (aux->frame_type == OS_FRAME_TYPE_EOD &&
- STp->first_frame_position < STp->eod_frame_ppos) {
- printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
- STp->first_frame_position);
- goto err_out;
- }
- if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
- if (!quiet) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
- name, ntohl(aux->frame_seq_num), frame_seq_number);
-#endif
- }
- goto err_out;
- }
- if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
- STps->eof = ST_FM_HIT;
-
- i = ntohl(aux->filemark_cnt);
- if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
- STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
- STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
- i, STp->first_frame_position - 1);
-#endif
- STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
- if (i >= STp->filemark_cnt)
- STp->filemark_cnt = i+1;
- }
- }
- if (aux->frame_type == OS_FRAME_TYPE_EOD) {
- STps->eof = ST_EOD_1;
- STp->frame_in_buffer = 1;
- }
- if (aux->frame_type == OS_FRAME_TYPE_DATA) {
- blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
- blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
- STp->buffer->buffer_bytes = blk_cnt * blk_sz;
- STp->buffer->read_pointer = 0;
- STp->frame_in_buffer = 1;
-
- /* See what block size was used to write file */
- if (STp->block_size != blk_sz && blk_sz > 0) {
- printk(KERN_INFO
- "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
- name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
- STp->block_size<1024?STp->block_size:STp->block_size/1024,
- STp->block_size<1024?'b':'k');
- STp->block_size = blk_sz;
- STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
- }
- STps->eof = ST_NOEOF;
- }
- STp->frame_seq_number = ntohl(aux->frame_seq_num);
- STp->logical_blk_num = ntohl(aux->logical_blk_num);
- return 1;
-
-err_out:
- if (STp->read_error_frame == 0)
- STp->read_error_frame = STp->first_frame_position - 1;
- return 0;
-}
-
-/*
- * Wait for the unit to become Ready
- */
-static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt,
- unsigned timeout, int initial_delay)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- unsigned long startwait = jiffies;
-#if DEBUG
- int dbg = debugging;
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
-#endif
-
- if (initial_delay > 0)
- msleep(jiffies_to_msecs(initial_delay));
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt) return (-EBUSY);
-
- while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
- (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
- (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) ||
- ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 &&
- SRpnt->sense[13] == 0 ) )) {
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
- printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
- debugging = 0;
- }
-#endif
- msleep(100);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- }
- *aSRpnt = SRpnt;
-#if DEBUG
- debugging = dbg;
-#endif
- if ( STp->buffer->syscall_result &&
- osst_write_error_recovery(STp, aSRpnt, 0) ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
- printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
- STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
- SRpnt->sense[12], SRpnt->sense[13]);
-#endif
- return (-EIO);
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
-#endif
- return 0;
-}
-
-/*
- * Wait for a tape to be inserted in the unit
- */
-static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- unsigned long startwait = jiffies;
-#if DEBUG
- int dbg = debugging;
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
-#endif
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt) return (-EBUSY);
-
- while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
- SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) {
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
- printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
- debugging = 0;
- }
-#endif
- msleep(100);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- }
- *aSRpnt = SRpnt;
-#if DEBUG
- debugging = dbg;
-#endif
- if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 &&
- SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
- printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
- STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2],
- SRpnt->sense[12], SRpnt->sense[13]);
-#endif
- return 0;
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
-#endif
- return 1;
-}
-
-static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame)
-{
- int retval;
-
- osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
- retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
- if (retval) return (retval);
- osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
- return (osst_get_frame_position(STp, aSRpnt));
-}
-
-/*
- * Wait for write(s) to complete
- */
-static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- int result = 0;
- int delay = OSST_WAIT_WRITE_COMPLETE;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
-#endif
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_FILEMARKS;
- cmd[1] = 1;
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt) return (-EBUSY);
- if (STp->buffer->syscall_result) {
- if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) {
- if (SRpnt->sense[13] == 8) {
- delay = OSST_WAIT_LONG_WRITE_COMPLETE;
- }
- } else
- result = osst_write_error_recovery(STp, aSRpnt, 0);
- }
- result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
- STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
-
- return (result);
-}
-
-#define OSST_POLL_PER_SEC 10
-static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to)
-{
- unsigned long startwait = jiffies;
- char * name = tape_name(STp);
-#if DEBUG
- char notyetprinted = 1;
-#endif
- if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
- printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
-
- while (time_before (jiffies, startwait + to*HZ))
- {
- int result;
- result = osst_get_frame_position(STp, aSRpnt);
- if (result == -EIO)
- if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
- return 0; /* successful recovery leaves drive ready for frame */
- if (result < 0) break;
- if (STp->first_frame_position == curr &&
- ((minlast < 0 &&
- (signed)STp->last_frame_position > (signed)curr + minlast) ||
- (minlast >= 0 && STp->cur_frames > minlast)
- ) && result >= 0)
- {
-#if DEBUG
- if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC))
- printk (OSST_DEB_MSG
- "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
- name, curr, curr+minlast, STp->first_frame_position,
- STp->last_frame_position, STp->cur_frames,
- result, (jiffies-startwait)/HZ,
- (((jiffies-startwait)%HZ)*10)/HZ);
-#endif
- return 0;
- }
-#if DEBUG
- if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted)
- {
- printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
- name, curr, curr+minlast, STp->first_frame_position,
- STp->last_frame_position, STp->cur_frames, result);
- notyetprinted--;
- }
-#endif
- msleep(1000 / OSST_POLL_PER_SEC);
- }
-#if DEBUG
- printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
- name, curr, curr+minlast, STp->first_frame_position,
- STp->last_frame_position, STp->cur_frames,
- (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
-#endif
- return -EBUSY;
-}
-
-static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing)
-{
- struct osst_request * SRpnt;
- unsigned char cmd[MAX_COMMAND_SIZE];
- unsigned long startwait = jiffies;
- int retval = 1;
- char * name = tape_name(STp);
-
- if (writing) {
- char mybuf[24];
- char * olddata = STp->buffer->b_data;
- int oldsize = STp->buffer->buffer_size;
-
- /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_FILEMARKS;
- cmd[1] = 1;
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
- MAX_RETRIES, 1);
-
- while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
-
- if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) {
-
- /* some failure - not just not-ready */
- retval = osst_write_error_recovery(STp, aSRpnt, 0);
- break;
- }
- schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC);
-
- STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = READ_POSITION;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
- MAX_RETRIES, 1);
-
- retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
- STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
- }
- if (retval)
- printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
- } else
- /* TODO - figure out which error conditions can be handled */
- if (STp->buffer->syscall_result)
- printk(KERN_WARNING
- "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
- (*aSRpnt)->sense[ 2] & 0x0f,
- (*aSRpnt)->sense[12],
- (*aSRpnt)->sense[13]);
-
- return retval;
-}
-
-/*
- * Read the next OnStream tape frame at the current location
- */
-static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- int retval = 0;
-#if DEBUG
- os_aux_t * aux = STp->buffer->aux;
- char * name = tape_name(STp);
-#endif
-
- if (STp->poll)
- if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
- retval = osst_recover_wait_frame(STp, aSRpnt, 0);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = READ_6;
- cmd[1] = 1;
- cmd[4] = 1;
-
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
-#endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt)
- return (-EBUSY);
-
- if ((STp->buffer)->syscall_result) {
- retval = 1;
- if (STp->read_error_frame == 0) {
- STp->read_error_frame = STp->first_frame_position;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
-#endif
- }
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
- name,
- SRpnt->sense[0], SRpnt->sense[1],
- SRpnt->sense[2], SRpnt->sense[3],
- SRpnt->sense[4], SRpnt->sense[5],
- SRpnt->sense[6], SRpnt->sense[7]);
-#endif
- }
- else
- STp->first_frame_position++;
-#if DEBUG
- if (debugging) {
- char sig[8]; int i;
- for (i=0;i<4;i++)
- sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
- sig[4] = '\0';
- printk(OSST_DEB_MSG
- "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
- ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
- aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
- aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL",
- ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
- ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
- if (aux->frame_type==2)
- printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
- ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
- printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
- }
-#endif
- return (retval);
-}
-
-static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- struct osst_request * SRpnt ;
- unsigned char cmd[MAX_COMMAND_SIZE];
- int retval = 0;
- char * name = tape_name(STp);
-
- if (STps->rw != ST_READING) { /* Initialize read operation */
- if (STps->rw == ST_WRITING || STp->dirty) {
- STp->write_type = OS_WRITE_DATA;
- osst_flush_write_buffer(STp, aSRpnt);
- osst_flush_drive_buffer(STp, aSRpnt);
- }
- STps->rw = ST_READING;
- STp->frame_in_buffer = 0;
-
- /*
- * Issue a read 0 command to get the OnStream drive
- * read frames into its buffer.
- */
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = READ_6;
- cmd[1] = 1;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
-#endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if ((retval = STp->buffer->syscall_result))
- printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
- }
-
- return retval;
-}
-
-static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt,
- int frame_seq_number, int quiet)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- char * name = tape_name(STp);
- int cnt = 0,
- bad = 0,
- past = 0,
- x,
- position;
-
- /*
- * If we want just any frame (-1) and there is a frame in the buffer, return it
- */
- if (frame_seq_number == -1 && STp->frame_in_buffer) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
-#endif
- return (STps->eof);
- }
- /*
- * Search and wait for the next logical tape frame
- */
- while (1) {
- if (cnt++ > 400) {
- printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
- name, frame_seq_number);
- if (STp->read_error_frame) {
- osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
- name, STp->read_error_frame);
-#endif
- STp->read_error_frame = 0;
- STp->abort_count++;
- }
- return (-EIO);
- }
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
- name, frame_seq_number, cnt);
-#endif
- if ( osst_initiate_read(STp, aSRpnt)
- || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
- if (STp->raw)
- return (-EIO);
- position = osst_get_frame_position(STp, aSRpnt);
- if (position >= 0xbae && position < 0xbb8)
- position = 0xbb8;
- else if (position > STp->eod_frame_ppos || ++bad == 10) {
- position = STp->read_error_frame - 1;
- bad = 0;
- }
- else {
- position += 29;
- cnt += 19;
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
- name, position);
-#endif
- osst_set_frame_position(STp, aSRpnt, position, 0);
- continue;
- }
- if (osst_verify_frame(STp, frame_seq_number, quiet))
- break;
- if (osst_verify_frame(STp, -1, quiet)) {
- x = ntohl(STp->buffer->aux->frame_seq_num);
- if (STp->fast_open) {
- printk(KERN_WARNING
- "%s:W: Found logical frame %d instead of %d after fast open\n",
- name, x, frame_seq_number);
- STp->header_ok = 0;
- STp->read_error_frame = 0;
- return (-EIO);
- }
- if (x > frame_seq_number) {
- if (++past > 3) {
- /* positioning backwards did not bring us to the desired frame */
- position = STp->read_error_frame - 1;
- }
- else {
- position = osst_get_frame_position(STp, aSRpnt)
- + frame_seq_number - x - 1;
-
- if (STp->first_frame_position >= 3000 && position < 3000)
- position -= 10;
- }
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Found logical frame %d while looking for %d: back up %d\n",
- name, x, frame_seq_number,
- STp->first_frame_position - position);
-#endif
- osst_set_frame_position(STp, aSRpnt, position, 0);
- cnt += 10;
- }
- else
- past = 0;
- }
- if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
-#endif
- osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
- cnt--;
- }
- STp->frame_in_buffer = 0;
- }
- if (cnt > 1) {
- STp->recover_count++;
- STp->recover_erreg++;
- printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n",
- name, STp->read_error_frame);
- }
- STp->read_count++;
-
-#if DEBUG
- if (debugging || STps->eof)
- printk(OSST_DEB_MSG
- "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
- name, frame_seq_number, STp->frame_seq_number, STps->eof);
-#endif
- STp->fast_open = 0;
- STp->read_error_frame = 0;
- return (STps->eof);
-}
-
-static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- char * name = tape_name(STp);
- int retries = 0;
- int frame_seq_estimate, ppos_estimate, move;
-
- if (logical_blk_num < 0) logical_blk_num = 0;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
- name, logical_blk_num, STp->logical_blk_num,
- STp->block_size<1024?STp->block_size:STp->block_size/1024,
- STp->block_size<1024?'b':'k');
-#endif
- /* Do we know where we are? */
- if (STps->drv_block >= 0) {
- move = logical_blk_num - STp->logical_blk_num;
- if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
- move /= (OS_DATA_SIZE / STp->block_size);
- frame_seq_estimate = STp->frame_seq_number + move;
- } else
- frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE;
-
- if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
- else ppos_estimate = frame_seq_estimate + 20;
- while (++retries < 10) {
- if (ppos_estimate > STp->eod_frame_ppos-2) {
- frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
- ppos_estimate = STp->eod_frame_ppos - 2;
- }
- if (frame_seq_estimate < 0) {
- frame_seq_estimate = 0;
- ppos_estimate = 10;
- }
- osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
- if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
- /* we've located the estimated frame, now does it have our block? */
- if (logical_blk_num < STp->logical_blk_num ||
- logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
- if (STps->eof == ST_FM_HIT)
- move = logical_blk_num < STp->logical_blk_num? -2 : 1;
- else {
- move = logical_blk_num - STp->logical_blk_num;
- if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
- move /= (OS_DATA_SIZE / STp->block_size);
- }
- if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
- name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
- STp->logical_blk_num, logical_blk_num, move);
-#endif
- frame_seq_estimate += move;
- ppos_estimate += move;
- continue;
- } else {
- STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
- STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
- STp->logical_blk_num = logical_blk_num;
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
- name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer,
- STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size,
- STp->block_size);
-#endif
- STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
- if (STps->eof == ST_FM_HIT) {
- STps->drv_file++;
- STps->drv_block = 0;
- } else {
- STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
- STp->logical_blk_num -
- (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
- -1;
- }
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
- return 0;
- }
- }
- if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
- goto error;
- /* we are not yet at the estimated frame, adjust our estimate of its physical position */
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n",
- name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate,
- STp->logical_blk_num, logical_blk_num);
-#endif
- if (frame_seq_estimate != STp->frame_seq_number)
- ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
- else
- break;
- }
-error:
- printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n",
- name, logical_blk_num, STp->logical_blk_num, retries);
- return (-EIO);
-}
-
-/* The values below are based on the OnStream frame payload size of 32K == 2**15,
- * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
- * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
- * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
- */
-#define OSST_FRAME_SHIFT 6
-#define OSST_SECTOR_SHIFT 9
-#define OSST_SECTOR_MASK 0x03F
-
-static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int sector;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG
- "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
- name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
- STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block,
- STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
- STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
- STp->buffer->read_pointer, STp->ps[STp->partition].eof);
-#endif
- /* do we know where we are inside a file? */
- if (STp->ps[STp->partition].drv_block >= 0) {
- sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
- STp->first_frame_position) << OSST_FRAME_SHIFT;
- if (STp->ps[STp->partition].rw == ST_WRITING)
- sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
- else
- sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
- } else {
- sector = osst_get_frame_position(STp, aSRpnt);
- if (sector > 0)
- sector <<= OSST_FRAME_SHIFT;
- }
- return sector;
-}
-
-static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- int frame = sector >> OSST_FRAME_SHIFT,
- offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT,
- r;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
- name, sector, frame, offset);
-#endif
- if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
-
- if (frame <= STp->first_data_ppos) {
- STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
- return (osst_set_frame_position(STp, aSRpnt, frame, 0));
- }
- r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
- if (r < 0) return r;
-
- r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
- if (r < 0) return r;
-
- if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
-
- if (offset) {
- STp->logical_blk_num += offset / STp->block_size;
- STp->buffer->read_pointer = offset;
- STp->buffer->buffer_bytes -= offset;
- } else {
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
- }
- STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
- if (STps->eof == ST_FM_HIT) {
- STps->drv_file++;
- STps->drv_block = 0;
- } else {
- STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
- STp->logical_blk_num -
- (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
- -1;
- }
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
- name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
- STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
-#endif
- return 0;
-}
-
-/*
- * Read back the drive's internal buffer contents, as a part
- * of the write error recovery mechanism for old OnStream
- * firmware revisions.
- * Precondition for this function to work: all frames in the
- * drive's buffer must be of one type (DATA, MARK or EOD)!
- */
-static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt,
- unsigned int frame, unsigned int skip, int pending)
-{
- struct osst_request * SRpnt = * aSRpnt;
- unsigned char * buffer, * p;
- unsigned char cmd[MAX_COMMAND_SIZE];
- int flag, new_frame, i;
- int nframes = STp->cur_frames;
- int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
- - (nframes + pending - 1);
- int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num)
- - (nframes + pending - 1) * blks_per_frame;
- char * name = tape_name(STp);
- unsigned long startwait = jiffies;
-#if DEBUG
- int dbg = debugging;
-#endif
-
- if ((buffer = vmalloc(array_size((nframes + 1), OS_DATA_SIZE))) == NULL)
- return (-EIO);
-
- printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
- name, nframes, pending?" and one that was pending":"");
-
- osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
-#if DEBUG
- if (pending && debugging)
- printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
- name, frame_seq_number + nframes,
- logical_blk_num + nframes * blks_per_frame,
- p[0], p[1], p[2], p[3]);
-#endif
- for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = 0x3C; /* Buffer Read */
- cmd[1] = 6; /* Retrieve Faulty Block */
- cmd[7] = 32768 >> 8;
- cmd[8] = 32768 & 0xff;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
-
- if ((STp->buffer)->syscall_result || !SRpnt) {
- printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
- vfree(buffer);
- *aSRpnt = SRpnt;
- return (-EIO);
- }
- osst_copy_from_buffer(STp->buffer, p);
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
- name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
-#endif
- }
- *aSRpnt = SRpnt;
- osst_get_frame_position(STp, aSRpnt);
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
-#endif
- /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
- /* In the header we don't actually re-write the frames that fail, just the ones after them */
-
- for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
-
- if (flag) {
- if (STp->write_type == OS_WRITE_HEADER) {
- i += skip;
- p += skip * OS_DATA_SIZE;
- }
- else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
- new_frame = 3000-i;
- else
- new_frame += skip;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
- name, new_frame+i, frame_seq_number+i);
-#endif
- osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
- osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
- osst_get_frame_position(STp, aSRpnt);
- SRpnt = * aSRpnt;
-
- if (new_frame > frame + 1000) {
- printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
- vfree(buffer);
- return (-EIO);
- }
- if ( i >= nframes + pending ) break;
- flag = 0;
- }
- osst_copy_to_buffer(STp->buffer, p);
- /*
- * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
- */
- osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
- logical_blk_num + i*blks_per_frame,
- ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1;
-
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG
- "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
- name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
- p[0], p[1], p[2], p[3]);
-#endif
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
-
- if (STp->buffer->syscall_result)
- flag = 1;
- else {
- p += OS_DATA_SIZE; i++;
-
- /* if we just sent the last frame, wait till all successfully written */
- if ( i == nframes + pending ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
-#endif
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_FILEMARKS;
- cmd[1] = 1;
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
- STp->timeout, MAX_RETRIES, 1);
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
- printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
- debugging = 0;
- }
-#endif
- flag = STp->buffer->syscall_result;
- while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
- MAX_RETRIES, 1);
-
- if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 &&
- (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) {
- /* in the process of becoming ready */
- msleep(100);
- continue;
- }
- if (STp->buffer->syscall_result)
- flag = 1;
- break;
- }
-#if DEBUG
- debugging = dbg;
- printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
-#endif
- }
- }
- *aSRpnt = SRpnt;
- if (flag) {
- if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
- SRpnt->sense[12] == 0 &&
- SRpnt->sense[13] == 2) {
- printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
- vfree(buffer);
- return (-EIO); /* hit end of tape = fail */
- }
- i = ((SRpnt->sense[3] << 24) |
- (SRpnt->sense[4] << 16) |
- (SRpnt->sense[5] << 8) |
- SRpnt->sense[6] ) - new_frame;
- p = &buffer[i * OS_DATA_SIZE];
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
-#endif
- osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
- name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
-#endif
- }
- }
- if (flag) {
- /* error recovery did not successfully complete */
- printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
- STp->write_type == OS_WRITE_HEADER?"header":"body");
- }
- if (!pending)
- osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */
- vfree(buffer);
- return 0;
-}
-
-static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt,
- unsigned int frame, unsigned int skip, int pending)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- char * name = tape_name(STp);
- int expected = 0;
- int attempts = 1000 / skip;
- int flag = 1;
- unsigned long startwait = jiffies;
-#if DEBUG
- int dbg = debugging;
-#endif
-
- while (attempts && time_before(jiffies, startwait + 60*HZ)) {
- if (flag) {
-#if DEBUG
- debugging = dbg;
-#endif
- if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
- frame = 3000-skip;
- expected = frame+skip+STp->cur_frames+pending;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
- name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
-#endif
- osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
- flag = 0;
- attempts--;
- schedule_timeout_interruptible(msecs_to_jiffies(100));
- }
- if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
- name, STp->first_frame_position,
- STp->last_frame_position, STp->cur_frames);
-#endif
- frame = STp->last_frame_position;
- flag = 1;
- continue;
- }
- if (pending && STp->cur_frames < 50) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
- name, STp->frame_seq_number-1, STp->first_frame_position);
-#endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
-
- if (STp->buffer->syscall_result) { /* additional write error */
- if ((SRpnt->sense[ 2] & 0x0f) == 13 &&
- SRpnt->sense[12] == 0 &&
- SRpnt->sense[13] == 2) {
- printk(KERN_ERR
- "%s:E: Volume overflow in write error recovery\n",
- name);
- break; /* hit end of tape = fail */
- }
- flag = 1;
- }
- else
- pending = 0;
-
- continue;
- }
- if (STp->cur_frames == 0) {
-#if DEBUG
- debugging = dbg;
- printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
-#endif
- if (STp->first_frame_position != expected) {
- printk(KERN_ERR "%s:A: Actual position %d - expected %d\n",
- name, STp->first_frame_position, expected);
- return (-EIO);
- }
- return 0;
- }
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
- printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
- debugging = 0;
- }
-#endif
- schedule_timeout_interruptible(msecs_to_jiffies(100));
- }
- printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
-#if DEBUG
- debugging = dbg;
-#endif
- return (-EIO);
-}
-
-/*
- * Error recovery algorithm for the OnStream tape.
- */
-
-static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending)
-{
- struct osst_request * SRpnt = * aSRpnt;
- struct st_partstat * STps = & STp->ps[STp->partition];
- char * name = tape_name(STp);
- int retval = 0;
- int rw_state;
- unsigned int frame, skip;
-
- rw_state = STps->rw;
-
- if ((SRpnt->sense[ 2] & 0x0f) != 3
- || SRpnt->sense[12] != 12
- || SRpnt->sense[13] != 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
- SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]);
-#endif
- return (-EIO);
- }
- frame = (SRpnt->sense[3] << 24) |
- (SRpnt->sense[4] << 16) |
- (SRpnt->sense[5] << 8) |
- SRpnt->sense[6];
- skip = SRpnt->sense[9];
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
-#endif
- osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
- name, STp->first_frame_position, STp->last_frame_position);
-#endif
- switch (STp->write_type) {
- case OS_WRITE_DATA:
- case OS_WRITE_EOD:
- case OS_WRITE_NEW_MARK:
- printk(KERN_WARNING
- "%s:I: Relocating %d buffered logical frames from position %u to %u\n",
- name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
- if (STp->os_fw_rev >= 10600)
- retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
- else
- retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
- printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
- retval?"E" :"I",
- retval?"" :"Don't worry, ",
- retval?" not ":" ");
- break;
- case OS_WRITE_LAST_MARK:
- printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
- osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
- retval = -EIO;
- break;
- case OS_WRITE_HEADER:
- printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
- retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
- break;
- default:
- printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
- osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
- }
- osst_get_frame_position(STp, aSRpnt);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n",
- name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
- printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
-#endif
- if (retval == 0) {
- STp->recover_count++;
- STp->recover_erreg++;
- } else
- STp->abort_count++;
-
- STps->rw = rw_state;
- return retval;
-}
-
-static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt,
- int mt_op, int mt_count)
-{
- char * name = tape_name(STp);
- int cnt;
- int last_mark_ppos = -1;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
-#endif
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
-#endif
- return -EIO;
- }
- if (STp->linux_media_version >= 4) {
- /*
- * direct lookup in header filemark list
- */
- cnt = ntohl(STp->buffer->aux->filemark_cnt);
- if (STp->header_ok &&
- STp->header_cache != NULL &&
- (cnt - mt_count) >= 0 &&
- (cnt - mt_count) < OS_FM_TAB_MAX &&
- (cnt - mt_count) < STp->filemark_cnt &&
- STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
-
- last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
-#if DEBUG
- if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
- printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
- STp->header_cache == NULL?"lack of header cache":"count out of range");
- else
- printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
- name, cnt,
- ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
- (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
- STp->buffer->aux->last_mark_ppos))?"match":"error",
- mt_count, last_mark_ppos);
-#endif
- if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
- osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
- name, last_mark_ppos);
- return (-EIO);
- }
- goto found;
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
-#endif
- }
- cnt = 0;
- while (cnt != mt_count) {
- last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
- if (last_mark_ppos == -1)
- return (-EIO);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
-#endif
- osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
- cnt++;
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
- name, last_mark_ppos);
- return (-EIO);
- }
- }
-found:
- if (mt_op == MTBSFM) {
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->buffer->buffer_bytes = 0;
- STp->buffer->read_pointer = 0;
- STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- }
- return 0;
-}
-
-/*
- * ADRL 1.1 compatible "slow" space filemarks fwd version
- *
- * Just scans for the filemark sequentially.
- */
-static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt,
- int mt_op, int mt_count)
-{
- int cnt = 0;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
-#endif
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
-#endif
- return (-EIO);
- }
- while (1) {
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
- cnt++;
- if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
-#endif
- if (STp->first_frame_position > STp->eod_frame_ppos+1) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
- name, STp->eod_frame_ppos, STp->first_frame_position-1);
-#endif
- STp->eod_frame_ppos = STp->first_frame_position-1;
- }
- return (-EIO);
- }
- if (cnt == mt_count)
- break;
- STp->frame_in_buffer = 0;
- }
- if (mt_op == MTFSF) {
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->buffer->buffer_bytes = 0;
- STp->buffer->read_pointer = 0;
- STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- }
- return 0;
-}
-
-/*
- * Fast linux specific version of OnStream FSF
- */
-static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt,
- int mt_op, int mt_count)
-{
- char * name = tape_name(STp);
- int cnt = 0,
- next_mark_ppos = -1;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
-#endif
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
-#endif
- return (-EIO);
- }
-
- if (STp->linux_media_version >= 4) {
- /*
- * direct lookup in header filemark list
- */
- cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
- if (STp->header_ok &&
- STp->header_cache != NULL &&
- (cnt + mt_count) < OS_FM_TAB_MAX &&
- (cnt + mt_count) < STp->filemark_cnt &&
- ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
- (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
-
- next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
-#if DEBUG
- if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
- printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
- STp->header_cache == NULL?"lack of header cache":"count out of range");
- else
- printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
- name, cnt,
- ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
- (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
- STp->buffer->aux->last_mark_ppos))?"match":"error",
- mt_count, next_mark_ppos);
-#endif
- if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
- return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
- } else {
- osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
- name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
- name, next_mark_ppos);
- return (-EIO);
- }
- if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
- printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
- name, cnt+mt_count, next_mark_ppos,
- ntohl(STp->buffer->aux->filemark_cnt));
- return (-EIO);
- }
- }
- } else {
- /*
- * Find nearest (usually previous) marker, then jump from marker to marker
- */
- while (1) {
- if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
- break;
- if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
-#endif
- return (-EIO);
- }
- if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
- if (STp->first_mark_ppos == -1) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
- return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
- }
- osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
- name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
- name, STp->first_mark_ppos);
- return (-EIO);
- }
- } else {
- if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
- return (-EIO);
- mt_count++;
- }
- }
- cnt++;
- while (cnt != mt_count) {
- next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
- if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
-#endif
- return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
- }
-#if DEBUG
- else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
-#endif
- osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
- cnt++;
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
- name);
-#endif
- return (-EIO);
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
- printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
- name, next_mark_ppos);
- return (-EIO);
- }
- }
- }
- if (mt_op == MTFSF) {
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->buffer->buffer_bytes = 0;
- STp->buffer->read_pointer = 0;
- STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
- }
- return 0;
-}
-
-/*
- * In debug mode, we want to see as many errors as possible
- * to test the error recovery mechanism.
- */
-#if DEBUG
-static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt = * aSRpnt;
- char * name = tape_name(STp);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- (STp->buffer)->b_data[0] = cmd[4] - 1;
- (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
- (STp->buffer)->b_data[2] = 0; /* Reserved */
- (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
-
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result)
- printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
-}
-#endif
-
-
-static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int result;
- int this_mark_ppos = STp->first_frame_position;
- int this_mark_lbn = STp->logical_blk_num;
-#if DEBUG
- char * name = tape_name(STp);
-#endif
-
- if (STp->raw) return 0;
-
- STp->write_type = OS_WRITE_NEW_MARK;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n",
- name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
-#endif
- STp->dirty = 1;
- result = osst_flush_write_buffer(STp, aSRpnt);
- result |= osst_flush_drive_buffer(STp, aSRpnt);
- STp->last_mark_ppos = this_mark_ppos;
- STp->last_mark_lbn = this_mark_lbn;
- if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
- STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
- if (STp->filemark_cnt++ == 0)
- STp->first_mark_ppos = this_mark_ppos;
- return result;
-}
-
-static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int result;
-#if DEBUG
- char * name = tape_name(STp);
-#endif
-
- if (STp->raw) return 0;
-
- STp->write_type = OS_WRITE_EOD;
- STp->eod_frame_ppos = STp->first_frame_position;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
- STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
-#endif
- STp->dirty = 1;
-
- result = osst_flush_write_buffer(STp, aSRpnt);
- result |= osst_flush_drive_buffer(STp, aSRpnt);
- STp->eod_frame_lfa = --(STp->frame_seq_number);
- return result;
-}
-
-static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
-{
- char * name = tape_name(STp);
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
-#endif
- osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
- osst_set_frame_position(STp, aSRpnt, where, 0);
- STp->write_type = OS_WRITE_FILLER;
- while (count--) {
- memcpy(STp->buffer->b_data, "Filler", 6);
- STp->buffer->buffer_bytes = 6;
- STp->dirty = 1;
- if (osst_flush_write_buffer(STp, aSRpnt)) {
- printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
- return (-EIO);
- }
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
-#endif
- return osst_flush_drive_buffer(STp, aSRpnt);
-}
-
-static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count)
-{
- char * name = tape_name(STp);
- int result;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
-#endif
- osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
- osst_set_frame_position(STp, aSRpnt, where, 0);
- STp->write_type = OS_WRITE_HEADER;
- while (count--) {
- osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
- STp->buffer->buffer_bytes = sizeof(os_header_t);
- STp->dirty = 1;
- if (osst_flush_write_buffer(STp, aSRpnt)) {
- printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
- return (-EIO);
- }
- }
- result = osst_flush_drive_buffer(STp, aSRpnt);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
-#endif
- return result;
-}
-
-static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod)
-{
- os_header_t * header;
- int result;
- char * name = tape_name(STp);
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
-#endif
- if (STp->raw) return 0;
-
- if (STp->header_cache == NULL) {
- if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
- printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
- return (-ENOMEM);
- }
- memset(STp->header_cache, 0, sizeof(os_header_t));
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
-#endif
- }
- if (STp->header_ok) STp->update_frame_cntr++;
- else STp->update_frame_cntr = 0;
-
- header = STp->header_cache;
- strcpy(header->ident_str, "ADR_SEQ");
- header->major_rev = 1;
- header->minor_rev = 4;
- header->ext_trk_tb_off = htons(17192);
- header->pt_par_num = 1;
- header->partition[0].partition_num = OS_DATA_PARTITION;
- header->partition[0].par_desc_ver = OS_PARTITION_VERSION;
- header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr);
- header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos);
- header->partition[0].last_frame_ppos = htonl(STp->capacity);
- header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos);
- header->cfg_col_width = htonl(20);
- header->dat_col_width = htonl(1500);
- header->qfa_col_width = htonl(0);
- header->ext_track_tb.nr_stream_part = 1;
- header->ext_track_tb.et_ent_sz = 32;
- header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
- header->ext_track_tb.dat_ext_trk_ey.fmt = 1;
- header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736);
- header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
- header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa);
- header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos);
- header->dat_fm_tab.fm_part_num = 0;
- header->dat_fm_tab.fm_tab_ent_sz = 4;
- header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
- STp->filemark_cnt:OS_FM_TAB_MAX);
-
- result = __osst_write_header(STp, aSRpnt, 0xbae, 5);
- if (STp->update_frame_cntr == 0)
- osst_write_filler(STp, aSRpnt, 0xbb3, 5);
- result &= __osst_write_header(STp, aSRpnt, 5, 5);
-
- if (locate_eod) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
-#endif
- osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
- }
- if (result)
- printk(KERN_ERR "%s:E: Write header failed\n", name);
- else {
- memcpy(STp->application_sig, "LIN4", 4);
- STp->linux_media = 1;
- STp->linux_media_version = 4;
- STp->header_ok = 1;
- }
- return result;
-}
-
-static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- if (STp->header_cache != NULL)
- memset(STp->header_cache, 0, sizeof(os_header_t));
-
- STp->logical_blk_num = STp->frame_seq_number = 0;
- STp->frame_in_buffer = 0;
- STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
- STp->filemark_cnt = 0;
- STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
- return osst_write_header(STp, aSRpnt, 1);
-}
-
-static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos)
-{
- char * name = tape_name(STp);
- os_header_t * header;
- os_aux_t * aux;
- char id_string[8];
- int linux_media_version,
- update_frame_cntr;
-
- if (STp->raw)
- return 1;
-
- if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
- if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
- printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
- osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
- if (osst_initiate_read (STp, aSRpnt)) {
- printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
- return 0;
- }
- }
- if (osst_read_frame(STp, aSRpnt, 180)) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
-#endif
- return 0;
- }
- header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */
- aux = STp->buffer->aux;
- if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
-#endif
- return 0;
- }
- if (ntohl(aux->frame_seq_num) != 0 ||
- ntohl(aux->logical_blk_num) != 0 ||
- aux->partition.partition_num != OS_CONFIG_PARTITION ||
- ntohl(aux->partition.first_frame_ppos) != 0 ||
- ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
- ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
- aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
- ntohl(aux->partition.last_frame_ppos));
-#endif
- return 0;
- }
- if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
- strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
- strlcpy(id_string, header->ident_str, 8);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
-#endif
- return 0;
- }
- update_frame_cntr = ntohl(aux->update_frame_cntr);
- if (update_frame_cntr < STp->update_frame_cntr) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
- name, ppos, update_frame_cntr, STp->update_frame_cntr);
-#endif
- return 0;
- }
- if (header->major_rev != 1 || header->minor_rev != 4 ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n",
- name, (header->major_rev != 1 || header->minor_rev < 2 ||
- header->minor_rev > 4 )? "Invalid" : "Warning:",
- header->major_rev, header->minor_rev);
-#endif
- if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
- return 0;
- }
-#if DEBUG
- if (header->pt_par_num != 1)
- printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n",
- name, header->pt_par_num);
-#endif
- memcpy(id_string, aux->application_sig, 4);
- id_string[4] = 0;
- if (memcmp(id_string, "LIN", 3) == 0) {
- STp->linux_media = 1;
- linux_media_version = id_string[3] - '0';
- if (linux_media_version != 4)
- printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
- name, linux_media_version);
- } else {
- printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
- return 0;
- }
- if (linux_media_version < STp->linux_media_version) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
- name, ppos, linux_media_version);
-#endif
- return 0;
- }
- if (linux_media_version > STp->linux_media_version) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
- name, ppos, linux_media_version);
-#endif
- memcpy(STp->application_sig, id_string, 5);
- STp->linux_media_version = linux_media_version;
- STp->update_frame_cntr = -1;
- }
- if (update_frame_cntr > STp->update_frame_cntr) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
- name, ppos, update_frame_cntr);
-#endif
- if (STp->header_cache == NULL) {
- if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) {
- printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
- return 0;
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
-#endif
- }
- osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
- header = STp->header_cache; /* further accesses from cached (full) copy */
-
- STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr);
- STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos);
- STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos);
- STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
- STp->filemark_cnt = ntohl(aux->filemark_cnt);
- STp->first_mark_ppos = ntohl(aux->next_mark_ppos);
- STp->last_mark_ppos = ntohl(aux->last_mark_ppos);
- STp->last_mark_lbn = ntohl(aux->last_mark_lbn);
- STp->update_frame_cntr = update_frame_cntr;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
- name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
- printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
- STp->first_data_ppos,
- ntohl(header->partition[0].last_frame_ppos),
- ntohl(header->partition[0].eod_frame_ppos));
- printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n",
- name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
-#endif
- if (header->minor_rev < 4 && STp->linux_media_version == 4) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
-#endif
- memcpy((void *)header->dat_fm_tab.fm_tab_ent,
- (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
- memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
- }
- if (header->minor_rev == 4 &&
- (header->ext_trk_tb_off != htons(17192) ||
- header->partition[0].partition_num != OS_DATA_PARTITION ||
- header->partition[0].par_desc_ver != OS_PARTITION_VERSION ||
- header->partition[0].last_frame_ppos != htonl(STp->capacity) ||
- header->cfg_col_width != htonl(20) ||
- header->dat_col_width != htonl(1500) ||
- header->qfa_col_width != htonl(0) ||
- header->ext_track_tb.nr_stream_part != 1 ||
- header->ext_track_tb.et_ent_sz != 32 ||
- header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION ||
- header->ext_track_tb.dat_ext_trk_ey.fmt != 1 ||
- header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) ||
- header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 ||
- header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) ||
- header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION ||
- header->dat_fm_tab.fm_tab_ent_sz != 4 ||
- header->dat_fm_tab.fm_tab_ent_cnt !=
- htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
- printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
-
- }
-
- return 1;
-}
-
-static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int position, ppos;
- int first, last;
- int valid = 0;
- char * name = tape_name(STp);
-
- position = osst_get_frame_position(STp, aSRpnt);
-
- if (STp->raw) {
- STp->header_ok = STp->linux_media = 1;
- STp->linux_media_version = 0;
- return 1;
- }
- STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
- STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
- STp->eod_frame_ppos = STp->first_data_ppos = -1;
- STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
-#endif
-
- /* optimization for speed - if we are positioned at ppos 10, read second group first */
- /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
-
- first = position==10?0xbae: 5;
- last = position==10?0xbb3:10;
-
- for (ppos = first; ppos < last; ppos++)
- if (__osst_analyze_headers(STp, aSRpnt, ppos))
- valid = 1;
-
- first = position==10? 5:0xbae;
- last = position==10?10:0xbb3;
-
- for (ppos = first; ppos < last; ppos++)
- if (__osst_analyze_headers(STp, aSRpnt, ppos))
- valid = 1;
-
- if (!valid) {
- printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
- STp->eod_frame_ppos = STp->first_data_ppos = 0;
- osst_set_frame_position(STp, aSRpnt, 10, 0);
- return 0;
- }
- if (position <= STp->first_data_ppos) {
- position = STp->first_data_ppos;
- STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
- }
- osst_set_frame_position(STp, aSRpnt, position, 0);
- STp->header_ok = 1;
-
- return 1;
-}
-
-static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt)
-{
- int frame_position = STp->first_frame_position;
- int frame_seq_numbr = STp->frame_seq_number;
- int logical_blk_num = STp->logical_blk_num;
- int halfway_frame = STp->frame_in_buffer;
- int read_pointer = STp->buffer->read_pointer;
- int prev_mark_ppos = -1;
- int actual_mark_ppos, i, n;
-#if DEBUG
- char * name = tape_name(STp);
-
- printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
-#endif
- osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
- if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
-#endif
- return (-EIO);
- }
- if (STp->linux_media_version >= 4) {
- for (i=0; i<STp->filemark_cnt; i++)
- if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
- prev_mark_ppos = n;
- } else
- prev_mark_ppos = frame_position - 1; /* usually - we don't really know */
- actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
- frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
- if (frame_position != STp->first_frame_position ||
- frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
- prev_mark_ppos != actual_mark_ppos ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
- STp->first_frame_position, frame_position,
- STp->frame_seq_number + (halfway_frame?0:1),
- frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
-#endif
- return (-EIO);
- }
- if (halfway_frame) {
- /* prepare buffer for append and rewrite on top of original */
- osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
- STp->buffer->buffer_bytes = read_pointer;
- STp->ps[STp->partition].rw = ST_WRITING;
- STp->dirty = 1;
- }
- STp->frame_in_buffer = halfway_frame;
- STp->frame_seq_number = frame_seq_numbr;
- STp->logical_blk_num = logical_blk_num;
- return 0;
-}
-
-/* Acc. to OnStream, the vers. numbering is the following:
- * X.XX for released versions (X=digit),
- * XXXY for unreleased versions (Y=letter)
- * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06
- * This fn makes monoton numbers out of this scheme ...
- */
-static unsigned int osst_parse_firmware_rev (const char * str)
-{
- if (str[1] == '.') {
- return (str[0]-'0')*10000
- +(str[2]-'0')*1000
- +(str[3]-'0')*100;
- } else {
- return (str[0]-'0')*10000
- +(str[1]-'0')*1000
- +(str[2]-'0')*100 - 100
- +(str[3]-'@');
- }
-}
-
-/*
- * Configure the OnStream SCII tape drive for default operation
- */
-static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- char * name = tape_name(STp);
- struct osst_request * SRpnt = * aSRpnt;
- osst_mode_parameter_header_t * header;
- osst_block_size_page_t * bs;
- osst_capabilities_page_t * cp;
- osst_tape_paramtr_page_t * prm;
- int drive_buffer_size;
-
- if (STp->ready != ST_READY) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
-#endif
- return (-EIO);
- }
-
- if (STp->os_fw_rev < 10600) {
- printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
- printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
- }
-
- /*
- * Configure 32.5KB (data+aux) frame size.
- * Get the current frame size from the block size mode page
- */
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = BLOCK_SIZE_PAGE;
- cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
- if (SRpnt == NULL) {
-#if DEBUG
- printk(OSST_DEB_MSG "osst :D: Busy\n");
-#endif
- return (-EBUSY);
- }
- *aSRpnt = SRpnt;
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
- return (-EIO);
- }
-
- header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
- bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No");
- printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No");
- printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No");
- printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No");
-#endif
-
- /*
- * Configure default auto columns mode, 32.5KB transfer mode
- */
- bs->one = 1;
- bs->play32 = 0;
- bs->play32_5 = 1;
- bs->record32 = 0;
- bs->record32_5 = 1;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
- return (-EIO);
- }
-
-#if DEBUG
- printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
- /*
- * In debug mode, we want to see as many errors as possible
- * to test the error recovery mechanism.
- */
- osst_set_retries(STp, aSRpnt, 0);
- SRpnt = * aSRpnt;
-#endif
-
- /*
- * Set vendor name to 'LIN4' for "Linux support version 4".
- */
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
- header->medium_type = 0; /* Medium Type - ignoring */
- header->dsp = 0; /* Reserved */
- header->bdl = 0; /* Block Descriptor Length */
-
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name,
- (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
- return (-EIO);
- }
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = CAPABILITIES_PAGE;
- cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
- return (-EIO);
- }
-
- header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
- cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data +
- sizeof(osst_mode_parameter_header_t) + header->bdl);
-
- drive_buffer_size = ntohs(cp->buffer_size) / 2;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = TAPE_PARAMTR_PAGE;
- cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result != 0) {
- printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
- return (-EIO);
- }
-
- header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
- prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data +
- sizeof(osst_mode_parameter_header_t) + header->bdl);
-
- STp->density = prm->density;
- STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
- name, STp->density, STp->capacity / 32, drive_buffer_size);
-#endif
-
- return 0;
-
-}
-
-
-/* Step over EOF if it has been inadvertently crossed (ioctl not used because
- it messes up the block number). */
-static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward)
-{
- int result;
- char * name = tape_name(STp);
-
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
- name, forward ? "forward" : "backward");
-#endif
-
- if (forward) {
- /* assumes that the filemark is already read by the drive, so this is low cost */
- result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
- }
- else
- /* assumes this is only called if we just read the filemark! */
- result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
-
- if (result < 0)
- printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
- name, forward ? "forward" : "backward");
-
- return result;
-}
-
-
-/* Get the tape position. */
-
-static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
- unsigned char scmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- int result = 0;
- char * name = tape_name(STp);
-
- /* KG: We want to be able to use it for checking Write Buffer availability
- * and thus don't want to risk to overwrite anything. Exchange buffers ... */
- char mybuf[24];
- char * olddata = STp->buffer->b_data;
- int oldsize = STp->buffer->buffer_size;
-
- if (STp->ready != ST_READY) return (-EIO);
-
- memset (scmd, 0, MAX_COMMAND_SIZE);
- scmd[0] = READ_POSITION;
-
- STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
- SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
- if (!SRpnt) {
- STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
- return (-EBUSY);
- }
- *aSRpnt = SRpnt;
-
- if (STp->buffer->syscall_result)
- result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */
-
- if (result == -EINVAL)
- printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
- else {
- if (result == -EIO) { /* re-read position - this needs to preserve media errors */
- unsigned char mysense[16];
- memcpy (mysense, SRpnt->sense, 16);
- memset (scmd, 0, MAX_COMMAND_SIZE);
- scmd[0] = READ_POSITION;
- STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
- SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
- name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
- SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]);
-#endif
- if (!STp->buffer->syscall_result)
- memcpy (SRpnt->sense, mysense, 16);
- else
- printk(KERN_WARNING "%s:W: Double error in get position\n", name);
- }
- STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
- + ((STp->buffer)->b_data[5] << 16)
- + ((STp->buffer)->b_data[6] << 8)
- + (STp->buffer)->b_data[7];
- STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24)
- + ((STp->buffer)->b_data[ 9] << 16)
- + ((STp->buffer)->b_data[10] << 8)
- + (STp->buffer)->b_data[11];
- STp->cur_frames = (STp->buffer)->b_data[15];
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
- STp->first_frame_position, STp->last_frame_position,
- ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
- ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
- STp->cur_frames);
- }
-#endif
- if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
- STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
-#endif
- STp->first_frame_position = STp->last_frame_position;
- }
- }
- STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
-
- return (result == 0 ? STp->first_frame_position : result);
-}
-
-
-/* Set the tape block */
-static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip)
-{
- unsigned char scmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- struct st_partstat * STps;
- int result = 0;
- int pp = (ppos == 3000 && !skip)? 0 : ppos;
- char * name = tape_name(STp);
-
- if (STp->ready != ST_READY) return (-EIO);
-
- STps = &(STp->ps[STp->partition]);
-
- if (ppos < 0 || ppos > STp->capacity) {
- printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
- pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
- result = (-EINVAL);
- }
-
- do {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
-#endif
- memset (scmd, 0, MAX_COMMAND_SIZE);
- scmd[0] = SEEK_10;
- scmd[1] = 1;
- scmd[3] = (pp >> 24);
- scmd[4] = (pp >> 16);
- scmd[5] = (pp >> 8);
- scmd[6] = pp;
- if (skip)
- scmd[9] = 0x80;
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
- MAX_RETRIES, 1);
- if (!SRpnt)
- return (-EBUSY);
- *aSRpnt = SRpnt;
-
- if ((STp->buffer)->syscall_result != 0) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
- name, STp->first_frame_position, pp);
-#endif
- result = (-EIO);
- }
- if (pp != ppos)
- osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
- } while ((pp != ppos) && (pp = ppos));
- STp->first_frame_position = STp->last_frame_position = ppos;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->rw = ST_IDLE;
- STp->frame_in_buffer = 0;
- return result;
-}
-
-static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT)
-{
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- int result = 0;
-
- if (STp->write_type != OS_WRITE_NEW_MARK) {
- /* true unless the user wrote the filemark for us */
- result = osst_flush_drive_buffer(STp, aSRpnt);
- if (result < 0) goto out;
- result = osst_write_filemark(STp, aSRpnt);
- if (result < 0) goto out;
-
- if (STps->drv_file >= 0)
- STps->drv_file++ ;
- STps->drv_block = 0;
- }
- result = osst_write_eod(STp, aSRpnt);
- osst_write_header(STp, aSRpnt, leave_at_EOT);
-
- STps->eof = ST_FM;
-out:
- return result;
-}
-
-/* osst versions of st functions - augmented and stripped to suit OnStream only */
-
-/* Flush the write buffer (never need to write if variable blocksize). */
-static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt)
-{
- int offset, transfer, blks = 0;
- int result = 0;
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt = *aSRpnt;
- struct st_partstat * STps;
- char * name = tape_name(STp);
-
- if ((STp->buffer)->writing) {
- if (SRpnt == (STp->buffer)->last_SRpnt)
-#if DEBUG
- { printk(OSST_DEB_MSG
- "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name);
-#endif
- *aSRpnt = SRpnt = NULL;
-#if DEBUG
- } else if (SRpnt)
- printk(OSST_DEB_MSG
- "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name);
-#endif
- osst_write_behind_check(STp);
- if ((STp->buffer)->syscall_result) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
- name, (STp->buffer)->midlevel_result);
-#endif
- if ((STp->buffer)->midlevel_result == INT_MAX)
- return (-ENOSPC);
- return (-EIO);
- }
- }
-
- result = 0;
- if (STp->dirty == 1) {
-
- STp->write_count++;
- STps = &(STp->ps[STp->partition]);
- STps->rw = ST_WRITING;
- offset = STp->buffer->buffer_bytes;
- blks = (offset + STp->block_size - 1) / STp->block_size;
- transfer = OS_FRAME_SIZE;
-
- if (offset < OS_DATA_SIZE)
- osst_zero_buffer_tail(STp->buffer);
-
- if (STp->poll)
- if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
- result = osst_recover_wait_frame(STp, aSRpnt, 1);
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1;
-
- switch (STp->write_type) {
- case OS_WRITE_DATA:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
- name, blks, STp->frame_seq_number,
- STp->logical_blk_num - blks, STp->logical_blk_num - 1);
-#endif
- osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
- STp->logical_blk_num - blks, STp->block_size, blks);
- break;
- case OS_WRITE_EOD:
- osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
- STp->logical_blk_num, 0, 0);
- break;
- case OS_WRITE_NEW_MARK:
- osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
- STp->logical_blk_num++, 0, blks=1);
- break;
- case OS_WRITE_HEADER:
- osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
- break;
- default: /* probably FILLER */
- osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
- }
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n",
- name, offset, transfer, blks);
-#endif
-
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
- STp->timeout, MAX_RETRIES, 1);
- *aSRpnt = SRpnt;
- if (!SRpnt)
- return (-EBUSY);
-
- if ((STp->buffer)->syscall_result != 0) {
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
- name, SRpnt->sense[0], SRpnt->sense[2],
- SRpnt->sense[12], SRpnt->sense[13]);
-#endif
- if ((SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
- (SRpnt->sense[2] & 0x0f) == NO_SENSE) {
- STp->dirty = 0;
- (STp->buffer)->buffer_bytes = 0;
- result = (-ENOSPC);
- }
- else {
- if (osst_write_error_recovery(STp, aSRpnt, 1)) {
- printk(KERN_ERR "%s:E: Error on flush write.\n", name);
- result = (-EIO);
- }
- }
- STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */
- }
- else {
- STp->first_frame_position++;
- STp->dirty = 0;
- (STp->buffer)->buffer_bytes = 0;
- }
- }
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
-#endif
- return result;
-}
-
-
-/* Flush the tape buffer. The tape will be positioned correctly unless
- seek_next is true. */
-static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next)
-{
- struct st_partstat * STps;
- int backspace = 0, result = 0;
-#if DEBUG
- char * name = tape_name(STp);
-#endif
-
- /*
- * If there was a bus reset, block further access
- * to this device.
- */
- if( STp->pos_unknown)
- return (-EIO);
-
- if (STp->ready != ST_READY)
- return 0;
-
- STps = &(STp->ps[STp->partition]);
- if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
- STp->write_type = OS_WRITE_DATA;
- return osst_flush_write_buffer(STp, aSRpnt);
- }
- if (STp->block_size == 0)
- return 0;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
-#endif
-
- if (!STp->can_bsr) {
- backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
- ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ;
- (STp->buffer)->buffer_bytes = 0;
- (STp->buffer)->read_pointer = 0;
- STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */
- }
-
- if (!seek_next) {
- if (STps->eof == ST_FM_HIT) {
- result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
- if (!result)
- STps->eof = ST_NOEOF;
- else {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- }
- }
- if (!result && backspace > 0) /* TODO -- design and run a test case for this */
- result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
- }
- else if (STps->eof == ST_FM_HIT) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_NOEOF;
- }
-
- return result;
-}
-
-static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous)
-{
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt;
- int blks;
-#if DEBUG
- char * name = tape_name(STp);
-#endif
-
- if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
-#endif
- if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
- return (-EIO);
- }
- /* error recovery may have bumped us past the header partition */
- if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
-#endif
- osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
- }
- }
-
- if (STp->poll)
- if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
- if (osst_recover_wait_frame(STp, aSRpnt, 1))
- return (-EIO);
-
-// osst_build_stats(STp, &SRpnt);
-
- STp->ps[STp->partition].rw = ST_WRITING;
- STp->write_type = OS_WRITE_DATA;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = WRITE_6;
- cmd[1] = 1;
- cmd[4] = 1; /* one frame at a time... */
- blks = STp->buffer->buffer_bytes / STp->block_size;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks,
- STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
-#endif
- osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
- STp->logical_blk_num - blks, STp->block_size, blks);
-
-#if DEBUG
- if (!synchronous)
- STp->write_pending = 1;
-#endif
- SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
- MAX_RETRIES, synchronous);
- if (!SRpnt)
- return (-EBUSY);
- *aSRpnt = SRpnt;
-
- if (synchronous) {
- if (STp->buffer->syscall_result != 0) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
-#endif
- if ((SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x40)) {
- if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW)
- return (-ENOSPC);
- }
- else {
- if (osst_write_error_recovery(STp, aSRpnt, 1))
- return (-EIO);
- }
- }
- else
- STp->first_frame_position++;
- }
-
- STp->write_count++;
-
- return 0;
-}
-
-/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
-static int do_door_lock(struct osst_tape * STp, int do_lock)
-{
- int retval;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
-#endif
-
- retval = scsi_set_medium_removal(STp->device,
- do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
- if (!retval)
- STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
- else
- STp->door_locked = ST_LOCK_FAILS;
- return retval;
-}
-
-/* Set the internal state after reset */
-static void reset_state(struct osst_tape *STp)
-{
- int i;
- struct st_partstat *STps;
-
- STp->pos_unknown = 0;
- for (i = 0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = 0;
- STps->drv_block = -1;
- STps->drv_file = -1;
- }
-}
-
-
-/* Entry points to osst */
-
-/* Write command */
-static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
-{
- ssize_t total, retval = 0;
- ssize_t i, do_count, blks, transfer;
- int write_threshold;
- int doing_write = 0;
- const char __user * b_point;
- struct osst_request * SRpnt = NULL;
- struct st_modedef * STm;
- struct st_partstat * STps;
- struct osst_tape * STp = filp->private_data;
- char * name = tape_name(STp);
-
-
- if (mutex_lock_interruptible(&STp->lock))
- return (-ERESTARTSYS);
-
- /*
- * If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.
- */
- if( !scsi_block_when_processing_errors(STp->device) ) {
- retval = (-ENXIO);
- goto out;
- }
-
- if (STp->ready != ST_READY) {
- if (STp->ready == ST_NO_TAPE)
- retval = (-ENOMEDIUM);
- else
- retval = (-EIO);
- goto out;
- }
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
- if (count == 0)
- goto out;
-
- /*
- * If there was a bus reset, block further access
- * to this device.
- */
- if (STp->pos_unknown) {
- retval = (-EIO);
- goto out;
- }
-
-#if DEBUG
- if (!STp->in_use) {
- printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
- retval = (-EIO);
- goto out;
- }
-#endif
-
- if (STp->write_prot) {
- retval = (-EACCES);
- goto out;
- }
-
- /* Write must be integral number of blocks */
- if (STp->block_size != 0 && (count % STp->block_size) != 0) {
- printk(KERN_ERR "%s:E: Write (%zd bytes) not multiple of tape block size (%d%c).\n",
- name, count, STp->block_size<1024?
- STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
- retval = (-EINVAL);
- goto out;
- }
-
- if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
- printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
- name, STp->first_frame_position);
- retval = (-ENOSPC);
- goto out;
- }
-
- if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
- STp->door_locked = ST_LOCKED_AUTO;
-
- STps = &(STp->ps[STp->partition]);
-
- if (STps->rw == ST_READING) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
- STps->drv_file, STps->drv_block);
-#endif
- retval = osst_flush_buffer(STp, &SRpnt, 0);
- if (retval)
- goto out;
- STps->rw = ST_IDLE;
- }
- if (STps->rw != ST_WRITING) {
- /* Are we totally rewriting this tape? */
- if (!STp->header_ok ||
- (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
- (STps->drv_file == 0 && STps->drv_block == 0)) {
- STp->wrt_pass_cntr++;
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
- name, STp->wrt_pass_cntr);
-#endif
- osst_reset_header(STp, &SRpnt);
- STps->drv_file = STps->drv_block = 0;
- }
- /* Do we know where we'll be writing on the tape? */
- else {
- if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
- STps->drv_file < 0 || STps->drv_block < 0) {
- if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */
- STps->drv_file = STp->filemark_cnt;
- STps->drv_block = 0;
- }
- else {
- /* We have no idea where the tape is positioned - give up */
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: Cannot write at indeterminate position.\n", name);
-#endif
- retval = (-EIO);
- goto out;
- }
- }
- if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
- STp->filemark_cnt = STps->drv_file;
- STp->last_mark_ppos =
- ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
- printk(KERN_WARNING
- "%s:W: Overwriting file %d with old write pass counter %d\n",
- name, STps->drv_file, STp->wrt_pass_cntr);
- printk(KERN_WARNING
- "%s:W: may lead to stale data being accepted on reading back!\n",
- name);
-#if DEBUG
- printk(OSST_DEB_MSG
- "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
- name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
-#endif
- }
- }
- STp->fast_open = 0;
- }
- if (!STp->header_ok) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
-#endif
- retval = (-EIO);
- goto out;
- }
-
- if ((STp->buffer)->writing) {
-if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
- osst_write_behind_check(STp);
- if ((STp->buffer)->syscall_result) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
- (STp->buffer)->midlevel_result);
-#endif
- if ((STp->buffer)->midlevel_result == INT_MAX)
- STps->eof = ST_EOM_OK;
- else
- STps->eof = ST_EOM_ERROR;
- }
- }
- if (STps->eof == ST_EOM_OK) {
- retval = (-ENOSPC);
- goto out;
- }
- else if (STps->eof == ST_EOM_ERROR) {
- retval = (-EIO);
- goto out;
- }
-
- /* Check the buffer readability in cases where copy_user might catch
- the problems after some tape movement. */
- if ((copy_from_user(&i, buf, 1) != 0 ||
- copy_from_user(&i, buf + count - 1, 1) != 0)) {
- retval = (-EFAULT);
- goto out;
- }
-
- if (!STm->do_buffer_writes) {
- write_threshold = 1;
- }
- else
- write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
- if (!STm->do_async_writes)
- write_threshold--;
-
- total = count;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
- name, (int) count, STps->drv_file, STps->drv_block,
- STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
-#endif
- b_point = buf;
- while ((STp->buffer)->buffer_bytes + count > write_threshold)
- {
- doing_write = 1;
- do_count = (STp->buffer)->buffer_blocks * STp->block_size -
- (STp->buffer)->buffer_bytes;
- if (do_count > count)
- do_count = count;
-
- i = append_to_buffer(b_point, STp->buffer, do_count);
- if (i) {
- retval = i;
- goto out;
- }
-
- blks = do_count / STp->block_size;
- STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */
-
- i = osst_write_frame(STp, &SRpnt, 1);
-
- if (i == (-ENOSPC)) {
- transfer = STp->buffer->writing; /* FIXME -- check this logic */
- if (transfer <= do_count) {
- *ppos += do_count - transfer;
- count -= do_count - transfer;
- if (STps->drv_block >= 0) {
- STps->drv_block += (do_count - transfer) / STp->block_size;
- }
- STps->eof = ST_EOM_OK;
- retval = (-ENOSPC); /* EOM within current request */
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
- name, (int) transfer);
-#endif
- }
- else {
- STps->eof = ST_EOM_ERROR;
- STps->drv_block = (-1); /* Too cautious? */
- retval = (-EIO); /* EOM for old data */
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
-#endif
- }
- }
- else
- retval = i;
-
- if (retval < 0) {
- if (SRpnt != NULL) {
- osst_release_request(SRpnt);
- SRpnt = NULL;
- }
- STp->buffer->buffer_bytes = 0;
- STp->dirty = 0;
- if (count < total)
- retval = total - count;
- goto out;
- }
-
- *ppos += do_count;
- b_point += do_count;
- count -= do_count;
- if (STps->drv_block >= 0) {
- STps->drv_block += blks;
- }
- STp->buffer->buffer_bytes = 0;
- STp->dirty = 0;
- } /* end while write threshold exceeded */
-
- if (count != 0) {
- STp->dirty = 1;
- i = append_to_buffer(b_point, STp->buffer, count);
- if (i) {
- retval = i;
- goto out;
- }
- blks = count / STp->block_size;
- STp->logical_blk_num += blks;
- if (STps->drv_block >= 0) {
- STps->drv_block += blks;
- }
- *ppos += count;
- count = 0;
- }
-
- if (doing_write && (STp->buffer)->syscall_result != 0) {
- retval = (STp->buffer)->syscall_result;
- goto out;
- }
-
- if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) {
- /* Schedule an asynchronous write */
- (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
- STp->block_size) * STp->block_size;
- STp->dirty = !((STp->buffer)->writing ==
- (STp->buffer)->buffer_bytes);
-
- i = osst_write_frame(STp, &SRpnt, 0);
- if (i < 0) {
- retval = (-EIO);
- goto out;
- }
- SRpnt = NULL; /* Prevent releasing this request! */
- }
- STps->at_sm &= (total == 0);
- if (total > 0)
- STps->eof = ST_NOEOF;
-
- retval = total;
-
-out:
- if (SRpnt != NULL) osst_release_request(SRpnt);
-
- mutex_unlock(&STp->lock);
-
- return retval;
-}
-
-
-/* Read command */
-static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
-{
- ssize_t total, retval = 0;
- ssize_t i, transfer;
- int special;
- struct st_modedef * STm;
- struct st_partstat * STps;
- struct osst_request * SRpnt = NULL;
- struct osst_tape * STp = filp->private_data;
- char * name = tape_name(STp);
-
-
- if (mutex_lock_interruptible(&STp->lock))
- return (-ERESTARTSYS);
-
- /*
- * If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.
- */
- if( !scsi_block_when_processing_errors(STp->device) ) {
- retval = (-ENXIO);
- goto out;
- }
-
- if (STp->ready != ST_READY) {
- if (STp->ready == ST_NO_TAPE)
- retval = (-ENOMEDIUM);
- else
- retval = (-EIO);
- goto out;
- }
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
-#if DEBUG
- if (!STp->in_use) {
- printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
- retval = (-EIO);
- goto out;
- }
-#endif
- /* Must have initialized medium */
- if (!STp->header_ok) {
- retval = (-EIO);
- goto out;
- }
-
- if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
- STp->door_locked = ST_LOCKED_AUTO;
-
- STps = &(STp->ps[STp->partition]);
- if (STps->rw == ST_WRITING) {
- retval = osst_flush_buffer(STp, &SRpnt, 0);
- if (retval)
- goto out;
- STps->rw = ST_IDLE;
- /* FIXME -- this may leave the tape without EOD and up2date headers */
- }
-
- if ((count % STp->block_size) != 0) {
- printk(KERN_WARNING
- "%s:W: Read (%zd bytes) not multiple of tape block size (%d%c).\n", name, count,
- STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
- }
-
-#if DEBUG
- if (debugging && STps->eof != ST_NOEOF)
- printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
- STps->eof, (STp->buffer)->buffer_bytes);
-#endif
- if ((STp->buffer)->buffer_bytes == 0 &&
- STps->eof >= ST_EOD_1) {
- if (STps->eof < ST_EOD) {
- STps->eof += 1;
- retval = 0;
- goto out;
- }
- retval = (-EIO); /* EOM or Blank Check */
- goto out;
- }
-
- /* Check the buffer writability before any tape movement. Don't alter
- buffer data. */
- if (copy_from_user(&i, buf, 1) != 0 ||
- copy_to_user (buf, &i, 1) != 0 ||
- copy_from_user(&i, buf + count - 1, 1) != 0 ||
- copy_to_user (buf + count - 1, &i, 1) != 0) {
- retval = (-EFAULT);
- goto out;
- }
-
- /* Loop until enough data in buffer or a special condition found */
- for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
-
- /* Get new data if the buffer is empty */
- if ((STp->buffer)->buffer_bytes == 0) {
- if (STps->eof == ST_FM_HIT)
- break;
- special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
- if (special < 0) { /* No need to continue read */
- STp->frame_in_buffer = 0;
- retval = special;
- goto out;
- }
- }
-
- /* Move the data from driver buffer to user buffer */
- if ((STp->buffer)->buffer_bytes > 0) {
-#if DEBUG
- if (debugging && STps->eof != ST_NOEOF)
- printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
- STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total));
-#endif
- /* force multiple of block size, note block_size may have been adjusted */
- transfer = (((STp->buffer)->buffer_bytes < count - total ?
- (STp->buffer)->buffer_bytes : count - total)/
- STp->block_size) * STp->block_size;
-
- if (transfer == 0) {
- printk(KERN_WARNING
- "%s:W: Nothing can be transferred, requested %zd, tape block size (%d%c).\n",
- name, count, STp->block_size < 1024?
- STp->block_size:STp->block_size/1024,
- STp->block_size<1024?'b':'k');
- break;
- }
- i = from_buffer(STp->buffer, buf, transfer);
- if (i) {
- retval = i;
- goto out;
- }
- STp->logical_blk_num += transfer / STp->block_size;
- STps->drv_block += transfer / STp->block_size;
- *ppos += transfer;
- buf += transfer;
- total += transfer;
- }
-
- if ((STp->buffer)->buffer_bytes == 0) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
- name, STp->frame_seq_number);
-#endif
- STp->frame_in_buffer = 0;
- STp->frame_seq_number++; /* frame to look for next time */
- }
- } /* for (total = 0, special = 0; total < count && !special; ) */
-
- /* Change the eof state if no data from tape or buffer */
- if (total == 0) {
- if (STps->eof == ST_FM_HIT) {
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
- STps->drv_block = 0;
- if (STps->drv_file >= 0)
- STps->drv_file++;
- }
- else if (STps->eof == ST_EOD_1) {
- STps->eof = ST_EOD_2;
- if (STps->drv_block > 0 && STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- }
- else if (STps->eof == ST_EOD_2)
- STps->eof = ST_EOD;
- }
- else if (STps->eof == ST_FM)
- STps->eof = ST_NOEOF;
-
- retval = total;
-
-out:
- if (SRpnt != NULL) osst_release_request(SRpnt);
-
- mutex_unlock(&STp->lock);
-
- return retval;
-}
-
-
-/* Set the driver options */
-static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
-{
- printk(KERN_INFO
-"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
- name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
- STm->do_read_ahead);
- printk(KERN_INFO
-"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
- name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
- printk(KERN_INFO
-"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
- name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
- STp->scsi2_logical);
- printk(KERN_INFO
-"%s:I: sysv: %d\n", name, STm->sysv);
-#if DEBUG
- printk(KERN_INFO
- "%s:D: debugging: %d\n",
- name, debugging);
-#endif
-}
-
-
-static int osst_set_options(struct osst_tape *STp, long options)
-{
- int value;
- long code;
- struct st_modedef * STm;
- char * name = tape_name(STp);
-
- STm = &(STp->modes[STp->current_mode]);
- if (!STm->defined) {
- memcpy(STm, &(STp->modes[0]), sizeof(*STm));
- modes_defined = 1;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
- name, STp->current_mode);
-#endif
- }
-
- code = options & MT_ST_OPTIONS;
- if (code == MT_ST_BOOLEANS) {
- STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
- STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
- STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
- STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
- STp->two_fm = (options & MT_ST_TWO_FM) != 0;
- STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
- STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
- STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
- STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
- if ((STp->device)->scsi_level >= SCSI_2)
- STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
- STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
- STm->sysv = (options & MT_ST_SYSV) != 0;
-#if DEBUG
- debugging = (options & MT_ST_DEBUGGING) != 0;
-#endif
- osst_log_options(STp, STm, name);
- }
- else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
- value = (code == MT_ST_SETBOOLEANS);
- if ((options & MT_ST_BUFFER_WRITES) != 0)
- STm->do_buffer_writes = value;
- if ((options & MT_ST_ASYNC_WRITES) != 0)
- STm->do_async_writes = value;
- if ((options & MT_ST_DEF_WRITES) != 0)
- STm->defaults_for_writes = value;
- if ((options & MT_ST_READ_AHEAD) != 0)
- STm->do_read_ahead = value;
- if ((options & MT_ST_TWO_FM) != 0)
- STp->two_fm = value;
- if ((options & MT_ST_FAST_MTEOM) != 0)
- STp->fast_mteom = value;
- if ((options & MT_ST_AUTO_LOCK) != 0)
- STp->do_auto_lock = value;
- if ((options & MT_ST_CAN_BSR) != 0)
- STp->can_bsr = value;
- if ((options & MT_ST_NO_BLKLIMS) != 0)
- STp->omit_blklims = value;
- if ((STp->device)->scsi_level >= SCSI_2 &&
- (options & MT_ST_CAN_PARTITIONS) != 0)
- STp->can_partitions = value;
- if ((options & MT_ST_SCSI2LOGICAL) != 0)
- STp->scsi2_logical = value;
- if ((options & MT_ST_SYSV) != 0)
- STm->sysv = value;
-#if DEBUG
- if ((options & MT_ST_DEBUGGING) != 0)
- debugging = value;
-#endif
- osst_log_options(STp, STm, name);
- }
- else if (code == MT_ST_WRITE_THRESHOLD) {
- value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
- if (value < 1 || value > osst_buffer_size) {
- printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
- name, value);
- return (-EIO);
- }
- STp->write_threshold = value;
- printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
- name, value);
- }
- else if (code == MT_ST_DEF_BLKSIZE) {
- value = (options & ~MT_ST_OPTIONS);
- if (value == ~MT_ST_OPTIONS) {
- STm->default_blksize = (-1);
- printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
- }
- else {
- if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
- printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
- name, value);
- return (-EINVAL);
- }
- STm->default_blksize = value;
- printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
- name, STm->default_blksize);
- }
- }
- else if (code == MT_ST_TIMEOUTS) {
- value = (options & ~MT_ST_OPTIONS);
- if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
- STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
- printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
- (value & ~MT_ST_SET_LONG_TIMEOUT));
- }
- else {
- STp->timeout = value * HZ;
- printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
- }
- }
- else if (code == MT_ST_DEF_OPTIONS) {
- code = (options & ~MT_ST_CLEAR_DEFAULT);
- value = (options & MT_ST_CLEAR_DEFAULT);
- if (code == MT_ST_DEF_DENSITY) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STm->default_density = (-1);
- printk(KERN_INFO "%s:I: Density default disabled.\n", name);
- }
- else {
- STm->default_density = value & 0xff;
- printk(KERN_INFO "%s:I: Density default set to %x\n",
- name, STm->default_density);
- }
- }
- else if (code == MT_ST_DEF_DRVBUFFER) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STp->default_drvbuffer = 0xff;
- printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
- }
- else {
- STp->default_drvbuffer = value & 7;
- printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
- name, STp->default_drvbuffer);
- }
- }
- else if (code == MT_ST_DEF_COMPRESSION) {
- if (value == MT_ST_CLEAR_DEFAULT) {
- STm->default_compression = ST_DONT_TOUCH;
- printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
- }
- else {
- STm->default_compression = (value & 1 ? ST_YES : ST_NO);
- printk(KERN_INFO "%s:I: Compression default set to %x\n",
- name, (value & 1));
- }
- }
- }
- else
- return (-EIO);
-
- return 0;
-}
-
-
-/* Internal ioctl function */
-static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt,
- unsigned int cmd_in, unsigned long arg)
-{
- int timeout;
- long ltmp;
- int i, ioctl_result;
- int chg_eof = 1;
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt = * aSRpnt;
- struct st_partstat * STps;
- int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
- int datalen = 0, direction = DMA_NONE;
- char * name = tape_name(STp);
-
- if (STp->ready != ST_READY && cmd_in != MTLOAD) {
- if (STp->ready == ST_NO_TAPE)
- return (-ENOMEDIUM);
- else
- return (-EIO);
- }
- timeout = STp->long_timeout;
- STps = &(STp->ps[STp->partition]);
- fileno = STps->drv_file;
- blkno = STps->drv_block;
- at_sm = STps->at_sm;
- frame_seq_numbr = STp->frame_seq_number;
- logical_blk_num = STp->logical_blk_num;
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- switch (cmd_in) {
- case MTFSFM:
- chg_eof = 0; /* Changed from the FSF after this */
- case MTFSF:
- if (STp->raw)
- return (-EIO);
- if (STp->linux_media)
- ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
- else
- ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
- if (fileno >= 0)
- fileno += arg;
- blkno = 0;
- at_sm &= (arg == 0);
- goto os_bypass;
-
- case MTBSF:
- chg_eof = 0; /* Changed from the FSF after this */
- case MTBSFM:
- if (STp->raw)
- return (-EIO);
- ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
- if (fileno >= 0)
- fileno -= arg;
- blkno = (-1); /* We can't know the block number */
- at_sm &= (arg == 0);
- goto os_bypass;
-
- case MTFSR:
- case MTBSR:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
- name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
-#endif
- if (cmd_in == MTFSR) {
- logical_blk_num += arg;
- if (blkno >= 0) blkno += arg;
- }
- else {
- logical_blk_num -= arg;
- if (blkno >= 0) blkno -= arg;
- }
- ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
- fileno = STps->drv_file;
- blkno = STps->drv_block;
- at_sm &= (arg == 0);
- goto os_bypass;
-
- case MTFSS:
- cmd[0] = SPACE;
- cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
- cmd[2] = (arg >> 16);
- cmd[3] = (arg >> 8);
- cmd[4] = arg;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
- if (arg != 0) {
- blkno = fileno = (-1);
- at_sm = 1;
- }
- break;
- case MTBSS:
- cmd[0] = SPACE;
- cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */
- ltmp = (-arg);
- cmd[2] = (ltmp >> 16);
- cmd[3] = (ltmp >> 8);
- cmd[4] = ltmp;
-#if DEBUG
- if (debugging) {
- if (cmd[2] & 0x80)
- ltmp = 0xff000000;
- ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
- name, (-ltmp));
- }
-#endif
- if (arg != 0) {
- blkno = fileno = (-1);
- at_sm = 1;
- }
- break;
- case MTWEOF:
- if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
- STp->write_type = OS_WRITE_DATA;
- ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
- } else
- ioctl_result = 0;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
-#endif
- for (i=0; i<arg; i++)
- ioctl_result |= osst_write_filemark(STp, &SRpnt);
- if (fileno >= 0) fileno += arg;
- if (blkno >= 0) blkno = 0;
- goto os_bypass;
-
- case MTWSM:
- if (STp->write_prot)
- return (-EACCES);
- if (!STp->raw)
- return 0;
- cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */
- if (cmd_in == MTWSM)
- cmd[1] = 2;
- cmd[2] = (arg >> 16);
- cmd[3] = (arg >> 8);
- cmd[4] = arg;
- timeout = STp->timeout;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
- if (fileno >= 0)
- fileno += arg;
- blkno = 0;
- at_sm = (cmd_in == MTWSM);
- break;
- case MTOFFL:
- case MTLOAD:
- case MTUNLOAD:
- case MTRETEN:
- cmd[0] = START_STOP;
- cmd[1] = 1; /* Don't wait for completion */
- if (cmd_in == MTLOAD) {
- if (STp->ready == ST_NO_TAPE)
- cmd[4] = 4; /* open tray */
- else
- cmd[4] = 1; /* load */
- }
- if (cmd_in == MTRETEN)
- cmd[4] = 3; /* retension then mount */
- if (cmd_in == MTOFFL)
- cmd[4] = 4; /* rewind then eject */
- timeout = STp->timeout;
-#if DEBUG
- if (debugging) {
- switch (cmd_in) {
- case MTUNLOAD:
- printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
- break;
- case MTLOAD:
- printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
- break;
- case MTRETEN:
- printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
- break;
- case MTOFFL:
- printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
- break;
- }
- }
-#endif
- fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
- break;
- case MTNOP:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
-#endif
- return 0; /* Should do something ? */
- break;
- case MTEOM:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
-#endif
- if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
- (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) {
- ioctl_result = -EIO;
- goto os_bypass;
- }
- if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
-#endif
- ioctl_result = -EIO;
- goto os_bypass;
- }
- ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
- fileno = STp->filemark_cnt;
- blkno = at_sm = 0;
- goto os_bypass;
-
- case MTERASE:
- if (STp->write_prot)
- return (-EACCES);
- ioctl_result = osst_reset_header(STp, &SRpnt);
- i = osst_write_eod(STp, &SRpnt);
- if (i < ioctl_result) ioctl_result = i;
- i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
- if (i < ioctl_result) ioctl_result = i;
- fileno = blkno = at_sm = 0 ;
- goto os_bypass;
-
- case MTREW:
- cmd[0] = REZERO_UNIT; /* rewind */
- cmd[1] = 1;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
-#endif
- fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
- break;
-
- case MTSETBLK: /* Set block length */
- if ((STps->drv_block == 0 ) &&
- !STp->dirty &&
- ((STp->buffer)->buffer_bytes == 0) &&
- ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) &&
- ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
- !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) {
- /*
- * Only allowed to change the block size if you opened the
- * device at the beginning of a file before writing anything.
- * Note, that when reading, changing block_size is futile,
- * as the size used when writing overrides it.
- */
- STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
- printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
- name, STp->block_size);
- return 0;
- }
- case MTSETDENSITY: /* Set tape density */
- case MTSETDRVBUFFER: /* Set drive buffering */
- case SET_DENS_AND_BLK: /* Set density and block size */
- chg_eof = 0;
- if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
- return (-EIO); /* Not allowed if data in buffer */
- if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
- (arg & MT_ST_BLKSIZE_MASK) != 0 &&
- (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) {
- printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
- name, (int)(arg & MT_ST_BLKSIZE_MASK),
- (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
- return (-EINVAL);
- }
- return 0; /* FIXME silently ignore if block size didn't change */
-
- default:
- return (-ENOSYS);
- }
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
-
- ioctl_result = (STp->buffer)->syscall_result;
-
- if (!SRpnt) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
-#endif
- return ioctl_result;
- }
-
- if (!ioctl_result) { /* SCSI command successful */
- STp->frame_seq_number = frame_seq_numbr;
- STp->logical_blk_num = logical_blk_num;
- }
-
-os_bypass:
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
-#endif
-
- if (!ioctl_result) { /* success */
-
- if (cmd_in == MTFSFM) {
- fileno--;
- blkno--;
- }
- if (cmd_in == MTBSFM) {
- fileno++;
- blkno++;
- }
- STps->drv_block = blkno;
- STps->drv_file = fileno;
- STps->at_sm = at_sm;
-
- if (cmd_in == MTEOM)
- STps->eof = ST_EOD;
- else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
- ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
- STps->drv_block++;
- STp->logical_blk_num++;
- STp->frame_seq_number++;
- STp->frame_in_buffer = 0;
- STp->buffer->read_pointer = 0;
- }
- else if (cmd_in == MTFSF)
- STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
- else if (chg_eof)
- STps->eof = ST_NOEOF;
-
- if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
- STp->rew_at_close = 0;
- else if (cmd_in == MTLOAD) {
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STp->ps[i].rw = ST_IDLE;
- STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
- }
- STp->partition = 0;
- }
-
- if (cmd_in == MTREW) {
- ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
- if (ioctl_result > 0)
- ioctl_result = 0;
- }
-
- } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
- if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
- STps->drv_file = STps->drv_block = -1;
- else
- STps->drv_file = STps->drv_block = 0;
- STps->eof = ST_NOEOF;
- } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
- if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
- STps->drv_file = STps->drv_block = -1;
- else {
- STps->drv_file = STp->filemark_cnt;
- STps->drv_block = 0;
- }
- STps->eof = ST_EOD;
- } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
- STps->drv_file = STps->drv_block = (-1);
- STps->eof = ST_NOEOF;
- STp->header_ok = 0;
- } else if (cmd_in == MTERASE) {
- STp->header_ok = 0;
- } else if (SRpnt) { /* SCSI command was not completely successful. */
- if (SRpnt->sense[2] & 0x40) {
- STps->eof = ST_EOM_OK;
- STps->drv_block = 0;
- }
- if (chg_eof)
- STps->eof = ST_NOEOF;
-
- if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK)
- STps->eof = ST_EOD;
-
- if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
- ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
- }
- *aSRpnt = SRpnt;
-
- return ioctl_result;
-}
-
-
-/* Open the device */
-static int __os_scsi_tape_open(struct inode * inode, struct file * filp)
-{
- unsigned short flags;
- int i, b_size, new_session = 0, retval = 0;
- unsigned char cmd[MAX_COMMAND_SIZE];
- struct osst_request * SRpnt = NULL;
- struct osst_tape * STp;
- struct st_modedef * STm;
- struct st_partstat * STps;
- char * name;
- int dev = TAPE_NR(inode);
- int mode = TAPE_MODE(inode);
-
- /*
- * We really want to do nonseekable_open(inode, filp); here, but some
- * versions of tar incorrectly call lseek on tapes and bail out if that
- * fails. So we disallow pread() and pwrite(), but permit lseeks.
- */
- filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
-
- write_lock(&os_scsi_tapes_lock);
- if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
- (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
- write_unlock(&os_scsi_tapes_lock);
- return (-ENXIO);
- }
-
- name = tape_name(STp);
-
- if (STp->in_use) {
- write_unlock(&os_scsi_tapes_lock);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
-#endif
- return (-EBUSY);
- }
- if (scsi_device_get(STp->device)) {
- write_unlock(&os_scsi_tapes_lock);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
-#endif
- return (-ENXIO);
- }
- filp->private_data = STp;
- STp->in_use = 1;
- write_unlock(&os_scsi_tapes_lock);
- STp->rew_at_close = TAPE_REWIND(inode);
-
- if( !scsi_block_when_processing_errors(STp->device) ) {
- return -ENXIO;
- }
-
- if (mode != STp->current_mode) {
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
- name, STp->current_mode, mode);
-#endif
- new_session = 1;
- STp->current_mode = mode;
- }
- STm = &(STp->modes[STp->current_mode]);
-
- flags = filp->f_flags;
- STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
-
- STp->raw = TAPE_IS_RAW(inode);
- if (STp->raw)
- STp->header_ok = 0;
-
- /* Allocate data segments for this device's tape buffer */
- if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
- printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
- retval = (-EOVERFLOW);
- goto err_out;
- }
- if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
- for (i = 0, b_size = 0;
- (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
- b_size += STp->buffer->sg[i++].length);
- STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
- STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
- printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
- STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
-#endif
- } else {
- STp->buffer->aux = NULL; /* this had better never happen! */
- printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
- retval = (-EIO);
- goto err_out;
- }
- STp->buffer->writing = 0;
- STp->buffer->syscall_result = 0;
- STp->dirty = 0;
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE;
- }
- STp->ready = ST_READY;
-#if DEBUG
- STp->nbr_waits = STp->nbr_finished = 0;
-#endif
-
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
- if (!SRpnt) {
- retval = (STp->buffer)->syscall_result; /* FIXME - valid? */
- goto err_out;
- }
- if ((SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x0f) == NOT_READY &&
- SRpnt->sense[12] == 4 ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]);
-#endif
- if (filp->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto err_out;
- }
- if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = START_STOP;
- cmd[1] = 1;
- cmd[4] = 1;
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
- STp->timeout, MAX_RETRIES, 1);
- }
- osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0);
- }
- if ((SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
-#endif
- STp->header_ok = 0;
-
- for (i=0; i < 10; i++) {
-
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
- STp->timeout, MAX_RETRIES, 1);
- if ((SRpnt->sense[0] & 0x70) != 0x70 ||
- (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION)
- break;
- }
-
- STp->pos_unknown = 0;
- STp->partition = STp->new_partition = 0;
- if (STp->can_partitions)
- STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(STp->ps[i]);
- STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = 0;
- STps->drv_block = 0;
- STps->drv_file = 0 ;
- }
- new_session = 1;
- STp->recover_count = 0;
- STp->abort_count = 0;
- }
- /*
- * if we have valid headers from before, and the drive/tape seem untouched,
- * open without reconfiguring and re-reading the headers
- */
- if (!STp->buffer->syscall_result && STp->header_ok &&
- !SRpnt->result && SRpnt->sense[0] == 0) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SENSE;
- cmd[1] = 8;
- cmd[2] = VENDOR_IDENT_PAGE;
- cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
-
- if (STp->buffer->syscall_result ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
- STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) {
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
- STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
- STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
-#endif
- STp->header_ok = 0;
- }
- i = STp->first_frame_position;
- if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
- if (STp->door_locked == ST_UNLOCKED) {
- if (do_door_lock(STp, 1))
- printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
- else
- STp->door_locked = ST_LOCKED_AUTO;
- }
- if (!STp->frame_in_buffer) {
- STp->block_size = (STm->default_blksize > 0) ?
- STm->default_blksize : OS_DATA_SIZE;
- STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
- }
- STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
- STp->fast_open = 1;
- osst_release_request(SRpnt);
- return 0;
- }
-#if DEBUG
- if (i != STp->first_frame_position)
- printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
- name, i, STp->first_frame_position);
-#endif
- STp->header_ok = 0;
- }
- STp->fast_open = 0;
-
- if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */
- (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) {
-
- memset(cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = MODE_SELECT;
- cmd[1] = 0x10;
- cmd[4] = 4 + MODE_HEADER_LENGTH;
-
- (STp->buffer)->b_data[0] = cmd[4] - 1;
- (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */
- (STp->buffer)->b_data[2] = 0; /* Reserved */
- (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
- (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
-
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
-#endif
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
-
- STp->header_ok = 0;
-
- for (i=0; i < 10; i++) {
-
- memset (cmd, 0, MAX_COMMAND_SIZE);
- cmd[0] = TEST_UNIT_READY;
-
- SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
- STp->timeout, MAX_RETRIES, 1);
- if ((SRpnt->sense[0] & 0x70) != 0x70 ||
- (SRpnt->sense[2] & 0x0f) == NOT_READY)
- break;
-
- if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) {
- int j;
-
- STp->pos_unknown = 0;
- STp->partition = STp->new_partition = 0;
- if (STp->can_partitions)
- STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
- for (j = 0; j < ST_NBR_PARTITIONS; j++) {
- STps = &(STp->ps[j]);
- STps->rw = ST_IDLE;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = 0;
- STps->drv_block = 0;
- STps->drv_file = 0 ;
- }
- new_session = 1;
- }
- }
- }
-
- if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
- printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
-
- if ((STp->buffer)->syscall_result != 0) {
- if ((STp->device)->scsi_level >= SCSI_2 &&
- (SRpnt->sense[0] & 0x70) == 0x70 &&
- (SRpnt->sense[2] & 0x0f) == NOT_READY &&
- SRpnt->sense[12] == 0x3a) { /* Check ASC */
- STp->ready = ST_NO_TAPE;
- } else
- STp->ready = ST_NOT_READY;
- osst_release_request(SRpnt);
- SRpnt = NULL;
- STp->density = 0; /* Clear the erroneous "residue" */
- STp->write_prot = 0;
- STp->block_size = 0;
- STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
- STp->partition = STp->new_partition = 0;
- STp->door_locked = ST_UNLOCKED;
- return 0;
- }
-
- osst_configure_onstream(STp, &SRpnt);
-
- STp->block_size = STp->raw ? OS_FRAME_SIZE : (
- (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
- STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
- STp->buffer->buffer_bytes =
- STp->buffer->read_pointer =
- STp->frame_in_buffer = 0;
-
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
- name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
- (STp->buffer)->buffer_blocks);
-#endif
-
- if (STp->drv_write_prot) {
- STp->write_prot = 1;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
-#endif
- if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
- retval = (-EROFS);
- goto err_out;
- }
- }
-
- if (new_session) { /* Change the drive parameters for the new mode */
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: New Session\n", name);
-#endif
- STp->density_changed = STp->blksize_changed = 0;
- STp->compression_changed = 0;
- }
-
- /*
- * properly position the tape and check the ADR headers
- */
- if (STp->door_locked == ST_UNLOCKED) {
- if (do_door_lock(STp, 1))
- printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
- else
- STp->door_locked = ST_LOCKED_AUTO;
- }
-
- osst_analyze_headers(STp, &SRpnt);
-
- osst_release_request(SRpnt);
- SRpnt = NULL;
-
- return 0;
-
-err_out:
- if (SRpnt != NULL)
- osst_release_request(SRpnt);
- normalize_buffer(STp->buffer);
- STp->header_ok = 0;
- STp->in_use = 0;
- scsi_device_put(STp->device);
-
- return retval;
-}
-
-/* BKL pushdown: spaghetti avoidance wrapper */
-static int os_scsi_tape_open(struct inode * inode, struct file * filp)
-{
- int ret;
-
- mutex_lock(&osst_int_mutex);
- ret = __os_scsi_tape_open(inode, filp);
- mutex_unlock(&osst_int_mutex);
- return ret;
-}
-
-
-
-/* Flush the tape buffer before close */
-static int os_scsi_tape_flush(struct file * filp, fl_owner_t id)
-{
- int result = 0, result2;
- struct osst_tape * STp = filp->private_data;
- struct st_modedef * STm = &(STp->modes[STp->current_mode]);
- struct st_partstat * STps = &(STp->ps[STp->partition]);
- struct osst_request * SRpnt = NULL;
- char * name = tape_name(STp);
-
- if (file_count(filp) > 1)
- return 0;
-
- if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
- STp->write_type = OS_WRITE_DATA;
- result = osst_flush_write_buffer(STp, &SRpnt);
- if (result != 0 && result != (-ENOSPC))
- goto out;
- }
- if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
-
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
- name, (long)(filp->f_pos));
- printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
- name, STp->nbr_waits, STp->nbr_finished);
- }
-#endif
- result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
- name, 1+STp->two_fm);
-#endif
- }
- else if (!STp->rew_at_close) {
- STps = &(STp->ps[STp->partition]);
- if (!STm->sysv || STps->rw != ST_READING) {
- if (STp->can_bsr)
- result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
- else if (STps->eof == ST_FM_HIT) {
- result = cross_eof(STp, &SRpnt, 0);
- if (result) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_FM;
- }
- else
- STps->eof = ST_NOEOF;
- }
- }
- else if ((STps->eof == ST_NOEOF &&
- !(result = cross_eof(STp, &SRpnt, 1))) ||
- STps->eof == ST_FM_HIT) {
- if (STps->drv_file >= 0)
- STps->drv_file++;
- STps->drv_block = 0;
- STps->eof = ST_FM;
- }
- }
-
-out:
- if (STp->rew_at_close) {
- result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
- STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
- if (result == 0 && result2 < 0)
- result = result2;
- }
- if (SRpnt) osst_release_request(SRpnt);
-
- if (STp->abort_count || STp->recover_count) {
- printk(KERN_INFO "%s:I:", name);
- if (STp->abort_count)
- printk(" %d unrecovered errors", STp->abort_count);
- if (STp->recover_count)
- printk(" %d recovered errors", STp->recover_count);
- if (STp->write_count)
- printk(" in %d frames written", STp->write_count);
- if (STp->read_count)
- printk(" in %d frames read", STp->read_count);
- printk("\n");
- STp->recover_count = 0;
- STp->abort_count = 0;
- }
- STp->write_count = 0;
- STp->read_count = 0;
-
- return result;
-}
-
-
-/* Close the device and release it */
-static int os_scsi_tape_close(struct inode * inode, struct file * filp)
-{
- int result = 0;
- struct osst_tape * STp = filp->private_data;
-
- if (STp->door_locked == ST_LOCKED_AUTO)
- do_door_lock(STp, 0);
-
- if (STp->raw)
- STp->header_ok = 0;
-
- normalize_buffer(STp->buffer);
- write_lock(&os_scsi_tapes_lock);
- STp->in_use = 0;
- write_unlock(&os_scsi_tapes_lock);
-
- scsi_device_put(STp->device);
-
- return result;
-}
-
-
-/* The ioctl command */
-static long osst_ioctl(struct file * file,
- unsigned int cmd_in, unsigned long arg)
-{
- int i, cmd_nr, cmd_type, blk, retval = 0;
- struct st_modedef * STm;
- struct st_partstat * STps;
- struct osst_request * SRpnt = NULL;
- struct osst_tape * STp = file->private_data;
- char * name = tape_name(STp);
- void __user * p = (void __user *)arg;
-
- mutex_lock(&osst_int_mutex);
- if (mutex_lock_interruptible(&STp->lock)) {
- mutex_unlock(&osst_int_mutex);
- return -ERESTARTSYS;
- }
-
-#if DEBUG
- if (debugging && !STp->in_use) {
- printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
- retval = (-EIO);
- goto out;
- }
-#endif
- STm = &(STp->modes[STp->current_mode]);
- STps = &(STp->ps[STp->partition]);
-
- /*
- * If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.
- */
- retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
- file->f_flags & O_NDELAY);
- if (retval)
- goto out;
-
- cmd_type = _IOC_TYPE(cmd_in);
- cmd_nr = _IOC_NR(cmd_in);
-#if DEBUG
- printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
- cmd_type, cmd_nr, STp->raw?"raw":"normal");
-#endif
- if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
- struct mtop mtc;
- int auto_weof = 0;
-
- if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
- retval = (-EINVAL);
- goto out;
- }
-
- i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
- if (i) {
- retval = (-EFAULT);
- goto out;
- }
-
- if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
- printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
- retval = (-EPERM);
- goto out;
- }
-
- if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
- retval = (-ENXIO);
- goto out;
- }
-
- if (!STp->pos_unknown) {
-
- if (STps->eof == ST_FM_HIT) {
- if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
- mtc.mt_count -= 1;
- if (STps->drv_file >= 0)
- STps->drv_file += 1;
- }
- else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
- mtc.mt_count += 1;
- if (STps->drv_file >= 0)
- STps->drv_file += 1;
- }
- }
-
- if (mtc.mt_op == MTSEEK) {
- /* Old position must be restored if partition will be changed */
- i = !STp->can_partitions || (STp->new_partition != STp->partition);
- }
- else {
- i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
- mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
- mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
- mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
- mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
- mtc.mt_op == MTCOMPRESSION;
- }
- i = osst_flush_buffer(STp, &SRpnt, i);
- if (i < 0) {
- retval = i;
- goto out;
- }
- }
- else {
- /*
- * If there was a bus reset, block further access
- * to this device. If the user wants to rewind the tape,
- * then reset the flag and allow access again.
- */
- if(mtc.mt_op != MTREW &&
- mtc.mt_op != MTOFFL &&
- mtc.mt_op != MTRETEN &&
- mtc.mt_op != MTERASE &&
- mtc.mt_op != MTSEEK &&
- mtc.mt_op != MTEOM) {
- retval = (-EIO);
- goto out;
- }
- reset_state(STp);
- /* remove this when the midlevel properly clears was_reset */
- STp->device->was_reset = 0;
- }
-
- if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK &&
- mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
- mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER &&
- mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART &&
- mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) {
-
- /*
- * The user tells us to move to another position on the tape.
- * If we were appending to the tape content, that would leave
- * the tape without proper end, in that case write EOD and
- * update the header to reflect its position.
- */
-#if DEBUG
- printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
- STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
- STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
- STp->logical_blk_num, STps->drv_file, STps->drv_block );
-#endif
- if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
- auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
- !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
- i = osst_write_trailer(STp, &SRpnt,
- !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
-#if DEBUG
- printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
- name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
- STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
-#endif
- if (i < 0) {
- retval = i;
- goto out;
- }
- }
- STps->rw = ST_IDLE;
- }
-
- if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
- do_door_lock(STp, 0); /* Ignore result! */
-
- if (mtc.mt_op == MTSETDRVBUFFER &&
- (mtc.mt_count & MT_ST_OPTIONS) != 0) {
- retval = osst_set_options(STp, mtc.mt_count);
- goto out;
- }
-
- if (mtc.mt_op == MTSETPART) {
- if (mtc.mt_count >= STp->nbr_partitions)
- retval = -EINVAL;
- else {
- STp->new_partition = mtc.mt_count;
- retval = 0;
- }
- goto out;
- }
-
- if (mtc.mt_op == MTMKPART) {
- if (!STp->can_partitions) {
- retval = (-EINVAL);
- goto out;
- }
- if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
- (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
- retval = i;
- goto out;
- }
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STp->ps[i].rw = ST_IDLE;
- STp->ps[i].at_sm = 0;
- STp->ps[i].last_block_valid = 0;
- }
- STp->partition = STp->new_partition = 0;
- STp->nbr_partitions = 1; /* Bad guess ?-) */
- STps->drv_block = STps->drv_file = 0;
- retval = 0;
- goto out;
- }
-
- if (mtc.mt_op == MTSEEK) {
- if (STp->raw)
- i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
- else
- i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
- if (!STp->can_partitions)
- STp->ps[0].rw = ST_IDLE;
- retval = i;
- goto out;
- }
-
- if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
- retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
- goto out;
- }
-
- if (auto_weof)
- cross_eof(STp, &SRpnt, 0);
-
- if (mtc.mt_op == MTCOMPRESSION)
- retval = -EINVAL; /* OnStream drives don't have compression hardware */
- else
- /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
- * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
- retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
- goto out;
- }
-
- if (!STm->defined) {
- retval = (-ENXIO);
- goto out;
- }
-
- if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
- retval = i;
- goto out;
- }
-
- if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
- struct mtget mt_status;
-
- if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
- retval = (-EINVAL);
- goto out;
- }
-
- mt_status.mt_type = MT_ISONSTREAM_SC;
- mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
- mt_status.mt_dsreg =
- ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
- ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
- mt_status.mt_blkno = STps->drv_block;
- mt_status.mt_fileno = STps->drv_file;
- if (STp->block_size != 0) {
- if (STps->rw == ST_WRITING)
- mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
- else if (STps->rw == ST_READING)
- mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
- STp->block_size - 1) / STp->block_size;
- }
-
- mt_status.mt_gstat = 0;
- if (STp->drv_write_prot)
- mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
- if (mt_status.mt_blkno == 0) {
- if (mt_status.mt_fileno == 0)
- mt_status.mt_gstat |= GMT_BOT(0xffffffff);
- else
- mt_status.mt_gstat |= GMT_EOF(0xffffffff);
- }
- mt_status.mt_resid = STp->partition;
- if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
- mt_status.mt_gstat |= GMT_EOT(0xffffffff);
- else if (STps->eof >= ST_EOM_OK)
- mt_status.mt_gstat |= GMT_EOD(0xffffffff);
- if (STp->density == 1)
- mt_status.mt_gstat |= GMT_D_800(0xffffffff);
- else if (STp->density == 2)
- mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
- else if (STp->density == 3)
- mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
- if (STp->ready == ST_READY)
- mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
- if (STp->ready == ST_NO_TAPE)
- mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
- if (STps->at_sm)
- mt_status.mt_gstat |= GMT_SM(0xffffffff);
- if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
- STp->drv_buffer != 0)
- mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
-
- i = copy_to_user(p, &mt_status, sizeof(struct mtget));
- if (i) {
- retval = (-EFAULT);
- goto out;
- }
-
- STp->recover_erreg = 0; /* Clear after read */
- retval = 0;
- goto out;
- } /* End of MTIOCGET */
-
- if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
- struct mtpos mt_pos;
-
- if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
- retval = (-EINVAL);
- goto out;
- }
- if (STp->raw)
- blk = osst_get_frame_position(STp, &SRpnt);
- else
- blk = osst_get_sector(STp, &SRpnt);
- if (blk < 0) {
- retval = blk;
- goto out;
- }
- mt_pos.mt_blkno = blk;
- i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
- if (i)
- retval = -EFAULT;
- goto out;
- }
- if (SRpnt) osst_release_request(SRpnt);
-
- mutex_unlock(&STp->lock);
-
- retval = scsi_ioctl(STp->device, cmd_in, p);
- mutex_unlock(&osst_int_mutex);
- return retval;
-
-out:
- if (SRpnt) osst_release_request(SRpnt);
-
- mutex_unlock(&STp->lock);
- mutex_unlock(&osst_int_mutex);
-
- return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
-{
- struct osst_tape *STp = file->private_data;
- struct scsi_device *sdev = STp->device;
- int ret = -ENOIOCTLCMD;
- if (sdev->host->hostt->compat_ioctl) {
-
- ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
-
- }
- return ret;
-}
-#endif
-
-
-
-/* Memory handling routines */
-
-/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
-static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
-{
- int i;
- gfp_t priority;
- struct osst_buffer *tb;
-
- if (from_initialization)
- priority = GFP_ATOMIC;
- else
- priority = GFP_KERNEL;
-
- i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
- tb = kzalloc(i, priority);
- if (!tb) {
- printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
- return NULL;
- }
-
- tb->sg_segs = tb->orig_sg_segs = 0;
- tb->use_sg = max_sg;
- tb->in_use = 1;
- tb->dma = need_dma;
- tb->buffer_size = 0;
-#if DEBUG
- if (debugging)
- printk(OSST_DEB_MSG
- "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
- i, max_sg, need_dma);
-#endif
- return tb;
-}
-
-/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
-static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
-{
- int segs, nbr, max_segs, b_size, order, got;
- gfp_t priority;
-
- if (STbuffer->buffer_size >= OS_FRAME_SIZE)
- return 1;
-
- if (STbuffer->sg_segs) {
- printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
- normalize_buffer(STbuffer);
- }
- /* See how many segments we can use -- need at least two */
- nbr = max_segs = STbuffer->use_sg;
- if (nbr <= 2)
- return 0;
-
- priority = GFP_KERNEL /* | __GFP_NOWARN */;
- if (need_dma)
- priority |= GFP_DMA;
-
- /* Try to allocate the first segment up to OS_DATA_SIZE and the others
- big enough to reach the goal (code assumes no segments in place) */
- for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
- struct page *page = alloc_pages(priority, order);
-
- STbuffer->sg[0].offset = 0;
- if (page != NULL) {
- sg_set_page(&STbuffer->sg[0], page, b_size, 0);
- STbuffer->b_data = page_address(page);
- break;
- }
- }
- if (sg_page(&STbuffer->sg[0]) == NULL) {
- printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
- return 0;
- }
- /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
- for (segs=STbuffer->sg_segs=1, got=b_size;
- segs < max_segs && got < OS_FRAME_SIZE; ) {
- struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
- STbuffer->sg[segs].offset = 0;
- if (page == NULL) {
- printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
- OS_FRAME_SIZE);
-#if DEBUG
- STbuffer->buffer_size = got;
-#endif
- normalize_buffer(STbuffer);
- return 0;
- }
- sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0);
- got += STbuffer->sg[segs].length;
- STbuffer->buffer_size = got;
- STbuffer->sg_segs = ++segs;
- }
-#if DEBUG
- if (debugging) {
- printk(OSST_DEB_MSG
- "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
- got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
- printk(OSST_DEB_MSG
- "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
- STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
- STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
- }
-#endif
-
- return 1;
-}
-
-
-/* Release the segments */
-static void normalize_buffer(struct osst_buffer *STbuffer)
-{
- int i, order, b_size;
-
- for (i=0; i < STbuffer->sg_segs; i++) {
-
- for (b_size = PAGE_SIZE, order = 0;
- b_size < STbuffer->sg[i].length;
- b_size *= 2, order++);
-
- __free_pages(sg_page(&STbuffer->sg[i]), order);
- STbuffer->buffer_size -= STbuffer->sg[i].length;
- }
-#if DEBUG
- if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
- printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
- STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
-#endif
- STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
-}
-
-
-/* Move data from the user buffer to the tape buffer. Returns zero (success) or
- negative error code. */
-static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
-{
- int i, cnt, res, offset;
-
- for (i=0, offset=st_bp->buffer_bytes;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
- return (-EIO);
- }
- for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count;
- res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
- if (res)
- return (-EFAULT);
- do_count -= cnt;
- st_bp->buffer_bytes += cnt;
- ubp += cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
- do_count);
- return (-EIO);
- }
- return 0;
-}
-
-
-/* Move data from the tape buffer to the user buffer. Returns zero (success) or
- negative error code. */
-static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
-{
- int i, cnt, res, offset;
-
- for (i=0, offset=st_bp->read_pointer;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
- return (-EIO);
- }
- for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count;
- res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
- if (res)
- return (-EFAULT);
- do_count -= cnt;
- st_bp->buffer_bytes -= cnt;
- st_bp->read_pointer += cnt;
- ubp += cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
- return (-EIO);
- }
- return 0;
-}
-
-/* Sets the tail of the buffer after fill point to zero.
- Returns zero (success) or negative error code. */
-static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
-{
- int i, offset, do_count, cnt;
-
- for (i = 0, offset = st_bp->buffer_bytes;
- i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
- offset -= st_bp->sg[i].length;
- if (i == st_bp->sg_segs) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
- return (-EIO);
- }
- for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
- i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length - offset < do_count ?
- st_bp->sg[i].length - offset : do_count ;
- memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
- do_count -= cnt;
- offset = 0;
- }
- if (do_count) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
- return (-EIO);
- }
- return 0;
-}
-
-/* Copy a osst 32K chunk of memory into the buffer.
- Returns zero (success) or negative error code. */
-static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
-{
- int i, cnt, do_count = OS_DATA_SIZE;
-
- for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length < do_count ?
- st_bp->sg[i].length : do_count ;
- memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
- do_count -= cnt;
- ptr += cnt;
- }
- if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
- do_count, i);
- return (-EIO);
- }
- return 0;
-}
-
-/* Copy a osst 32K chunk of memory from the buffer.
- Returns zero (success) or negative error code. */
-static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
-{
- int i, cnt, do_count = OS_DATA_SIZE;
-
- for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
- cnt = st_bp->sg[i].length < do_count ?
- st_bp->sg[i].length : do_count ;
- memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
- do_count -= cnt;
- ptr += cnt;
- }
- if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */
- printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
- do_count, i);
- return (-EIO);
- }
- return 0;
-}
-
-
-/* Module housekeeping */
-
-static void validate_options (void)
-{
- if (max_dev > 0)
- osst_max_dev = max_dev;
- if (write_threshold_kbs > 0)
- osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
- if (osst_write_threshold > osst_buffer_size)
- osst_write_threshold = osst_buffer_size;
- if (max_sg_segs >= OSST_FIRST_SG)
- osst_max_sg_segs = max_sg_segs;
-#if DEBUG
- printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
- osst_max_dev, osst_write_threshold, osst_max_sg_segs);
-#endif
-}
-
-#ifndef MODULE
-/* Set the boot options. Syntax: osst=xxx,yyy,...
- where xxx is write threshold in 1024 byte blocks,
- and yyy is number of s/g segments to use. */
-static int __init osst_setup (char *str)
-{
- int i, ints[5];
- char *stp;
-
- stp = get_options(str, ARRAY_SIZE(ints), ints);
-
- if (ints[0] > 0) {
- for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
- *parms[i].val = ints[i + 1];
- } else {
- while (stp != NULL) {
- for (i = 0; i < ARRAY_SIZE(parms); i++) {
- int len = strlen(parms[i].name);
- if (!strncmp(stp, parms[i].name, len) &&
- (*(stp + len) == ':' || *(stp + len) == '=')) {
- *parms[i].val =
- simple_strtoul(stp + len + 1, NULL, 0);
- break;
- }
- }
- if (i >= ARRAY_SIZE(parms))
- printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
- stp);
- stp = strchr(stp, ',');
- if (stp)
- stp++;
- }
- }
-
- return 1;
-}
-
-__setup("osst=", osst_setup);
-
-#endif
-
-static const struct file_operations osst_fops = {
- .owner = THIS_MODULE,
- .read = osst_read,
- .write = osst_write,
- .unlocked_ioctl = osst_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = osst_compat_ioctl,
-#endif
- .open = os_scsi_tape_open,
- .flush = os_scsi_tape_flush,
- .release = os_scsi_tape_close,
- .llseek = noop_llseek,
-};
-
-static int osst_supports(struct scsi_device * SDp)
-{
- struct osst_support_data {
- char *vendor;
- char *model;
- char *rev;
- char *driver_hint; /* Name of the correct driver, NULL if unknown */
- };
-
-static struct osst_support_data support_list[] = {
- /* {"XXX", "Yy-", "", NULL}, example */
- SIGS_FROM_OSST,
- {NULL, }};
-
- struct osst_support_data *rp;
-
- /* We are willing to drive OnStream SC-x0 as well as the
- * * IDE, ParPort, FireWire, USB variants, if accessible by
- * * emulation layer (ide-scsi, usb-storage, ...) */
-
- for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
- if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
- !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
- !strncmp(rp->rev, SDp->rev, strlen(rp->rev)))
- return 1;
- return 0;
-}
-
-/*
- * sysfs support for osst driver parameter information
- */
-
-static ssize_t version_show(struct device_driver *ddd, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
-}
-
-static DRIVER_ATTR_RO(version);
-
-static int osst_create_sysfs_files(struct device_driver *sysfs)
-{
- return driver_create_file(sysfs, &driver_attr_version);
-}
-
-static void osst_remove_sysfs_files(struct device_driver *sysfs)
-{
- driver_remove_file(sysfs, &driver_attr_version);
-}
-
-/*
- * sysfs support for accessing ADR header information
- */
-
-static ssize_t osst_adr_rev_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
- return l;
-}
-
-DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
-
-static ssize_t osst_linux_media_version_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
- return l;
-}
-
-DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
-
-static ssize_t osst_capacity_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
- return l;
-}
-
-DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
-
-static ssize_t osst_first_data_ppos_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
- return l;
-}
-
-DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
-
-static ssize_t osst_eod_frame_ppos_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
- return l;
-}
-
-DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
-
-static ssize_t osst_filemark_cnt_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev);
- ssize_t l = 0;
-
- if (STp && STp->header_ok && STp->linux_media)
- l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
- return l;
-}
-
-DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
-
-static struct class *osst_sysfs_class;
-
-static int osst_sysfs_init(void)
-{
- osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
- if (IS_ERR(osst_sysfs_class)) {
- printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
- return PTR_ERR(osst_sysfs_class);
- }
-
- return 0;
-}
-
-static void osst_sysfs_destroy(dev_t dev)
-{
- device_destroy(osst_sysfs_class, dev);
-}
-
-static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
-{
- struct device *osst_member;
- int err;
-
- osst_member = device_create(osst_sysfs_class, device, dev, STp,
- "%s", name);
- if (IS_ERR(osst_member)) {
- printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
- return PTR_ERR(osst_member);
- }
-
- err = device_create_file(osst_member, &dev_attr_ADR_rev);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_media_version);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_capacity);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_BOT_frame);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_EOD_frame);
- if (err)
- goto err_out;
- err = device_create_file(osst_member, &dev_attr_file_count);
- if (err)
- goto err_out;
-
- return 0;
-
-err_out:
- osst_sysfs_destroy(dev);
- return err;
-}
-
-static void osst_sysfs_cleanup(void)
-{
- class_destroy(osst_sysfs_class);
-}
-
-/*
- * osst startup / cleanup code
- */
-
-static int osst_probe(struct device *dev)
-{
- struct scsi_device * SDp = to_scsi_device(dev);
- struct osst_tape * tpnt;
- struct st_modedef * STm;
- struct st_partstat * STps;
- struct osst_buffer * buffer;
- struct gendisk * drive;
- int i, dev_num, err = -ENODEV;
-
- if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
- return -ENODEV;
-
- drive = alloc_disk(1);
- if (!drive) {
- printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
- return -ENODEV;
- }
-
- /* if this is the first attach, build the infrastructure */
- write_lock(&os_scsi_tapes_lock);
- if (os_scsi_tapes == NULL) {
- os_scsi_tapes = kmalloc_array(osst_max_dev,
- sizeof(struct osst_tape *),
- GFP_ATOMIC);
- if (os_scsi_tapes == NULL) {
- write_unlock(&os_scsi_tapes_lock);
- printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
- goto out_put_disk;
- }
- for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
- }
-
- if (osst_nr_dev >= osst_max_dev) {
- write_unlock(&os_scsi_tapes_lock);
- printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
- goto out_put_disk;
- }
-
- /* find a free minor number */
- for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++)
- ;
- if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
- dev_num = i;
-
- /* allocate a struct osst_tape for this device */
- tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
- if (!tpnt) {
- write_unlock(&os_scsi_tapes_lock);
- printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
- goto out_put_disk;
- }
-
- /* allocate a buffer for this device */
- i = SDp->host->sg_tablesize;
- if (osst_max_sg_segs < i)
- i = osst_max_sg_segs;
- buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
- if (buffer == NULL) {
- write_unlock(&os_scsi_tapes_lock);
- printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
- kfree(tpnt);
- goto out_put_disk;
- }
- os_scsi_tapes[dev_num] = tpnt;
- tpnt->buffer = buffer;
- tpnt->device = SDp;
- drive->private_data = &tpnt->driver;
- sprintf(drive->disk_name, "osst%d", dev_num);
- tpnt->driver = &osst_template;
- tpnt->drive = drive;
- tpnt->in_use = 0;
- tpnt->capacity = 0xfffff;
- tpnt->dirty = 0;
- tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
- tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
- tpnt->density = 0;
- tpnt->do_auto_lock = OSST_AUTO_LOCK;
- tpnt->can_bsr = OSST_IN_FILE_POS;
- tpnt->can_partitions = 0;
- tpnt->two_fm = OSST_TWO_FM;
- tpnt->fast_mteom = OSST_FAST_MTEOM;
- tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
- tpnt->write_threshold = osst_write_threshold;
- tpnt->default_drvbuffer = 0xff; /* No forced buffering */
- tpnt->partition = 0;
- tpnt->new_partition = 0;
- tpnt->nbr_partitions = 0;
- tpnt->min_block = 512;
- tpnt->max_block = OS_DATA_SIZE;
- tpnt->timeout = OSST_TIMEOUT;
- tpnt->long_timeout = OSST_LONG_TIMEOUT;
-
- /* Recognize OnStream tapes */
- /* We don't need to test for OnStream, as this has been done in detect () */
- tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
- tpnt->omit_blklims = 1;
-
- tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
- (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
- tpnt->frame_in_buffer = 0;
- tpnt->header_ok = 0;
- tpnt->linux_media = 0;
- tpnt->header_cache = NULL;
-
- for (i=0; i < ST_NBR_MODES; i++) {
- STm = &(tpnt->modes[i]);
- STm->defined = 0;
- STm->sysv = OSST_SYSV;
- STm->defaults_for_writes = 0;
- STm->do_async_writes = OSST_ASYNC_WRITES;
- STm->do_buffer_writes = OSST_BUFFER_WRITES;
- STm->do_read_ahead = OSST_READ_AHEAD;
- STm->default_compression = ST_DONT_TOUCH;
- STm->default_blksize = 512;
- STm->default_density = (-1); /* No forced density */
- }
-
- for (i=0; i < ST_NBR_PARTITIONS; i++) {
- STps = &(tpnt->ps[i]);
- STps->rw = ST_IDLE;
- STps->eof = ST_NOEOF;
- STps->at_sm = 0;
- STps->last_block_valid = 0;
- STps->drv_block = (-1);
- STps->drv_file = (-1);
- }
-
- tpnt->current_mode = 0;
- tpnt->modes[0].defined = 1;
- tpnt->modes[2].defined = 1;
- tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
-
- mutex_init(&tpnt->lock);
- osst_nr_dev++;
- write_unlock(&os_scsi_tapes_lock);
-
- {
- char name[8];
-
- /* Rewind entry */
- err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
- if (err)
- goto out_free_buffer;
-
- /* No-rewind entry */
- snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
- err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
- if (err)
- goto out_free_sysfs1;
- }
-
- sdev_printk(KERN_INFO, SDp,
- "osst :I: Attached OnStream %.5s tape as %s\n",
- SDp->model, tape_name(tpnt));
-
- return 0;
-
-out_free_sysfs1:
- osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
-out_free_buffer:
- kfree(buffer);
-out_put_disk:
- put_disk(drive);
- return err;
-};
-
-static int osst_remove(struct device *dev)
-{
- struct scsi_device * SDp = to_scsi_device(dev);
- struct osst_tape * tpnt;
- int i;
-
- if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
- return 0;
-
- write_lock(&os_scsi_tapes_lock);
- for(i=0; i < osst_max_dev; i++) {
- if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
- osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
- osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
- tpnt->device = NULL;
- put_disk(tpnt->drive);
- os_scsi_tapes[i] = NULL;
- osst_nr_dev--;
- write_unlock(&os_scsi_tapes_lock);
- vfree(tpnt->header_cache);
- if (tpnt->buffer) {
- normalize_buffer(tpnt->buffer);
- kfree(tpnt->buffer);
- }
- kfree(tpnt);
- return 0;
- }
- }
- write_unlock(&os_scsi_tapes_lock);
- return 0;
-}
-
-static int __init init_osst(void)
-{
- int err;
-
- printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
-
- validate_options();
-
- err = osst_sysfs_init();
- if (err)
- return err;
-
- err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
- if (err < 0) {
- printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
- goto err_out;
- }
-
- err = scsi_register_driver(&osst_template.gendrv);
- if (err)
- goto err_out_chrdev;
-
- err = osst_create_sysfs_files(&osst_template.gendrv);
- if (err)
- goto err_out_scsidrv;
-
- return 0;
-
-err_out_scsidrv:
- scsi_unregister_driver(&osst_template.gendrv);
-err_out_chrdev:
- unregister_chrdev(OSST_MAJOR, "osst");
-err_out:
- osst_sysfs_cleanup();
- return err;
-}
-
-static void __exit exit_osst (void)
-{
- int i;
- struct osst_tape * STp;
-
- osst_remove_sysfs_files(&osst_template.gendrv);
- scsi_unregister_driver(&osst_template.gendrv);
- unregister_chrdev(OSST_MAJOR, "osst");
- osst_sysfs_cleanup();
-
- if (os_scsi_tapes) {
- for (i=0; i < osst_max_dev; ++i) {
- if (!(STp = os_scsi_tapes[i])) continue;
- /* This is defensive, supposed to happen during detach */
- vfree(STp->header_cache);
- if (STp->buffer) {
- normalize_buffer(STp->buffer);
- kfree(STp->buffer);
- }
- put_disk(STp->drive);
- kfree(STp);
- }
- kfree(os_scsi_tapes);
- }
- printk(KERN_INFO "osst :I: Unloaded.\n");
-}
-
-module_init(init_osst);
-module_exit(exit_osst);
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
deleted file mode 100644
index b90ae280853d..000000000000
--- a/drivers/scsi/osst.h
+++ /dev/null
@@ -1,651 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * $Header: /cvsroot/osst/Driver/osst.h,v 1.16 2005/01/01 21:13:35 wriede Exp $
- */
-
-#include <asm/byteorder.h>
-#include <linux/completion.h>
-#include <linux/mutex.h>
-
-/* FIXME - rename and use the following two types or delete them!
- * and the types really should go to st.h anyway...
- * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
- */
-typedef struct {
- unsigned device_type :5; /* Peripheral Device Type */
- unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */
- unsigned reserved1_6t0 :7; /* Reserved */
- unsigned rmb :1; /* Removable Medium Bit */
- unsigned ansi_version :3; /* ANSI Version */
- unsigned ecma_version :3; /* ECMA Version */
- unsigned iso_version :2; /* ISO Version */
- unsigned response_format :4; /* Response Data Format */
- unsigned reserved3_45 :2; /* Reserved */
- unsigned reserved3_6 :1; /* TrmIOP - Reserved */
- unsigned reserved3_7 :1; /* AENC - Reserved */
- u8 additional_length; /* Additional Length (total_length-4) */
- u8 rsv5, rsv6, rsv7; /* Reserved */
- u8 vendor_id[8]; /* Vendor Identification */
- u8 product_id[16]; /* Product Identification */
- u8 revision_level[4]; /* Revision Level */
- u8 vendor_specific[20]; /* Vendor Specific - Optional */
- u8 reserved56t95[40]; /* Reserved - Optional */
- /* Additional information may be returned */
-} idetape_inquiry_result_t;
-
-/*
- * READ POSITION packet command - Data Format (From Table 6-57)
- */
-typedef struct {
- unsigned reserved0_10 :2; /* Reserved */
- unsigned bpu :1; /* Block Position Unknown */
- unsigned reserved0_543 :3; /* Reserved */
- unsigned eop :1; /* End Of Partition */
- unsigned bop :1; /* Beginning Of Partition */
- u8 partition; /* Partition Number */
- u8 reserved2, reserved3; /* Reserved */
- u32 first_block; /* First Block Location */
- u32 last_block; /* Last Block Location (Optional) */
- u8 reserved12; /* Reserved */
- u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */
- u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */
-} idetape_read_position_result_t;
-
-/*
- * Follows structures which are related to the SELECT SENSE / MODE SENSE
- * packet commands.
- */
-#define COMPRESSION_PAGE 0x0f
-#define COMPRESSION_PAGE_LENGTH 16
-
-#define CAPABILITIES_PAGE 0x2a
-#define CAPABILITIES_PAGE_LENGTH 20
-
-#define TAPE_PARAMTR_PAGE 0x2b
-#define TAPE_PARAMTR_PAGE_LENGTH 16
-
-#define NUMBER_RETRIES_PAGE 0x2f
-#define NUMBER_RETRIES_PAGE_LENGTH 4
-
-#define BLOCK_SIZE_PAGE 0x30
-#define BLOCK_SIZE_PAGE_LENGTH 4
-
-#define BUFFER_FILLING_PAGE 0x33
-#define BUFFER_FILLING_PAGE_LENGTH 4
-
-#define VENDOR_IDENT_PAGE 0x36
-#define VENDOR_IDENT_PAGE_LENGTH 8
-
-#define LOCATE_STATUS_PAGE 0x37
-#define LOCATE_STATUS_PAGE_LENGTH 0
-
-#define MODE_HEADER_LENGTH 4
-
-
-/*
- * REQUEST SENSE packet command result - Data Format.
- */
-typedef struct {
- unsigned error_code :7; /* Current of deferred errors */
- unsigned valid :1; /* The information field conforms to QIC-157C */
- u8 reserved1 :8; /* Segment Number - Reserved */
- unsigned sense_key :4; /* Sense Key */
- unsigned reserved2_4 :1; /* Reserved */
- unsigned ili :1; /* Incorrect Length Indicator */
- unsigned eom :1; /* End Of Medium */
- unsigned filemark :1; /* Filemark */
- u32 information __attribute__ ((packed));
- u8 asl; /* Additional sense length (n-7) */
- u32 command_specific; /* Additional command specific information */
- u8 asc; /* Additional Sense Code */
- u8 ascq; /* Additional Sense Code Qualifier */
- u8 replaceable_unit_code; /* Field Replaceable Unit Code */
- unsigned sk_specific1 :7; /* Sense Key Specific */
- unsigned sksv :1; /* Sense Key Specific information is valid */
- u8 sk_specific2; /* Sense Key Specific */
- u8 sk_specific3; /* Sense Key Specific */
- u8 pad[2]; /* Padding to 20 bytes */
-} idetape_request_sense_result_t;
-
-/*
- * Mode Parameter Header for the MODE SENSE packet command
- */
-typedef struct {
- u8 mode_data_length; /* Length of the following data transfer */
- u8 medium_type; /* Medium Type */
- u8 dsp; /* Device Specific Parameter */
- u8 bdl; /* Block Descriptor Length */
-} osst_mode_parameter_header_t;
-
-/*
- * Mode Parameter Block Descriptor the MODE SENSE packet command
- *
- * Support for block descriptors is optional.
- */
-typedef struct {
- u8 density_code; /* Medium density code */
- u8 blocks[3]; /* Number of blocks */
- u8 reserved4; /* Reserved */
- u8 length[3]; /* Block Length */
-} osst_parameter_block_descriptor_t;
-
-/*
- * The Data Compression Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1;
- unsigned reserved0 :1; /* Reserved */
- unsigned page_code :6; /* Page Code - Should be 0xf */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page Code - Should be 0xf */
- unsigned reserved0 :1; /* Reserved */
- unsigned ps :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 page_length; /* Page Length - Should be 14 */
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned dce :1; /* Data Compression Enable */
- unsigned dcc :1; /* Data Compression Capable */
- unsigned reserved2 :6; /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved2 :6; /* Reserved */
- unsigned dcc :1; /* Data Compression Capable */
- unsigned dce :1; /* Data Compression Enable */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned dde :1; /* Data Decompression Enable */
- unsigned red :2; /* Report Exception on Decompression */
- unsigned reserved3 :5; /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved3 :5; /* Reserved */
- unsigned red :2; /* Report Exception on Decompression */
- unsigned dde :1; /* Data Decompression Enable */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u32 ca; /* Compression Algorithm */
- u32 da; /* Decompression Algorithm */
- u8 reserved[4]; /* Reserved */
-} osst_data_compression_page_t;
-
-/*
- * The Medium Partition Page, as returned by the MODE SENSE packet command.
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1;
- unsigned reserved1_6 :1; /* Reserved */
- unsigned page_code :6; /* Page Code - Should be 0x11 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page Code - Should be 0x11 */
- unsigned reserved1_6 :1; /* Reserved */
- unsigned ps :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 page_length; /* Page Length - Should be 6 */
- u8 map; /* Maximum Additional Partitions - Should be 0 */
- u8 apd; /* Additional Partitions Defined - Should be 0 */
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned fdp :1; /* Fixed Data Partitions */
- unsigned sdp :1; /* Should be 0 */
- unsigned idp :1; /* Should be 0 */
- unsigned psum :2; /* Should be 0 */
- unsigned reserved4_012 :3; /* Reserved */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved4_012 :3; /* Reserved */
- unsigned psum :2; /* Should be 0 */
- unsigned idp :1; /* Should be 0 */
- unsigned sdp :1; /* Should be 0 */
- unsigned fdp :1; /* Fixed Data Partitions */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 mfr; /* Medium Format Recognition */
- u8 reserved[2]; /* Reserved */
-} osst_medium_partition_page_t;
-
-/*
- * Capabilities and Mechanical Status Page
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned reserved1_67 :2;
- unsigned page_code :6; /* Page code - Should be 0x2a */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page code - Should be 0x2a */
- unsigned reserved1_67 :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 page_length; /* Page Length - Should be 0x12 */
- u8 reserved2, reserved3;
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned reserved4_67 :2;
- unsigned sprev :1; /* Supports SPACE in the reverse direction */
- unsigned reserved4_1234 :4;
- unsigned ro :1; /* Read Only Mode */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned ro :1; /* Read Only Mode */
- unsigned reserved4_1234 :4;
- unsigned sprev :1; /* Supports SPACE in the reverse direction */
- unsigned reserved4_67 :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned reserved5_67 :2;
- unsigned qfa :1; /* Supports the QFA two partition formats */
- unsigned reserved5_4 :1;
- unsigned efmt :1; /* Supports ERASE command initiated formatting */
- unsigned reserved5_012 :3;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved5_012 :3;
- unsigned efmt :1; /* Supports ERASE command initiated formatting */
- unsigned reserved5_4 :1;
- unsigned qfa :1; /* Supports the QFA two partition formats */
- unsigned reserved5_67 :2;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned cmprs :1; /* Supports data compression */
- unsigned ecc :1; /* Supports error correction */
- unsigned reserved6_45 :2; /* Reserved */
- unsigned eject :1; /* The device can eject the volume */
- unsigned prevent :1; /* The device defaults in the prevent state after power up */
- unsigned locked :1; /* The volume is locked */
- unsigned lock :1; /* Supports locking the volume */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned lock :1; /* Supports locking the volume */
- unsigned locked :1; /* The volume is locked */
- unsigned prevent :1; /* The device defaults in the prevent state after power up */
- unsigned eject :1; /* The device can eject the volume */
- unsigned reserved6_45 :2; /* Reserved */
- unsigned ecc :1; /* Supports error correction */
- unsigned cmprs :1; /* Supports data compression */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */
- /* transfers for slow buffer memory ??? */
- /* Also 32768 block size in some cases */
- unsigned reserved7_3_6 :4;
- unsigned blk1024 :1; /* Supports 1024 bytes block size */
- unsigned blk512 :1; /* Supports 512 bytes block size */
- unsigned reserved7_0 :1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned reserved7_0 :1;
- unsigned blk512 :1; /* Supports 512 bytes block size */
- unsigned blk1024 :1; /* Supports 1024 bytes block size */
- unsigned reserved7_3_6 :4;
- unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */
- /* transfers for slow buffer memory ??? */
- /* Also 32768 block size in some cases */
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- __be16 max_speed; /* Maximum speed supported in KBps */
- u8 reserved10, reserved11;
- __be16 ctl; /* Continuous Transfer Limit in blocks */
- __be16 speed; /* Current Speed, in KBps */
- __be16 buffer_size; /* Buffer Size, in 512 bytes */
- u8 reserved18, reserved19;
-} osst_capabilities_page_t;
-
-/*
- * Block Size Page
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1;
- unsigned reserved1_6 :1;
- unsigned page_code :6; /* Page code - Should be 0x30 */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page code - Should be 0x30 */
- unsigned reserved1_6 :1;
- unsigned ps :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 page_length; /* Page Length - Should be 2 */
- u8 reserved2;
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned one :1;
- unsigned reserved2_6 :1;
- unsigned record32_5 :1;
- unsigned record32 :1;
- unsigned reserved2_23 :2;
- unsigned play32_5 :1;
- unsigned play32 :1;
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned play32 :1;
- unsigned play32_5 :1;
- unsigned reserved2_23 :2;
- unsigned record32 :1;
- unsigned record32_5 :1;
- unsigned reserved2_6 :1;
- unsigned one :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-} osst_block_size_page_t;
-
-/*
- * Tape Parameters Page
- */
-typedef struct {
-#if defined(__BIG_ENDIAN_BITFIELD)
- unsigned ps :1;
- unsigned reserved1_6 :1;
- unsigned page_code :6; /* Page code - Should be 0x2b */
-#elif defined(__LITTLE_ENDIAN_BITFIELD)
- unsigned page_code :6; /* Page code - Should be 0x2b */
- unsigned reserved1_6 :1;
- unsigned ps :1;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- u8 reserved2;
- u8 density;
- u8 reserved3,reserved4;
- __be16 segtrk;
- __be16 trks;
- u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
-} osst_tape_paramtr_page_t;
-
-/* OnStream definitions */
-
-#define OS_CONFIG_PARTITION (0xff)
-#define OS_DATA_PARTITION (0)
-#define OS_PARTITION_VERSION (1)
-
-/*
- * partition
- */
-typedef struct os_partition_s {
- __u8 partition_num;
- __u8 par_desc_ver;
- __be16 wrt_pass_cntr;
- __be32 first_frame_ppos;
- __be32 last_frame_ppos;
- __be32 eod_frame_ppos;
-} os_partition_t;
-
-/*
- * DAT entry
- */
-typedef struct os_dat_entry_s {
- __be32 blk_sz;
- __be16 blk_cnt;
- __u8 flags;
- __u8 reserved;
-} os_dat_entry_t;
-
-/*
- * DAT
- */
-#define OS_DAT_FLAGS_DATA (0xc)
-#define OS_DAT_FLAGS_MARK (0x1)
-
-typedef struct os_dat_s {
- __u8 dat_sz;
- __u8 reserved1;
- __u8 entry_cnt;
- __u8 reserved3;
- os_dat_entry_t dat_list[16];
-} os_dat_t;
-
-/*
- * Frame types
- */
-#define OS_FRAME_TYPE_FILL (0)
-#define OS_FRAME_TYPE_EOD (1 << 0)
-#define OS_FRAME_TYPE_MARKER (1 << 1)
-#define OS_FRAME_TYPE_HEADER (1 << 3)
-#define OS_FRAME_TYPE_DATA (1 << 7)
-
-/*
- * AUX
- */
-typedef struct os_aux_s {
- __be32 format_id; /* hardware compatibility AUX is based on */
- char application_sig[4]; /* driver used to write this media */
- __be32 hdwr; /* reserved */
- __be32 update_frame_cntr; /* for configuration frame */
- __u8 frame_type;
- __u8 frame_type_reserved;
- __u8 reserved_18_19[2];
- os_partition_t partition;
- __u8 reserved_36_43[8];
- __be32 frame_seq_num;
- __be32 logical_blk_num_high;
- __be32 logical_blk_num;
- os_dat_t dat;
- __u8 reserved188_191[4];
- __be32 filemark_cnt;
- __be32 phys_fm;
- __be32 last_mark_ppos;
- __u8 reserved204_223[20];
-
- /*
- * __u8 app_specific[32];
- *
- * Linux specific fields:
- */
- __be32 next_mark_ppos; /* when known, points to next marker */
- __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
- __u8 linux_specific[24];
-
- __u8 reserved_256_511[256];
-} os_aux_t;
-
-#define OS_FM_TAB_MAX 1024
-
-typedef struct os_fm_tab_s {
- __u8 fm_part_num;
- __u8 reserved_1;
- __u8 fm_tab_ent_sz;
- __u8 reserved_3;
- __be16 fm_tab_ent_cnt;
- __u8 reserved6_15[10];
- __be32 fm_tab_ent[OS_FM_TAB_MAX];
-} os_fm_tab_t;
-
-typedef struct os_ext_trk_ey_s {
- __u8 et_part_num;
- __u8 fmt;
- __be16 fm_tab_off;
- __u8 reserved4_7[4];
- __be32 last_hlb_hi;
- __be32 last_hlb;
- __be32 last_pp;
- __u8 reserved20_31[12];
-} os_ext_trk_ey_t;
-
-typedef struct os_ext_trk_tb_s {
- __u8 nr_stream_part;
- __u8 reserved_1;
- __u8 et_ent_sz;
- __u8 reserved3_15[13];
- os_ext_trk_ey_t dat_ext_trk_ey;
- os_ext_trk_ey_t qfa_ext_trk_ey;
-} os_ext_trk_tb_t;
-
-typedef struct os_header_s {
- char ident_str[8];
- __u8 major_rev;
- __u8 minor_rev;
- __be16 ext_trk_tb_off;
- __u8 reserved12_15[4];
- __u8 pt_par_num;
- __u8 pt_reserved1_3[3];
- os_partition_t partition[16];
- __be32 cfg_col_width;
- __be32 dat_col_width;
- __be32 qfa_col_width;
- __u8 cartridge[16];
- __u8 reserved304_511[208];
- __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */
- os_ext_trk_tb_t ext_track_tb;
- __u8 reserved17272_17735[464];
- os_fm_tab_t dat_fm_tab;
- os_fm_tab_t qfa_fm_tab;
- __u8 reserved25960_32767[6808];
-} os_header_t;
-
-
-/*
- * OnStream ADRL frame
- */
-#define OS_FRAME_SIZE (32 * 1024 + 512)
-#define OS_DATA_SIZE (32 * 1024)
-#define OS_AUX_SIZE (512)
-//#define OSST_MAX_SG 2
-
-/* The OnStream tape buffer descriptor. */
-struct osst_buffer {
- unsigned char in_use;
- unsigned char dma; /* DMA-able buffer */
- int buffer_size;
- int buffer_blocks;
- int buffer_bytes;
- int read_pointer;
- int writing;
- int midlevel_result;
- int syscall_result;
- struct osst_request *last_SRpnt;
- struct st_cmdstatus cmdstat;
- struct rq_map_data map_data;
- unsigned char *b_data;
- os_aux_t *aux; /* onstream AUX structure at end of each block */
- unsigned short use_sg; /* zero or number of s/g segments for this adapter */
- unsigned short sg_segs; /* number of segments in s/g list */
- unsigned short orig_sg_segs; /* number of segments allocated at first try */
- struct scatterlist sg[1]; /* MUST BE last item */
-} ;
-
-/* The OnStream tape drive descriptor */
-struct osst_tape {
- struct scsi_driver *driver;
- unsigned capacity;
- struct scsi_device *device;
- struct mutex lock; /* for serialization */
- struct completion wait; /* for SCSI commands */
- struct osst_buffer * buffer;
-
- /* Drive characteristics */
- unsigned char omit_blklims;
- unsigned char do_auto_lock;
- unsigned char can_bsr;
- unsigned char can_partitions;
- unsigned char two_fm;
- unsigned char fast_mteom;
- unsigned char restr_dma;
- unsigned char scsi2_logical;
- unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */
- unsigned char pos_unknown; /* after reset position unknown */
- int write_threshold;
- int timeout; /* timeout for normal commands */
- int long_timeout; /* timeout for commands known to take long time*/
-
- /* Mode characteristics */
- struct st_modedef modes[ST_NBR_MODES];
- int current_mode;
-
- /* Status variables */
- int partition;
- int new_partition;
- int nbr_partitions; /* zero until partition support enabled */
- struct st_partstat ps[ST_NBR_PARTITIONS];
- unsigned char dirty;
- unsigned char ready;
- unsigned char write_prot;
- unsigned char drv_write_prot;
- unsigned char in_use;
- unsigned char blksize_changed;
- unsigned char density_changed;
- unsigned char compression_changed;
- unsigned char drv_buffer;
- unsigned char density;
- unsigned char door_locked;
- unsigned char rew_at_close;
- unsigned char inited;
- int block_size;
- int min_block;
- int max_block;
- int recover_count; /* from tape opening */
- int abort_count;
- int write_count;
- int read_count;
- int recover_erreg; /* from last status call */
- /*
- * OnStream specific data
- */
- int os_fw_rev; /* the firmware revision * 10000 */
- unsigned char raw; /* flag OnStream raw access (32.5KB block size) */
- unsigned char poll; /* flag that this drive needs polling (IDE|firmware) */
- unsigned char frame_in_buffer; /* flag that the frame as per frame_seq_number
- * has been read into STp->buffer and is valid */
- int frame_seq_number; /* logical frame number */
- int logical_blk_num; /* logical block number */
- unsigned first_frame_position; /* physical frame to be transferred to/from host */
- unsigned last_frame_position; /* physical frame to be transferd to/from tape */
- int cur_frames; /* current number of frames in internal buffer */
- int max_frames; /* max number of frames in internal buffer */
- char application_sig[5]; /* application signature */
- unsigned char fast_open; /* flag that reminds us we didn't check headers at open */
- unsigned short wrt_pass_cntr; /* write pass counter */
- int update_frame_cntr; /* update frame counter */
- int onstream_write_error; /* write error recovery active */
- int header_ok; /* header frame verified ok */
- int linux_media; /* reading linux-specifc media */
- int linux_media_version;
- os_header_t * header_cache; /* cache is kept for filemark positions */
- int filemark_cnt;
- int first_mark_ppos;
- int last_mark_ppos;
- int last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
- int first_data_ppos;
- int eod_frame_ppos;
- int eod_frame_lfa;
- int write_type; /* used in write error recovery */
- int read_error_frame; /* used in read error recovery */
- unsigned long cmd_start_time;
- unsigned long max_cmd_time;
-
-#if DEBUG
- unsigned char write_pending;
- int nbr_finished;
- int nbr_waits;
- unsigned char last_cmnd[6];
- unsigned char last_sense[16];
-#endif
- struct gendisk *drive;
-} ;
-
-/* scsi tape command */
-struct osst_request {
- unsigned char cmd[MAX_COMMAND_SIZE];
- unsigned char sense[SCSI_SENSE_BUFFERSIZE];
- int result;
- struct osst_tape *stp;
- struct completion *waiting;
- struct bio *bio;
-};
-
-/* Values of write_type */
-#define OS_WRITE_DATA 0
-#define OS_WRITE_EOD 1
-#define OS_WRITE_NEW_MARK 2
-#define OS_WRITE_LAST_MARK 3
-#define OS_WRITE_HEADER 4
-#define OS_WRITE_FILLER 5
-
-/* Additional rw state */
-#define OS_WRITING_COMPLETE 3
diff --git a/drivers/scsi/osst_detect.h b/drivers/scsi/osst_detect.h
deleted file mode 100644
index 83c1d4fb11db..000000000000
--- a/drivers/scsi/osst_detect.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#define SIGS_FROM_OSST \
- {"OnStream", "SC-", "", "osst"}, \
- {"OnStream", "DI-", "", "osst"}, \
- {"OnStream", "DP-", "", "osst"}, \
- {"OnStream", "FW-", "", "osst"}, \
- {"OnStream", "USB", "", "osst"}
diff --git a/drivers/scsi/osst_options.h b/drivers/scsi/osst_options.h
deleted file mode 100644
index a6a389b88876..000000000000
--- a/drivers/scsi/osst_options.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- The compile-time configurable defaults for the Linux SCSI tape driver.
-
- Copyright 1995 Kai Makisara.
-
- Last modified: Wed Sep 2 21:24:07 1998 by root@home
-
- Changed (and renamed) for OnStream SCSI drives garloff@suse.de
- 2000-06-21
-
- $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $
-*/
-
-#ifndef _OSST_OPTIONS_H
-#define _OSST_OPTIONS_H
-
-/* The minimum limit for the number of SCSI tape devices is determined by
- OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by
- OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */
-#define OSST_MAX_TAPES 4
-
-/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the
- record been read by the user program even if the tape has moved further
- because of buffered reads. Should be set to zero to support also drives
- that can't space backwards over records. NOTE: The tape will be
- spaced backwards over an "accidentally" crossed filemark in any case. */
-#define OSST_IN_FILE_POS 1
-
-/* The tape driver buffer size in kilobytes. */
-/* Don't change, as this is the HW blocksize */
-#define OSST_BUFFER_BLOCKS 32
-
-/* The number of kilobytes of data in the buffer that triggers an
- asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES
- below. */
-#define OSST_WRITE_THRESHOLD_BLOCKS 32
-
-/* OSST_EOM_RESERVE defines the number of frames are kept in reserve for
- * * write error recovery when writing near end of medium. ENOSPC is returned
- * * when write() is called and the tape write position is within this number
- * * of blocks from the tape capacity. */
-#define OSST_EOM_RESERVE 300
-
-/* The maximum number of tape buffers the driver allocates. The number
- is also constrained by the number of drives detected. Determines the
- maximum number of concurrently active tape drives. */
-#define OSST_MAX_BUFFERS OSST_MAX_TAPES
-
-/* Maximum number of scatter/gather segments */
-/* Fit one buffer in pages and add one for the AUX header */
-#define OSST_MAX_SG (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1)
-
-/* The number of scatter/gather segments to allocate at first try (must be
- smaller or equal to the maximum). */
-#define OSST_FIRST_SG ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE)
-
-/* The size of the first scatter/gather segments (determines the maximum block
- size for SCSI adapters not supporting scatter/gather). The default is set
- to try to allocate the buffer as one chunk. */
-#define OSST_FIRST_ORDER (15-PAGE_SHIFT)
-
-
-/* The following lines define defaults for properties that can be set
- separately for each drive using the MTSTOPTIONS ioctl. */
-
-/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a
- file being written. Some drives can't handle two filemarks at the
- end of data. */
-#define OSST_TWO_FM 0
-
-/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are
- buffered until the driver buffer is full or asynchronous write is
- triggered. */
-#define OSST_BUFFER_WRITES 1
-
-/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started
- without waiting for it to finish. May cause problems in multiple
- tape backups. */
-#define OSST_ASYNC_WRITES 1
-
-/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block
- mode. */
-#define OSST_READ_AHEAD 1
-
-/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first
- read or write command after the device is opened. The door is opened
- when the device is closed. */
-#define OSST_AUTO_LOCK 0
-
-/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the
- direct SCSI command. The file number status is lost but this method
- is fast with some drives. Otherwise MTEOM is done by spacing over
- files and the file number status is retained. */
-#define OSST_FAST_MTEOM 0
-
-/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for
- MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL
- is zero. */
-#define OSST_SCSI2LOGICAL 0
-
-/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics.
- The default is BSD semantics. */
-#define OSST_SYSV 0
-
-
-#endif
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index 2d435f105b16..2368f34efba3 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# PCMCIA SCSI adapter configuration
#
@@ -19,6 +20,16 @@ config PCMCIA_AHA152X
To compile this driver as a module, choose M here: the
module will be called aha152x_cs.
+config PCMCIA_FDOMAIN
+ tristate "Future Domain PCMCIA support"
+ select SCSI_FDOMAIN
+ help
+ Say Y here if you intend to attach this type of PCMCIA SCSI host
+ adapter to your computer.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fdomain_cs.
+
config PCMCIA_NINJA_SCSI
tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
depends on !64BIT
diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile
index a5a24dd44e7e..02f5b44a2685 100644
--- a/drivers/scsi/pcmcia/Makefile
+++ b/drivers/scsi/pcmcia/Makefile
@@ -4,6 +4,7 @@ ccflags-y := -I $(srctree)/drivers/scsi
# 16-bit client drivers
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o
+obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o
obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o
obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o
obj-$(CONFIG_PCMCIA_SYM53C500) += sym53c500_cs.o
diff --git a/drivers/scsi/pcmcia/fdomain_cs.c b/drivers/scsi/pcmcia/fdomain_cs.c
new file mode 100644
index 000000000000..e42acf314d06
--- /dev/null
+++ b/drivers/scsi/pcmcia/fdomain_cs.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
+/*
+ * Driver for Future Domain-compatible PCMCIA SCSI cards
+ * Copyright 2019 Ondrej Zary
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <scsi/scsi_host.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include "fdomain.h"
+
+MODULE_AUTHOR("Ondrej Zary, David Hinds");
+MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data)
+{
+ p_dev->io_lines = 10;
+ p_dev->resource[0]->end = FDOMAIN_REGION_SIZE;
+ p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+ p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+ return pcmcia_request_io(p_dev);
+}
+
+static int fdomain_probe(struct pcmcia_device *link)
+{
+ int ret;
+ struct Scsi_Host *sh;
+
+ link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+ link->config_regs = PRESENT_OPTION;
+
+ ret = pcmcia_loop_config(link, fdomain_config_check, NULL);
+ if (ret)
+ return ret;
+
+ ret = pcmcia_enable_device(link);
+ if (ret)
+ goto fail_disable;
+
+ if (!request_region(link->resource[0]->start, FDOMAIN_REGION_SIZE,
+ "fdomain_cs"))
+ goto fail_disable;
+
+ sh = fdomain_create(link->resource[0]->start, link->irq, 7, &link->dev);
+ if (!sh) {
+ dev_err(&link->dev, "Controller initialization failed");
+ ret = -ENODEV;
+ goto fail_release;
+ }
+
+ link->priv = sh;
+
+ return 0;
+
+fail_release:
+ release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE);
+fail_disable:
+ pcmcia_disable_device(link);
+ return ret;
+}
+
+static void fdomain_remove(struct pcmcia_device *link)
+{
+ fdomain_destroy(link->priv);
+ release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE);
+ pcmcia_disable_device(link);
+}
+
+static const struct pcmcia_device_id fdomain_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88,
+ 0x859cad20),
+ PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
+ PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation",
+ "SCSI PCMCIA Credit Card Controller",
+ 0x182bdafe, 0xc80d106f),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
+
+static struct pcmcia_driver fdomain_cs_driver = {
+ .owner = THIS_MODULE,
+ .name = "fdomain_cs",
+ .probe = fdomain_probe,
+ .remove = fdomain_remove,
+ .id_table = fdomain_ids,
+};
+
+module_pcmcia_driver(fdomain_cs_driver);
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index a81748e6e8fb..97416e1dcc5b 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -789,7 +789,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
SCpnt->SCp.buffers_residual != 0 ) {
//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
SCpnt->SCp.buffers_residual--;
- SCpnt->SCp.buffer++;
+ SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
SCpnt->SCp.ptr = BUFFER_ADDR;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
time_out = 1000;
@@ -887,7 +887,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
SCpnt->SCp.buffers_residual != 0 ) {
//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
SCpnt->SCp.buffers_residual--;
- SCpnt->SCp.buffer++;
+ SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
SCpnt->SCp.ptr = BUFFER_ADDR;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
time_out = 1000;
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index d1e98a6ea28f..a366ff1a3959 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* sym53c500_cs.c Bob Tracy (rct@frus.com)
*
@@ -25,16 +26,6 @@
* Original by Tom Corner (tcorner@via.at) was adapted from a
* driver for the Qlogic SCSI card written by
* David Hinds (dhinds@allegro.stanford.edu).
-*
-* 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, 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.
*/
#define SYM53C500_DEBUG 0
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index d193961ea82f..6b85016b4db3 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -462,6 +462,24 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
}
static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL);
/**
+ * event_log_size_show - event log size
+ * @cdev: pointer to embedded class device
+ * @buf: the buffer returned
+ *
+ * A sysfs read shost attribute.
+ */
+static ssize_t event_log_size_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+ struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size);
+}
+static DEVICE_ATTR_RO(event_log_size);
+/**
* pm8001_ctl_aap_log_show - IOP event log
* @cdev: pointer to embedded class device
* @buf: the buffer returned
@@ -474,25 +492,26 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
struct Scsi_Host *shost = class_to_shost(cdev);
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
-#define IOP_MEMMAP(r, c) \
- (*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \
- + (c)))
- int i;
char *str = buf;
- int max = 2;
- for (i = 0; i < max; i++) {
- str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
- "0x%08x 0x%08x\n",
- IOP_MEMMAP(i, 0),
- IOP_MEMMAP(i, 4),
- IOP_MEMMAP(i, 8),
- IOP_MEMMAP(i, 12),
- IOP_MEMMAP(i, 16),
- IOP_MEMMAP(i, 20),
- IOP_MEMMAP(i, 24),
- IOP_MEMMAP(i, 28));
+ u32 read_size =
+ pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024;
+ static u32 start, end, count;
+ u32 max_read_times = 32;
+ u32 max_count = (read_size * 1024) / (max_read_times * 4);
+ u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr;
+
+ if ((count % max_count) == 0) {
+ start = 0;
+ end = max_read_times;
+ count = 0;
+ } else {
+ start = end;
+ end = end + max_read_times;
}
+ for (; start < end; start++)
+ str += sprintf(str, "%08x ", *(temp+start));
+ count++;
return str - buf;
}
static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
@@ -796,6 +815,7 @@ struct device_attribute *pm8001_host_attrs[] = {
&dev_attr_max_sg_list,
&dev_attr_sas_spec_support,
&dev_attr_logging_level,
+ &dev_attr_event_log_size,
&dev_attr_host_sas_address,
&dev_attr_bios_version,
&dev_attr_ib_log,
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index d0bb357034d8..68a8217032d0 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -960,9 +960,9 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
return -1;
}
regVal = pm8001_cr32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET);
- PM8001_INIT_DBG(pm8001_ha,
- pm8001_printk("GPIO Output Control Register:"
- " = 0x%x\n", regVal));
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("GPIO Output Control Register:"
+ " = 0x%x\n", regVal));
/* set GPIO-0 output control to tri-state */
regVal &= 0xFFFFFFFC;
pm8001_cw32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET, regVal);
@@ -1204,6 +1204,7 @@ void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha)
}
}
+#ifndef PM8001_USE_MSIX
/**
* pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
* @pm8001_ha: our hba card information
@@ -1225,6 +1226,8 @@ pm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha)
pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_MASK_ALL);
}
+#else
+
/**
* pm8001_chip_msix_interrupt_enable - enable PM8001 chip interrupt
* @pm8001_ha: our hba card information
@@ -1256,6 +1259,7 @@ pm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha,
msi_index += MSIX_TABLE_BASE;
pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_DISABLE);
}
+#endif
/**
* pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
@@ -1266,10 +1270,9 @@ pm8001_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
#ifdef PM8001_USE_MSIX
pm8001_chip_msix_interrupt_enable(pm8001_ha, 0);
- return;
-#endif
+#else
pm8001_chip_intx_interrupt_enable(pm8001_ha);
-
+#endif
}
/**
@@ -1281,10 +1284,9 @@ pm8001_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
#ifdef PM8001_USE_MSIX
pm8001_chip_msix_interrupt_disable(pm8001_ha, 0);
- return;
-#endif
+#else
pm8001_chip_intx_interrupt_disable(pm8001_ha);
-
+#endif
}
/**
@@ -2354,7 +2356,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
(status != IO_UNDERFLOW)) {
if (!((t->dev->parent) &&
- (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) {
+ (dev_is_expander(t->dev->parent->dev_type)))) {
for (i = 0 , j = 4; j <= 7 && i <= 3; i++ , j++)
sata_addr_low[i] = pm8001_ha->sas_addr[j];
for (i = 0 , j = 0; j <= 3 && i <= 3; i++ , j++)
@@ -2898,7 +2900,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
static void
mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
- u32 param;
struct sas_task *t;
struct pm8001_ccb_info *ccb;
unsigned long flags;
@@ -2913,7 +2914,6 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
tag = le32_to_cpu(psmpPayload->tag);
ccb = &pm8001_ha->ccb_info[tag];
- param = le32_to_cpu(psmpPayload->param);
t = ccb->task;
ts = &t->task_status;
pm8001_dev = ccb->device;
@@ -2928,7 +2928,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n"));
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAM_STAT_GOOD;
- if (pm8001_dev)
+ if (pm8001_dev)
pm8001_dev->running_req--;
break;
case IO_ABORTED:
@@ -3244,11 +3244,9 @@ void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i)
{
struct pm8001_phy *phy = &pm8001_ha->phy[i];
struct asd_sas_phy *sas_phy = &phy->sas_phy;
- struct sas_ha_struct *sas_ha;
if (!phy->phy_attached)
return;
- sas_ha = pm8001_ha->sas;
if (sas_phy->phy) {
struct sas_phy *sphy = sas_phy->phy;
sphy->negotiated_linkrate = sas_phy->linkrate;
@@ -4562,7 +4560,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
stp_sspsmp_sata = 0x01; /*ssp or smp*/
}
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
phy_id = parent_dev->ex_dev.ex_phy->phy_id;
else
phy_id = pm8001_dev->attached_phy;
@@ -4627,17 +4625,18 @@ static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
return ret;
}
-static u32 pm8001_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha)
+static u32 pm8001_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha)
{
- u32 value;
#ifdef PM8001_USE_MSIX
return 1;
-#endif
+#else
+ u32 value;
+
value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR);
if (value)
return 1;
return 0;
-
+#endif
}
/**
@@ -5123,7 +5122,7 @@ const struct pm8001_dispatch pm8001_8001_dispatch = {
.chip_rst = pm8001_hw_chip_rst,
.chip_iounmap = pm8001_chip_iounmap,
.isr = pm8001_chip_isr,
- .is_our_interupt = pm8001_chip_is_our_interupt,
+ .is_our_interrupt = pm8001_chip_is_our_interrupt,
.isr_process_oq = process_oq,
.interrupt_enable = pm8001_chip_interrupt_enable,
.interrupt_disable = pm8001_chip_interrupt_disable,
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index a36060c23b37..3374f553c617 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -201,7 +201,7 @@ static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque)
if (unlikely(!pm8001_ha))
return IRQ_NONE;
- if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha))
+ if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha))
return IRQ_NONE;
#ifdef PM8001_USE_TASKLET
tasklet_schedule(&pm8001_ha->tasklet[irq_vector->irq_id]);
@@ -224,7 +224,7 @@ static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id)
pm8001_ha = sha->lldd_ha;
if (unlikely(!pm8001_ha))
return IRQ_NONE;
- if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha))
+ if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha))
return IRQ_NONE;
#ifdef PM8001_USE_TASKLET
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 084f2fcced0a..dd38c356a1a4 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -634,7 +634,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
dev->lldd_dev = pm8001_device;
pm8001_device->dev_type = dev->dev_type;
pm8001_device->dcompletion = &completion;
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
int phy_id;
struct ex_phy *phy;
for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys;
@@ -740,8 +740,8 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
wait_for_completion(&task->slow_task->completion);
if (pm8001_ha->chip_id != chip_8001) {
pm8001_dev->setds_completion = &completion_setstate;
- PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
- pm8001_dev, 0x01);
+ PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
+ pm8001_dev, 0x01);
wait_for_completion(&completion_setstate);
}
res = -TMF_RESP_FUNC_FAILED;
@@ -1181,7 +1181,7 @@ int pm8001_query_task(struct sas_task *task)
return rc;
}
-/* mandatory SAM-3, still need free task/ccb info, abord the specified task */
+/* mandatory SAM-3, still need free task/ccb info, abort the specified task */
int pm8001_abort_task(struct sas_task *task)
{
unsigned long flags;
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index f88b0d33c385..ff17c6aff63d 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -103,7 +103,6 @@ do { \
#define PM8001_READ_VPD
-#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) \
@@ -197,7 +196,7 @@ struct pm8001_dispatch {
int (*chip_ioremap)(struct pm8001_hba_info *pm8001_ha);
void (*chip_iounmap)(struct pm8001_hba_info *pm8001_ha);
irqreturn_t (*isr)(struct pm8001_hba_info *pm8001_ha, u8 vec);
- u32 (*is_our_interupt)(struct pm8001_hba_info *pm8001_ha);
+ u32 (*is_our_interrupt)(struct pm8001_hba_info *pm8001_ha);
int (*isr_process_oq)(struct pm8001_hba_info *pm8001_ha, u8 vec);
void (*interrupt_enable)(struct pm8001_hba_info *pm8001_ha, u8 vec);
void (*interrupt_disable)(struct pm8001_hba_info *pm8001_ha, u8 vec);
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 63e4f7d34d6c..1128d86d241a 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -1316,7 +1316,7 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
static void pm80xx_hw_chip_rst(struct pm8001_hba_info *pm8001_ha)
{
- u32 i;
+ u32 i;
PM8001_INIT_DBG(pm8001_ha,
pm8001_printk("chip reset start\n"));
@@ -2066,7 +2066,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
(status != IO_UNDERFLOW)) {
if (!((t->dev->parent) &&
- (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) {
+ (dev_is_expander(t->dev->parent->dev_type)))) {
for (i = 0 , j = 4; i <= 3 && j <= 7; i++ , j++)
sata_addr_low[i] = pm8001_ha->sas_addr[j];
for (i = 0 , j = 0; i <= 3 && j <= 3; i++ , j++)
@@ -4381,27 +4381,27 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
sata_cmd.len = cpu_to_le32(task->total_xfer_len);
sata_cmd.esgl = 0;
}
- /* scsi cdb */
- sata_cmd.atapi_scsi_cdb[0] =
- cpu_to_le32(((task->ata_task.atapi_packet[0]) |
- (task->ata_task.atapi_packet[1] << 8) |
- (task->ata_task.atapi_packet[2] << 16) |
- (task->ata_task.atapi_packet[3] << 24)));
- sata_cmd.atapi_scsi_cdb[1] =
- cpu_to_le32(((task->ata_task.atapi_packet[4]) |
- (task->ata_task.atapi_packet[5] << 8) |
- (task->ata_task.atapi_packet[6] << 16) |
- (task->ata_task.atapi_packet[7] << 24)));
- sata_cmd.atapi_scsi_cdb[2] =
- cpu_to_le32(((task->ata_task.atapi_packet[8]) |
- (task->ata_task.atapi_packet[9] << 8) |
- (task->ata_task.atapi_packet[10] << 16) |
- (task->ata_task.atapi_packet[11] << 24)));
- sata_cmd.atapi_scsi_cdb[3] =
- cpu_to_le32(((task->ata_task.atapi_packet[12]) |
- (task->ata_task.atapi_packet[13] << 8) |
- (task->ata_task.atapi_packet[14] << 16) |
- (task->ata_task.atapi_packet[15] << 24)));
+ /* scsi cdb */
+ sata_cmd.atapi_scsi_cdb[0] =
+ cpu_to_le32(((task->ata_task.atapi_packet[0]) |
+ (task->ata_task.atapi_packet[1] << 8) |
+ (task->ata_task.atapi_packet[2] << 16) |
+ (task->ata_task.atapi_packet[3] << 24)));
+ sata_cmd.atapi_scsi_cdb[1] =
+ cpu_to_le32(((task->ata_task.atapi_packet[4]) |
+ (task->ata_task.atapi_packet[5] << 8) |
+ (task->ata_task.atapi_packet[6] << 16) |
+ (task->ata_task.atapi_packet[7] << 24)));
+ sata_cmd.atapi_scsi_cdb[2] =
+ cpu_to_le32(((task->ata_task.atapi_packet[8]) |
+ (task->ata_task.atapi_packet[9] << 8) |
+ (task->ata_task.atapi_packet[10] << 16) |
+ (task->ata_task.atapi_packet[11] << 24)));
+ sata_cmd.atapi_scsi_cdb[3] =
+ cpu_to_le32(((task->ata_task.atapi_packet[12]) |
+ (task->ata_task.atapi_packet[13] << 8) |
+ (task->ata_task.atapi_packet[14] << 16) |
+ (task->ata_task.atapi_packet[15] << 24)));
}
/* Check for read log for failed drive and return */
@@ -4561,7 +4561,7 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
stp_sspsmp_sata = 0x01; /*ssp or smp*/
}
- if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+ if (parent_dev && dev_is_expander(parent_dev->dev_type))
phy_id = parent_dev->ex_dev.ex_phy->phy_id;
else
phy_id = pm8001_dev->attached_phy;
@@ -4617,17 +4617,18 @@ static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
return pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
}
-static u32 pm80xx_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha)
+static u32 pm80xx_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha)
{
- u32 value;
#ifdef PM8001_USE_MSIX
return 1;
-#endif
+#else
+ u32 value;
+
value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR);
if (value)
return 1;
return 0;
-
+#endif
}
/**
@@ -4724,7 +4725,7 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = {
.chip_rst = pm80xx_hw_chip_rst,
.chip_iounmap = pm8001_chip_iounmap,
.isr = pm80xx_chip_isr,
- .is_our_interupt = pm80xx_chip_is_our_interupt,
+ .is_our_interrupt = pm80xx_chip_is_our_interrupt,
.isr_process_oq = process_oq,
.interrupt_enable = pm80xx_chip_interrupt_enable,
.interrupt_disable = pm80xx_chip_interrupt_disable,
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index e338d7a4f571..71ff3936da4f 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* pmcraid.c -- driver for PMC Sierra MaxRAID controller adapters
*
@@ -5,22 +6,6 @@
* PMC-Sierra Inc
*
* Copyright (C) 2008, 2009 PMC Sierra Inc
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
- * USA
- *
*/
#include <linux/fs.h>
#include <linux/init.h>
@@ -3270,7 +3255,7 @@ static int pmcraid_copy_sglist(
int direction
)
{
- struct scatterlist *scatterlist;
+ struct scatterlist *sg;
void *kaddr;
int bsize_elem;
int i;
@@ -3279,10 +3264,10 @@ static int pmcraid_copy_sglist(
/* Determine the actual number of bytes per element */
bsize_elem = PAGE_SIZE * (1 << sglist->order);
- scatterlist = sglist->scatterlist;
+ sg = sglist->scatterlist;
- for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
- struct page *page = sg_page(&scatterlist[i]);
+ for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), buffer += bsize_elem) {
+ struct page *page = sg_page(sg);
kaddr = kmap(page);
if (direction == DMA_TO_DEVICE)
@@ -3297,11 +3282,11 @@ static int pmcraid_copy_sglist(
return -EFAULT;
}
- scatterlist[i].length = bsize_elem;
+ sg->length = bsize_elem;
}
if (len % bsize_elem) {
- struct page *page = sg_page(&scatterlist[i]);
+ struct page *page = sg_page(sg);
kaddr = kmap(page);
@@ -3312,7 +3297,7 @@ static int pmcraid_copy_sglist(
kunmap(page);
- scatterlist[i].length = len % bsize_elem;
+ sg->length = len % bsize_elem;
}
if (rc) {
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index 754ef30927e2..a4f7eb8f50a3 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* pmcraid.h -- PMC Sierra MaxRAID controller driver header file
*
@@ -5,20 +6,6 @@
* PMC-Sierra Inc
*
* Copyright (C) 2008, 2009 PMC Sierra Inc.
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _PMCRAID_H
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index c182b5458f98..a406cc825426 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -590,7 +590,7 @@ static int ppa_completion(struct scsi_cmnd *cmd)
if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
/* if scatter/gather, advance to the next segment */
if (cmd->SCp.buffers_residual--) {
- cmd->SCp.buffer++;
+ cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
cmd->SCp.this_residual =
cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
@@ -717,6 +717,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
}
cmd->SCp.phase++;
}
+ /* fall through */
case 2: /* Phase 2 - We are now talking to the scsi bus */
if (!ppa_select(dev, scmd_id(cmd))) {
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
index 8d769138c01c..f75c0b5cd587 100644
--- a/drivers/scsi/ps3rom.c
+++ b/drivers/scsi/ps3rom.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* PS3 BD/DVD/CD-ROM Storage Driver
*
* Copyright (C) 2007 Sony Computer Entertainment Inc.
* Copyright 2007 Sony Corp.
- *
- * 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; version 2 of the License.
- *
- * 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.
- *
- * 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/cdrom.h>
diff --git a/drivers/scsi/qedf/Kconfig b/drivers/scsi/qedf/Kconfig
index 943f5ee45807..7cd993be4e57 100644
--- a/drivers/scsi/qedf/Kconfig
+++ b/drivers/scsi/qedf/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config QEDF
tristate "QLogic QEDF 25/40/100Gb FCoE Initiator Driver Support"
depends on PCI && SCSI
diff --git a/drivers/scsi/qedf/Makefile b/drivers/scsi/qedf/Makefile
index 414f2a772a5f..c46287826fb8 100644
--- a/drivers/scsi/qedf/Makefile
+++ b/drivers/scsi/qedf/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_QEDF) := qedf.o
qedf-y = qedf_dbg.o qedf_main.o qedf_io.o qedf_fip.o \
qedf_attr.o qedf_els.o drv_scsi_fw_funcs.o drv_fcoe_fw_funcs.o
diff --git a/drivers/scsi/qedf/drv_fcoe_fw_funcs.c b/drivers/scsi/qedf/drv_fcoe_fw_funcs.c
index 5bd10b534c99..747af96dd15c 100644
--- a/drivers/scsi/qedf/drv_fcoe_fw_funcs.c
+++ b/drivers/scsi/qedf/drv_fcoe_fw_funcs.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include "drv_fcoe_fw_funcs.h"
#include "drv_scsi_fw_funcs.h"
diff --git a/drivers/scsi/qedf/drv_fcoe_fw_funcs.h b/drivers/scsi/qedf/drv_fcoe_fw_funcs.h
index 42fde55ac735..1ee31a5f063b 100644
--- a/drivers/scsi/qedf/drv_fcoe_fw_funcs.h
+++ b/drivers/scsi/qedf/drv_fcoe_fw_funcs.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _FCOE_FW_FUNCS_H
#define _FCOE_FW_FUNCS_H
diff --git a/drivers/scsi/qedf/drv_scsi_fw_funcs.c b/drivers/scsi/qedf/drv_scsi_fw_funcs.c
index 29a55257224f..3289b71031d6 100644
--- a/drivers/scsi/qedf/drv_scsi_fw_funcs.c
+++ b/drivers/scsi/qedf/drv_scsi_fw_funcs.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include "drv_scsi_fw_funcs.h"
diff --git a/drivers/scsi/qedf/drv_scsi_fw_funcs.h b/drivers/scsi/qedf/drv_scsi_fw_funcs.h
index bf102204fe56..6195f13dece8 100644
--- a/drivers/scsi/qedf/drv_scsi_fw_funcs.h
+++ b/drivers/scsi/qedf/drv_scsi_fw_funcs.h
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _SCSI_FW_FUNCS_H
#define _SCSI_FW_FUNCS_H
diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h
index 2c78d8fb9122..5a021217bfc9 100644
--- a/drivers/scsi/qedf/qedf.h
+++ b/drivers/scsi/qedf/qedf.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _QEDFC_H_
#define _QEDFC_H_
@@ -35,9 +32,6 @@
#define QEDF_DESCR "QLogic FCoE Offload Driver"
#define QEDF_MODULE_NAME "qedf"
-#define QEDF_MIN_XID 0
-#define QEDF_MAX_SCSI_XID (NUM_TASKS_PER_CONNECTION - 1)
-#define QEDF_MAX_ELS_XID 4095
#define QEDF_FLOGI_RETRY_CNT 3
#define QEDF_RPORT_RETRY_CNT 255
#define QEDF_MAX_SESSIONS 1024
@@ -52,8 +46,8 @@
sizeof(struct fc_frame_header))
#define QEDF_MAX_NPIV 64
#define QEDF_TM_TIMEOUT 10
-#define QEDF_ABORT_TIMEOUT 10
-#define QEDF_CLEANUP_TIMEOUT 10
+#define QEDF_ABORT_TIMEOUT (10 * 1000)
+#define QEDF_CLEANUP_TIMEOUT 1
#define QEDF_MAX_CDB_LEN 16
#define UPSTREAM_REMOVE 1
@@ -85,6 +79,7 @@ struct qedf_els_cb_arg {
};
enum qedf_ioreq_event {
+ QEDF_IOREQ_EV_NONE,
QEDF_IOREQ_EV_ABORT_SUCCESS,
QEDF_IOREQ_EV_ABORT_FAILED,
QEDF_IOREQ_EV_SEND_RRQ,
@@ -105,7 +100,6 @@ struct qedf_ioreq {
struct list_head link;
uint16_t xid;
struct scsi_cmnd *sc_cmd;
- bool use_slowpath; /* Use slow SGL for this I/O */
#define QEDF_SCSI_CMD 1
#define QEDF_TASK_MGMT_CMD 2
#define QEDF_ABTS 3
@@ -117,22 +111,43 @@ struct qedf_ioreq {
#define QEDF_CMD_IN_ABORT 0x1
#define QEDF_CMD_IN_CLEANUP 0x2
#define QEDF_CMD_SRR_SENT 0x3
+#define QEDF_CMD_DIRTY 0x4
+#define QEDF_CMD_ERR_SCSI_DONE 0x5
u8 io_req_flags;
uint8_t tm_flags;
struct qedf_rport *fcport;
+#define QEDF_CMD_ST_INACTIVE 0
+#define QEDFC_CMD_ST_IO_ACTIVE 1
+#define QEDFC_CMD_ST_ABORT_ACTIVE 2
+#define QEDFC_CMD_ST_ABORT_ACTIVE_EH 3
+#define QEDFC_CMD_ST_CLEANUP_ACTIVE 4
+#define QEDFC_CMD_ST_CLEANUP_ACTIVE_EH 5
+#define QEDFC_CMD_ST_RRQ_ACTIVE 6
+#define QEDFC_CMD_ST_RRQ_WAIT 7
+#define QEDFC_CMD_ST_OXID_RETIRE_WAIT 8
+#define QEDFC_CMD_ST_TMF_ACTIVE 9
+#define QEDFC_CMD_ST_DRAIN_ACTIVE 10
+#define QEDFC_CMD_ST_CLEANED 11
+#define QEDFC_CMD_ST_ELS_ACTIVE 12
+ atomic_t state;
unsigned long flags;
enum qedf_ioreq_event event;
size_t data_xfer_len;
+ /* ID: 001: Alloc cmd (qedf_alloc_cmd) */
+ /* ID: 002: Initiate ABTS (qedf_initiate_abts) */
+ /* ID: 003: For RRQ (qedf_process_abts_compl) */
struct kref refcount;
struct qedf_cmd_mgr *cmd_mgr;
struct io_bdt *bd_tbl;
struct delayed_work timeout_work;
struct completion tm_done;
struct completion abts_done;
+ struct completion cleanup_done;
struct e4_fcoe_task_context *task;
struct fcoe_task_params *task_params;
struct scsi_sgl_task_params *sgl_task_params;
int idx;
+ int lun;
/*
* Need to allocate enough room for both sense data and FCP response data
* which has a max length of 8 bytes according to spec.
@@ -155,9 +170,9 @@ struct qedf_ioreq {
int fp_idx;
unsigned int cpu;
unsigned int int_cpu;
-#define QEDF_IOREQ_SLOW_SGE 0
-#define QEDF_IOREQ_SINGLE_SGE 1
-#define QEDF_IOREQ_FAST_SGE 2
+#define QEDF_IOREQ_UNKNOWN_SGE 1
+#define QEDF_IOREQ_SLOW_SGE 2
+#define QEDF_IOREQ_FAST_SGE 3
u8 sge_type;
struct delayed_work rrq_work;
@@ -172,6 +187,8 @@ struct qedf_ioreq {
* during some form of error processing.
*/
bool return_scsi_cmd_on_abts;
+
+ unsigned int alloc;
};
extern struct workqueue_struct *qedf_io_wq;
@@ -181,7 +198,10 @@ struct qedf_rport {
#define QEDF_RPORT_SESSION_READY 1
#define QEDF_RPORT_UPLOADING_CONNECTION 2
#define QEDF_RPORT_IN_RESET 3
+#define QEDF_RPORT_IN_LUN_RESET 4
+#define QEDF_RPORT_IN_TARGET_RESET 5
unsigned long flags;
+ int lun_reset_lun;
unsigned long retry_delay_timestamp;
struct fc_rport *rport;
struct fc_rport_priv *rdata;
@@ -191,6 +211,7 @@ struct qedf_rport {
void __iomem *p_doorbell;
/* Send queue management */
atomic_t free_sqes;
+ atomic_t ios_to_queue;
atomic_t num_active_ios;
struct fcoe_wqe *sq;
dma_addr_t sq_dma;
@@ -295,8 +316,6 @@ struct qedf_ctx {
#define QEDF_DCBX_PENDING 0
#define QEDF_DCBX_DONE 1
atomic_t dcbx;
- uint16_t max_scsi_xid;
- uint16_t max_els_xid;
#define QEDF_NULL_VLAN_ID -1
#define QEDF_FALLBACK_VLAN 1002
#define QEDF_DEFAULT_PRIO 3
@@ -371,7 +390,6 @@ struct qedf_ctx {
u32 slow_sge_ios;
u32 fast_sge_ios;
- u32 single_sge_ios;
uint8_t *grcdump;
uint32_t grcdump_size;
@@ -396,6 +414,8 @@ struct qedf_ctx {
u8 target_resets;
u8 task_set_fulls;
u8 busy;
+ /* Used for flush routine */
+ struct mutex flush_mutex;
};
struct io_bdt {
@@ -435,6 +455,12 @@ static inline void qedf_stop_all_io(struct qedf_ctx *qedf)
/*
* Externs
*/
+
+/*
+ * (QEDF_LOG_NPIV | QEDF_LOG_SESS | QEDF_LOG_LPORT | QEDF_LOG_ELS | QEDF_LOG_MQ
+ * | QEDF_LOG_IO | QEDF_LOG_UNSOL | QEDF_LOG_SCSI_TM | QEDF_LOG_MP_REQ |
+ * QEDF_LOG_EVT | QEDF_LOG_CONN | QEDF_LOG_DISC | QEDF_LOG_INFO)
+ */
#define QEDF_DEFAULT_LOG_MASK 0x3CFB6
extern const struct qed_fcoe_ops *qed_ops;
extern uint qedf_dump_frames;
@@ -494,7 +520,7 @@ extern void qedf_set_vlan_id(struct qedf_ctx *qedf, int vlan_id);
extern void qedf_create_sysfs_ctx_attr(struct qedf_ctx *qedf);
extern void qedf_remove_sysfs_ctx_attr(struct qedf_ctx *qedf);
extern void qedf_capture_grc_dump(struct qedf_ctx *qedf);
-extern void qedf_wait_for_upload(struct qedf_ctx *qedf);
+bool qedf_wait_for_upload(struct qedf_ctx *qedf);
extern void qedf_process_unsol_compl(struct qedf_ctx *qedf, uint16_t que_idx,
struct fcoe_cqe *cqe);
extern void qedf_restart_rport(struct qedf_rport *fcport);
@@ -508,6 +534,8 @@ extern void qedf_get_protocol_tlv_data(void *dev, void *data);
extern void qedf_fp_io_handler(struct work_struct *work);
extern void qedf_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data);
extern void qedf_wq_grcdump(struct work_struct *work);
+void qedf_stag_change_work(struct work_struct *work);
+void qedf_ctx_soft_reset(struct fc_lport *lport);
#define FCOE_WORD_TO_BYTE 4
#define QEDF_MAX_TASK_NUM 0xFFFF
diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c
index 0487b7237104..d995f72a6759 100644
--- a/drivers/scsi/qedf/qedf_attr.c
+++ b/drivers/scsi/qedf/qedf_attr.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include "qedf.h"
diff --git a/drivers/scsi/qedf/qedf_dbg.c b/drivers/scsi/qedf/qedf_dbg.c
index f2397ee9ba69..e0387e495261 100644
--- a/drivers/scsi/qedf/qedf_dbg.c
+++ b/drivers/scsi/qedf/qedf_dbg.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include "qedf_dbg.h"
#include <linux/vmalloc.h>
@@ -15,10 +12,6 @@ qedf_dbg_err(struct qedf_dbg_ctx *qedf, const char *func, u32 line,
{
va_list va;
struct va_format vaf;
- char nfunc[32];
-
- memset(nfunc, 0, sizeof(nfunc));
- memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
@@ -27,9 +20,9 @@ qedf_dbg_err(struct qedf_dbg_ctx *qedf, const char *func, u32 line,
if (likely(qedf) && likely(qedf->pdev))
pr_err("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)),
- nfunc, line, qedf->host_no, &vaf);
+ func, line, qedf->host_no, &vaf);
else
- pr_err("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+ pr_err("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf);
va_end(va);
}
@@ -40,10 +33,6 @@ qedf_dbg_warn(struct qedf_dbg_ctx *qedf, const char *func, u32 line,
{
va_list va;
struct va_format vaf;
- char nfunc[32];
-
- memset(nfunc, 0, sizeof(nfunc));
- memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
@@ -55,9 +44,9 @@ qedf_dbg_warn(struct qedf_dbg_ctx *qedf, const char *func, u32 line,
if (likely(qedf) && likely(qedf->pdev))
pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)),
- nfunc, line, qedf->host_no, &vaf);
+ func, line, qedf->host_no, &vaf);
else
- pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+ pr_warn("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf);
ret:
va_end(va);
@@ -69,10 +58,6 @@ qedf_dbg_notice(struct qedf_dbg_ctx *qedf, const char *func, u32 line,
{
va_list va;
struct va_format vaf;
- char nfunc[32];
-
- memset(nfunc, 0, sizeof(nfunc));
- memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
@@ -84,10 +69,10 @@ qedf_dbg_notice(struct qedf_dbg_ctx *qedf, const char *func, u32 line,
if (likely(qedf) && likely(qedf->pdev))
pr_notice("[%s]:[%s:%d]:%d: %pV",
- dev_name(&(qedf->pdev->dev)), nfunc, line,
+ dev_name(&(qedf->pdev->dev)), func, line,
qedf->host_no, &vaf);
else
- pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+ pr_notice("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf);
ret:
va_end(va);
@@ -99,10 +84,6 @@ qedf_dbg_info(struct qedf_dbg_ctx *qedf, const char *func, u32 line,
{
va_list va;
struct va_format vaf;
- char nfunc[32];
-
- memset(nfunc, 0, sizeof(nfunc));
- memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
@@ -114,9 +95,9 @@ qedf_dbg_info(struct qedf_dbg_ctx *qedf, const char *func, u32 line,
if (likely(qedf) && likely(qedf->pdev))
pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&(qedf->pdev->dev)),
- nfunc, line, qedf->host_no, &vaf);
+ func, line, qedf->host_no, &vaf);
else
- pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+ pr_info("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf);
ret:
va_end(va);
diff --git a/drivers/scsi/qedf/qedf_dbg.h b/drivers/scsi/qedf/qedf_dbg.h
index dd0109653aa3..d979f095aeda 100644
--- a/drivers/scsi/qedf/qedf_dbg.h
+++ b/drivers/scsi/qedf/qedf_dbg.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _QEDF_DBG_H_
#define _QEDF_DBG_H_
diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c
index a32d8ee4666e..d905a307302d 100644
--- a/drivers/scsi/qedf/qedf_debugfs.c
+++ b/drivers/scsi/qedf/qedf_debugfs.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 QLogic Corporation
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifdef CONFIG_DEBUG_FS
@@ -293,6 +290,33 @@ qedf_dbg_io_trace_open(struct inode *inode, struct file *file)
return single_open(file, qedf_io_trace_show, qedf);
}
+/* Based on fip_state enum from libfcoe.h */
+static char *fip_state_names[] = {
+ "FIP_ST_DISABLED",
+ "FIP_ST_LINK_WAIT",
+ "FIP_ST_AUTO",
+ "FIP_ST_NON_FIP",
+ "FIP_ST_ENABLED",
+ "FIP_ST_VNMP_START",
+ "FIP_ST_VNMP_PROBE1",
+ "FIP_ST_VNMP_PROBE2",
+ "FIP_ST_VNMP_CLAIM",
+ "FIP_ST_VNMP_UP",
+};
+
+/* Based on fc_rport_state enum from libfc.h */
+static char *fc_rport_state_names[] = {
+ "RPORT_ST_INIT",
+ "RPORT_ST_FLOGI",
+ "RPORT_ST_PLOGI_WAIT",
+ "RPORT_ST_PLOGI",
+ "RPORT_ST_PRLI",
+ "RPORT_ST_RTV",
+ "RPORT_ST_READY",
+ "RPORT_ST_ADISC",
+ "RPORT_ST_DELETE",
+};
+
static int
qedf_driver_stats_show(struct seq_file *s, void *unused)
{
@@ -300,10 +324,28 @@ qedf_driver_stats_show(struct seq_file *s, void *unused)
struct qedf_rport *fcport;
struct fc_rport_priv *rdata;
+ seq_printf(s, "Host WWNN/WWPN: %016llx/%016llx\n",
+ qedf->wwnn, qedf->wwpn);
+ seq_printf(s, "Host NPortID: %06x\n", qedf->lport->port_id);
+ seq_printf(s, "Link State: %s\n", atomic_read(&qedf->link_state) ?
+ "Up" : "Down");
+ seq_printf(s, "Logical Link State: %s\n", qedf->lport->link_up ?
+ "Up" : "Down");
+ seq_printf(s, "FIP state: %s\n", fip_state_names[qedf->ctlr.state]);
+ seq_printf(s, "FIP VLAN ID: %d\n", qedf->vlan_id & 0xfff);
+ seq_printf(s, "FIP 802.1Q Priority: %d\n", qedf->prio);
+ if (qedf->ctlr.sel_fcf) {
+ seq_printf(s, "FCF WWPN: %016llx\n",
+ qedf->ctlr.sel_fcf->switch_name);
+ seq_printf(s, "FCF MAC: %pM\n", qedf->ctlr.sel_fcf->fcf_mac);
+ } else {
+ seq_puts(s, "FCF not selected\n");
+ }
+
+ seq_puts(s, "\nSGE stats:\n\n");
seq_printf(s, "cmg_mgr free io_reqs: %d\n",
atomic_read(&qedf->cmd_mgr->free_list_cnt));
seq_printf(s, "slow SGEs: %d\n", qedf->slow_sge_ios);
- seq_printf(s, "single SGEs: %d\n", qedf->single_sge_ios);
seq_printf(s, "fast SGEs: %d\n\n", qedf->fast_sge_ios);
seq_puts(s, "Offloaded ports:\n\n");
@@ -313,9 +355,12 @@ qedf_driver_stats_show(struct seq_file *s, void *unused)
rdata = fcport->rdata;
if (rdata == NULL)
continue;
- seq_printf(s, "%06x: free_sqes: %d, num_active_ios: %d\n",
- rdata->ids.port_id, atomic_read(&fcport->free_sqes),
- atomic_read(&fcport->num_active_ios));
+ seq_printf(s, "%016llx/%016llx/%06x: state=%s, free_sqes=%d, num_active_ios=%d\n",
+ rdata->rport->node_name, rdata->rport->port_name,
+ rdata->ids.port_id,
+ fc_rport_state_names[rdata->rp_state],
+ atomic_read(&fcport->free_sqes),
+ atomic_read(&fcport->num_active_ios));
}
rcu_read_unlock();
@@ -361,7 +406,6 @@ qedf_dbg_clear_stats_cmd_write(struct file *filp,
/* Clear stat counters exposed by 'stats' node */
qedf->slow_sge_ios = 0;
- qedf->single_sge_ios = 0;
qedf->fast_sge_ios = 0;
return count;
diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c
index 04f0c4d2e256..5996f68fbf2b 100644
--- a/drivers/scsi/qedf/qedf_els.c
+++ b/drivers/scsi/qedf/qedf_els.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include "qedf.h"
@@ -23,8 +20,6 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op,
int rc = 0;
uint32_t did, sid;
uint16_t xid;
- uint32_t start_time = jiffies / HZ;
- uint32_t current_time;
struct fcoe_wqe *sqe;
unsigned long flags;
u16 sqe_idx;
@@ -59,18 +54,12 @@ static int qedf_initiate_els(struct qedf_rport *fcport, unsigned int op,
goto els_err;
}
-retry_els:
els_req = qedf_alloc_cmd(fcport, QEDF_ELS);
if (!els_req) {
- current_time = jiffies / HZ;
- if ((current_time - start_time) > 10) {
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS,
- "els: Failed els 0x%x\n", op);
- rc = -ENOMEM;
- goto els_err;
- }
- mdelay(20 * USEC_PER_MSEC);
- goto retry_els;
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_ELS,
+ "Failed to alloc ELS request 0x%x\n", op);
+ rc = -ENOMEM;
+ goto els_err;
}
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "initiate_els els_req = "
@@ -143,6 +132,8 @@ retry_els:
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Ringing doorbell for ELS "
"req\n");
qedf_ring_doorbell(fcport);
+ set_bit(QEDF_CMD_OUTSTANDING, &els_req->flags);
+
spin_unlock_irqrestore(&fcport->rport_lock, flags);
els_err:
return rc;
@@ -151,21 +142,16 @@ els_err:
void qedf_process_els_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
struct qedf_ioreq *els_req)
{
- struct fcoe_task_context *task_ctx;
- struct scsi_cmnd *sc_cmd;
- uint16_t xid;
struct fcoe_cqe_midpath_info *mp_info;
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Entered with xid = 0x%x"
" cmd_type = %d.\n", els_req->xid, els_req->cmd_type);
+ clear_bit(QEDF_CMD_OUTSTANDING, &els_req->flags);
+
/* Kill the ELS timer */
cancel_delayed_work(&els_req->timeout_work);
- xid = els_req->xid;
- task_ctx = qedf_get_task_mem(&qedf->tasks, xid);
- sc_cmd = els_req->sc_cmd;
-
/* Get ELS response length from CQE */
mp_info = &cqe->cqe_info.midpath_info;
els_req->mp_req.resp_len = mp_info->data_placement_size;
@@ -205,8 +191,12 @@ static void qedf_rrq_compl(struct qedf_els_cb_arg *cb_arg)
" orig xid = 0x%x, rrq_xid = 0x%x, refcount=%d\n",
orig_io_req, orig_io_req->xid, rrq_req->xid, refcount);
- /* This should return the aborted io_req to the command pool */
- if (orig_io_req)
+ /*
+ * This should return the aborted io_req to the command pool. Note that
+ * we need to check the refcound in case the original request was
+ * flushed but we get a completion on this xid.
+ */
+ if (orig_io_req && refcount > 0)
kref_put(&orig_io_req->refcount, qedf_release_cmd);
out_free:
@@ -233,6 +223,7 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req)
uint32_t sid;
uint32_t r_a_tov;
int rc;
+ int refcount;
if (!aborted_io_req) {
QEDF_ERR(NULL, "abort_io_req is NULL.\n");
@@ -241,6 +232,15 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req)
fcport = aborted_io_req->fcport;
+ if (!fcport) {
+ refcount = kref_read(&aborted_io_req->refcount);
+ QEDF_ERR(NULL,
+ "RRQ work was queued prior to a flush xid=0x%x, refcount=%d.\n",
+ aborted_io_req->xid, refcount);
+ kref_put(&aborted_io_req->refcount, qedf_release_cmd);
+ return -EINVAL;
+ }
+
/* Check that fcport is still offloaded */
if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
QEDF_ERR(NULL, "fcport is no longer offloaded.\n");
@@ -253,6 +253,19 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req)
}
qedf = fcport->qedf;
+
+ /*
+ * Sanity check that we can send a RRQ to make sure that refcount isn't
+ * 0
+ */
+ refcount = kref_read(&aborted_io_req->refcount);
+ if (refcount != 1) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_ELS,
+ "refcount for xid=%x io_req=%p refcount=%d is not 1.\n",
+ aborted_io_req->xid, aborted_io_req, refcount);
+ return -EINVAL;
+ }
+
lport = qedf->lport;
sid = fcport->sid;
r_a_tov = lport->r_a_tov;
@@ -335,32 +348,49 @@ void qedf_restart_rport(struct qedf_rport *fcport)
struct fc_lport *lport;
struct fc_rport_priv *rdata;
u32 port_id;
+ unsigned long flags;
if (!fcport)
return;
+ spin_lock_irqsave(&fcport->rport_lock, flags);
if (test_bit(QEDF_RPORT_IN_RESET, &fcport->flags) ||
!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) ||
test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
QEDF_ERR(&(fcport->qedf->dbg_ctx), "fcport %p already in reset or not offloaded.\n",
fcport);
+ spin_unlock_irqrestore(&fcport->rport_lock, flags);
return;
}
/* Set that we are now in reset */
set_bit(QEDF_RPORT_IN_RESET, &fcport->flags);
+ spin_unlock_irqrestore(&fcport->rport_lock, flags);
rdata = fcport->rdata;
- if (rdata) {
+ if (rdata && !kref_get_unless_zero(&rdata->kref)) {
+ fcport->rdata = NULL;
+ rdata = NULL;
+ }
+
+ if (rdata && rdata->rp_state == RPORT_ST_READY) {
lport = fcport->qedf->lport;
port_id = rdata->ids.port_id;
QEDF_ERR(&(fcport->qedf->dbg_ctx),
"LOGO port_id=%x.\n", port_id);
fc_rport_logoff(rdata);
+ kref_put(&rdata->kref, fc_rport_destroy);
+ mutex_lock(&lport->disc.disc_mutex);
/* Recreate the rport and log back in */
rdata = fc_rport_create(lport, port_id);
- if (rdata)
+ if (rdata) {
+ mutex_unlock(&lport->disc.disc_mutex);
fc_rport_login(rdata);
+ fcport->rdata = rdata;
+ } else {
+ mutex_unlock(&lport->disc.disc_mutex);
+ fcport->rdata = NULL;
+ }
}
clear_bit(QEDF_RPORT_IN_RESET, &fcport->flags);
}
@@ -569,7 +599,7 @@ static int qedf_send_srr(struct qedf_ioreq *orig_io_req, u32 offset, u8 r_ctl)
struct qedf_rport *fcport;
struct fc_lport *lport;
struct qedf_els_cb_arg *cb_arg = NULL;
- u32 sid, r_a_tov;
+ u32 r_a_tov;
int rc;
if (!orig_io_req) {
@@ -595,7 +625,6 @@ static int qedf_send_srr(struct qedf_ioreq *orig_io_req, u32 offset, u8 r_ctl)
qedf = fcport->qedf;
lport = qedf->lport;
- sid = fcport->sid;
r_a_tov = lport->r_a_tov;
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS, "Sending SRR orig_io=%p, "
diff --git a/drivers/scsi/qedf/qedf_fip.c b/drivers/scsi/qedf/qedf_fip.c
index 3fd3af799b3d..362d2bed72fb 100644
--- a/drivers/scsi/qedf/qedf_fip.c
+++ b/drivers/scsi/qedf/qedf_fip.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
@@ -19,17 +16,16 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf)
{
struct sk_buff *skb;
char *eth_fr;
- int fr_len;
struct fip_vlan *vlan;
#define MY_FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
static u8 my_fcoe_all_fcfs[ETH_ALEN] = MY_FIP_ALL_FCF_MACS;
unsigned long flags = 0;
+ int rc = -1;
skb = dev_alloc_skb(sizeof(struct fip_vlan));
if (!skb)
return;
- fr_len = sizeof(*vlan);
eth_fr = (char *)skb->data;
vlan = (struct fip_vlan *)eth_fr;
@@ -68,7 +64,13 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf)
}
set_bit(QED_LL2_XMIT_FLAGS_FIP_DISCOVERY, &flags);
- qed_ops->ll2->start_xmit(qedf->cdev, skb, flags);
+ rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, flags);
+ if (rc) {
+ QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc);
+ kfree_skb(skb);
+ return;
+ }
+
}
static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf,
@@ -95,6 +97,12 @@ static void qedf_fcoe_process_vlan_resp(struct qedf_ctx *qedf,
rlen -= dlen;
}
+ if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Dropping VLAN response as link is down.\n");
+ return;
+ }
+
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "VLAN response, "
"vid=0x%x.\n", vid);
@@ -114,6 +122,7 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
struct fip_header *fiph;
u16 op, vlan_tci = 0;
u8 sub;
+ int rc = -1;
if (!test_bit(QEDF_LL2_STARTED, &qedf->flags)) {
QEDF_WARN(&(qedf->dbg_ctx), "LL2 not started\n");
@@ -142,9 +151,16 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb->len, false);
- qed_ops->ll2->start_xmit(qedf->cdev, skb, 0);
+ rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0);
+ if (rc) {
+ QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc);
+ kfree_skb(skb);
+ return;
+ }
}
+static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;
+
/* Process incoming FIP frames. */
void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
{
@@ -157,20 +173,37 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
size_t rlen, dlen;
u16 op;
u8 sub;
- bool do_reset = false;
+ bool fcf_valid = false;
+ /* Default is to handle CVL regardless of fabric id descriptor */
+ bool fabric_id_valid = true;
+ bool fc_wwpn_valid = false;
+ u64 switch_name;
+ u16 vlan = 0;
eth_hdr = (struct ethhdr *)skb_mac_header(skb);
fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2);
op = ntohs(fiph->fip_op);
sub = fiph->fip_subcode;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame received: "
- "skb=%p fiph=%p source=%pM op=%x sub=%x", skb, fiph,
- eth_hdr->h_source, op, sub);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
+ "FIP frame received: skb=%p fiph=%p source=%pM destn=%pM op=%x sub=%x vlan=%04x",
+ skb, fiph, eth_hdr->h_source, eth_hdr->h_dest, op,
+ sub, vlan);
if (qedf_dump_frames)
print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb->len, false);
+ if (!ether_addr_equal(eth_hdr->h_dest, qedf->mac) &&
+ !ether_addr_equal(eth_hdr->h_dest, fcoe_all_enode) &&
+ !ether_addr_equal(eth_hdr->h_dest, qedf->data_src_addr)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
+ "Dropping FIP type 0x%x pkt due to destination MAC mismatch dest_mac=%pM ctlr.dest_addr=%pM data_src_addr=%pM.\n",
+ op, eth_hdr->h_dest, qedf->mac,
+ qedf->data_src_addr);
+ kfree_skb(skb);
+ return;
+ }
+
/* Handle FIP VLAN resp in the driver */
if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) {
qedf_fcoe_process_vlan_resp(qedf, skb);
@@ -199,25 +232,36 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
switch (desc->fip_dtype) {
case FIP_DT_MAC:
mp = (struct fip_mac_desc *)desc;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
- "fd_mac=%pM\n", mp->fd_mac);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Switch fd_mac=%pM.\n", mp->fd_mac);
if (ether_addr_equal(mp->fd_mac,
qedf->ctlr.sel_fcf->fcf_mac))
- do_reset = true;
+ fcf_valid = true;
break;
case FIP_DT_NAME:
wp = (struct fip_wwn_desc *)desc;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
- "fc_wwpn=%016llx.\n",
- get_unaligned_be64(&wp->fd_wwn));
+ switch_name = get_unaligned_be64(&wp->fd_wwn);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Switch fd_wwn=%016llx fcf_switch_name=%016llx.\n",
+ switch_name,
+ qedf->ctlr.sel_fcf->switch_name);
+ if (switch_name ==
+ qedf->ctlr.sel_fcf->switch_name)
+ fc_wwpn_valid = true;
break;
case FIP_DT_VN_ID:
vp = (struct fip_vn_desc *)desc;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
- "fd_fc_id=%x.\n", ntoh24(vp->fd_fc_id));
- if (ntoh24(vp->fd_fc_id) ==
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "vx_port fd_fc_id=%x fd_mac=%pM.\n",
+ ntoh24(vp->fd_fc_id), vp->fd_mac);
+ /* Check vx_port fabric ID */
+ if (ntoh24(vp->fd_fc_id) !=
qedf->lport->port_id)
- do_reset = true;
+ fabric_id_valid = false;
+ /* Check vx_port MAC */
+ if (!ether_addr_equal(vp->fd_mac,
+ qedf->data_src_addr))
+ fabric_id_valid = false;
break;
default:
/* Ignore anything else */
@@ -227,13 +271,11 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
rlen -= dlen;
}
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
- "do_reset=%d.\n", do_reset);
- if (do_reset) {
- fcoe_ctlr_link_down(&qedf->ctlr);
- qedf_wait_for_upload(qedf);
- fcoe_ctlr_link_up(&qedf->ctlr);
- }
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "fcf_valid=%d fabric_id_valid=%d fc_wwpn_valid=%d.\n",
+ fcf_valid, fabric_id_valid, fc_wwpn_valid);
+ if (fcf_valid && fabric_id_valid && fc_wwpn_valid)
+ qedf_ctx_soft_reset(qedf->lport);
kfree_skb(skb);
} else {
/* Everything else is handled by libfcoe */
diff --git a/drivers/scsi/qedf/qedf_hsi.h b/drivers/scsi/qedf/qedf_hsi.h
index f6f634e48d69..ecd5cb53b750 100644
--- a/drivers/scsi/qedf/qedf_hsi.h
+++ b/drivers/scsi/qedf/qedf_hsi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef __QEDF_HSI__
#define __QEDF_HSI__
diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c
index 6ca583bdde23..d881e822f92c 100644
--- a/drivers/scsi/qedf/qedf_io.c
+++ b/drivers/scsi/qedf/qedf_io.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
@@ -43,8 +40,9 @@ static void qedf_cmd_timeout(struct work_struct *work)
switch (io_req->cmd_type) {
case QEDF_ABTS:
if (qedf == NULL) {
- QEDF_INFO(NULL, QEDF_LOG_IO, "qedf is NULL for xid=0x%x.\n",
- io_req->xid);
+ QEDF_INFO(NULL, QEDF_LOG_IO,
+ "qedf is NULL for ABTS xid=0x%x.\n",
+ io_req->xid);
return;
}
@@ -61,6 +59,9 @@ static void qedf_cmd_timeout(struct work_struct *work)
*/
kref_put(&io_req->refcount, qedf_release_cmd);
+ /* Clear in abort bit now that we're done with the command */
+ clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags);
+
/*
* Now that the original I/O and the ABTS are complete see
* if we need to reconnect to the target.
@@ -68,6 +69,15 @@ static void qedf_cmd_timeout(struct work_struct *work)
qedf_restart_rport(fcport);
break;
case QEDF_ELS:
+ if (!qedf) {
+ QEDF_INFO(NULL, QEDF_LOG_IO,
+ "qedf is NULL for ELS xid=0x%x.\n",
+ io_req->xid);
+ return;
+ }
+ /* ELS request no longer outstanding since it timed out */
+ clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
+
kref_get(&io_req->refcount);
/*
* Don't attempt to clean an ELS timeout as any subseqeunt
@@ -103,7 +113,7 @@ void qedf_cmd_mgr_free(struct qedf_cmd_mgr *cmgr)
struct io_bdt *bdt_info;
struct qedf_ctx *qedf = cmgr->qedf;
size_t bd_tbl_sz;
- u16 min_xid = QEDF_MIN_XID;
+ u16 min_xid = 0;
u16 max_xid = (FCOE_PARAMS_NUM_TASKS - 1);
int num_ios;
int i;
@@ -157,6 +167,7 @@ static void qedf_handle_rrq(struct work_struct *work)
struct qedf_ioreq *io_req =
container_of(work, struct qedf_ioreq, rrq_work.work);
+ atomic_set(&io_req->state, QEDFC_CMD_ST_RRQ_ACTIVE);
qedf_send_rrq(io_req);
}
@@ -169,7 +180,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf)
u16 xid;
int i;
int num_ios;
- u16 min_xid = QEDF_MIN_XID;
+ u16 min_xid = 0;
u16 max_xid = (FCOE_PARAMS_NUM_TASKS - 1);
/* Make sure num_queues is already set before calling this function */
@@ -201,7 +212,7 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf)
/*
* Initialize I/O request fields.
*/
- xid = QEDF_MIN_XID;
+ xid = 0;
for (i = 0; i < num_ios; i++) {
io_req = &cmgr->cmds[i];
@@ -329,7 +340,7 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type)
cmd_mgr->idx = 0;
/* Check to make sure command was previously freed */
- if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags))
+ if (!io_req->alloc)
break;
}
@@ -338,7 +349,14 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type)
goto out_failed;
}
- set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
+ if (test_bit(QEDF_CMD_DIRTY, &io_req->flags))
+ QEDF_ERR(&qedf->dbg_ctx,
+ "io_req found to be dirty ox_id = 0x%x.\n",
+ io_req->xid);
+
+ /* Clear any flags now that we've reallocated the xid */
+ io_req->flags = 0;
+ io_req->alloc = 1;
spin_unlock_irqrestore(&cmd_mgr->lock, flags);
atomic_inc(&fcport->num_active_ios);
@@ -349,8 +367,13 @@ struct qedf_ioreq *qedf_alloc_cmd(struct qedf_rport *fcport, u8 cmd_type)
io_req->cmd_mgr = cmd_mgr;
io_req->fcport = fcport;
+ /* Clear any stale sc_cmd back pointer */
+ io_req->sc_cmd = NULL;
+ io_req->lun = -1;
+
/* Hold the io_req against deletion */
- kref_init(&io_req->refcount);
+ kref_init(&io_req->refcount); /* ID: 001 */
+ atomic_set(&io_req->state, QEDFC_CMD_ST_IO_ACTIVE);
/* Bind io_bdt for this io_req */
/* Have a static link between io_req and io_bdt_pool */
@@ -412,6 +435,10 @@ void qedf_release_cmd(struct kref *ref)
container_of(ref, struct qedf_ioreq, refcount);
struct qedf_cmd_mgr *cmd_mgr = io_req->cmd_mgr;
struct qedf_rport *fcport = io_req->fcport;
+ unsigned long flags;
+
+ if (io_req->cmd_type == QEDF_SCSI_CMD)
+ WARN_ON(io_req->sc_cmd);
if (io_req->cmd_type == QEDF_ELS ||
io_req->cmd_type == QEDF_TASK_MGMT_CMD)
@@ -419,36 +446,20 @@ void qedf_release_cmd(struct kref *ref)
atomic_inc(&cmd_mgr->free_list_cnt);
atomic_dec(&fcport->num_active_ios);
+ atomic_set(&io_req->state, QEDF_CMD_ST_INACTIVE);
if (atomic_read(&fcport->num_active_ios) < 0)
QEDF_WARN(&(fcport->qedf->dbg_ctx), "active_ios < 0.\n");
/* Increment task retry identifier now that the request is released */
io_req->task_retry_identifier++;
+ io_req->fcport = NULL;
- clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
-}
-
-static int qedf_split_bd(struct qedf_ioreq *io_req, u64 addr, int sg_len,
- int bd_index)
-{
- struct scsi_sge *bd = io_req->bd_tbl->bd_tbl;
- int frag_size, sg_frags;
-
- sg_frags = 0;
- while (sg_len) {
- if (sg_len > QEDF_BD_SPLIT_SZ)
- frag_size = QEDF_BD_SPLIT_SZ;
- else
- frag_size = sg_len;
- bd[bd_index + sg_frags].sge_addr.lo = U64_LO(addr);
- bd[bd_index + sg_frags].sge_addr.hi = U64_HI(addr);
- bd[bd_index + sg_frags].sge_len = (uint16_t)frag_size;
-
- addr += (u64)frag_size;
- sg_frags++;
- sg_len -= frag_size;
- }
- return sg_frags;
+ clear_bit(QEDF_CMD_DIRTY, &io_req->flags);
+ io_req->cpu = 0;
+ spin_lock_irqsave(&cmd_mgr->lock, flags);
+ io_req->fcport = NULL;
+ io_req->alloc = 0;
+ spin_unlock_irqrestore(&cmd_mgr->lock, flags);
}
static int qedf_map_sg(struct qedf_ioreq *io_req)
@@ -462,75 +473,45 @@ static int qedf_map_sg(struct qedf_ioreq *io_req)
int byte_count = 0;
int sg_count = 0;
int bd_count = 0;
- int sg_frags;
- unsigned int sg_len;
+ u32 sg_len;
u64 addr, end_addr;
- int i;
+ int i = 0;
sg_count = dma_map_sg(&qedf->pdev->dev, scsi_sglist(sc),
scsi_sg_count(sc), sc->sc_data_direction);
-
sg = scsi_sglist(sc);
- /*
- * New condition to send single SGE as cached-SGL with length less
- * than 64k.
- */
- if ((sg_count == 1) && (sg_dma_len(sg) <=
- QEDF_MAX_SGLEN_FOR_CACHESGL)) {
- sg_len = sg_dma_len(sg);
- addr = (u64)sg_dma_address(sg);
-
- bd[bd_count].sge_addr.lo = (addr & 0xffffffff);
- bd[bd_count].sge_addr.hi = (addr >> 32);
- bd[bd_count].sge_len = (u16)sg_len;
+ io_req->sge_type = QEDF_IOREQ_UNKNOWN_SGE;
- return ++bd_count;
- }
+ if (sg_count <= 8 || io_req->io_req_flags == QEDF_READ)
+ io_req->sge_type = QEDF_IOREQ_FAST_SGE;
scsi_for_each_sg(sc, sg, sg_count, i) {
- sg_len = sg_dma_len(sg);
+ sg_len = (u32)sg_dma_len(sg);
addr = (u64)sg_dma_address(sg);
end_addr = (u64)(addr + sg_len);
/*
- * First s/g element in the list so check if the end_addr
- * is paged aligned. Also check to make sure the length is
- * at least page size.
- */
- if ((i == 0) && (sg_count > 1) &&
- ((end_addr % QEDF_PAGE_SIZE) ||
- sg_len < QEDF_PAGE_SIZE))
- io_req->use_slowpath = true;
- /*
- * Last s/g element so check if the start address is paged
- * aligned.
- */
- else if ((i == (sg_count - 1)) && (sg_count > 1) &&
- (addr % QEDF_PAGE_SIZE))
- io_req->use_slowpath = true;
- /*
* Intermediate s/g element so check if start and end address
- * is page aligned.
+ * is page aligned. Only required for writes and only if the
+ * number of scatter/gather elements is 8 or more.
*/
- else if ((i != 0) && (i != (sg_count - 1)) &&
- ((addr % QEDF_PAGE_SIZE) || (end_addr % QEDF_PAGE_SIZE)))
- io_req->use_slowpath = true;
+ if (io_req->sge_type == QEDF_IOREQ_UNKNOWN_SGE && (i) &&
+ (i != (sg_count - 1)) && sg_len < QEDF_PAGE_SIZE)
+ io_req->sge_type = QEDF_IOREQ_SLOW_SGE;
- if (sg_len > QEDF_MAX_BD_LEN) {
- sg_frags = qedf_split_bd(io_req, addr, sg_len,
- bd_count);
- } else {
- sg_frags = 1;
- bd[bd_count].sge_addr.lo = U64_LO(addr);
- bd[bd_count].sge_addr.hi = U64_HI(addr);
- bd[bd_count].sge_len = (uint16_t)sg_len;
- }
+ bd[bd_count].sge_addr.lo = cpu_to_le32(U64_LO(addr));
+ bd[bd_count].sge_addr.hi = cpu_to_le32(U64_HI(addr));
+ bd[bd_count].sge_len = cpu_to_le32(sg_len);
- bd_count += sg_frags;
+ bd_count++;
byte_count += sg_len;
}
+ /* To catch a case where FAST and SLOW nothing is set, set FAST */
+ if (io_req->sge_type == QEDF_IOREQ_UNKNOWN_SGE)
+ io_req->sge_type = QEDF_IOREQ_FAST_SGE;
+
if (byte_count != scsi_bufflen(sc))
QEDF_ERR(&(qedf->dbg_ctx), "byte_count = %d != "
"scsi_bufflen = %d, task_id = 0x%x.\n", byte_count,
@@ -655,8 +636,10 @@ static void qedf_init_task(struct qedf_rport *fcport, struct fc_lport *lport,
io_req->sgl_task_params->num_sges = bd_count;
io_req->sgl_task_params->total_buffer_size =
scsi_bufflen(io_req->sc_cmd);
- io_req->sgl_task_params->small_mid_sge =
- io_req->use_slowpath;
+ if (io_req->sge_type == QEDF_IOREQ_SLOW_SGE)
+ io_req->sgl_task_params->small_mid_sge = 1;
+ else
+ io_req->sgl_task_params->small_mid_sge = 0;
}
/* Fill in physical address of sense buffer */
@@ -679,16 +662,10 @@ static void qedf_init_task(struct qedf_rport *fcport, struct fc_lport *lport,
io_req->task_retry_identifier, fcp_cmnd);
/* Increment SGL type counters */
- if (bd_count == 1) {
- qedf->single_sge_ios++;
- io_req->sge_type = QEDF_IOREQ_SINGLE_SGE;
- } else if (io_req->use_slowpath) {
+ if (io_req->sge_type == QEDF_IOREQ_SLOW_SGE)
qedf->slow_sge_ios++;
- io_req->sge_type = QEDF_IOREQ_SLOW_SGE;
- } else {
+ else
qedf->fast_sge_ios++;
- io_req->sge_type = QEDF_IOREQ_FAST_SGE;
- }
}
void qedf_init_mp_task(struct qedf_ioreq *io_req,
@@ -770,9 +747,6 @@ void qedf_init_mp_task(struct qedf_ioreq *io_req,
&task_fc_hdr,
&tx_sgl_task_params,
&rx_sgl_task_params, 0);
-
- /* Midpath requests always consume 1 SGE */
- qedf->single_sge_ios++;
}
/* Presumed that fcport->rport_lock is held */
@@ -804,10 +778,18 @@ void qedf_ring_doorbell(struct qedf_rport *fcport)
FCOE_DB_DATA_AGG_VAL_SEL_SHIFT;
dbell.sq_prod = fcport->fw_sq_prod_idx;
+ /* wmb makes sure that the BDs data is updated before updating the
+ * producer, otherwise FW may read old data from the BDs.
+ */
+ wmb();
+ barrier();
writel(*(u32 *)&dbell, fcport->p_doorbell);
- /* Make sure SQ index is updated so f/w prcesses requests in order */
+ /*
+ * Fence required to flush the write combined buffer, since another
+ * CPU may write to the same doorbell address and data may be lost
+ * due to relaxed order nature of write combined bar.
+ */
wmb();
- mmiowb();
}
static void qedf_trace_io(struct qedf_rport *fcport, struct qedf_ioreq *io_req,
@@ -872,7 +854,7 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req)
/* Initialize rest of io_req fileds */
io_req->data_xfer_len = scsi_bufflen(sc_cmd);
sc_cmd->SCp.ptr = (char *)io_req;
- io_req->use_slowpath = false; /* Assume fast SGL by default */
+ io_req->sge_type = QEDF_IOREQ_FAST_SGE; /* Assume fast SGL by default */
/* Record which cpu this request is associated with */
io_req->cpu = smp_processor_id();
@@ -895,15 +877,24 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req)
/* Build buffer descriptor list for firmware from sg list */
if (qedf_build_bd_list_from_sg(io_req)) {
QEDF_ERR(&(qedf->dbg_ctx), "BD list creation failed.\n");
+ /* Release cmd will release io_req, but sc_cmd is assigned */
+ io_req->sc_cmd = NULL;
kref_put(&io_req->refcount, qedf_release_cmd);
return -EAGAIN;
}
- if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
+ if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) ||
+ test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
QEDF_ERR(&(qedf->dbg_ctx), "Session not offloaded yet.\n");
+ /* Release cmd will release io_req, but sc_cmd is assigned */
+ io_req->sc_cmd = NULL;
kref_put(&io_req->refcount, qedf_release_cmd);
+ return -EINVAL;
}
+ /* Record LUN number for later use if we neeed them */
+ io_req->lun = (int)sc_cmd->device->lun;
+
/* Obtain free SQE */
sqe_idx = qedf_get_sqe_idx(fcport);
sqe = &fcport->sq[sqe_idx];
@@ -914,6 +905,8 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req)
if (!task_ctx) {
QEDF_WARN(&(qedf->dbg_ctx), "task_ctx is NULL, xid=%d.\n",
xid);
+ /* Release cmd will release io_req, but sc_cmd is assigned */
+ io_req->sc_cmd = NULL;
kref_put(&io_req->refcount, qedf_release_cmd);
return -EINVAL;
}
@@ -923,6 +916,9 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req)
/* Ring doorbell */
qedf_ring_doorbell(fcport);
+ /* Set that command is with the firmware now */
+ set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
+
if (qedf_io_tracing && io_req->sc_cmd)
qedf_trace_io(fcport, io_req, QEDF_IO_TRACE_REQ);
@@ -941,7 +937,17 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd)
int rc = 0;
int rval;
unsigned long flags = 0;
-
+ int num_sgs = 0;
+
+ num_sgs = scsi_sg_count(sc_cmd);
+ if (scsi_sg_count(sc_cmd) > QEDF_MAX_BDS_PER_CMD) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Number of SG elements %d exceeds what hardware limitation of %d.\n",
+ num_sgs, QEDF_MAX_BDS_PER_CMD);
+ sc_cmd->result = DID_ERROR;
+ sc_cmd->scsi_done(sc_cmd);
+ return 0;
+ }
if (test_bit(QEDF_UNLOADING, &qedf->flags) ||
test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) {
@@ -981,7 +987,8 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd)
/* rport and tgt are allocated together, so tgt should be non-NULL */
fcport = (struct qedf_rport *)&rp[1];
- if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
+ if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) ||
+ test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
/*
* Session is not offloaded yet. Let SCSI-ml retry
* the command.
@@ -989,12 +996,16 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd)
rc = SCSI_MLQUEUE_TARGET_BUSY;
goto exit_qcmd;
}
+
+ atomic_inc(&fcport->ios_to_queue);
+
if (fcport->retry_delay_timestamp) {
if (time_after(jiffies, fcport->retry_delay_timestamp)) {
fcport->retry_delay_timestamp = 0;
} else {
/* If retry_delay timer is active, flow off the ML */
rc = SCSI_MLQUEUE_TARGET_BUSY;
+ atomic_dec(&fcport->ios_to_queue);
goto exit_qcmd;
}
}
@@ -1002,6 +1013,7 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd)
io_req = qedf_alloc_cmd(fcport, QEDF_SCSI_CMD);
if (!io_req) {
rc = SCSI_MLQUEUE_HOST_BUSY;
+ atomic_dec(&fcport->ios_to_queue);
goto exit_qcmd;
}
@@ -1016,6 +1028,7 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd)
rc = SCSI_MLQUEUE_HOST_BUSY;
}
spin_unlock_irqrestore(&fcport->rport_lock, flags);
+ atomic_dec(&fcport->ios_to_queue);
exit_qcmd:
return rc;
@@ -1092,7 +1105,7 @@ static void qedf_unmap_sg_list(struct qedf_ctx *qedf, struct qedf_ioreq *io_req)
void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
struct qedf_ioreq *io_req)
{
- u16 xid, rval;
+ u16 xid;
struct e4_fcoe_task_context *task_ctx;
struct scsi_cmnd *sc_cmd;
struct fcoe_cqe_rsp_info *fcp_rsp;
@@ -1106,6 +1119,15 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
if (!cqe)
return;
+ if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) ||
+ test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) ||
+ test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "io_req xid=0x%x already in cleanup or abort processing or already completed.\n",
+ io_req->xid);
+ return;
+ }
+
xid = io_req->xid;
task_ctx = qedf_get_task_mem(&qedf->tasks, xid);
sc_cmd = io_req->sc_cmd;
@@ -1122,6 +1144,12 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
return;
}
+ if (!sc_cmd->device) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Device for sc_cmd %p is NULL.\n", sc_cmd);
+ return;
+ }
+
if (!sc_cmd->request) {
QEDF_WARN(&(qedf->dbg_ctx), "sc_cmd->request is NULL, "
"sc_cmd=%p.\n", sc_cmd);
@@ -1136,6 +1164,19 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
fcport = io_req->fcport;
+ /*
+ * When flush is active, let the cmds be completed from the cleanup
+ * context
+ */
+ if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags) ||
+ (test_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags) &&
+ sc_cmd->device->lun == (u64)fcport->lun_reset_lun)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Dropping good completion xid=0x%x as fcport is flushing",
+ io_req->xid);
+ return;
+ }
+
qedf_parse_fcp_rsp(io_req, fcp_rsp);
qedf_unmap_sg_list(qedf, io_req);
@@ -1153,25 +1194,18 @@ void qedf_scsi_completion(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
fw_residual_flag = GET_FIELD(cqe->cqe_info.rsp_info.fw_error_flags,
FCOE_CQE_RSP_INFO_FW_UNDERRUN);
if (fw_residual_flag) {
- QEDF_ERR(&(qedf->dbg_ctx),
- "Firmware detected underrun: xid=0x%x fcp_rsp.flags=0x%02x "
- "fcp_resid=%d fw_residual=0x%x.\n", io_req->xid,
- fcp_rsp->rsp_flags.flags, io_req->fcp_resid,
- cqe->cqe_info.rsp_info.fw_residual);
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Firmware detected underrun: xid=0x%x fcp_rsp.flags=0x%02x fcp_resid=%d fw_residual=0x%x lba=%02x%02x%02x%02x.\n",
+ io_req->xid, fcp_rsp->rsp_flags.flags,
+ io_req->fcp_resid,
+ cqe->cqe_info.rsp_info.fw_residual, sc_cmd->cmnd[2],
+ sc_cmd->cmnd[3], sc_cmd->cmnd[4], sc_cmd->cmnd[5]);
if (io_req->cdb_status == 0)
sc_cmd->result = (DID_ERROR << 16) | io_req->cdb_status;
else
sc_cmd->result = (DID_OK << 16) | io_req->cdb_status;
- /* Abort the command since we did not get all the data */
- init_completion(&io_req->abts_done);
- rval = qedf_initiate_abts(io_req, true);
- if (rval) {
- QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n");
- sc_cmd->result = (DID_ERROR << 16) | io_req->cdb_status;
- }
-
/*
* Set resid to the whole buffer length so we won't try to resue
* any previously data.
@@ -1243,6 +1277,12 @@ out:
if (qedf_io_tracing)
qedf_trace_io(fcport, io_req, QEDF_IO_TRACE_RSP);
+ /*
+ * We wait till the end of the function to clear the
+ * outstanding bit in case we need to send an abort
+ */
+ clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
+
io_req->sc_cmd = NULL;
sc_cmd->SCp.ptr = NULL;
sc_cmd->scsi_done(sc_cmd);
@@ -1260,6 +1300,19 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req,
if (!io_req)
return;
+ if (test_and_set_bit(QEDF_CMD_ERR_SCSI_DONE, &io_req->flags)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "io_req:%p scsi_done handling already done\n",
+ io_req);
+ return;
+ }
+
+ /*
+ * We will be done with this command after this call so clear the
+ * outstanding bit.
+ */
+ clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
+
xid = io_req->xid;
sc_cmd = io_req->sc_cmd;
@@ -1268,12 +1321,50 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req,
return;
}
+ if (!virt_addr_valid(sc_cmd)) {
+ QEDF_ERR(&qedf->dbg_ctx, "sc_cmd=%p is not valid.", sc_cmd);
+ goto bad_scsi_ptr;
+ }
+
if (!sc_cmd->SCp.ptr) {
QEDF_WARN(&(qedf->dbg_ctx), "SCp.ptr is NULL, returned in "
"another context.\n");
return;
}
+ if (!sc_cmd->device) {
+ QEDF_ERR(&qedf->dbg_ctx, "Device for sc_cmd %p is NULL.\n",
+ sc_cmd);
+ goto bad_scsi_ptr;
+ }
+
+ if (!virt_addr_valid(sc_cmd->device)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Device pointer for sc_cmd %p is bad.\n", sc_cmd);
+ goto bad_scsi_ptr;
+ }
+
+ if (!sc_cmd->sense_buffer) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "sc_cmd->sense_buffer for sc_cmd %p is NULL.\n",
+ sc_cmd);
+ goto bad_scsi_ptr;
+ }
+
+ if (!virt_addr_valid(sc_cmd->sense_buffer)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "sc_cmd->sense_buffer for sc_cmd %p is bad.\n",
+ sc_cmd);
+ goto bad_scsi_ptr;
+ }
+
+ if (!sc_cmd->scsi_done) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "sc_cmd->scsi_done for sc_cmd %p is NULL.\n",
+ sc_cmd);
+ goto bad_scsi_ptr;
+ }
+
qedf_unmap_sg_list(qedf, io_req);
sc_cmd->result = result << 16;
@@ -1300,6 +1391,15 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req,
sc_cmd->SCp.ptr = NULL;
sc_cmd->scsi_done(sc_cmd);
kref_put(&io_req->refcount, qedf_release_cmd);
+ return;
+
+bad_scsi_ptr:
+ /*
+ * Clear the io_req->sc_cmd backpointer so we don't try to process
+ * this again
+ */
+ io_req->sc_cmd = NULL;
+ kref_put(&io_req->refcount, qedf_release_cmd); /* ID: 001 */
}
/*
@@ -1438,6 +1538,10 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun)
struct qedf_ctx *qedf;
struct qedf_cmd_mgr *cmd_mgr;
int i, rc;
+ unsigned long flags;
+ int flush_cnt = 0;
+ int wait_cnt = 100;
+ int refcount = 0;
if (!fcport)
return;
@@ -1449,18 +1553,102 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun)
}
qedf = fcport->qedf;
+
+ if (!qedf) {
+ QEDF_ERR(NULL, "qedf is NULL.\n");
+ return;
+ }
+
+ /* Only wait for all commands to be queued in the Upload context */
+ if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags) &&
+ (lun == -1)) {
+ while (atomic_read(&fcport->ios_to_queue)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Waiting for %d I/Os to be queued\n",
+ atomic_read(&fcport->ios_to_queue));
+ if (wait_cnt == 0) {
+ QEDF_ERR(NULL,
+ "%d IOs request could not be queued\n",
+ atomic_read(&fcport->ios_to_queue));
+ }
+ msleep(20);
+ wait_cnt--;
+ }
+ }
+
cmd_mgr = qedf->cmd_mgr;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Flush active i/o's.\n");
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Flush active i/o's num=0x%x fcport=0x%p port_id=0x%06x scsi_id=%d.\n",
+ atomic_read(&fcport->num_active_ios), fcport,
+ fcport->rdata->ids.port_id, fcport->rport->scsi_target_id);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Locking flush mutex.\n");
+
+ mutex_lock(&qedf->flush_mutex);
+ if (lun == -1) {
+ set_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags);
+ } else {
+ set_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags);
+ fcport->lun_reset_lun = lun;
+ }
for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) {
io_req = &cmd_mgr->cmds[i];
if (!io_req)
continue;
+ if (!io_req->fcport)
+ continue;
+
+ spin_lock_irqsave(&cmd_mgr->lock, flags);
+
+ if (io_req->alloc) {
+ if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) {
+ if (io_req->cmd_type == QEDF_SCSI_CMD)
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Allocated but not queued, xid=0x%x\n",
+ io_req->xid);
+ }
+ spin_unlock_irqrestore(&cmd_mgr->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&cmd_mgr->lock, flags);
+ continue;
+ }
+
if (io_req->fcport != fcport)
continue;
- if (io_req->cmd_type == QEDF_ELS) {
+
+ /* In case of ABTS, CMD_OUTSTANDING is cleared on ABTS response,
+ * but RRQ is still pending.
+ * Workaround: Within qedf_send_rrq, we check if the fcport is
+ * NULL, and we drop the ref on the io_req to clean it up.
+ */
+ if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags)) {
+ refcount = kref_read(&io_req->refcount);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Not outstanding, xid=0x%x, cmd_type=%d refcount=%d.\n",
+ io_req->xid, io_req->cmd_type, refcount);
+ /* If RRQ work has been queue, try to cancel it and
+ * free the io_req
+ */
+ if (atomic_read(&io_req->state) ==
+ QEDFC_CMD_ST_RRQ_WAIT) {
+ if (cancel_delayed_work_sync
+ (&io_req->rrq_work)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Putting reference for pending RRQ work xid=0x%x.\n",
+ io_req->xid);
+ /* ID: 003 */
+ kref_put(&io_req->refcount,
+ qedf_release_cmd);
+ }
+ }
+ continue;
+ }
+
+ /* Only consider flushing ELS during target reset */
+ if (io_req->cmd_type == QEDF_ELS &&
+ lun == -1) {
rc = kref_get_unless_zero(&io_req->refcount);
if (!rc) {
QEDF_ERR(&(qedf->dbg_ctx),
@@ -1468,6 +1656,7 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun)
io_req, io_req->xid);
continue;
}
+ flush_cnt++;
qedf_flush_els_req(qedf, io_req);
/*
* Release the kref and go back to the top of the
@@ -1477,6 +1666,7 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun)
}
if (io_req->cmd_type == QEDF_ABTS) {
+ /* ID: 004 */
rc = kref_get_unless_zero(&io_req->refcount);
if (!rc) {
QEDF_ERR(&(qedf->dbg_ctx),
@@ -1484,28 +1674,50 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun)
io_req, io_req->xid);
continue;
}
+ if (lun != -1 && io_req->lun != lun)
+ goto free_cmd;
+
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
"Flushing abort xid=0x%x.\n", io_req->xid);
- clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags);
-
- if (io_req->sc_cmd) {
- if (io_req->return_scsi_cmd_on_abts)
- qedf_scsi_done(qedf, io_req, DID_ERROR);
+ if (cancel_delayed_work_sync(&io_req->rrq_work)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Putting ref for cancelled RRQ work xid=0x%x.\n",
+ io_req->xid);
+ kref_put(&io_req->refcount, qedf_release_cmd);
}
- /* Notify eh_abort handler that ABTS is complete */
- complete(&io_req->abts_done);
- kref_put(&io_req->refcount, qedf_release_cmd);
-
+ if (cancel_delayed_work_sync(&io_req->timeout_work)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Putting ref for cancelled tmo work xid=0x%x.\n",
+ io_req->xid);
+ qedf_initiate_cleanup(io_req, true);
+ /* Notify eh_abort handler that ABTS is
+ * complete
+ */
+ complete(&io_req->abts_done);
+ clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags);
+ /* ID: 002 */
+ kref_put(&io_req->refcount, qedf_release_cmd);
+ }
+ flush_cnt++;
goto free_cmd;
}
if (!io_req->sc_cmd)
continue;
- if (lun > 0) {
- if (io_req->sc_cmd->device->lun !=
- (u64)lun)
+ if (!io_req->sc_cmd->device) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Device backpointer NULL for sc_cmd=%p.\n",
+ io_req->sc_cmd);
+ /* Put reference for non-existent scsi_cmnd */
+ io_req->sc_cmd = NULL;
+ qedf_initiate_cleanup(io_req, false);
+ kref_put(&io_req->refcount, qedf_release_cmd);
+ continue;
+ }
+ if (lun > -1) {
+ if (io_req->lun != lun)
continue;
}
@@ -1519,15 +1731,65 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun)
"io_req=0x%p xid=0x%x\n", io_req, io_req->xid);
continue;
}
+
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO,
"Cleanup xid=0x%x.\n", io_req->xid);
+ flush_cnt++;
/* Cleanup task and return I/O mid-layer */
qedf_initiate_cleanup(io_req, true);
free_cmd:
- kref_put(&io_req->refcount, qedf_release_cmd);
+ kref_put(&io_req->refcount, qedf_release_cmd); /* ID: 004 */
+ }
+
+ wait_cnt = 60;
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Flushed 0x%x I/Os, active=0x%x.\n",
+ flush_cnt, atomic_read(&fcport->num_active_ios));
+ /* Only wait for all commands to complete in the Upload context */
+ if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags) &&
+ (lun == -1)) {
+ while (atomic_read(&fcport->num_active_ios)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Flushed 0x%x I/Os, active=0x%x cnt=%d.\n",
+ flush_cnt,
+ atomic_read(&fcport->num_active_ios),
+ wait_cnt);
+ if (wait_cnt == 0) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Flushed %d I/Os, active=%d.\n",
+ flush_cnt,
+ atomic_read(&fcport->num_active_ios));
+ for (i = 0; i < FCOE_PARAMS_NUM_TASKS; i++) {
+ io_req = &cmd_mgr->cmds[i];
+ if (io_req->fcport &&
+ io_req->fcport == fcport) {
+ refcount =
+ kref_read(&io_req->refcount);
+ set_bit(QEDF_CMD_DIRTY,
+ &io_req->flags);
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Outstanding io_req =%p xid=0x%x flags=0x%lx, sc_cmd=%p refcount=%d cmd_type=%d.\n",
+ io_req, io_req->xid,
+ io_req->flags,
+ io_req->sc_cmd,
+ refcount,
+ io_req->cmd_type);
+ }
+ }
+ WARN_ON(1);
+ break;
+ }
+ msleep(500);
+ wait_cnt--;
+ }
}
+
+ clear_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags);
+ clear_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Unlocking flush mutex.\n");
+ mutex_unlock(&qedf->flush_mutex);
}
/*
@@ -1546,52 +1808,60 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts)
unsigned long flags;
struct fcoe_wqe *sqe;
u16 sqe_idx;
+ int refcount = 0;
/* Sanity check qedf_rport before dereferencing any pointers */
if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
QEDF_ERR(NULL, "tgt not offloaded\n");
rc = 1;
- goto abts_err;
+ goto out;
}
+ qedf = fcport->qedf;
rdata = fcport->rdata;
+
+ if (!rdata || !kref_get_unless_zero(&rdata->kref)) {
+ QEDF_ERR(&qedf->dbg_ctx, "stale rport\n");
+ rc = 1;
+ goto out;
+ }
+
r_a_tov = rdata->r_a_tov;
- qedf = fcport->qedf;
lport = qedf->lport;
if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
QEDF_ERR(&(qedf->dbg_ctx), "link is not ready\n");
rc = 1;
- goto abts_err;
+ goto drop_rdata_kref;
}
if (atomic_read(&qedf->link_down_tmo_valid) > 0) {
QEDF_ERR(&(qedf->dbg_ctx), "link_down_tmo active.\n");
rc = 1;
- goto abts_err;
+ goto drop_rdata_kref;
}
/* Ensure room on SQ */
if (!atomic_read(&fcport->free_sqes)) {
QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n");
rc = 1;
- goto abts_err;
+ goto drop_rdata_kref;
}
if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
QEDF_ERR(&qedf->dbg_ctx, "fcport is uploading.\n");
rc = 1;
- goto out;
+ goto drop_rdata_kref;
}
if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) ||
test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) ||
test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) {
- QEDF_ERR(&(qedf->dbg_ctx), "io_req xid=0x%x already in "
- "cleanup or abort processing or already "
- "completed.\n", io_req->xid);
+ QEDF_ERR(&qedf->dbg_ctx,
+ "io_req xid=0x%x sc_cmd=%p already in cleanup or abort processing or already completed.\n",
+ io_req->xid, io_req->sc_cmd);
rc = 1;
- goto out;
+ goto drop_rdata_kref;
}
kref_get(&io_req->refcount);
@@ -1600,18 +1870,17 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts)
qedf->control_requests++;
qedf->packet_aborts++;
- /* Set the return CPU to be the same as the request one */
- io_req->cpu = smp_processor_id();
-
/* Set the command type to abort */
io_req->cmd_type = QEDF_ABTS;
io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts;
set_bit(QEDF_CMD_IN_ABORT, &io_req->flags);
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "ABTS io_req xid = "
- "0x%x\n", xid);
+ refcount = kref_read(&io_req->refcount);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM,
+ "ABTS io_req xid = 0x%x refcount=%d\n",
+ xid, refcount);
- qedf_cmd_timer_set(qedf, io_req, QEDF_ABORT_TIMEOUT * HZ);
+ qedf_cmd_timer_set(qedf, io_req, QEDF_ABORT_TIMEOUT);
spin_lock_irqsave(&fcport->rport_lock, flags);
@@ -1625,13 +1894,8 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts)
spin_unlock_irqrestore(&fcport->rport_lock, flags);
- return rc;
-abts_err:
- /*
- * If the ABTS task fails to queue then we need to cleanup the
- * task at the firmware.
- */
- qedf_initiate_cleanup(io_req, return_scsi_cmd_on_abts);
+drop_rdata_kref:
+ kref_put(&rdata->kref, fc_rport_destroy);
out:
return rc;
}
@@ -1641,27 +1905,62 @@ void qedf_process_abts_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
{
uint32_t r_ctl;
uint16_t xid;
+ int rc;
+ struct qedf_rport *fcport = io_req->fcport;
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "Entered with xid = "
"0x%x cmd_type = %d\n", io_req->xid, io_req->cmd_type);
- cancel_delayed_work(&io_req->timeout_work);
-
xid = io_req->xid;
r_ctl = cqe->cqe_info.abts_info.r_ctl;
+ /* This was added at a point when we were scheduling abts_compl &
+ * cleanup_compl on different CPUs and there was a possibility of
+ * the io_req to be freed from the other context before we got here.
+ */
+ if (!fcport) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Dropping ABTS completion xid=0x%x as fcport is NULL",
+ io_req->xid);
+ return;
+ }
+
+ /*
+ * When flush is active, let the cmds be completed from the cleanup
+ * context
+ */
+ if (test_bit(QEDF_RPORT_IN_TARGET_RESET, &fcport->flags) ||
+ test_bit(QEDF_RPORT_IN_LUN_RESET, &fcport->flags)) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Dropping ABTS completion xid=0x%x as fcport is flushing",
+ io_req->xid);
+ return;
+ }
+
+ if (!cancel_delayed_work(&io_req->timeout_work)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Wasn't able to cancel abts timeout work.\n");
+ }
+
switch (r_ctl) {
case FC_RCTL_BA_ACC:
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM,
"ABTS response - ACC Send RRQ after R_A_TOV\n");
io_req->event = QEDF_IOREQ_EV_ABORT_SUCCESS;
+ rc = kref_get_unless_zero(&io_req->refcount); /* ID: 003 */
+ if (!rc) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM,
+ "kref is already zero so ABTS was already completed or flushed xid=0x%x.\n",
+ io_req->xid);
+ return;
+ }
/*
* Dont release this cmd yet. It will be relesed
* after we get RRQ response
*/
- kref_get(&io_req->refcount);
queue_delayed_work(qedf->dpc_wq, &io_req->rrq_work,
msecs_to_jiffies(qedf->lport->r_a_tov));
+ atomic_set(&io_req->state, QEDFC_CMD_ST_RRQ_WAIT);
break;
/* For error cases let the cleanup return the command */
case FC_RCTL_BA_RJT:
@@ -1803,6 +2102,7 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req,
unsigned long flags;
struct fcoe_wqe *sqe;
u16 sqe_idx;
+ int refcount = 0;
fcport = io_req->fcport;
if (!fcport) {
@@ -1824,36 +2124,45 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req,
}
if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) ||
- test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags)) {
+ test_and_set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags)) {
QEDF_ERR(&(qedf->dbg_ctx), "io_req xid=0x%x already in "
"cleanup processing or already completed.\n",
io_req->xid);
return SUCCESS;
}
+ set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags);
/* Ensure room on SQ */
if (!atomic_read(&fcport->free_sqes)) {
QEDF_ERR(&(qedf->dbg_ctx), "No SQ entries available\n");
+ /* Need to make sure we clear the flag since it was set */
+ clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags);
return FAILED;
}
+ if (io_req->cmd_type == QEDF_CLEANUP) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "io_req=0x%x is already a cleanup command cmd_type=%d.\n",
+ io_req->xid, io_req->cmd_type);
+ clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags);
+ return SUCCESS;
+ }
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_IO, "Entered xid=0x%x\n",
- io_req->xid);
+ refcount = kref_read(&io_req->refcount);
+
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO,
+ "Entered xid=0x%x sc_cmd=%p cmd_type=%d flags=0x%lx refcount=%d fcport=%p port_id=0x%06x\n",
+ io_req->xid, io_req->sc_cmd, io_req->cmd_type, io_req->flags,
+ refcount, fcport, fcport->rdata->ids.port_id);
/* Cleanup cmds re-use the same TID as the original I/O */
xid = io_req->xid;
io_req->cmd_type = QEDF_CLEANUP;
io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts;
- /* Set the return CPU to be the same as the request one */
- io_req->cpu = smp_processor_id();
-
- set_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags);
-
task = qedf_get_task_mem(&qedf->tasks, xid);
- init_completion(&io_req->tm_done);
+ init_completion(&io_req->cleanup_done);
spin_lock_irqsave(&fcport->rport_lock, flags);
@@ -1867,8 +2176,8 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req,
spin_unlock_irqrestore(&fcport->rport_lock, flags);
- tmo = wait_for_completion_timeout(&io_req->tm_done,
- QEDF_CLEANUP_TIMEOUT * HZ);
+ tmo = wait_for_completion_timeout(&io_req->cleanup_done,
+ QEDF_CLEANUP_TIMEOUT * HZ);
if (!tmo) {
rc = FAILED;
@@ -1881,6 +2190,16 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req,
qedf_drain_request(qedf);
}
+ /* If it TASK MGMT handle it, reference will be decreased
+ * in qedf_execute_tmf
+ */
+ if (io_req->tm_flags == FCP_TMF_LUN_RESET ||
+ io_req->tm_flags == FCP_TMF_TGT_RESET) {
+ clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
+ io_req->sc_cmd = NULL;
+ complete(&io_req->tm_done);
+ }
+
if (io_req->sc_cmd) {
if (io_req->return_scsi_cmd_on_abts)
qedf_scsi_done(qedf, io_req, DID_ERROR);
@@ -1903,7 +2222,7 @@ void qedf_process_cleanup_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
clear_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags);
/* Complete so we can finish cleaning up the I/O */
- complete(&io_req->tm_done);
+ complete(&io_req->cleanup_done);
}
static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
@@ -1916,6 +2235,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
int rc = 0;
uint16_t xid;
int tmo = 0;
+ int lun = 0;
unsigned long flags;
struct fcoe_wqe *sqe;
u16 sqe_idx;
@@ -1925,20 +2245,18 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
return FAILED;
}
+ lun = (int)sc_cmd->device->lun;
if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
QEDF_ERR(&(qedf->dbg_ctx), "fcport not offloaded\n");
rc = FAILED;
- return FAILED;
+ goto no_flush;
}
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_SCSI_TM, "portid = 0x%x "
- "tm_flags = %d\n", fcport->rdata->ids.port_id, tm_flags);
-
io_req = qedf_alloc_cmd(fcport, QEDF_TASK_MGMT_CMD);
if (!io_req) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed TMF");
rc = -EAGAIN;
- goto reset_tmf_err;
+ goto no_flush;
}
if (tm_flags == FCP_TMF_LUN_RESET)
@@ -1951,7 +2269,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
io_req->fcport = fcport;
io_req->cmd_type = QEDF_TASK_MGMT_CMD;
- /* Set the return CPU to be the same as the request one */
+ /* Record which cpu this request is associated with */
io_req->cpu = smp_processor_id();
/* Set TM flags */
@@ -1960,7 +2278,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
io_req->tm_flags = tm_flags;
/* Default is to return a SCSI command when an error occurs */
- io_req->return_scsi_cmd_on_abts = true;
+ io_req->return_scsi_cmd_on_abts = false;
/* Obtain exchange id */
xid = io_req->xid;
@@ -1984,12 +2302,16 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
spin_unlock_irqrestore(&fcport->rport_lock, flags);
+ set_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
tmo = wait_for_completion_timeout(&io_req->tm_done,
QEDF_TM_TIMEOUT * HZ);
if (!tmo) {
rc = FAILED;
QEDF_ERR(&(qedf->dbg_ctx), "wait for tm_cmpl timeout!\n");
+ /* Clear outstanding bit since command timed out */
+ clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
+ io_req->sc_cmd = NULL;
} else {
/* Check TMF response code */
if (io_req->fcp_rsp_code == 0)
@@ -1997,14 +2319,25 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
else
rc = FAILED;
}
+ /*
+ * Double check that fcport has not gone into an uploading state before
+ * executing the command flush for the LUN/target.
+ */
+ if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "fcport is uploading, not executing flush.\n");
+ goto no_flush;
+ }
+ /* We do not need this io_req any more */
+ kref_put(&io_req->refcount, qedf_release_cmd);
+
if (tm_flags == FCP_TMF_LUN_RESET)
- qedf_flush_active_ios(fcport, (int)sc_cmd->device->lun);
+ qedf_flush_active_ios(fcport, lun);
else
qedf_flush_active_ios(fcport, -1);
- kref_put(&io_req->refcount, qedf_release_cmd);
-
+no_flush:
if (rc != SUCCESS) {
QEDF_ERR(&(qedf->dbg_ctx), "task mgmt command failed...\n");
rc = FAILED;
@@ -2012,7 +2345,6 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
QEDF_ERR(&(qedf->dbg_ctx), "task mgmt command success...\n");
rc = SUCCESS;
}
-reset_tmf_err:
return rc;
}
@@ -2022,26 +2354,65 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags)
struct fc_rport_libfc_priv *rp = rport->dd_data;
struct qedf_rport *fcport = (struct qedf_rport *)&rp[1];
struct qedf_ctx *qedf;
- struct fc_lport *lport;
+ struct fc_lport *lport = shost_priv(sc_cmd->device->host);
int rc = SUCCESS;
int rval;
+ struct qedf_ioreq *io_req = NULL;
+ int ref_cnt = 0;
+ struct fc_rport_priv *rdata = fcport->rdata;
- rval = fc_remote_port_chkready(rport);
+ QEDF_ERR(NULL,
+ "tm_flags 0x%x sc_cmd %p op = 0x%02x target_id = 0x%x lun=%d\n",
+ tm_flags, sc_cmd, sc_cmd->cmnd[0], rport->scsi_target_id,
+ (int)sc_cmd->device->lun);
+
+ if (!rdata || !kref_get_unless_zero(&rdata->kref)) {
+ QEDF_ERR(NULL, "stale rport\n");
+ return FAILED;
+ }
+
+ QEDF_ERR(NULL, "portid=%06x tm_flags =%s\n", rdata->ids.port_id,
+ (tm_flags == FCP_TMF_TGT_RESET) ? "TARGET RESET" :
+ "LUN RESET");
+
+ if (sc_cmd->SCp.ptr) {
+ io_req = (struct qedf_ioreq *)sc_cmd->SCp.ptr;
+ ref_cnt = kref_read(&io_req->refcount);
+ QEDF_ERR(NULL,
+ "orig io_req = %p xid = 0x%x ref_cnt = %d.\n",
+ io_req, io_req->xid, ref_cnt);
+ }
+ rval = fc_remote_port_chkready(rport);
if (rval) {
QEDF_ERR(NULL, "device_reset rport not ready\n");
rc = FAILED;
goto tmf_err;
}
- if (fcport == NULL) {
+ rc = fc_block_scsi_eh(sc_cmd);
+ if (rc)
+ goto tmf_err;
+
+ if (!fcport) {
QEDF_ERR(NULL, "device_reset: rport is NULL\n");
rc = FAILED;
goto tmf_err;
}
qedf = fcport->qedf;
- lport = qedf->lport;
+
+ if (!qedf) {
+ QEDF_ERR(NULL, "qedf is NULL.\n");
+ rc = FAILED;
+ goto tmf_err;
+ }
+
+ if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
+ QEDF_ERR(&qedf->dbg_ctx, "Connection is getting uploaded.\n");
+ rc = SUCCESS;
+ goto tmf_err;
+ }
if (test_bit(QEDF_UNLOADING, &qedf->flags) ||
test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) {
@@ -2055,9 +2426,22 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags)
goto tmf_err;
}
+ if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
+ if (!fcport->rdata)
+ QEDF_ERR(&qedf->dbg_ctx, "fcport %p is uploading.\n",
+ fcport);
+ else
+ QEDF_ERR(&qedf->dbg_ctx,
+ "fcport %p port_id=%06x is uploading.\n",
+ fcport, fcport->rdata->ids.port_id);
+ rc = FAILED;
+ goto tmf_err;
+ }
+
rc = qedf_execute_tmf(fcport, sc_cmd, tm_flags);
tmf_err:
+ kref_put(&rdata->kref, fc_rport_destroy);
return rc;
}
@@ -2066,6 +2450,8 @@ void qedf_process_tmf_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe,
{
struct fcoe_cqe_rsp_info *fcp_rsp;
+ clear_bit(QEDF_CMD_OUTSTANDING, &io_req->flags);
+
fcp_rsp = &cqe->cqe_info.rsp_info;
qedf_parse_fcp_rsp(io_req, fcp_rsp);
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index 9f9431a4cc0e..a42babde036d 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include <linux/init.h>
#include <linux/kernel.h>
@@ -124,21 +121,24 @@ static bool qedf_initiate_fipvlan_req(struct qedf_ctx *qedf)
{
int rc;
- if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) {
- QEDF_ERR(&(qedf->dbg_ctx), "Link not up.\n");
- return false;
- }
-
while (qedf->fipvlan_retries--) {
+ /* This is to catch if link goes down during fipvlan retries */
+ if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) {
+ QEDF_ERR(&qedf->dbg_ctx, "Link not up.\n");
+ return false;
+ }
+
if (qedf->vlan_id > 0)
return true;
+
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
"Retry %d.\n", qedf->fipvlan_retries);
init_completion(&qedf->fipvlan_compl);
qedf_fcoe_send_vlan_req(qedf);
rc = wait_for_completion_timeout(&qedf->fipvlan_compl,
1 * HZ);
- if (rc > 0) {
+ if (rc > 0 &&
+ (atomic_read(&qedf->link_state) == QEDF_LINK_UP)) {
fcoe_ctlr_link_up(&qedf->ctlr);
return true;
}
@@ -153,12 +153,19 @@ static void qedf_handle_link_update(struct work_struct *work)
container_of(work, struct qedf_ctx, link_update.work);
int rc;
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Entered.\n");
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Entered. link_state=%d.\n",
+ atomic_read(&qedf->link_state));
if (atomic_read(&qedf->link_state) == QEDF_LINK_UP) {
rc = qedf_initiate_fipvlan_req(qedf);
if (rc)
return;
+
+ if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) {
+ qedf->vlan_id = 0;
+ return;
+ }
+
/*
* If we get here then we never received a repsonse to our
* fip vlan request so set the vlan_id to the default and
@@ -185,7 +192,9 @@ static void qedf_handle_link_update(struct work_struct *work)
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
"Calling fcoe_ctlr_link_down().\n");
fcoe_ctlr_link_down(&qedf->ctlr);
- qedf_wait_for_upload(qedf);
+ if (qedf_wait_for_upload(qedf) == false)
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Could not upload all sessions.\n");
/* Reset the number of FIP VLAN retries */
qedf->fipvlan_retries = qedf_fipvlan_retries;
}
@@ -615,50 +624,113 @@ static struct scsi_transport_template *qedf_fc_vport_transport_template;
static int qedf_eh_abort(struct scsi_cmnd *sc_cmd)
{
struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct qedf_rport *fcport;
struct fc_lport *lport;
struct qedf_ctx *qedf;
struct qedf_ioreq *io_req;
+ struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fc_rport_priv *rdata;
+ struct qedf_rport *fcport = NULL;
int rc = FAILED;
+ int wait_count = 100;
+ int refcount = 0;
int rval;
-
- if (fc_remote_port_chkready(rport)) {
- QEDF_ERR(NULL, "rport not ready\n");
- goto out;
- }
+ int got_ref = 0;
lport = shost_priv(sc_cmd->device->host);
qedf = (struct qedf_ctx *)lport_priv(lport);
- if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) {
- QEDF_ERR(&(qedf->dbg_ctx), "link not ready.\n");
+ /* rport and tgt are allocated together, so tgt should be non-NULL */
+ fcport = (struct qedf_rport *)&rp[1];
+ rdata = fcport->rdata;
+ if (!rdata || !kref_get_unless_zero(&rdata->kref)) {
+ QEDF_ERR(&qedf->dbg_ctx, "stale rport, sc_cmd=%p\n", sc_cmd);
+ rc = 1;
goto out;
}
- fcport = (struct qedf_rport *)&rp[1];
io_req = (struct qedf_ioreq *)sc_cmd->SCp.ptr;
if (!io_req) {
- QEDF_ERR(&(qedf->dbg_ctx), "io_req is NULL.\n");
+ QEDF_ERR(&qedf->dbg_ctx,
+ "sc_cmd not queued with lld, sc_cmd=%p op=0x%02x, port_id=%06x\n",
+ sc_cmd, sc_cmd->cmnd[0],
+ rdata->ids.port_id);
rc = SUCCESS;
- goto out;
+ goto drop_rdata_kref;
}
- QEDF_ERR(&(qedf->dbg_ctx), "Aborting io_req sc_cmd=%p xid=0x%x "
- "fp_idx=%d.\n", sc_cmd, io_req->xid, io_req->fp_idx);
+ rval = kref_get_unless_zero(&io_req->refcount); /* ID: 005 */
+ if (rval)
+ got_ref = 1;
+
+ /* If we got a valid io_req, confirm it belongs to this sc_cmd. */
+ if (!rval || io_req->sc_cmd != sc_cmd) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Freed/Incorrect io_req, io_req->sc_cmd=%p, sc_cmd=%p, port_id=%06x, bailing out.\n",
+ io_req->sc_cmd, sc_cmd, rdata->ids.port_id);
+
+ goto drop_rdata_kref;
+ }
+
+ if (fc_remote_port_chkready(rport)) {
+ refcount = kref_read(&io_req->refcount);
+ QEDF_ERR(&qedf->dbg_ctx,
+ "rport not ready, io_req=%p, xid=0x%x sc_cmd=%p op=0x%02x, refcount=%d, port_id=%06x\n",
+ io_req, io_req->xid, sc_cmd, sc_cmd->cmnd[0],
+ refcount, rdata->ids.port_id);
+
+ goto drop_rdata_kref;
+ }
+
+ rc = fc_block_scsi_eh(sc_cmd);
+ if (rc)
+ goto drop_rdata_kref;
+
+ if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Connection uploading, xid=0x%x., port_id=%06x\n",
+ io_req->xid, rdata->ids.port_id);
+ while (io_req->sc_cmd && (wait_count != 0)) {
+ msleep(100);
+ wait_count--;
+ }
+ if (wait_count) {
+ QEDF_ERR(&qedf->dbg_ctx, "ABTS succeeded\n");
+ rc = SUCCESS;
+ } else {
+ QEDF_ERR(&qedf->dbg_ctx, "ABTS failed\n");
+ rc = FAILED;
+ }
+ goto drop_rdata_kref;
+ }
+
+ if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
+ QEDF_ERR(&qedf->dbg_ctx, "link not ready.\n");
+ goto drop_rdata_kref;
+ }
+
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Aborting io_req=%p sc_cmd=%p xid=0x%x fp_idx=%d, port_id=%06x.\n",
+ io_req, sc_cmd, io_req->xid, io_req->fp_idx,
+ rdata->ids.port_id);
if (qedf->stop_io_on_error) {
qedf_stop_all_io(qedf);
rc = SUCCESS;
- goto out;
+ goto drop_rdata_kref;
}
init_completion(&io_req->abts_done);
rval = qedf_initiate_abts(io_req, true);
if (rval) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n");
- goto out;
+ /*
+ * If we fail to queue the ABTS then return this command to
+ * the SCSI layer as it will own and free the xid
+ */
+ rc = SUCCESS;
+ qedf_scsi_done(qedf, io_req, DID_ERROR);
+ goto drop_rdata_kref;
}
wait_for_completion(&io_req->abts_done);
@@ -684,38 +756,68 @@ static int qedf_eh_abort(struct scsi_cmnd *sc_cmd)
QEDF_ERR(&(qedf->dbg_ctx), "ABTS failed, xid=0x%x.\n",
io_req->xid);
+drop_rdata_kref:
+ kref_put(&rdata->kref, fc_rport_destroy);
out:
+ if (got_ref)
+ kref_put(&io_req->refcount, qedf_release_cmd);
return rc;
}
static int qedf_eh_target_reset(struct scsi_cmnd *sc_cmd)
{
- QEDF_ERR(NULL, "TARGET RESET Issued...");
+ QEDF_ERR(NULL, "%d:0:%d:%lld: TARGET RESET Issued...",
+ sc_cmd->device->host->host_no, sc_cmd->device->id,
+ sc_cmd->device->lun);
return qedf_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET);
}
static int qedf_eh_device_reset(struct scsi_cmnd *sc_cmd)
{
- QEDF_ERR(NULL, "LUN RESET Issued...\n");
+ QEDF_ERR(NULL, "%d:0:%d:%lld: LUN RESET Issued... ",
+ sc_cmd->device->host->host_no, sc_cmd->device->id,
+ sc_cmd->device->lun);
return qedf_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET);
}
-void qedf_wait_for_upload(struct qedf_ctx *qedf)
+bool qedf_wait_for_upload(struct qedf_ctx *qedf)
{
- while (1) {
+ struct qedf_rport *fcport = NULL;
+ int wait_cnt = 120;
+
+ while (wait_cnt--) {
if (atomic_read(&qedf->num_offloads))
- QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
- "Waiting for all uploads to complete.\n");
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Waiting for all uploads to complete num_offloads = 0x%x.\n",
+ atomic_read(&qedf->num_offloads));
else
- break;
+ return true;
msleep(500);
}
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(fcport, &qedf->fcports, peers) {
+ if (fcport && test_bit(QEDF_RPORT_SESSION_READY,
+ &fcport->flags)) {
+ if (fcport->rdata)
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Waiting for fcport %p portid=%06x.\n",
+ fcport, fcport->rdata->ids.port_id);
+ } else {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Waiting for fcport %p.\n", fcport);
+ }
+ }
+ rcu_read_unlock();
+ return false;
+
}
/* Performs soft reset of qedf_ctx by simulating a link down/up */
-static void qedf_ctx_soft_reset(struct fc_lport *lport)
+void qedf_ctx_soft_reset(struct fc_lport *lport)
{
struct qedf_ctx *qedf;
+ struct qed_link_output if_link;
if (lport->vport) {
QEDF_ERR(NULL, "Cannot issue host reset on NPIV port.\n");
@@ -726,11 +828,32 @@ static void qedf_ctx_soft_reset(struct fc_lport *lport)
/* For host reset, essentially do a soft link up/down */
atomic_set(&qedf->link_state, QEDF_LINK_DOWN);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Queuing link down work.\n");
queue_delayed_work(qedf->link_update_wq, &qedf->link_update,
0);
- qedf_wait_for_upload(qedf);
+
+ if (qedf_wait_for_upload(qedf) == false) {
+ QEDF_ERR(&qedf->dbg_ctx, "Could not upload all sessions.\n");
+ WARN_ON(atomic_read(&qedf->num_offloads));
+ }
+
+ /* Before setting link up query physical link state */
+ qed_ops->common->get_link(qedf->cdev, &if_link);
+ /* Bail if the physical link is not up */
+ if (!if_link.link_up) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Physical link is not up.\n");
+ return;
+ }
+ /* Flush and wait to make sure link down is processed */
+ flush_delayed_work(&qedf->link_update);
+ msleep(500);
+
atomic_set(&qedf->link_state, QEDF_LINK_UP);
qedf->vlan_id = 0;
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Queue link up work.\n");
queue_delayed_work(qedf->link_update_wq, &qedf->link_update,
0);
}
@@ -740,22 +863,6 @@ static int qedf_eh_host_reset(struct scsi_cmnd *sc_cmd)
{
struct fc_lport *lport;
struct qedf_ctx *qedf;
- struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct qedf_rport *fcport = (struct qedf_rport *)&rp[1];
- int rval;
-
- rval = fc_remote_port_chkready(rport);
-
- if (rval) {
- QEDF_ERR(NULL, "device_reset rport not ready\n");
- return FAILED;
- }
-
- if (fcport == NULL) {
- QEDF_ERR(NULL, "device_reset: rport is NULL\n");
- return FAILED;
- }
lport = shost_priv(sc_cmd->device->host);
qedf = lport_priv(lport);
@@ -907,8 +1014,10 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp)
"Dropping FCoE frame to %06x.\n", ntoh24(fh->fh_d_id));
kfree_skb(skb);
rdata = fc_rport_lookup(lport, ntoh24(fh->fh_d_id));
- if (rdata)
+ if (rdata) {
rdata->retries = lport->max_rport_retry_count;
+ kref_put(&rdata->kref, fc_rport_destroy);
+ }
return -EINVAL;
}
/* End NPIV filtering */
@@ -1031,7 +1140,12 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp)
if (qedf_dump_frames)
print_hex_dump(KERN_WARNING, "fcoe: ", DUMP_PREFIX_OFFSET, 16,
1, skb->data, skb->len, false);
- qed_ops->ll2->start_xmit(qedf->cdev, skb, 0);
+ rc = qed_ops->ll2->start_xmit(qedf->cdev, skb, 0);
+ if (rc) {
+ QEDF_ERR(&qedf->dbg_ctx, "start_xmit failed rc = %d.\n", rc);
+ kfree_skb(skb);
+ return rc;
+ }
return 0;
}
@@ -1224,6 +1338,8 @@ static void qedf_upload_connection(struct qedf_ctx *qedf,
static void qedf_cleanup_fcport(struct qedf_ctx *qedf,
struct qedf_rport *fcport)
{
+ struct fc_rport_priv *rdata = fcport->rdata;
+
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "Cleaning up portid=%06x.\n",
fcport->rdata->ids.port_id);
@@ -1235,6 +1351,7 @@ static void qedf_cleanup_fcport(struct qedf_ctx *qedf,
qedf_free_sq(qedf, fcport);
fcport->rdata = NULL;
fcport->qedf = NULL;
+ kref_put(&rdata->kref, fc_rport_destroy);
}
/**
@@ -1310,6 +1427,8 @@ static void qedf_rport_event_handler(struct fc_lport *lport,
break;
}
+ /* Initial reference held on entry, so this can't fail */
+ kref_get(&rdata->kref);
fcport->rdata = rdata;
fcport->rport = rport;
@@ -1369,11 +1488,15 @@ static void qedf_rport_event_handler(struct fc_lport *lport,
*/
fcport = (struct qedf_rport *)&rp[1];
+ spin_lock_irqsave(&fcport->rport_lock, flags);
/* Only free this fcport if it is offloaded already */
- if (test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
- set_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags);
+ if (test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags) &&
+ !test_bit(QEDF_RPORT_UPLOADING_CONNECTION,
+ &fcport->flags)) {
+ set_bit(QEDF_RPORT_UPLOADING_CONNECTION,
+ &fcport->flags);
+ spin_unlock_irqrestore(&fcport->rport_lock, flags);
qedf_cleanup_fcport(qedf, fcport);
-
/*
* Remove fcport to list of qedf_ctx list of offloaded
* ports
@@ -1385,8 +1508,9 @@ static void qedf_rport_event_handler(struct fc_lport *lport,
clear_bit(QEDF_RPORT_UPLOADING_CONNECTION,
&fcport->flags);
atomic_dec(&qedf->num_offloads);
+ } else {
+ spin_unlock_irqrestore(&fcport->rport_lock, flags);
}
-
break;
case RPORT_EV_NONE:
@@ -1498,11 +1622,15 @@ static int qedf_lport_setup(struct qedf_ctx *qedf)
fc_set_wwnn(lport, qedf->wwnn);
fc_set_wwpn(lport, qedf->wwpn);
- fcoe_libfc_config(lport, &qedf->ctlr, &qedf_lport_template, 0);
+ if (fcoe_libfc_config(lport, &qedf->ctlr, &qedf_lport_template, 0)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "fcoe_libfc_config failed.\n");
+ return -ENOMEM;
+ }
/* Allocate the exchange manager */
- fc_exch_mgr_alloc(lport, FC_CLASS_3, qedf->max_scsi_xid + 1,
- qedf->max_els_xid, NULL);
+ fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_PARAMS_NUM_TASKS,
+ 0xfffe, NULL);
if (fc_lport_init_stats(lport))
return -ENOMEM;
@@ -1625,14 +1753,15 @@ static int qedf_vport_create(struct fc_vport *vport, bool disabled)
vport_qedf->wwpn = vn_port->wwpn;
vn_port->host->transportt = qedf_fc_vport_transport_template;
- vn_port->host->can_queue = QEDF_MAX_ELS_XID;
+ vn_port->host->can_queue = FCOE_PARAMS_NUM_TASKS;
vn_port->host->max_lun = qedf_max_lun;
vn_port->host->sg_tablesize = QEDF_MAX_BDS_PER_CMD;
vn_port->host->max_cmd_len = QEDF_MAX_CDB_LEN;
rc = scsi_add_host(vn_port->host, &vport->dev);
if (rc) {
- QEDF_WARN(&(base_qedf->dbg_ctx), "Error adding Scsi_Host.\n");
+ QEDF_WARN(&base_qedf->dbg_ctx,
+ "Error adding Scsi_Host rc=0x%x.\n", rc);
goto err2;
}
@@ -2086,16 +2215,21 @@ static void qedf_simd_int_handler(void *cookie)
static void qedf_sync_free_irqs(struct qedf_ctx *qedf)
{
int i;
+ u16 vector_idx = 0;
+ u32 vector;
if (qedf->int_info.msix_cnt) {
for (i = 0; i < qedf->int_info.used_cnt; i++) {
- synchronize_irq(qedf->int_info.msix[i].vector);
- irq_set_affinity_hint(qedf->int_info.msix[i].vector,
- NULL);
- irq_set_affinity_notifier(qedf->int_info.msix[i].vector,
- NULL);
- free_irq(qedf->int_info.msix[i].vector,
- &qedf->fp_array[i]);
+ vector_idx = i * qedf->dev_info.common.num_hwfns +
+ qed_ops->common->get_affin_hwfn_idx(qedf->cdev);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Freeing IRQ #%d vector_idx=%d.\n",
+ i, vector_idx);
+ vector = qedf->int_info.msix[vector_idx].vector;
+ synchronize_irq(vector);
+ irq_set_affinity_hint(vector, NULL);
+ irq_set_affinity_notifier(vector, NULL);
+ free_irq(vector, &qedf->fp_array[i]);
}
} else
qed_ops->common->simd_handler_clean(qedf->cdev,
@@ -2108,11 +2242,19 @@ static void qedf_sync_free_irqs(struct qedf_ctx *qedf)
static int qedf_request_msix_irq(struct qedf_ctx *qedf)
{
int i, rc, cpu;
+ u16 vector_idx = 0;
+ u32 vector;
cpu = cpumask_first(cpu_online_mask);
for (i = 0; i < qedf->num_queues; i++) {
- rc = request_irq(qedf->int_info.msix[i].vector,
- qedf_msix_handler, 0, "qedf", &qedf->fp_array[i]);
+ vector_idx = i * qedf->dev_info.common.num_hwfns +
+ qed_ops->common->get_affin_hwfn_idx(qedf->cdev);
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "Requesting IRQ #%d vector_idx=%d.\n",
+ i, vector_idx);
+ vector = qedf->int_info.msix[vector_idx].vector;
+ rc = request_irq(vector, qedf_msix_handler, 0, "qedf",
+ &qedf->fp_array[i]);
if (rc) {
QEDF_WARN(&(qedf->dbg_ctx), "request_irq failed.\n");
@@ -2121,8 +2263,7 @@ static int qedf_request_msix_irq(struct qedf_ctx *qedf)
}
qedf->int_info.used_cnt++;
- rc = irq_set_affinity_hint(qedf->int_info.msix[i].vector,
- get_cpu_mask(cpu));
+ rc = irq_set_affinity_hint(vector, get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
@@ -2155,7 +2296,8 @@ static int qedf_setup_int(struct qedf_ctx *qedf)
QEDF_SIMD_HANDLER_NUM, qedf_simd_int_handler);
qedf->int_info.used_cnt = 1;
- QEDF_ERR(&qedf->dbg_ctx, "Only MSI-X supported. Failing probe.\n");
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Cannot load driver due to a lack of MSI-X vectors.\n");
return -EINVAL;
}
@@ -2356,6 +2498,13 @@ static int qedf_ll2_rx(void *cookie, struct sk_buff *skb,
struct qedf_ctx *qedf = (struct qedf_ctx *)cookie;
struct qedf_skb_work *skb_work;
+ if (atomic_read(&qedf->link_state) == QEDF_LINK_DOWN) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
+ "Dropping frame as link state is down.\n");
+ kfree_skb(skb);
+ return 0;
+ }
+
skb_work = kzalloc(sizeof(struct qedf_skb_work), GFP_ATOMIC);
if (!skb_work) {
QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate skb_work so "
@@ -2990,6 +3139,8 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
goto err0;
}
+ fc_disc_init(lport);
+
/* Initialize qedf_ctx */
qedf = lport_priv(lport);
qedf->lport = lport;
@@ -3005,6 +3156,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
pci_set_drvdata(pdev, qedf);
init_completion(&qedf->fipvlan_compl);
mutex_init(&qedf->stats_mutex);
+ mutex_init(&qedf->flush_mutex);
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_INFO,
"QLogic FastLinQ FCoE Module qedf %s, "
@@ -3068,6 +3220,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
goto err1;
}
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
+ "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n",
+ qedf->dev_info.common.num_hwfns,
+ qed_ops->common->get_affin_hwfn_idx(qedf->cdev));
+
/* queue allocation code should come here
* order should be
* slowpath_start
@@ -3181,11 +3338,6 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
sprintf(host_buf, "host_%d", host->host_no);
qed_ops->common->set_name(qedf->cdev, host_buf);
-
- /* Set xid max values */
- qedf->max_scsi_xid = QEDF_MAX_SCSI_XID;
- qedf->max_els_xid = QEDF_MAX_ELS_XID;
-
/* Allocate cmd mgr */
qedf->cmd_mgr = qedf_cmd_mgr_alloc(qedf);
if (!qedf->cmd_mgr) {
@@ -3196,12 +3348,15 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
if (mode != QEDF_MODE_RECOVERY) {
host->transportt = qedf_fc_transport_template;
- host->can_queue = QEDF_MAX_ELS_XID;
host->max_lun = qedf_max_lun;
host->max_cmd_len = QEDF_MAX_CDB_LEN;
+ host->can_queue = FCOE_PARAMS_NUM_TASKS;
rc = scsi_add_host(host, &pdev->dev);
- if (rc)
+ if (rc) {
+ QEDF_WARN(&qedf->dbg_ctx,
+ "Error adding Scsi_Host rc=0x%x.\n", rc);
goto err6;
+ }
}
memset(&params, 0, sizeof(params));
@@ -3377,7 +3532,9 @@ static void __qedf_remove(struct pci_dev *pdev, int mode)
fcoe_ctlr_link_down(&qedf->ctlr);
else
fc_fabric_logoff(qedf->lport);
- qedf_wait_for_upload(qedf);
+
+ if (qedf_wait_for_upload(qedf) == false)
+ QEDF_ERR(&qedf->dbg_ctx, "Could not upload all sessions.\n");
#ifdef CONFIG_DEBUG_FS
qedf_dbg_host_exit(&(qedf->dbg_ctx));
diff --git a/drivers/scsi/qedf/qedf_version.h b/drivers/scsi/qedf/qedf_version.h
index 9455faacd5de..e57533de7e96 100644
--- a/drivers/scsi/qedf/qedf_version.h
+++ b/drivers/scsi/qedf/qedf_version.h
@@ -1,15 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic FCoE Offload Driver
* Copyright (c) 2016-2018 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
-#define QEDF_VERSION "8.33.16.20"
+#define QEDF_VERSION "8.37.25.20"
#define QEDF_DRIVER_MAJOR_VER 8
-#define QEDF_DRIVER_MINOR_VER 33
-#define QEDF_DRIVER_REV_VER 16
+#define QEDF_DRIVER_MINOR_VER 37
+#define QEDF_DRIVER_REV_VER 25
#define QEDF_DRIVER_ENG_VER 20
diff --git a/drivers/scsi/qedi/Kconfig b/drivers/scsi/qedi/Kconfig
index d1db92d24889..7ab07f3b453f 100644
--- a/drivers/scsi/qedi/Kconfig
+++ b/drivers/scsi/qedi/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config QEDI
tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support"
depends on PCI && SCSI && UIO
diff --git a/drivers/scsi/qedi/Makefile b/drivers/scsi/qedi/Makefile
index 90a6925577cc..d84eedfd031b 100644
--- a/drivers/scsi/qedi/Makefile
+++ b/drivers/scsi/qedi/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_QEDI) := qedi.o
qedi-y := qedi_main.o qedi_iscsi.o qedi_fw.o qedi_sysfs.o \
qedi_dbg.o qedi_fw_api.o
diff --git a/drivers/scsi/qedi/qedi.h b/drivers/scsi/qedi/qedi.h
index a26bb5066b90..9513fd320ffd 100644
--- a/drivers/scsi/qedi/qedi.h
+++ b/drivers/scsi/qedi/qedi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _QEDI_H_
diff --git a/drivers/scsi/qedi/qedi_dbg.c b/drivers/scsi/qedi/qedi_dbg.c
index 8fd28b056f73..2ebef4d20b5b 100644
--- a/drivers/scsi/qedi/qedi_dbg.c
+++ b/drivers/scsi/qedi/qedi_dbg.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include "qedi_dbg.h"
@@ -16,10 +13,6 @@ qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
{
va_list va;
struct va_format vaf;
- char nfunc[32];
-
- memset(nfunc, 0, sizeof(nfunc));
- memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
@@ -28,9 +21,9 @@ qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
if (likely(qedi) && likely(qedi->pdev))
pr_err("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
- nfunc, line, qedi->host_no, &vaf);
+ func, line, qedi->host_no, &vaf);
else
- pr_err("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+ pr_err("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf);
va_end(va);
}
@@ -41,10 +34,6 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
{
va_list va;
struct va_format vaf;
- char nfunc[32];
-
- memset(nfunc, 0, sizeof(nfunc));
- memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
@@ -56,9 +45,9 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
if (likely(qedi) && likely(qedi->pdev))
pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
- nfunc, line, qedi->host_no, &vaf);
+ func, line, qedi->host_no, &vaf);
else
- pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+ pr_warn("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf);
ret:
va_end(va);
@@ -70,10 +59,6 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
{
va_list va;
struct va_format vaf;
- char nfunc[32];
-
- memset(nfunc, 0, sizeof(nfunc));
- memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
@@ -85,10 +70,10 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
if (likely(qedi) && likely(qedi->pdev))
pr_notice("[%s]:[%s:%d]:%d: %pV",
- dev_name(&qedi->pdev->dev), nfunc, line,
+ dev_name(&qedi->pdev->dev), func, line,
qedi->host_no, &vaf);
else
- pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+ pr_notice("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf);
ret:
va_end(va);
@@ -100,10 +85,6 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
{
va_list va;
struct va_format vaf;
- char nfunc[32];
-
- memset(nfunc, 0, sizeof(nfunc));
- memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
@@ -115,9 +96,9 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
if (likely(qedi) && likely(qedi->pdev))
pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
- nfunc, line, qedi->host_no, &vaf);
+ func, line, qedi->host_no, &vaf);
else
- pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
+ pr_info("[0000:00:00.0]:[%s:%d]: %pV", func, line, &vaf);
ret:
va_end(va);
diff --git a/drivers/scsi/qedi/qedi_dbg.h b/drivers/scsi/qedi/qedi_dbg.h
index 0bc9c31d5a4f..243acc8b520a 100644
--- a/drivers/scsi/qedi/qedi_dbg.h
+++ b/drivers/scsi/qedi/qedi_dbg.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _QEDI_DBG_H_
diff --git a/drivers/scsi/qedi/qedi_debugfs.c b/drivers/scsi/qedi/qedi_debugfs.c
index 5667e4752e2e..42f5afb60055 100644
--- a/drivers/scsi/qedi/qedi_debugfs.c
+++ b/drivers/scsi/qedi/qedi_debugfs.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include "qedi.h"
diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index e2a995a6e8e7..946cebc4c932 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include <linux/blkdev.h>
@@ -155,12 +152,10 @@ static void qedi_tmf_resp_work(struct work_struct *work)
struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
struct iscsi_session *session = conn->session;
struct iscsi_tm_rsp *resp_hdr_ptr;
- struct iscsi_cls_session *cls_sess;
int rval = 0;
set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
resp_hdr_ptr = (struct iscsi_tm_rsp *)qedi_cmd->tmf_resp_buf;
- cls_sess = iscsi_conn_to_session(qedi_conn->cls_conn);
iscsi_block_session(session->cls_session);
rval = qedi_cleanup_all_io(qedi, qedi_conn, qedi_cmd->task, true);
@@ -985,7 +980,6 @@ static void qedi_ring_doorbell(struct qedi_conn *qedi_conn)
* others they are two different assembly operations.
*/
wmb();
- mmiowb();
QEDI_INFO(&qedi_conn->qedi->dbg_ctx, QEDI_LOG_MP_REQ,
"prod_idx=0x%x, fw_prod_idx=0x%x, cid=0x%x\n",
qedi_conn->ep->sq_prod_idx, qedi_conn->ep->fw_sq_prod_idx,
@@ -1367,7 +1361,6 @@ static void qedi_tmf_work(struct work_struct *work)
struct qedi_conn *qedi_conn = qedi_cmd->conn;
struct qedi_ctx *qedi = qedi_conn->qedi;
struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
- struct iscsi_cls_session *cls_sess;
struct qedi_work_map *list_work = NULL;
struct iscsi_task *mtask;
struct qedi_cmd *cmd;
@@ -1378,7 +1371,6 @@ static void qedi_tmf_work(struct work_struct *work)
mtask = qedi_cmd->task;
tmf_hdr = (struct iscsi_tm *)mtask->hdr;
- cls_sess = iscsi_conn_to_session(qedi_conn->cls_conn);
set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt);
diff --git a/drivers/scsi/qedi/qedi_fw_api.c b/drivers/scsi/qedi/qedi_fw_api.c
index 387dc87e4d22..52772904ef5d 100644
--- a/drivers/scsi/qedi/qedi_fw_api.c
+++ b/drivers/scsi/qedi/qedi_fw_api.c
@@ -1,9 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include <linux/types.h>
diff --git a/drivers/scsi/qedi/qedi_fw_iscsi.h b/drivers/scsi/qedi/qedi_fw_iscsi.h
index c3deb77ac388..10f19f0af0a3 100644
--- a/drivers/scsi/qedi/qedi_fw_iscsi.h
+++ b/drivers/scsi/qedi/qedi_fw_iscsi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _QEDI_FW_ISCSI_H_
diff --git a/drivers/scsi/qedi/qedi_fw_scsi.h b/drivers/scsi/qedi/qedi_fw_scsi.h
index cdaf918f1019..2524f9f3cf9e 100644
--- a/drivers/scsi/qedi/qedi_fw_scsi.h
+++ b/drivers/scsi/qedi/qedi_fw_scsi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _QEDI_FW_SCSI_H_
diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h
index a2aa06ed1620..8ba7c771ce4d 100644
--- a/drivers/scsi/qedi/qedi_gbl.h
+++ b/drivers/scsi/qedi/qedi_gbl.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _QEDI_GBL_H_
diff --git a/drivers/scsi/qedi/qedi_hsi.h b/drivers/scsi/qedi/qedi_hsi.h
index 8ca44c78f093..d82ab99acb04 100644
--- a/drivers/scsi/qedi/qedi_hsi.h
+++ b/drivers/scsi/qedi/qedi_hsi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef __QEDI_HSI__
#define __QEDI_HSI__
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 6d6d6013e35b..8829880a54c3 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include <linux/blkdev.h>
@@ -579,7 +576,7 @@ static int qedi_conn_start(struct iscsi_cls_conn *cls_conn)
rval = qedi_iscsi_update_conn(qedi, qedi_conn);
if (rval) {
iscsi_conn_printk(KERN_ALERT, conn,
- "conn_start: FW oflload conn failed.\n");
+ "conn_start: FW offload conn failed.\n");
rval = -EINVAL;
goto start_err;
}
@@ -590,7 +587,7 @@ static int qedi_conn_start(struct iscsi_cls_conn *cls_conn)
rval = iscsi_conn_start(cls_conn);
if (rval) {
iscsi_conn_printk(KERN_ALERT, conn,
- "iscsi_conn_start: FW oflload conn failed!!\n");
+ "iscsi_conn_start: FW offload conn failed!!\n");
}
start_err:
@@ -809,8 +806,6 @@ qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
struct qedi_endpoint *qedi_ep;
struct sockaddr_in *addr;
struct sockaddr_in6 *addr6;
- struct qed_dev *cdev = NULL;
- struct qedi_uio_dev *udev = NULL;
struct iscsi_path path_req;
u32 msg_type = ISCSI_KEVENT_IF_DOWN;
u32 iscsi_cid = QEDI_CID_RESERVED;
@@ -830,8 +825,6 @@ qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
}
qedi = iscsi_host_priv(shost);
- cdev = qedi->cdev;
- udev = qedi->udev;
if (test_bit(QEDI_IN_OFFLINE, &qedi->flags) ||
test_bit(QEDI_IN_RECOVERY, &qedi->flags)) {
@@ -993,13 +986,17 @@ static void qedi_ep_disconnect(struct iscsi_endpoint *ep)
struct iscsi_conn *conn = NULL;
struct qedi_ctx *qedi;
int ret = 0;
- int wait_delay = 20 * HZ;
+ int wait_delay;
int abrt_conn = 0;
int count = 10;
+ wait_delay = 60 * HZ + DEF_MAX_RT_TIME;
qedi_ep = ep->dd_data;
qedi = qedi_ep->qedi;
+ if (qedi_ep->state == EP_STATE_OFLDCONN_START)
+ goto ep_exit_recover;
+
flush_work(&qedi_ep->offload_work);
if (qedi_ep->conn) {
@@ -1163,7 +1160,7 @@ static void qedi_offload_work(struct work_struct *work)
struct qedi_endpoint *qedi_ep =
container_of(work, struct qedi_endpoint, offload_work);
struct qedi_ctx *qedi;
- int wait_delay = 20 * HZ;
+ int wait_delay = 5 * HZ;
int ret;
qedi = qedi_ep->qedi;
diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h
index 892d70d54553..67c3b7349271 100644
--- a/drivers/scsi/qedi/qedi_iscsi.h
+++ b/drivers/scsi/qedi/qedi_iscsi.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef _QEDI_ISCSI_H_
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index e5db9a9954dc..acb930b8c6a6 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include <linux/module.h>
@@ -990,6 +987,9 @@ static int qedi_find_boot_info(struct qedi_ctx *qedi,
if (!iscsi_is_session_online(cls_sess))
continue;
+ if (!sess->targetname)
+ continue;
+
if (pri_ctrl_flags) {
if (!strcmp(pri_tgt->iscsi_name, sess->targetname) &&
!strcmp(pri_tgt->ip_addr, ep_ip_addr)) {
@@ -1313,13 +1313,20 @@ static void qedi_simd_int_handler(void *cookie)
static void qedi_sync_free_irqs(struct qedi_ctx *qedi)
{
int i;
+ u16 idx;
if (qedi->int_info.msix_cnt) {
for (i = 0; i < qedi->int_info.used_cnt; i++) {
- synchronize_irq(qedi->int_info.msix[i].vector);
- irq_set_affinity_hint(qedi->int_info.msix[i].vector,
+ idx = i * qedi->dev_info.common.num_hwfns +
+ qedi_ops->common->get_affin_hwfn_idx(qedi->cdev);
+
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+ "Freeing IRQ #%d vector_idx=%d.\n", i, idx);
+
+ synchronize_irq(qedi->int_info.msix[idx].vector);
+ irq_set_affinity_hint(qedi->int_info.msix[idx].vector,
NULL);
- free_irq(qedi->int_info.msix[i].vector,
+ free_irq(qedi->int_info.msix[idx].vector,
&qedi->fp_array[i]);
}
} else {
@@ -1334,20 +1341,28 @@ static void qedi_sync_free_irqs(struct qedi_ctx *qedi)
static int qedi_request_msix_irq(struct qedi_ctx *qedi)
{
int i, rc, cpu;
+ u16 idx;
cpu = cpumask_first(cpu_online_mask);
- for (i = 0; i < qedi->int_info.msix_cnt; i++) {
- rc = request_irq(qedi->int_info.msix[i].vector,
+ for (i = 0; i < MIN_NUM_CPUS_MSIX(qedi); i++) {
+ idx = i * qedi->dev_info.common.num_hwfns +
+ qedi_ops->common->get_affin_hwfn_idx(qedi->cdev);
+
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+ "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n",
+ qedi->dev_info.common.num_hwfns,
+ qedi_ops->common->get_affin_hwfn_idx(qedi->cdev));
+
+ rc = request_irq(qedi->int_info.msix[idx].vector,
qedi_msix_handler, 0, "qedi",
&qedi->fp_array[i]);
-
if (rc) {
QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n");
qedi_sync_free_irqs(qedi);
return rc;
}
qedi->int_info.used_cnt++;
- rc = irq_set_affinity_hint(qedi->int_info.msix[i].vector,
+ rc = irq_set_affinity_hint(qedi->int_info.msix[idx].vector,
get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
@@ -2415,6 +2430,11 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
if (rc)
goto free_host;
+ QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+ "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n",
+ qedi->dev_info.common.num_hwfns,
+ qedi_ops->common->get_affin_hwfn_idx(qedi->cdev));
+
if (mode != QEDI_MODE_RECOVERY) {
rc = qedi_set_iscsi_pf_param(qedi);
if (rc) {
diff --git a/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h b/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h
index df39b69b366d..760864e43680 100644
--- a/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h
+++ b/drivers/scsi/qedi/qedi_nvm_iscsi_cfg.h
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#ifndef NVM_ISCSI_CFG_H
diff --git a/drivers/scsi/qedi/qedi_sysfs.c b/drivers/scsi/qedi/qedi_sysfs.c
index b10c48bd1428..04ee68e6499c 100644
--- a/drivers/scsi/qedi/qedi_sysfs.c
+++ b/drivers/scsi/qedi/qedi_sysfs.c
@@ -1,10 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
#include "qedi.h"
diff --git a/drivers/scsi/qedi/qedi_version.h b/drivers/scsi/qedi/qedi_version.h
index 41bcbbafebd4..0ac1055bd420 100644
--- a/drivers/scsi/qedi/qedi_version.h
+++ b/drivers/scsi/qedi/qedi_version.h
@@ -1,14 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
- *
- * This software is available under the terms of the GNU General Public License
- * (GPL) Version 2, available from the file COPYING in the main directory of
- * this source tree.
*/
-#define QEDI_MODULE_VERSION "8.33.0.21"
+#define QEDI_MODULE_VERSION "8.37.0.20"
#define QEDI_DRIVER_MAJOR_VER 8
-#define QEDI_DRIVER_MINOR_VER 33
+#define QEDI_DRIVER_MINOR_VER 37
#define QEDI_DRIVER_REV_VER 0
-#define QEDI_DRIVER_ENG_VER 21
+#define QEDI_DRIVER_ENG_VER 20
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 6856dfdfa473..e5760c4a27f0 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/******************************************************************************
* QLOGIC LINUX SOFTWARE
*
@@ -6,16 +7,6 @@
* Copyright (C) 2001-2004 Jes Sorensen, Wild Open Source Inc.
* Copyright (C) 2003-2004 Christoph Hellwig
*
-* 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, 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.
-*
******************************************************************************/
#define QLA1280_VERSION "3.27.1"
/*****************************************************************************
@@ -3004,8 +2995,6 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
sp->flags |= SRB_SENT;
ha->actthreads++;
WRT_REG_WORD(&reg->mailbox4, ha->req_ring_index);
- /* Enforce mmio write ordering; see comment in qla1280_isp_cmd(). */
- mmiowb();
out:
if (status)
@@ -3254,8 +3243,6 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
sp->flags |= SRB_SENT;
ha->actthreads++;
WRT_REG_WORD(&reg->mailbox4, ha->req_ring_index);
- /* Enforce mmio write ordering; see comment in qla1280_isp_cmd(). */
- mmiowb();
out:
if (status)
@@ -3367,19 +3354,8 @@ qla1280_isp_cmd(struct scsi_qla_host *ha)
/*
* Update request index to mailbox4 (Request Queue In).
- * The mmiowb() ensures that this write is ordered with writes by other
- * CPUs. Without the mmiowb(), it is possible for the following:
- * CPUA posts write of index 5 to mailbox4
- * CPUA releases host lock
- * CPUB acquires host lock
- * CPUB posts write of index 6 to mailbox4
- * On PCI bus, order reverses and write of 6 posts, then index 5,
- * causing chip to issue full queue of stale commands
- * The mmiowb() prevents future writes from crossing the barrier.
- * See Documentation/driver-api/device-io.rst for more information.
*/
WRT_REG_WORD(&reg->mailbox4, ha->req_ring_index);
- mmiowb();
LEAVE("qla1280_isp_cmd");
}
diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
index 1522aca2c8c8..b496206362a9 100644
--- a/drivers/scsi/qla1280.h
+++ b/drivers/scsi/qla1280.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/******************************************************************************
* QLOGIC LINUX SOFTWARE
*
@@ -5,16 +6,6 @@
* Copyright (C) 2000 Qlogic Corporation
* (www.qlogic.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, 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.
-*
******************************************************************************/
#ifndef _QLA1280_H
diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig
index 036cc3f217b1..764501838e21 100644
--- a/drivers/scsi/qla2xxx/Kconfig
+++ b/drivers/scsi/qla2xxx/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_QLA_FC
tristate "QLogic QLA2XXX Fibre Channel Support"
depends on PCI && SCSI
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index f928c4d3a1ef..8d560c562e9c 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -29,24 +29,27 @@ qla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
if (!(ha->fw_dump_reading || ha->mctp_dump_reading))
return 0;
+ mutex_lock(&ha->optrom_mutex);
if (IS_P3P_TYPE(ha)) {
if (off < ha->md_template_size) {
rval = memory_read_from_buffer(buf, count,
&off, ha->md_tmplt_hdr, ha->md_template_size);
- return rval;
+ } else {
+ off -= ha->md_template_size;
+ rval = memory_read_from_buffer(buf, count,
+ &off, ha->md_dump, ha->md_dump_size);
}
- off -= ha->md_template_size;
- rval = memory_read_from_buffer(buf, count,
- &off, ha->md_dump, ha->md_dump_size);
- return rval;
- } else if (ha->mctp_dumped && ha->mctp_dump_reading)
- return memory_read_from_buffer(buf, count, &off, ha->mctp_dump,
+ } else if (ha->mctp_dumped && ha->mctp_dump_reading) {
+ rval = memory_read_from_buffer(buf, count, &off, ha->mctp_dump,
MCTP_DUMP_SIZE);
- else if (ha->fw_dump_reading)
- return memory_read_from_buffer(buf, count, &off, ha->fw_dump,
+ } else if (ha->fw_dump_reading) {
+ rval = memory_read_from_buffer(buf, count, &off, ha->fw_dump,
ha->fw_dump_len);
- else
- return 0;
+ } else {
+ rval = 0;
+ }
+ mutex_unlock(&ha->optrom_mutex);
+ return rval;
}
static ssize_t
@@ -154,6 +157,8 @@ qla2x00_sysfs_read_nvram(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;
+ struct active_regions active_regions = { };
if (!capable(CAP_SYS_ADMIN))
return 0;
@@ -164,11 +169,21 @@ qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
return -EAGAIN;
}
- if (IS_NOCACHE_VPD_TYPE(ha))
- ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
- ha->nvram_size);
+ if (!IS_NOCACHE_VPD_TYPE(ha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ goto skip;
+ }
+
+ faddr = ha->flt_region_nvram;
+ if (IS_QLA28XX(ha)) {
+ if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_nvram_sec;
+ }
+ ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, ha->nvram_size);
+
mutex_unlock(&ha->optrom_mutex);
+skip:
return memory_read_from_buffer(buf, count, &off, ha->nvram,
ha->nvram_size);
}
@@ -223,9 +238,9 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
}
/* Write NVRAM. */
- ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->nvram_base, count);
- ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base,
- count);
+ ha->isp_ops->write_nvram(vha, buf, ha->nvram_base, count);
+ ha->isp_ops->read_nvram(vha, ha->nvram, ha->nvram_base,
+ count);
mutex_unlock(&ha->optrom_mutex);
ql_dbg(ql_dbg_user, vha, 0x7060,
@@ -364,7 +379,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
}
ha->optrom_region_start = start;
- ha->optrom_region_size = start + size;
+ ha->optrom_region_size = size;
ha->optrom_state = QLA_SREADING;
ha->optrom_buffer = vmalloc(ha->optrom_region_size);
@@ -418,6 +433,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
* 0x000000 -> 0x07ffff -- Boot code.
* 0x080000 -> 0x0fffff -- Firmware.
* 0x120000 -> 0x12ffff -- VPD and HBA parameters.
+ *
+ * > ISP25xx type boards:
+ *
+ * None -- should go through BSG.
*/
valid = 0;
if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
@@ -425,9 +444,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
else if (start == (ha->flt_region_boot * 4) ||
start == (ha->flt_region_fw * 4))
valid = 1;
- else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)
- || IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)
- || IS_QLA27XX(ha))
+ else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
valid = 1;
if (!valid) {
ql_log(ql_log_warn, vha, 0x7065,
@@ -437,7 +454,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
}
ha->optrom_region_start = start;
- ha->optrom_region_size = start + size;
+ ha->optrom_region_size = size;
ha->optrom_state = QLA_SWRITING;
ha->optrom_buffer = vmalloc(ha->optrom_region_size);
@@ -504,6 +521,7 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
uint32_t faddr;
+ struct active_regions active_regions = { };
if (unlikely(pci_channel_offline(ha->pdev)))
return -EAGAIN;
@@ -511,22 +529,33 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EINVAL;
- if (IS_NOCACHE_VPD_TYPE(ha)) {
- faddr = ha->flt_region_vpd << 2;
+ if (IS_NOCACHE_VPD_TYPE(ha))
+ goto skip;
+
+ faddr = ha->flt_region_vpd << 2;
- if (IS_QLA27XX(ha) &&
- qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE)
+ if (IS_QLA28XX(ha)) {
+ qla28xx_get_aux_images(vha, &active_regions);
+ if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
faddr = ha->flt_region_vpd_sec << 2;
- mutex_lock(&ha->optrom_mutex);
- if (qla2x00_chip_is_down(vha)) {
- mutex_unlock(&ha->optrom_mutex);
- return -EAGAIN;
- }
- ha->isp_ops->read_optrom(vha, ha->vpd, faddr,
- ha->vpd_size);
+ ql_dbg(ql_dbg_init, vha, 0x7070,
+ "Loading %s nvram image.\n",
+ active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
+ "primary" : "secondary");
+ }
+
+ mutex_lock(&ha->optrom_mutex);
+ if (qla2x00_chip_is_down(vha)) {
mutex_unlock(&ha->optrom_mutex);
+ return -EAGAIN;
}
+
+ ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
+ mutex_unlock(&ha->optrom_mutex);
+
+ ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
+skip:
return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
}
@@ -563,8 +592,8 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
}
/* Write NVRAM. */
- ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->vpd_base, count);
- ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, ha->vpd_base, count);
+ ha->isp_ops->write_nvram(vha, buf, ha->vpd_base, count);
+ ha->isp_ops->read_nvram(vha, ha->vpd, ha->vpd_base, count);
/* Update flash version information for 4Gb & above. */
if (!IS_FWI2_CAPABLE(ha)) {
@@ -645,6 +674,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
int type;
uint32_t idc_control;
uint8_t *tmp_data = NULL;
+
if (off != 0)
return -EINVAL;
@@ -682,7 +712,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
ql_log(ql_log_info, vha, 0x706f,
"Issuing MPI reset.\n");
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
uint32_t idc_control;
qla83xx_idc_lock(vha, 0);
@@ -858,7 +888,7 @@ do_read:
count = 0;
}
- count = actual_size > count ? count: actual_size;
+ count = actual_size > count ? count : actual_size;
memcpy(buf, ha->xgmac_data, count);
return count;
@@ -934,7 +964,7 @@ static struct bin_attribute sysfs_dcbx_tlv_attr = {
static struct sysfs_entry {
char *name;
struct bin_attribute *attr;
- int is4GBp_only;
+ int type;
} bin_file_entries[] = {
{ "fw_dump", &sysfs_fw_dump_attr, },
{ "nvram", &sysfs_nvram_attr, },
@@ -957,11 +987,11 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
int ret;
for (iter = bin_file_entries; iter->name; iter++) {
- if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw))
+ if (iter->type && !IS_FWI2_CAPABLE(vha->hw))
continue;
- if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw))
+ if (iter->type == 2 && !IS_QLA25XX(vha->hw))
continue;
- if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
+ if (iter->type == 3 && !(IS_CNA_CAPABLE(vha->hw)))
continue;
ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
@@ -985,13 +1015,14 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon)
struct qla_hw_data *ha = vha->hw;
for (iter = bin_file_entries; iter->name; iter++) {
- if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
+ if (iter->type && !IS_FWI2_CAPABLE(ha))
continue;
- if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
+ if (iter->type == 2 && !IS_QLA25XX(ha))
continue;
- if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
+ if (iter->type == 3 && !(IS_CNA_CAPABLE(ha)))
continue;
- if (iter->is4GBp_only == 0x27 && !IS_QLA27XX(vha->hw))
+ if (iter->type == 0x27 &&
+ (!IS_QLA27XX(ha) || !IS_QLA28XX(ha)))
continue;
sysfs_remove_bin_file(&host->shost_gendev.kobj,
@@ -1049,6 +1080,7 @@ qla2x00_isp_name_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
return scnprintf(buf, PAGE_SIZE, "ISP%04X\n", vha->hw->pdev->device);
}
@@ -1082,6 +1114,7 @@ qla2x00_model_desc_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
return scnprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_desc);
}
@@ -1294,6 +1327,7 @@ qla2x00_optrom_bios_version_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
+
return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
ha->bios_revision[0]);
}
@@ -1304,6 +1338,7 @@ qla2x00_optrom_efi_version_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
+
return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
ha->efi_revision[0]);
}
@@ -1314,6 +1349,7 @@ qla2x00_optrom_fcode_version_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
+
return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
ha->fcode_revision[0]);
}
@@ -1324,6 +1360,7 @@ qla2x00_optrom_fw_version_show(struct device *dev,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
+
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
ha->fw_revision[3]);
@@ -1336,7 +1373,8 @@ qla2x00_optrom_gold_fw_version_show(struct device *dev,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
@@ -1349,6 +1387,7 @@ qla2x00_total_isp_aborts_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
return scnprintf(buf, PAGE_SIZE, "%d\n",
vha->qla_stats.total_isp_aborts);
}
@@ -1358,24 +1397,40 @@ qla24xx_84xx_fw_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int rval = QLA_SUCCESS;
- uint16_t status[2] = {0, 0};
+ uint16_t status[2] = { 0 };
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA84XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
- if (ha->cs84xx->op_fw_version == 0)
+ if (!ha->cs84xx->op_fw_version) {
rval = qla84xx_verify_chip(vha, status);
- if ((rval == QLA_SUCCESS) && (status[0] == 0))
- return scnprintf(buf, PAGE_SIZE, "%u\n",
- (uint32_t)ha->cs84xx->op_fw_version);
+ if (!rval && !status[0])
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ (uint32_t)ha->cs84xx->op_fw_version);
+ }
return scnprintf(buf, PAGE_SIZE, "\n");
}
static ssize_t
+qla2x00_serdes_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+ return scnprintf(buf, PAGE_SIZE, "\n");
+
+ return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
+ ha->serdes_version[0], ha->serdes_version[1],
+ ha->serdes_version[2]);
+}
+
+static ssize_t
qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1383,7 +1438,7 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha) &&
- !IS_QLA27XX(ha))
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
@@ -1596,7 +1651,7 @@ qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA27XX(ha))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
@@ -1604,35 +1659,38 @@ qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr,
}
static ssize_t
-qla2x00_min_link_speed_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+qla2x00_min_supported_speed_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA27XX(ha))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
return scnprintf(buf, PAGE_SIZE, "%s\n",
- ha->min_link_speed == 5 ? "32Gps" :
- ha->min_link_speed == 4 ? "16Gps" :
- ha->min_link_speed == 3 ? "8Gps" :
- ha->min_link_speed == 2 ? "4Gps" :
- ha->min_link_speed != 0 ? "unknown" : "");
+ ha->min_supported_speed == 6 ? "64Gps" :
+ ha->min_supported_speed == 5 ? "32Gps" :
+ ha->min_supported_speed == 4 ? "16Gps" :
+ ha->min_supported_speed == 3 ? "8Gps" :
+ ha->min_supported_speed == 2 ? "4Gps" :
+ ha->min_supported_speed != 0 ? "unknown" : "");
}
static ssize_t
-qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+qla2x00_max_supported_speed_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA27XX(ha))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return scnprintf(buf, PAGE_SIZE, "\n");
return scnprintf(buf, PAGE_SIZE, "%s\n",
- ha->max_speed_sup ? "32Gps" : "16Gps");
+ ha->max_supported_speed == 2 ? "64Gps" :
+ ha->max_supported_speed == 1 ? "32Gps" :
+ ha->max_supported_speed == 0 ? "16Gps" : "unknown");
}
static ssize_t
@@ -1645,7 +1703,7 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
int mode = QLA_SET_DATA_RATE_LR;
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA27XX(vha->hw)) {
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
ql_log(ql_log_warn, vha, 0x70d8,
"Speed setting not supported \n");
return -EINVAL;
@@ -2164,6 +2222,32 @@ qla2x00_dif_bundle_statistics_show(struct device *dev,
ha->dif_bundle_dma_allocs, ha->pool.unusable.count);
}
+static ssize_t
+qla2x00_fw_attr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+ return scnprintf(buf, PAGE_SIZE, "\n");
+
+ return scnprintf(buf, PAGE_SIZE, "%llx\n",
+ (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);
+}
+
+static ssize_t
+qla2x00_port_no_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", vha->hw->port_no);
+}
+
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_driver_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -2192,6 +2276,7 @@ static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show,
NULL);
static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
NULL);
+static DEVICE_ATTR(serdes_version, 0444, qla2x00_serdes_version_show, NULL);
static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL);
static DEVICE_ATTR(phy_version, S_IRUGO, qla2x00_phy_version_show, NULL);
static DEVICE_ATTR(flash_block_size, S_IRUGO, qla2x00_flash_block_size_show,
@@ -2209,8 +2294,10 @@ static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR,
qla2x00_allow_cna_fw_dump_show,
qla2x00_allow_cna_fw_dump_store);
static DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL);
-static DEVICE_ATTR(min_link_speed, S_IRUGO, qla2x00_min_link_speed_show, NULL);
-static DEVICE_ATTR(max_speed_sup, S_IRUGO, qla2x00_max_speed_sup_show, NULL);
+static DEVICE_ATTR(min_supported_speed, 0444,
+ qla2x00_min_supported_speed_show, NULL);
+static DEVICE_ATTR(max_supported_speed, 0444,
+ qla2x00_max_supported_speed_show, NULL);
static DEVICE_ATTR(zio_threshold, 0644,
qla_zio_threshold_show,
qla_zio_threshold_store);
@@ -2221,6 +2308,8 @@ static DEVICE_ATTR(dif_bundle_statistics, 0444,
qla2x00_dif_bundle_statistics_show, NULL);
static DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show,
qla2x00_port_speed_store);
+static DEVICE_ATTR(port_no, 0444, qla2x00_port_no_show, NULL);
+static DEVICE_ATTR(fw_attr, 0444, qla2x00_fw_attr_show, NULL);
struct device_attribute *qla2x00_host_attrs[] = {
@@ -2242,6 +2331,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_optrom_fw_version,
&dev_attr_84xx_fw_version,
&dev_attr_total_isp_aborts,
+ &dev_attr_serdes_version,
&dev_attr_mpi_version,
&dev_attr_phy_version,
&dev_attr_flash_block_size,
@@ -2256,11 +2346,13 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_fw_dump_size,
&dev_attr_allow_cna_fw_dump,
&dev_attr_pep_version,
- &dev_attr_min_link_speed,
- &dev_attr_max_speed_sup,
+ &dev_attr_min_supported_speed,
+ &dev_attr_max_supported_speed,
&dev_attr_zio_threshold,
&dev_attr_dif_bundle_statistics,
&dev_attr_port_speed,
+ &dev_attr_port_no,
+ &dev_attr_fw_attr,
NULL, /* reserve for qlini_mode */
NULL, /* reserve for ql2xiniexchg */
NULL, /* reserve for ql2xexchoffld */
@@ -2296,16 +2388,15 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost)
static void
qla2x00_get_host_speed(struct Scsi_Host *shost)
{
- struct qla_hw_data *ha = ((struct scsi_qla_host *)
- (shost_priv(shost)))->hw;
- u32 speed = FC_PORTSPEED_UNKNOWN;
+ scsi_qla_host_t *vha = shost_priv(shost);
+ u32 speed;
- if (IS_QLAFX00(ha)) {
+ if (IS_QLAFX00(vha->hw)) {
qlafx00_get_host_speed(shost);
return;
}
- switch (ha->link_data_rate) {
+ switch (vha->hw->link_data_rate) {
case PORT_SPEED_1GB:
speed = FC_PORTSPEED_1GBIT;
break;
@@ -2327,7 +2418,14 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
case PORT_SPEED_32GB:
speed = FC_PORTSPEED_32GBIT;
break;
+ case PORT_SPEED_64GB:
+ speed = FC_PORTSPEED_64GBIT;
+ break;
+ default:
+ speed = FC_PORTSPEED_UNKNOWN;
+ break;
}
+
fc_host_speed(shost) = speed;
}
@@ -2335,7 +2433,7 @@ static void
qla2x00_get_host_port_type(struct Scsi_Host *shost)
{
scsi_qla_host_t *vha = shost_priv(shost);
- uint32_t port_type = FC_PORTTYPE_UNKNOWN;
+ uint32_t port_type;
if (vha->vp_idx) {
fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
@@ -2354,7 +2452,11 @@ qla2x00_get_host_port_type(struct Scsi_Host *shost)
case ISP_CFG_F:
port_type = FC_PORTTYPE_NPORT;
break;
+ default:
+ port_type = FC_PORTTYPE_UNKNOWN;
+ break;
}
+
fc_host_port_type(shost) = port_type;
}
@@ -2416,13 +2518,10 @@ qla2x00_get_starget_port_id(struct scsi_target *starget)
fc_starget_port_id(starget) = port_id;
}
-static void
+static inline void
qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
{
- if (timeout)
- rport->dev_loss_tmo = timeout;
- else
- rport->dev_loss_tmo = 1;
+ rport->dev_loss_tmo = timeout ? timeout : 1;
}
static void
@@ -2632,8 +2731,9 @@ static void
qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
{
scsi_qla_host_t *vha = shost_priv(shost);
- uint8_t node_name[WWN_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, \
- 0xFF, 0xFF, 0xFF, 0xFF};
+ static const uint8_t node_name[WWN_SIZE] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
u64 fabric_name = wwn_to_u64(node_name);
if (vha->device_flags & SWITCH_FOUND)
@@ -2711,8 +2811,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
/* initialized vport states */
atomic_set(&vha->loop_state, LOOP_DOWN);
- vha->vp_err_state= VP_ERR_PORTDWN;
- vha->vp_prev_err_state= VP_ERR_UNKWN;
+ vha->vp_err_state = VP_ERR_PORTDWN;
+ vha->vp_prev_err_state = VP_ERR_UNKWN;
/* Check if physical ha port is Up */
if (atomic_read(&base_vha->loop_state) == LOOP_DOWN ||
atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
@@ -2727,6 +2827,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
int prot = 0, guard;
+
vha->flags.difdix_supported = 1;
ql_dbg(ql_dbg_user, vha, 0x7082,
"Registered for DIF/DIX type 1 and 3 protection.\n");
@@ -2977,7 +3078,7 @@ void
qla2x00_init_host_attr(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
- u32 speed = FC_PORTSPEED_UNKNOWN;
+ u32 speeds = FC_PORTSPEED_UNKNOWN;
fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count;
fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
@@ -2988,25 +3089,45 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count;
if (IS_CNA_CAPABLE(ha))
- speed = FC_PORTSPEED_10GBIT;
- else if (IS_QLA2031(ha))
- speed = FC_PORTSPEED_16GBIT | FC_PORTSPEED_8GBIT |
- FC_PORTSPEED_4GBIT;
- else if (IS_QLA25XX(ha))
- speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
- FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
+ speeds = FC_PORTSPEED_10GBIT;
+ else if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
+ if (ha->max_supported_speed == 2) {
+ if (ha->min_supported_speed <= 6)
+ speeds |= FC_PORTSPEED_64GBIT;
+ }
+ if (ha->max_supported_speed == 2 ||
+ ha->max_supported_speed == 1) {
+ if (ha->min_supported_speed <= 5)
+ speeds |= FC_PORTSPEED_32GBIT;
+ }
+ if (ha->max_supported_speed == 2 ||
+ ha->max_supported_speed == 1 ||
+ ha->max_supported_speed == 0) {
+ if (ha->min_supported_speed <= 4)
+ speeds |= FC_PORTSPEED_16GBIT;
+ }
+ if (ha->max_supported_speed == 1 ||
+ ha->max_supported_speed == 0) {
+ if (ha->min_supported_speed <= 3)
+ speeds |= FC_PORTSPEED_8GBIT;
+ }
+ if (ha->max_supported_speed == 0) {
+ if (ha->min_supported_speed <= 2)
+ speeds |= FC_PORTSPEED_4GBIT;
+ }
+ } else if (IS_QLA2031(ha))
+ speeds = FC_PORTSPEED_16GBIT|FC_PORTSPEED_8GBIT|
+ FC_PORTSPEED_4GBIT;
+ else if (IS_QLA25XX(ha) || IS_QLAFX00(ha))
+ speeds = FC_PORTSPEED_8GBIT|FC_PORTSPEED_4GBIT|
+ FC_PORTSPEED_2GBIT|FC_PORTSPEED_1GBIT;
else if (IS_QLA24XX_TYPE(ha))
- speed = FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
- FC_PORTSPEED_1GBIT;
+ speeds = FC_PORTSPEED_4GBIT|FC_PORTSPEED_2GBIT|
+ FC_PORTSPEED_1GBIT;
else if (IS_QLA23XX(ha))
- speed = FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
- else if (IS_QLAFX00(ha))
- speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
- FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
- else if (IS_QLA27XX(ha))
- speed = FC_PORTSPEED_32GBIT | FC_PORTSPEED_16GBIT |
- FC_PORTSPEED_8GBIT;
+ speeds = FC_PORTSPEED_2GBIT|FC_PORTSPEED_1GBIT;
else
- speed = FC_PORTSPEED_1GBIT;
- fc_host_supported_speeds(vha->host) = speed;
+ speeds = FC_PORTSPEED_1GBIT;
+
+ fc_host_supported_speeds(vha->host) = speeds;
}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 17d42658ad9a..5441557b424b 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1,4 +1,4 @@
- /*
+/*
* QLogic Fibre Channel HBA Driver
* Copyright (c) 2003-2014 QLogic Corporation
*
@@ -84,8 +84,7 @@ qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha,
return 0;
}
- if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' ||
- bcode[3] != 'S') {
+ if (memcmp(bcode, "HQOS", 4)) {
/* Invalid FCP priority data header*/
ql_dbg(ql_dbg_user, vha, 0x7052,
"Invalid FCP Priority data header. bcode=0x%x.\n",
@@ -1044,7 +1043,7 @@ qla84xx_updatefw(struct bsg_job *bsg_job)
}
flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
- fw_ver = le32_to_cpu(*((uint32_t *)((uint32_t *)fw_buf + 2)));
+ fw_ver = get_unaligned_le32((uint32_t *)fw_buf + 2);
mn->entry_type = VERIFY_CHIP_IOCB_TYPE;
mn->entry_count = 1;
@@ -1057,9 +1056,8 @@ qla84xx_updatefw(struct bsg_job *bsg_job)
mn->fw_ver = cpu_to_le32(fw_ver);
mn->fw_size = cpu_to_le32(data_len);
mn->fw_seq_size = cpu_to_le32(data_len);
- mn->dseg_address[0] = cpu_to_le32(LSD(fw_dma));
- mn->dseg_address[1] = cpu_to_le32(MSD(fw_dma));
- mn->dseg_length = cpu_to_le32(data_len);
+ put_unaligned_le64(fw_dma, &mn->dsd.address);
+ mn->dsd.length = cpu_to_le32(data_len);
mn->data_seg_cnt = cpu_to_le16(1);
rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);
@@ -1238,9 +1236,8 @@ qla84xx_mgmt_cmd(struct bsg_job *bsg_job)
if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) {
mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len);
mn->dseg_count = cpu_to_le16(1);
- mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma));
- mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma));
- mn->dseg_length = cpu_to_le32(ql84_mgmt->mgmt.len);
+ put_unaligned_le64(mgmt_dma, &mn->dsd.address);
+ mn->dsd.length = cpu_to_le32(ql84_mgmt->mgmt.len);
}
rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0);
@@ -1354,7 +1351,7 @@ qla24xx_iidma(struct bsg_job *bsg_job)
if (rval) {
ql_log(ql_log_warn, vha, 0x704c,
- "iIDMA cmd failed for %8phN -- "
+ "iiDMA cmd failed for %8phN -- "
"%04x %x %04x %04x.\n", fcport->port_name,
rval, fcport->fp_speed, mb[0], mb[1]);
rval = (DID_ERROR << 16);
@@ -1412,7 +1409,8 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
start == (ha->flt_region_fw * 4))
valid = 1;
else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
- IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha))
+ IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha))
valid = 1;
if (!valid) {
ql_log(ql_log_warn, vha, 0x7058,
@@ -1534,6 +1532,7 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job)
uint32_t count;
dma_addr_t sfp_dma;
void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
+
if (!sfp) {
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
EXT_STATUS_NO_MEMORY;
@@ -1584,6 +1583,7 @@ qla2x00_read_fru_status(struct bsg_job *bsg_job)
struct qla_status_reg *sr = (void *)bsg;
dma_addr_t sfp_dma;
uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
+
if (!sfp) {
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
EXT_STATUS_NO_MEMORY;
@@ -1634,6 +1634,7 @@ qla2x00_write_fru_status(struct bsg_job *bsg_job)
struct qla_status_reg *sr = (void *)bsg;
dma_addr_t sfp_dma;
uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
+
if (!sfp) {
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
EXT_STATUS_NO_MEMORY;
@@ -1680,6 +1681,7 @@ qla2x00_write_i2c(struct bsg_job *bsg_job)
struct qla_i2c_access *i2c = (void *)bsg;
dma_addr_t sfp_dma;
uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
+
if (!sfp) {
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
EXT_STATUS_NO_MEMORY;
@@ -1725,6 +1727,7 @@ qla2x00_read_i2c(struct bsg_job *bsg_job)
struct qla_i2c_access *i2c = (void *)bsg;
dma_addr_t sfp_dma;
uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
+
if (!sfp) {
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
EXT_STATUS_NO_MEMORY;
@@ -1961,7 +1964,7 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_job)
/* Dump the vendor information */
ql_dump_buffer(ql_dbg_user + ql_dbg_verbose , vha, 0x70cf,
- (uint8_t *)piocb_rqst, sizeof(struct qla_mt_iocb_rqst_fx00));
+ piocb_rqst, sizeof(*piocb_rqst));
if (!vha->flags.online) {
ql_log(ql_log_warn, vha, 0x70d0,
@@ -2157,7 +2160,7 @@ qla27xx_get_flash_upd_cap(struct bsg_job *bsg_job)
struct qla_hw_data *ha = vha->hw;
struct qla_flash_update_caps cap;
- if (!(IS_QLA27XX(ha)))
+ if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha))
return -EPERM;
memset(&cap, 0, sizeof(cap));
@@ -2190,7 +2193,7 @@ qla27xx_set_flash_upd_cap(struct bsg_job *bsg_job)
uint64_t online_fw_attr = 0;
struct qla_flash_update_caps cap;
- if (!(IS_QLA27XX(ha)))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return -EPERM;
memset(&cap, 0, sizeof(cap));
@@ -2238,7 +2241,7 @@ qla27xx_get_bbcr_data(struct bsg_job *bsg_job)
uint8_t domain, area, al_pa, state;
int rval;
- if (!(IS_QLA27XX(ha)))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return -EPERM;
memset(&bbcr, 0, sizeof(bbcr));
@@ -2323,8 +2326,8 @@ qla2x00_get_priv_stats(struct bsg_job *bsg_job)
rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, options);
if (rval == QLA_SUCCESS) {
- ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e3,
- (uint8_t *)stats, sizeof(*stats));
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x70e5,
+ stats, sizeof(*stats));
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt, stats, sizeof(*stats));
}
@@ -2353,7 +2356,8 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
int rval;
struct qla_dport_diag *dd;
- if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw))
+ if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
+ !IS_QLA28XX(vha->hw))
return -EPERM;
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
@@ -2388,6 +2392,45 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
}
static int
+qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
+{
+ scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
+ struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+ struct qla_hw_data *ha = vha->hw;
+ struct qla_active_regions regions = { };
+ struct active_regions active_regions = { };
+
+ qla28xx_get_aux_images(vha, &active_regions);
+ regions.global_image = active_regions.global;
+
+ if (IS_QLA28XX(ha)) {
+ qla27xx_get_active_image(vha, &active_regions);
+ regions.board_config = active_regions.aux.board_config;
+ regions.vpd_nvram = active_regions.aux.vpd_nvram;
+ regions.npiv_config_0_1 = active_regions.aux.npiv_config_0_1;
+ regions.npiv_config_2_3 = active_regions.aux.npiv_config_2_3;
+ }
+
+ ql_dbg(ql_dbg_user, vha, 0x70e1,
+ "%s(%lu): FW=%u BCFG=%u VPDNVR=%u NPIV01=%u NPIV02=%u\n",
+ __func__, vha->host_no, regions.global_image,
+ regions.board_config, regions.vpd_nvram,
+ regions.npiv_config_0_1, regions.npiv_config_2_3);
+
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, &regions, sizeof(regions));
+
+ bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+ bsg_reply->reply_payload_rcv_len = sizeof(regions);
+ bsg_reply->result = DID_OK << 16;
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job_done(bsg_job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
+
+ return 0;
+}
+
+static int
qla2x00_process_vendor_specific(struct bsg_job *bsg_job)
{
struct fc_bsg_request *bsg_request = bsg_job->request;
@@ -2460,6 +2503,9 @@ qla2x00_process_vendor_specific(struct bsg_job *bsg_job)
case QL_VND_DPORT_DIAGNOSTICS:
return qla2x00_do_dport_diagnostics(bsg_job);
+ case QL_VND_SS_GET_FLASH_IMAGE_STATUS:
+ return qla2x00_get_flash_image_status(bsg_job);
+
default:
return -ENOSYS;
}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index d97dfd521356..7594fad7b5b5 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -31,6 +31,7 @@
#define QL_VND_GET_PRIV_STATS 0x18
#define QL_VND_DPORT_DIAGNOSTICS 0x19
#define QL_VND_GET_PRIV_STATS_EX 0x1A
+#define QL_VND_SS_GET_FLASH_IMAGE_STATUS 0x1E
/* BSG Vendor specific subcode returns */
#define EXT_STATUS_OK 0
@@ -279,4 +280,14 @@ struct qla_dport_diag {
#define QLA_DPORT_RESULT 0x0
#define QLA_DPORT_START 0x2
+/* active images in flash */
+struct qla_active_regions {
+ uint8_t global_image;
+ uint8_t board_config;
+ uint8_t vpd_nvram;
+ uint8_t npiv_config_0_1;
+ uint8_t npiv_config_2_3;
+ uint8_t reserved[32];
+} __packed;
+
#endif
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index c7533fa7f46e..9e80646722e2 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -111,30 +111,25 @@ int
qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
uint32_t ram_dwords, void **nxt)
{
- int rval;
- uint32_t cnt, stat, timer, dwords, idx;
- uint16_t mb0;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
dma_addr_t dump_dma = ha->gid_list_dma;
- uint32_t *dump = (uint32_t *)ha->gid_list;
-
- rval = QLA_SUCCESS;
- mb0 = 0;
+ uint32_t *chunk = (void *)ha->gid_list;
+ uint32_t dwords = qla2x00_gid_list_size(ha) / 4;
+ uint32_t stat;
+ ulong i, j, timer = 6000000;
+ int rval = QLA_FUNCTION_FAILED;
- WRT_REG_WORD(&reg->mailbox0, MBC_LOAD_DUMP_MPI_RAM);
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ for (i = 0; i < ram_dwords; i += dwords, addr += dwords) {
+ if (i + dwords > ram_dwords)
+ dwords = ram_dwords - i;
- dwords = qla2x00_gid_list_size(ha) / 4;
- for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
- cnt += dwords, addr += dwords) {
- if (cnt + dwords > ram_dwords)
- dwords = ram_dwords - cnt;
-
+ WRT_REG_WORD(&reg->mailbox0, MBC_LOAD_DUMP_MPI_RAM);
WRT_REG_WORD(&reg->mailbox1, LSW(addr));
WRT_REG_WORD(&reg->mailbox8, MSW(addr));
- WRT_REG_WORD(&reg->mailbox2, MSW(dump_dma));
- WRT_REG_WORD(&reg->mailbox3, LSW(dump_dma));
+ WRT_REG_WORD(&reg->mailbox2, MSW(LSD(dump_dma)));
+ WRT_REG_WORD(&reg->mailbox3, LSW(LSD(dump_dma)));
WRT_REG_WORD(&reg->mailbox6, MSW(MSD(dump_dma)));
WRT_REG_WORD(&reg->mailbox7, LSW(MSD(dump_dma)));
@@ -145,76 +140,76 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
ha->flags.mbox_int = 0;
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
- stat = RD_REG_DWORD(&reg->host_status);
- if (stat & HSRX_RISC_INT) {
- stat &= 0xff;
-
- if (stat == 0x1 || stat == 0x2 ||
- stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
+ while (timer--) {
+ udelay(5);
- mb0 = RD_REG_WORD(&reg->mailbox0);
- RD_REG_WORD(&reg->mailbox1);
+ stat = RD_REG_DWORD(&reg->host_status);
+ /* Check for pending interrupts. */
+ if (!(stat & HSRX_RISC_INT))
+ continue;
- WRT_REG_DWORD(&reg->hccr,
- HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- break;
- }
+ stat &= 0xff;
+ if (stat != 0x1 && stat != 0x2 &&
+ stat != 0x10 && stat != 0x11) {
/* Clear this intr; it wasn't a mailbox intr */
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
RD_REG_DWORD(&reg->hccr);
+ continue;
}
- udelay(5);
+
+ set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ rval = RD_REG_WORD(&reg->mailbox0) & MBS_MASK;
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ break;
}
ha->flags.mbox_int = 1;
+ *nxt = ram + i;
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb0 & MBS_MASK;
- for (idx = 0; idx < dwords; idx++)
- ram[cnt + idx] = IS_QLA27XX(ha) ?
- le32_to_cpu(dump[idx]) : swab32(dump[idx]);
- } else {
- rval = QLA_FUNCTION_FAILED;
+ if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+ /* no interrupt, timed out*/
+ return rval;
+ }
+ if (rval) {
+ /* error completion status */
+ return rval;
+ }
+ for (j = 0; j < dwords; j++) {
+ ram[i + j] =
+ (IS_QLA27XX(ha) || IS_QLA28XX(ha)) ?
+ chunk[j] : swab32(chunk[j]);
}
}
- *nxt = rval == QLA_SUCCESS ? &ram[cnt] : NULL;
- return rval;
+ *nxt = ram + i;
+ return QLA_SUCCESS;
}
int
qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
uint32_t ram_dwords, void **nxt)
{
- int rval;
- uint32_t cnt, stat, timer, dwords, idx;
- uint16_t mb0;
+ int rval = QLA_FUNCTION_FAILED;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
dma_addr_t dump_dma = ha->gid_list_dma;
- uint32_t *dump = (uint32_t *)ha->gid_list;
+ uint32_t *chunk = (void *)ha->gid_list;
+ uint32_t dwords = qla2x00_gid_list_size(ha) / 4;
+ uint32_t stat;
+ ulong i, j, timer = 6000000;
- rval = QLA_SUCCESS;
- mb0 = 0;
-
- WRT_REG_WORD(&reg->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
- dwords = qla2x00_gid_list_size(ha) / 4;
- for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
- cnt += dwords, addr += dwords) {
- if (cnt + dwords > ram_dwords)
- dwords = ram_dwords - cnt;
+ for (i = 0; i < ram_dwords; i += dwords, addr += dwords) {
+ if (i + dwords > ram_dwords)
+ dwords = ram_dwords - i;
+ WRT_REG_WORD(&reg->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
WRT_REG_WORD(&reg->mailbox1, LSW(addr));
WRT_REG_WORD(&reg->mailbox8, MSW(addr));
- WRT_REG_WORD(&reg->mailbox2, MSW(dump_dma));
- WRT_REG_WORD(&reg->mailbox3, LSW(dump_dma));
+ WRT_REG_WORD(&reg->mailbox2, MSW(LSD(dump_dma)));
+ WRT_REG_WORD(&reg->mailbox3, LSW(LSD(dump_dma)));
WRT_REG_WORD(&reg->mailbox6, MSW(MSD(dump_dma)));
WRT_REG_WORD(&reg->mailbox7, LSW(MSD(dump_dma)));
@@ -223,45 +218,48 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
ha->flags.mbox_int = 0;
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
+ while (timer--) {
+ udelay(5);
stat = RD_REG_DWORD(&reg->host_status);
- if (stat & HSRX_RISC_INT) {
- stat &= 0xff;
- if (stat == 0x1 || stat == 0x2 ||
- stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
-
- mb0 = RD_REG_WORD(&reg->mailbox0);
-
- WRT_REG_DWORD(&reg->hccr,
- HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- break;
- }
+ /* Check for pending interrupts. */
+ if (!(stat & HSRX_RISC_INT))
+ continue;
- /* Clear this intr; it wasn't a mailbox intr */
+ stat &= 0xff;
+ if (stat != 0x1 && stat != 0x2 &&
+ stat != 0x10 && stat != 0x11) {
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
RD_REG_DWORD(&reg->hccr);
+ continue;
}
- udelay(5);
+
+ set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ rval = RD_REG_WORD(&reg->mailbox0) & MBS_MASK;
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD(&reg->hccr);
+ break;
}
ha->flags.mbox_int = 1;
+ *nxt = ram + i;
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb0 & MBS_MASK;
- for (idx = 0; idx < dwords; idx++)
- ram[cnt + idx] = IS_QLA27XX(ha) ?
- le32_to_cpu(dump[idx]) : swab32(dump[idx]);
- } else {
- rval = QLA_FUNCTION_FAILED;
+ if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+ /* no interrupt, timed out*/
+ return rval;
+ }
+ if (rval) {
+ /* error completion status */
+ return rval;
+ }
+ for (j = 0; j < dwords; j++) {
+ ram[i + j] =
+ (IS_QLA27XX(ha) || IS_QLA28XX(ha)) ?
+ chunk[j] : swab32(chunk[j]);
}
}
- *nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL;
- return rval;
+ *nxt = ram + i;
+ return QLA_SUCCESS;
}
static int
@@ -447,7 +445,7 @@ qla2xxx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint16_t *ram,
}
}
- *nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL;
+ *nxt = rval == QLA_SUCCESS ? &ram[cnt] : NULL;
return rval;
}
@@ -669,7 +667,8 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
struct qla2xxx_mq_chain *mq = ptr;
device_reg_t *reg;
- if (!ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (!ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha))
return ptr;
mq = ptr;
@@ -2521,7 +2520,7 @@ qla83xx_fw_dump_failed:
/****************************************************************************/
static inline int
-ql_mask_match(uint32_t level)
+ql_mask_match(uint level)
{
return (level & ql2xextended_error_logging) == level;
}
@@ -2540,7 +2539,7 @@ ql_mask_match(uint32_t level)
* msg: The message to be displayed.
*/
void
-ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...)
+ql_dbg(uint level, scsi_qla_host_t *vha, uint id, const char *fmt, ...)
{
va_list va;
struct va_format vaf;
@@ -2583,8 +2582,7 @@ ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...)
* msg: The message to be displayed.
*/
void
-ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id,
- const char *fmt, ...)
+ql_dbg_pci(uint level, struct pci_dev *pdev, uint id, const char *fmt, ...)
{
va_list va;
struct va_format vaf;
@@ -2620,7 +2618,7 @@ ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id,
* msg: The message to be displayed.
*/
void
-ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...)
+ql_log(uint level, scsi_qla_host_t *vha, uint id, const char *fmt, ...)
{
va_list va;
struct va_format vaf;
@@ -2678,8 +2676,7 @@ ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...)
* msg: The message to be displayed.
*/
void
-ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id,
- const char *fmt, ...)
+ql_log_pci(uint level, struct pci_dev *pdev, uint id, const char *fmt, ...)
{
va_list va;
struct va_format vaf;
@@ -2719,7 +2716,7 @@ ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id,
}
void
-ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id)
+ql_dump_regs(uint level, scsi_qla_host_t *vha, uint id)
{
int i;
struct qla_hw_data *ha = vha->hw;
@@ -2741,13 +2738,12 @@ ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id)
ql_dbg(level, vha, id, "Mailbox registers:\n");
for (i = 0; i < 6; i++, mbx_reg++)
ql_dbg(level, vha, id,
- "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg));
+ "mbox[%d] %#04x\n", i, RD_REG_WORD(mbx_reg));
}
void
-ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id,
- uint8_t *buf, uint size)
+ql_dump_buffer(uint level, scsi_qla_host_t *vha, uint id, void *buf, uint size)
{
uint cnt;
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 8877aa97d829..bb01b680ce9f 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -318,20 +318,20 @@ struct qla2xxx_fw_dump {
* as compared to other log levels.
*/
-extern int ql_errlev;
+extern uint ql_errlev;
void __attribute__((format (printf, 4, 5)))
-ql_dbg(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...);
+ql_dbg(uint, scsi_qla_host_t *vha, uint, const char *fmt, ...);
void __attribute__((format (printf, 4, 5)))
-ql_dbg_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...);
+ql_dbg_pci(uint, struct pci_dev *pdev, uint, const char *fmt, ...);
void __attribute__((format (printf, 4, 5)))
ql_dbg_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...);
void __attribute__((format (printf, 4, 5)))
-ql_log(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...);
+ql_log(uint, scsi_qla_host_t *vha, uint, const char *fmt, ...);
void __attribute__((format (printf, 4, 5)))
-ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...);
+ql_log_pci(uint, struct pci_dev *pdev, uint, const char *fmt, ...);
void __attribute__((format (printf, 4, 5)))
ql_log_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 3d46975a5e5c..bad2b12604f1 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -35,6 +35,7 @@
#include <scsi/scsi_bsg_fc.h>
#include "qla_bsg.h"
+#include "qla_dsd.h"
#include "qla_nx.h"
#include "qla_nx2.h"
#include "qla_nvme.h"
@@ -531,6 +532,8 @@ typedef struct srb {
uint8_t cmd_type;
uint8_t pad[3];
atomic_t ref_count;
+ struct kref cmd_kref; /* need to migrate ref_count over to this */
+ void *priv;
wait_queue_head_t nvme_ls_waitq;
struct fc_port *fcport;
struct scsi_qla_host *vha;
@@ -545,7 +548,7 @@ typedef struct srb {
u32 gen2; /* scratch */
int rc;
int retry_count;
- struct completion comp;
+ struct completion *comp;
union {
struct srb_iocb iocb_cmd;
struct bsg_job *bsg_job;
@@ -553,6 +556,7 @@ typedef struct srb {
} u;
void (*done)(void *, int);
void (*free)(void *);
+ void (*put_fn)(struct kref *kref);
} srb_t;
#define GET_CMD_SP(sp) (sp->u.scmd.cmd)
@@ -1033,6 +1037,7 @@ struct mbx_cmd_32 {
#define MBC_GET_FIRMWARE_VERSION 8 /* Get firmware revision. */
#define MBC_LOAD_RISC_RAM 9 /* Load RAM command. */
#define MBC_DUMP_RISC_RAM 0xa /* Dump RAM command. */
+#define MBC_SECURE_FLASH_UPDATE 0xa /* Secure Flash Update(28xx) */
#define MBC_LOAD_RISC_RAM_EXTENDED 0xb /* Load RAM extended. */
#define MBC_DUMP_RISC_RAM_EXTENDED 0xc /* Dump RAM extended. */
#define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */
@@ -1203,6 +1208,10 @@ struct mbx_cmd_32 {
#define QLA27XX_IMG_STATUS_VER_MAJOR 0x01
#define QLA27XX_IMG_STATUS_VER_MINOR 0x00
#define QLA27XX_IMG_STATUS_SIGN 0xFACEFADE
+#define QLA28XX_IMG_STATUS_SIGN 0xFACEFADF
+#define QLA28XX_IMG_STATUS_SIGN 0xFACEFADF
+#define QLA28XX_AUX_IMG_STATUS_SIGN 0xFACEFAED
+#define QLA27XX_DEFAULT_IMAGE 0
#define QLA27XX_PRIMARY_IMAGE 1
#define QLA27XX_SECONDARY_IMAGE 2
@@ -1323,8 +1332,8 @@ typedef struct {
uint16_t response_q_inpointer;
uint16_t request_q_length;
uint16_t response_q_length;
- uint32_t request_q_address[2];
- uint32_t response_q_address[2];
+ __le64 request_q_address __packed;
+ __le64 response_q_address __packed;
uint16_t lun_enables;
uint8_t command_resource_count;
@@ -1749,12 +1758,10 @@ typedef struct {
uint16_t dseg_count; /* Data segment count. */
uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */
uint32_t byte_count; /* Total byte count. */
- uint32_t dseg_0_address; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
- uint32_t dseg_2_address; /* Data segment 2 address. */
- uint32_t dseg_2_length; /* Data segment 2 length. */
+ union {
+ struct dsd32 dsd32[3];
+ struct dsd64 dsd64[2];
+ };
} cmd_entry_t;
/*
@@ -1775,10 +1782,7 @@ typedef struct {
uint16_t dseg_count; /* Data segment count. */
uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */
uint32_t byte_count; /* Total byte count. */
- uint32_t dseg_0_address[2]; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address[2]; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
+ struct dsd64 dsd[2];
} cmd_a64_entry_t, request_t;
/*
@@ -1791,20 +1795,7 @@ typedef struct {
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t reserved;
- uint32_t dseg_0_address; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
- uint32_t dseg_2_address; /* Data segment 2 address. */
- uint32_t dseg_2_length; /* Data segment 2 length. */
- uint32_t dseg_3_address; /* Data segment 3 address. */
- uint32_t dseg_3_length; /* Data segment 3 length. */
- uint32_t dseg_4_address; /* Data segment 4 address. */
- uint32_t dseg_4_length; /* Data segment 4 length. */
- uint32_t dseg_5_address; /* Data segment 5 address. */
- uint32_t dseg_5_length; /* Data segment 5 length. */
- uint32_t dseg_6_address; /* Data segment 6 address. */
- uint32_t dseg_6_length; /* Data segment 6 length. */
+ struct dsd32 dsd[7];
} cont_entry_t;
/*
@@ -1816,16 +1807,7 @@ typedef struct {
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
- uint32_t dseg_0_address[2]; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address[2]; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
- uint32_t dseg_2_address [2]; /* Data segment 2 address. */
- uint32_t dseg_2_length; /* Data segment 2 length. */
- uint32_t dseg_3_address[2]; /* Data segment 3 address. */
- uint32_t dseg_3_length; /* Data segment 3 length. */
- uint32_t dseg_4_address[2]; /* Data segment 4 address. */
- uint32_t dseg_4_length; /* Data segment 4 length. */
+ struct dsd64 dsd[5];
} cont_a64_entry_t;
#define PO_MODE_DIF_INSERT 0
@@ -1869,8 +1851,7 @@ struct crc_context {
uint16_t reserved_2;
uint16_t reserved_3;
uint32_t reserved_4;
- uint32_t data_address[2];
- uint32_t data_length;
+ struct dsd64 data_dsd;
uint32_t reserved_5[2];
uint32_t reserved_6;
} nobundling;
@@ -1880,11 +1861,8 @@ struct crc_context {
uint16_t reserved_1;
__le16 dseg_count; /* Data segment count */
uint32_t reserved_2;
- uint32_t data_address[2];
- uint32_t data_length;
- uint32_t dif_address[2];
- uint32_t dif_length; /* Data segment 0
- * length */
+ struct dsd64 data_dsd;
+ struct dsd64 dif_dsd;
} bundling;
} u;
@@ -2083,10 +2061,8 @@ typedef struct {
uint32_t handle2;
uint32_t rsp_bytecount;
uint32_t req_bytecount;
- uint32_t dseg_req_address[2]; /* Data segment 0 address. */
- uint32_t dseg_req_length; /* Data segment 0 length. */
- uint32_t dseg_rsp_address[2]; /* Data segment 1 address. */
- uint32_t dseg_rsp_length; /* Data segment 1 length. */
+ struct dsd64 req_dsd;
+ struct dsd64 rsp_dsd;
} ms_iocb_entry_t;
@@ -2258,7 +2234,10 @@ typedef enum {
FCT_BROADCAST,
FCT_INITIATOR,
FCT_TARGET,
- FCT_NVME
+ FCT_NVME_INITIATOR = 0x10,
+ FCT_NVME_TARGET = 0x20,
+ FCT_NVME_DISCOVERY = 0x40,
+ FCT_NVME = 0xf0,
} fc_port_type_t;
enum qla_sess_deletion {
@@ -2360,7 +2339,6 @@ typedef struct fc_port {
unsigned int id_changed:1;
unsigned int scan_needed:1;
- struct work_struct nvme_del_work;
struct completion nvme_del_done;
uint32_t nvme_prli_service_param;
#define NVME_PRLI_SP_CONF BIT_7
@@ -2463,13 +2441,7 @@ struct event_arg {
#define FCS_DEVICE_LOST 3
#define FCS_ONLINE 4
-static const char * const port_state_str[] = {
- "Unknown",
- "UNCONFIGURED",
- "DEAD",
- "LOST",
- "ONLINE"
-};
+extern const char *const port_state_str[5];
/*
* FC port flags.
@@ -2672,6 +2644,7 @@ struct ct_fdmiv2_hba_attributes {
#define FDMI_PORT_SPEED_8GB 0x10
#define FDMI_PORT_SPEED_16GB 0x20
#define FDMI_PORT_SPEED_32GB 0x40
+#define FDMI_PORT_SPEED_64GB 0x80
#define FDMI_PORT_SPEED_UNKNOWN 0x8000
#define FC_CLASS_2 0x04
@@ -3060,7 +3033,7 @@ struct sns_cmd_pkt {
struct {
uint16_t buffer_length;
uint16_t reserved_1;
- uint32_t buffer_address[2];
+ __le64 buffer_address __packed;
uint16_t subcommand_length;
uint16_t reserved_2;
uint16_t subcommand;
@@ -3130,10 +3103,10 @@ struct rsp_que;
struct isp_operations {
int (*pci_config) (struct scsi_qla_host *);
- void (*reset_chip) (struct scsi_qla_host *);
+ int (*reset_chip)(struct scsi_qla_host *);
int (*chip_diag) (struct scsi_qla_host *);
void (*config_rings) (struct scsi_qla_host *);
- void (*reset_adapter) (struct scsi_qla_host *);
+ int (*reset_adapter)(struct scsi_qla_host *);
int (*nvram_config) (struct scsi_qla_host *);
void (*update_fw_options) (struct scsi_qla_host *);
int (*load_risc) (struct scsi_qla_host *, uint32_t *);
@@ -3159,9 +3132,9 @@ struct isp_operations {
void *(*prep_ms_fdmi_iocb) (struct scsi_qla_host *, uint32_t,
uint32_t);
- uint8_t *(*read_nvram) (struct scsi_qla_host *, uint8_t *,
+ uint8_t *(*read_nvram)(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
- int (*write_nvram) (struct scsi_qla_host *, uint8_t *, uint32_t,
+ int (*write_nvram)(struct scsi_qla_host *, void *, uint32_t,
uint32_t);
void (*fw_dump) (struct scsi_qla_host *, int);
@@ -3170,16 +3143,16 @@ struct isp_operations {
int (*beacon_off) (struct scsi_qla_host *);
void (*beacon_blink) (struct scsi_qla_host *);
- uint8_t * (*read_optrom) (struct scsi_qla_host *, uint8_t *,
+ void *(*read_optrom)(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
- int (*write_optrom) (struct scsi_qla_host *, uint8_t *, uint32_t,
+ int (*write_optrom)(struct scsi_qla_host *, void *, uint32_t,
uint32_t);
int (*get_flash_version) (struct scsi_qla_host *, void *);
int (*start_scsi) (srb_t *);
int (*start_scsi_mq) (srb_t *);
int (*abort_isp) (struct scsi_qla_host *);
- int (*iospace_config)(struct qla_hw_data*);
+ int (*iospace_config)(struct qla_hw_data *);
int (*initialize_adapter)(struct scsi_qla_host *);
};
@@ -3368,7 +3341,8 @@ struct qla_tc_param {
#define QLA_MQ_SIZE 32
#define QLA_MAX_QUEUES 256
#define ISP_QUE_REG(ha, id) \
- ((ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) ? \
+ ((ha->mqenable || IS_QLA83XX(ha) || \
+ IS_QLA27XX(ha) || IS_QLA28XX(ha)) ? \
((void __iomem *)ha->mqiobase + (QLA_QUE_PAGE * id)) :\
((void __iomem *)ha->iobase))
#define QLA_REQ_QUE_ID(tag) \
@@ -3621,6 +3595,8 @@ struct qla_hw_data {
uint32_t rida_fmt2:1;
uint32_t purge_mbox:1;
uint32_t n2n_bigger:1;
+ uint32_t secure_adapter:1;
+ uint32_t secure_fw:1;
} flags;
uint16_t max_exchg;
@@ -3703,6 +3679,7 @@ struct qla_hw_data {
#define PORT_SPEED_8GB 0x04
#define PORT_SPEED_16GB 0x05
#define PORT_SPEED_32GB 0x06
+#define PORT_SPEED_64GB 0x07
#define PORT_SPEED_10GB 0x13
uint16_t link_data_rate; /* F/W operating speed */
uint16_t set_data_rate; /* Set by user */
@@ -3729,6 +3706,11 @@ struct qla_hw_data {
#define PCI_DEVICE_ID_QLOGIC_ISP2071 0x2071
#define PCI_DEVICE_ID_QLOGIC_ISP2271 0x2271
#define PCI_DEVICE_ID_QLOGIC_ISP2261 0x2261
+#define PCI_DEVICE_ID_QLOGIC_ISP2061 0x2061
+#define PCI_DEVICE_ID_QLOGIC_ISP2081 0x2081
+#define PCI_DEVICE_ID_QLOGIC_ISP2089 0x2089
+#define PCI_DEVICE_ID_QLOGIC_ISP2281 0x2281
+#define PCI_DEVICE_ID_QLOGIC_ISP2289 0x2289
uint32_t isp_type;
#define DT_ISP2100 BIT_0
@@ -3753,7 +3735,12 @@ struct qla_hw_data {
#define DT_ISP2071 BIT_19
#define DT_ISP2271 BIT_20
#define DT_ISP2261 BIT_21
-#define DT_ISP_LAST (DT_ISP2261 << 1)
+#define DT_ISP2061 BIT_22
+#define DT_ISP2081 BIT_23
+#define DT_ISP2089 BIT_24
+#define DT_ISP2281 BIT_25
+#define DT_ISP2289 BIT_26
+#define DT_ISP_LAST (DT_ISP2289 << 1)
uint32_t device_type;
#define DT_T10_PI BIT_25
@@ -3788,6 +3775,8 @@ struct qla_hw_data {
#define IS_QLA2071(ha) (DT_MASK(ha) & DT_ISP2071)
#define IS_QLA2271(ha) (DT_MASK(ha) & DT_ISP2271)
#define IS_QLA2261(ha) (DT_MASK(ha) & DT_ISP2261)
+#define IS_QLA2081(ha) (DT_MASK(ha) & DT_ISP2081)
+#define IS_QLA2281(ha) (DT_MASK(ha) & DT_ISP2281)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -3797,6 +3786,7 @@ struct qla_hw_data {
#define IS_QLA83XX(ha) (IS_QLA2031(ha) || IS_QLA8031(ha))
#define IS_QLA84XX(ha) (IS_QLA8432(ha))
#define IS_QLA27XX(ha) (IS_QLA2071(ha) || IS_QLA2271(ha) || IS_QLA2261(ha))
+#define IS_QLA28XX(ha) (IS_QLA2081(ha) || IS_QLA2281(ha))
#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
IS_QLA84XX(ha))
#define IS_CNA_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha) || \
@@ -3805,14 +3795,15 @@ struct qla_hw_data {
#define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
- IS_QLA8044(ha) || IS_QLA27XX(ha))
+ IS_QLA8044(ha) || IS_QLA27XX(ha) || \
+ IS_QLA28XX(ha))
#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
- IS_QLA27XX(ha))
+ IS_QLA27XX(ha) || IS_QLA28XX(ha))
#define IS_NOPOLLING_TYPE(ha) (IS_QLA81XX(ha) && (ha)->flags.msix_enabled)
#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
- IS_QLA27XX(ha))
+ IS_QLA27XX(ha) || IS_QLA28XX(ha))
#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
- IS_QLA27XX(ha))
+ IS_QLA27XX(ha) || IS_QLA28XX(ha))
#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
#define IS_T10_PI_CAPABLE(ha) ((ha)->device_type & DT_T10_PI)
@@ -3823,28 +3814,34 @@ struct qla_hw_data {
#define HAS_EXTENDED_IDS(ha) ((ha)->device_type & DT_EXTENDED_IDS)
#define IS_CT6_SUPPORTED(ha) ((ha)->device_type & DT_CT6_SUPPORTED)
#define IS_MQUE_CAPABLE(ha) ((ha)->mqenable || IS_QLA83XX(ha) || \
- IS_QLA27XX(ha))
-#define IS_BIDI_CAPABLE(ha) ((IS_QLA25XX(ha) || IS_QLA2031(ha)))
+ IS_QLA27XX(ha) || IS_QLA28XX(ha))
+#define IS_BIDI_CAPABLE(ha) \
+ (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
/* Bit 21 of fw_attributes decides the MCTP capabilities */
#define IS_MCTP_CAPABLE(ha) (IS_QLA2031(ha) && \
((ha)->fw_attributes_ext[0] & BIT_0))
#define IS_PI_UNINIT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha))
#define IS_PI_IPGUARD_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha))
#define IS_PI_DIFB_DIX0_CAPABLE(ha) (0)
-#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
+ IS_QLA28XX(ha))
#define IS_PI_SPLIT_DET_CAPABLE(ha) (IS_PI_SPLIT_DET_CAPABLE_HBA(ha) && \
(((ha)->fw_attributes_h << 16 | (ha)->fw_attributes) & BIT_22))
-#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
+ IS_QLA28XX(ha))
#define IS_TGT_MODE_CAPABLE(ha) (ha->tgt.atio_q_length)
-#define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha))
-#define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha))
-#define IS_FAWWN_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+#define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+#define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
+ IS_QLA28XX(ha))
+#define IS_FAWWN_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
+ IS_QLA28XX(ha))
#define IS_EXCHG_OFFLD_CAPABLE(ha) \
- (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
#define IS_EXLOGIN_OFFLD_CAPABLE(ha) \
- (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
+ IS_QLA27XX(ha) || IS_QLA28XX(ha))
#define USE_ASYNC_SCAN(ha) (IS_QLA25XX(ha) || IS_QLA81XX(ha) ||\
- IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
/* HBA serial number */
uint8_t serial0;
@@ -3888,6 +3885,9 @@ struct qla_hw_data {
void *sfp_data;
dma_addr_t sfp_data_dma;
+ void *flt;
+ dma_addr_t flt_dma;
+
#define XGMAC_DATA_SIZE 4096
void *xgmac_data;
dma_addr_t xgmac_data_dma;
@@ -3999,18 +3999,23 @@ struct qla_hw_data {
uint8_t fw_seriallink_options[4];
uint16_t fw_seriallink_options24[4];
+ uint8_t serdes_version[3];
uint8_t mpi_version[3];
uint32_t mpi_capabilities;
uint8_t phy_version[3];
uint8_t pep_version[3];
/* Firmware dump template */
- void *fw_dump_template;
- uint32_t fw_dump_template_len;
- /* Firmware dump information. */
+ struct fwdt {
+ void *template;
+ ulong length;
+ ulong dump_size;
+ } fwdt[2];
struct qla2xxx_fw_dump *fw_dump;
uint32_t fw_dump_len;
- int fw_dumped;
+ u32 fw_dump_alloc_len;
+ bool fw_dumped;
+ bool fw_dump_mpi;
unsigned long fw_dump_cap_flags;
#define RISC_PAUSE_CMPL 0
#define DMA_SHUTDOWN_CMPL 1
@@ -4049,7 +4054,6 @@ struct qla_hw_data {
uint16_t product_id[4];
uint8_t model_number[16+1];
-#define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
char model_desc[80];
uint8_t adapter_id[16+1];
@@ -4089,22 +4093,28 @@ struct qla_hw_data {
uint32_t fdt_protect_sec_cmd;
uint32_t fdt_wrt_sts_reg_cmd;
- 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;
+ struct {
+ 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_nvram_sec;
+ uint32_t flt_region_vpd;
+ uint32_t flt_region_vpd_sec;
+ uint32_t flt_region_nvram;
+ uint32_t flt_region_nvram_sec;
+ 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;
+ uint32_t flt_region_aux_img_status_pri;
+ uint32_t flt_region_aux_img_status_sec;
+ };
uint8_t active_image;
/* Needed for BEACON */
@@ -4197,8 +4207,8 @@ struct qla_hw_data {
struct qlt_hw_data tgt;
int allow_cna_fw_dump;
uint32_t fw_ability_mask;
- uint16_t min_link_speed;
- uint16_t max_speed_sup;
+ uint16_t min_supported_speed;
+ uint16_t max_supported_speed;
/* DMA pool for the DIF bundling buffers */
struct dma_pool *dif_bundl_pool;
@@ -4225,9 +4235,20 @@ struct qla_hw_data {
atomic_t zio_threshold;
uint16_t last_zio_threshold;
+
#define DEFAULT_ZIO_THRESHOLD 5
};
+struct active_regions {
+ uint8_t global;
+ struct {
+ uint8_t board_config;
+ uint8_t vpd_nvram;
+ uint8_t npiv_config_0_1;
+ uint8_t npiv_config_2_3;
+ } aux;
+};
+
#define FW_ABILITY_MAX_SPEED_MASK 0xFUL
#define FW_ABILITY_MAX_SPEED_16G 0x0
#define FW_ABILITY_MAX_SPEED_32G 0x1
@@ -4315,6 +4336,7 @@ typedef struct scsi_qla_host {
#define N2N_LOGIN_NEEDED 30
#define IOCB_WORK_ACTIVE 31
#define SET_ZIO_THRESHOLD_NEEDED 32
+#define ISP_ABORT_TO_ROM 33
unsigned long pci_flags;
#define PFLG_DISCONNECTED 0 /* PCI device removed */
@@ -4356,7 +4378,6 @@ typedef struct scsi_qla_host {
struct nvme_fc_local_port *nvme_local_port;
struct completion nvme_del_done;
- struct list_head nvme_rport_list;
uint16_t fcoe_vlan_id;
uint16_t fcoe_fcf_idx;
@@ -4429,7 +4450,7 @@ typedef struct scsi_qla_host {
int fcport_count;
wait_queue_head_t fcport_waitQ;
wait_queue_head_t vref_waitq;
- uint8_t min_link_speed_feat;
+ uint8_t min_supported_speed;
uint8_t n2n_node_name[WWN_SIZE];
uint8_t n2n_port_name[WWN_SIZE];
uint16_t n2n_id;
@@ -4441,14 +4462,21 @@ typedef struct scsi_qla_host {
struct qla27xx_image_status {
uint8_t image_status_mask;
- uint16_t generation_number;
- uint8_t reserved[3];
- uint8_t ver_minor;
+ uint16_t generation;
uint8_t ver_major;
+ uint8_t ver_minor;
+ uint8_t bitmap; /* 28xx only */
+ uint8_t reserved[2];
uint32_t checksum;
uint32_t signature;
} __packed;
+/* 28xx aux image status bimap values */
+#define QLA28XX_AUX_IMG_BOARD_CONFIG BIT_0
+#define QLA28XX_AUX_IMG_VPD_NVRAM BIT_1
+#define QLA28XX_AUX_IMG_NPIV_CONFIG_0_1 BIT_2
+#define QLA28XX_AUX_IMG_NPIV_CONFIG_2_3 BIT_3
+
#define SET_VP_IDX 1
#define SET_AL_PA 2
#define RESET_VP_IDX 3
@@ -4495,6 +4523,24 @@ struct qla2_sgx {
} \
}
+
+#define SFUB_CHECKSUM_SIZE 4
+
+struct secure_flash_update_block {
+ uint32_t block_info;
+ uint32_t signature_lo;
+ uint32_t signature_hi;
+ uint32_t signature_upper[0x3e];
+};
+
+struct secure_flash_update_block_pk {
+ uint32_t block_info;
+ uint32_t signature_lo;
+ uint32_t signature_hi;
+ uint32_t signature_upper[0x3e];
+ uint32_t public_key[0x41];
+};
+
/*
* Macros to help code, maintain, etc.
*/
@@ -4595,6 +4641,7 @@ struct qla2_sgx {
#define OPTROM_SIZE_81XX 0x400000
#define OPTROM_SIZE_82XX 0x800000
#define OPTROM_SIZE_83XX 0x1000000
+#define OPTROM_SIZE_28XX 0x2000000
#define OPTROM_BURST_SIZE 0x1000
#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4)
@@ -4691,10 +4738,13 @@ struct sff_8247_a0 {
#define AUTO_DETECT_SFP_SUPPORT(_vha)\
(ql2xautodetectsfp && !_vha->vp_idx && \
(IS_QLA25XX(_vha->hw) || IS_QLA81XX(_vha->hw) ||\
- IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw)))
+ IS_QLA83XX(_vha->hw) || IS_QLA27XX(_vha->hw) || \
+ IS_QLA28XX(_vha->hw)))
+
+#define FLASH_SEMAPHORE_REGISTER_ADDR 0x00101016
#define USER_CTRL_IRQ(_ha) (ql2xuctrlirq && QLA_TGT_MODE_ENABLED() && \
- (IS_QLA27XX(_ha) || IS_QLA83XX(_ha)))
+ (IS_QLA27XX(_ha) || IS_QLA28XX(_ha) || IS_QLA83XX(_ha)))
#define SAVE_TOPO(_ha) { \
if (_ha->current_topology) \
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 5819a45ac5ef..a432caebefec 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -41,6 +41,7 @@ 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);
}
@@ -161,6 +162,7 @@ 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);
}
@@ -250,6 +252,7 @@ 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);
}
@@ -386,7 +389,7 @@ qla_dfs_naqp_write(struct file *file, const char __user *buffer,
int rc = 0;
unsigned long num_act_qp;
- if (!(IS_QLA27XX(ha) || IS_QLA83XX(ha))) {
+ if (!(IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))) {
pr_err("host%ld: this adapter does not support Multi Q.",
vha->host_no);
return -EINVAL;
@@ -438,7 +441,7 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
- !IS_QLA27XX(ha))
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
goto out;
if (!ha->fce)
goto out;
@@ -474,7 +477,7 @@ create_nodes:
ha->tgt.dfs_tgt_sess = debugfs_create_file("tgt_sess",
S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_sess_ops);
- if (IS_QLA27XX(ha) || IS_QLA83XX(ha))
+ if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))
ha->tgt.dfs_naqp = debugfs_create_file("naqp",
0400, ha->dfs_dir, vha, &dfs_naqp_ops);
out:
diff --git a/drivers/scsi/qla2xxx/qla_dsd.h b/drivers/scsi/qla2xxx/qla_dsd.h
new file mode 100644
index 000000000000..7479924ba422
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_dsd.h
@@ -0,0 +1,30 @@
+#ifndef _QLA_DSD_H_
+#define _QLA_DSD_H_
+
+/* 32-bit data segment descriptor (8 bytes) */
+struct dsd32 {
+ __le32 address;
+ __le32 length;
+};
+
+static inline void append_dsd32(struct dsd32 **dsd, struct scatterlist *sg)
+{
+ put_unaligned_le32(sg_dma_address(sg), &(*dsd)->address);
+ put_unaligned_le32(sg_dma_len(sg), &(*dsd)->length);
+ (*dsd)++;
+}
+
+/* 64-bit data segment descriptor (12 bytes) */
+struct dsd64 {
+ __le64 address;
+ __le32 length;
+} __packed;
+
+static inline void append_dsd64(struct dsd64 **dsd, struct scatterlist *sg)
+{
+ put_unaligned_le64(sg_dma_address(sg), &(*dsd)->address);
+ put_unaligned_le32(sg_dma_len(sg), &(*dsd)->length);
+ (*dsd)++;
+}
+
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 50c1e6c62e31..df079a8c2b33 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -10,6 +10,8 @@
#include <linux/nvme.h>
#include <linux/nvme-fc.h>
+#include "qla_dsd.h"
+
#define MBS_CHECKSUM_ERROR 0x4010
#define MBS_INVALID_PRODUCT_KEY 0x4020
@@ -339,9 +341,9 @@ struct init_cb_24xx {
uint16_t prio_request_q_length;
- uint32_t request_q_address[2];
- uint32_t response_q_address[2];
- uint32_t prio_request_q_address[2];
+ __le64 request_q_address __packed;
+ __le64 response_q_address __packed;
+ __le64 prio_request_q_address __packed;
uint16_t msix;
uint16_t msix_atio;
@@ -349,7 +351,7 @@ struct init_cb_24xx {
uint16_t atio_q_inpointer;
uint16_t atio_q_length;
- uint32_t atio_q_address[2];
+ __le64 atio_q_address __packed;
uint16_t interrupt_delay_timer; /* 100us increments. */
uint16_t login_timeout;
@@ -453,7 +455,7 @@ struct cmd_bidir {
#define BD_WRITE_DATA BIT_0
uint16_t fcp_cmnd_dseg_len; /* Data segment length. */
- uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */
+ __le64 fcp_cmnd_dseg_address __packed;/* Data segment address. */
uint16_t reserved[2]; /* Reserved */
@@ -463,8 +465,7 @@ struct cmd_bidir {
uint8_t port_id[3]; /* PortID of destination port.*/
uint8_t vp_index;
- uint32_t fcp_data_dseg_address[2]; /* Data segment address. */
- uint16_t fcp_data_dseg_len; /* Data segment length. */
+ struct dsd64 fcp_dsd;
};
#define COMMAND_TYPE_6 0x48 /* Command Type 6 entry */
@@ -491,18 +492,18 @@ struct cmd_type_6 {
#define CF_READ_DATA BIT_1
#define CF_WRITE_DATA BIT_0
- uint16_t fcp_cmnd_dseg_len; /* Data segment length. */
- uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */
-
- uint32_t fcp_rsp_dseg_address[2]; /* Data segment address. */
+ uint16_t fcp_cmnd_dseg_len; /* Data segment length. */
+ /* Data segment address. */
+ __le64 fcp_cmnd_dseg_address __packed;
+ /* Data segment address. */
+ __le64 fcp_rsp_dseg_address __packed;
uint32_t byte_count; /* Total byte count. */
uint8_t port_id[3]; /* PortID of destination port. */
uint8_t vp_index;
- uint32_t fcp_data_dseg_address[2]; /* Data segment address. */
- uint32_t fcp_data_dseg_len; /* Data segment length. */
+ struct dsd64 fcp_dsd;
};
#define COMMAND_TYPE_7 0x18 /* Command Type 7 entry */
@@ -548,8 +549,7 @@ struct cmd_type_7 {
uint8_t port_id[3]; /* PortID of destination port. */
uint8_t vp_index;
- uint32_t dseg_0_address[2]; /* Data segment 0 address. */
- uint32_t dseg_0_len; /* Data segment 0 length. */
+ struct dsd64 dsd;
};
#define COMMAND_TYPE_CRC_2 0x6A /* Command Type CRC_2 (Type 6)
@@ -573,17 +573,17 @@ struct cmd_type_crc_2 {
uint16_t control_flags; /* Control flags. */
- uint16_t fcp_cmnd_dseg_len; /* Data segment length. */
- uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */
-
- uint32_t fcp_rsp_dseg_address[2]; /* Data segment address. */
+ uint16_t fcp_cmnd_dseg_len; /* Data segment length. */
+ __le64 fcp_cmnd_dseg_address __packed;
+ /* Data segment address. */
+ __le64 fcp_rsp_dseg_address __packed;
uint32_t byte_count; /* Total byte count. */
uint8_t port_id[3]; /* PortID of destination port. */
uint8_t vp_index;
- uint32_t crc_context_address[2]; /* Data segment address. */
+ __le64 crc_context_address __packed; /* Data segment address. */
uint16_t crc_context_len; /* Data segment length. */
uint16_t reserved_1; /* MUST be set to 0. */
};
@@ -717,10 +717,7 @@ struct ct_entry_24xx {
uint32_t rsp_byte_count;
uint32_t cmd_byte_count;
- uint32_t dseg_0_address[2]; /* Data segment 0 address. */
- uint32_t dseg_0_len; /* Data segment 0 length. */
- uint32_t dseg_1_address[2]; /* Data segment 1 address. */
- uint32_t dseg_1_len; /* Data segment 1 length. */
+ struct dsd64 dsd[2];
};
/*
@@ -767,9 +764,9 @@ struct els_entry_24xx {
uint32_t rx_byte_count;
uint32_t tx_byte_count;
- uint32_t tx_address[2]; /* Data segment 0 address. */
+ __le64 tx_address __packed; /* Data segment 0 address. */
uint32_t tx_len; /* Data segment 0 length. */
- uint32_t rx_address[2]; /* Data segment 1 address. */
+ __le64 rx_address __packed; /* Data segment 1 address. */
uint32_t rx_len; /* Data segment 1 length. */
};
@@ -1422,9 +1419,9 @@ struct vf_evfp_entry_24xx {
uint16_t control_flags;
uint32_t io_parameter_0;
uint32_t io_parameter_1;
- uint32_t tx_address[2]; /* Data segment 0 address. */
+ __le64 tx_address __packed; /* Data segment 0 address. */
uint32_t tx_len; /* Data segment 0 length. */
- uint32_t rx_address[2]; /* Data segment 1 address. */
+ __le64 rx_address __packed; /* Data segment 1 address. */
uint32_t rx_len; /* Data segment 1 length. */
};
@@ -1515,13 +1512,31 @@ struct qla_flt_header {
#define FLT_REG_VPD_SEC_27XX_2 0xD8
#define FLT_REG_VPD_SEC_27XX_3 0xDA
+/* 28xx */
+#define FLT_REG_AUX_IMG_PRI_28XX 0x125
+#define FLT_REG_AUX_IMG_SEC_28XX 0x126
+#define FLT_REG_VPD_SEC_28XX_0 0x10C
+#define FLT_REG_VPD_SEC_28XX_1 0x10E
+#define FLT_REG_VPD_SEC_28XX_2 0x110
+#define FLT_REG_VPD_SEC_28XX_3 0x112
+#define FLT_REG_NVRAM_SEC_28XX_0 0x10D
+#define FLT_REG_NVRAM_SEC_28XX_1 0x10F
+#define FLT_REG_NVRAM_SEC_28XX_2 0x111
+#define FLT_REG_NVRAM_SEC_28XX_3 0x113
+
struct qla_flt_region {
- uint32_t code;
+ uint16_t code;
+ uint8_t attribute;
+ uint8_t reserved;
uint32_t size;
uint32_t start;
uint32_t end;
};
+#define FLT_REGION_SIZE 16
+#define FLT_MAX_REGIONS 0xFF
+#define FLT_REGIONS_SIZE (FLT_REGION_SIZE * FLT_MAX_REGIONS)
+
/* Flash NPIV Configuration Table ********************************************/
struct qla_npiv_header {
@@ -1588,8 +1603,7 @@ struct verify_chip_entry_84xx {
uint32_t fw_seq_size;
uint32_t relative_offset;
- uint32_t dseg_address[2];
- uint32_t dseg_length;
+ struct dsd64 dsd;
};
struct verify_chip_rsp_84xx {
@@ -1646,8 +1660,7 @@ struct access_chip_84xx {
uint32_t total_byte_cnt;
uint32_t reserved4;
- uint32_t dseg_address[2];
- uint32_t dseg_length;
+ struct dsd64 dsd;
};
struct access_chip_rsp_84xx {
@@ -1711,6 +1724,10 @@ struct access_chip_rsp_84xx {
#define LR_DIST_FW_SHIFT (LR_DIST_FW_POS - LR_DIST_NV_POS)
#define LR_DIST_FW_FIELD(x) ((x) << LR_DIST_FW_SHIFT & 0xf000)
+/* FAC semaphore defines */
+#define FAC_SEMAPHORE_UNLOCK 0
+#define FAC_SEMAPHORE_LOCK 1
+
struct nvram_81xx {
/* NVRAM header. */
uint8_t id[4];
@@ -1757,7 +1774,7 @@ struct nvram_81xx {
uint16_t reserved_6_3[14];
/* Offset 192. */
- uint8_t min_link_speed;
+ uint8_t min_supported_speed;
uint8_t reserved_7_0;
uint16_t reserved_7[31];
@@ -1911,15 +1928,15 @@ struct init_cb_81xx {
uint16_t prio_request_q_length;
- uint32_t request_q_address[2];
- uint32_t response_q_address[2];
- uint32_t prio_request_q_address[2];
+ __le64 request_q_address __packed;
+ __le64 response_q_address __packed;
+ __le64 prio_request_q_address __packed;
uint8_t reserved_4[8];
uint16_t atio_q_inpointer;
uint16_t atio_q_length;
- uint32_t atio_q_address[2];
+ __le64 atio_q_address __packed;
uint16_t interrupt_delay_timer; /* 100us increments. */
uint16_t login_timeout;
@@ -2005,6 +2022,8 @@ struct ex_init_cb_81xx {
#define FARX_ACCESS_FLASH_CONF_81XX 0x7FFD0000
#define FARX_ACCESS_FLASH_DATA_81XX 0x7F800000
+#define FARX_ACCESS_FLASH_CONF_28XX 0x7FFD0000
+#define FARX_ACCESS_FLASH_DATA_28XX 0x7F7D0000
/* FCP priority config defines *************************************/
/* operations */
@@ -2079,6 +2098,7 @@ struct qla_fcp_prio_cfg {
#define FA_NPIV_CONF1_ADDR_81 0xD2000
/* 83XX Flash locations -- occupies second 8MB region. */
-#define FA_FLASH_LAYOUT_ADDR_83 0xFC400
+#define FA_FLASH_LAYOUT_ADDR_83 (0x3F1000/4)
+#define FA_FLASH_LAYOUT_ADDR_28 (0x11000/4)
#endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 4eefe69ca807..f9669fdf7798 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -18,14 +18,14 @@ extern int qla2100_pci_config(struct scsi_qla_host *);
extern int qla2300_pci_config(struct scsi_qla_host *);
extern int qla24xx_pci_config(scsi_qla_host_t *);
extern int qla25xx_pci_config(scsi_qla_host_t *);
-extern void qla2x00_reset_chip(struct scsi_qla_host *);
-extern void qla24xx_reset_chip(struct scsi_qla_host *);
+extern int qla2x00_reset_chip(struct scsi_qla_host *);
+extern int qla24xx_reset_chip(struct scsi_qla_host *);
extern int qla2x00_chip_diag(struct scsi_qla_host *);
extern int qla24xx_chip_diag(struct scsi_qla_host *);
extern void qla2x00_config_rings(struct scsi_qla_host *);
extern void qla24xx_config_rings(struct scsi_qla_host *);
-extern void qla2x00_reset_adapter(struct scsi_qla_host *);
-extern void qla24xx_reset_adapter(struct scsi_qla_host *);
+extern int qla2x00_reset_adapter(struct scsi_qla_host *);
+extern int qla24xx_reset_adapter(struct scsi_qla_host *);
extern int qla2x00_nvram_config(struct scsi_qla_host *);
extern int qla24xx_nvram_config(struct scsi_qla_host *);
extern int qla81xx_nvram_config(struct scsi_qla_host *);
@@ -38,8 +38,7 @@ extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *);
extern int qla2x00_perform_loop_resync(scsi_qla_host_t *);
extern int qla2x00_loop_resync(scsi_qla_host_t *);
-
-extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
+extern void qla2x00_clear_loop_id(fc_port_t *fcport);
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 *);
@@ -80,6 +79,7 @@ int qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e);
extern void *qla2x00_alloc_iocbs_ready(struct qla_qpair *, srb_t *);
extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *);
+extern void qla2x00_set_fcport_state(fc_port_t *fcport, int state);
extern fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
@@ -93,7 +93,6 @@ 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 *);
extern struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *,
int, int, bool);
extern int qla2xxx_delete_qpair(struct scsi_qla_host *, struct qla_qpair *);
@@ -108,6 +107,11 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *);
int qla24xx_detect_sfp(scsi_qla_host_t *vha);
int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
+extern void qla28xx_get_aux_images(struct scsi_qla_host *,
+ struct active_regions *);
+extern void qla27xx_get_active_image(struct scsi_qla_host *,
+ struct active_regions *);
+
void qla2x00_async_prlo_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_prlo_work(struct scsi_qla_host *, fc_port_t *,
@@ -118,6 +122,7 @@ int qla_post_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport);
void qla_do_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport);
int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *);
void qla_rscn_replay(fc_port_t *fcport);
+extern bool qla24xx_risc_firmware_invalid(uint32_t *);
/*
* Global Data in qla_os.c source file.
@@ -215,7 +220,6 @@ extern void qla24xx_sched_upd_fcport(fc_port_t *);
void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *);
-int qla24xx_async_abort_cmd(srb_t *, bool);
int qla24xx_post_relogin_work(struct scsi_qla_host *vha);
void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *);
@@ -238,7 +242,7 @@ extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
struct vp_rpt_id_entry_24xx *);
extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
-extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
+extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *);
extern void qla2x00_sp_free_dma(void *);
extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
@@ -276,21 +280,20 @@ extern int qla2x00_start_sp(srb_t *);
extern int qla24xx_dif_start_scsi(srb_t *);
extern int qla2x00_start_bidir(srb_t *, struct scsi_qla_host *, uint32_t);
extern int qla2xxx_dif_start_scsi_mq(srb_t *);
+extern void qla2x00_init_timer(srb_t *sp, unsigned long tmo);
extern unsigned long qla2x00_get_async_timeout(struct scsi_qla_host *);
extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *);
extern void *__qla2x00_alloc_iocbs(struct qla_qpair *, srb_t *);
extern int qla2x00_issue_marker(scsi_qla_host_t *, int);
extern int qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *, srb_t *,
- uint32_t *, uint16_t, struct qla_tc_param *);
+ struct dsd64 *, uint16_t, struct qla_tc_param *);
extern int qla24xx_walk_and_build_sglist(struct qla_hw_data *, srb_t *,
- uint32_t *, uint16_t, struct qla_tc_param *);
+ struct dsd64 *, uint16_t, struct qla_tc_param *);
extern int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *, srb_t *,
- uint32_t *, uint16_t, struct qla_tgt_cmd *);
+ struct dsd64 *, uint16_t, struct qla_tgt_cmd *);
extern int qla24xx_get_one_block_sg(uint32_t, struct qla2_sgx *, uint32_t *);
extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *);
-extern int qla24xx_build_scsi_crc_2_iocbs(srb_t *,
- struct cmd_type_crc_2 *, uint16_t, uint16_t, uint16_t);
/*
* Global Function Prototypes in qla_mbx.c source file.
@@ -466,6 +469,8 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *, int);
extern int
qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t);
+extern int qla81xx_fac_semaphore_access(scsi_qla_host_t *, int);
+
extern int
qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *);
@@ -511,6 +516,14 @@ extern int qla27xx_get_zio_threshold(scsi_qla_host_t *, uint16_t *);
extern int qla27xx_set_zio_threshold(scsi_qla_host_t *, uint16_t);
int qla24xx_res_count_wait(struct scsi_qla_host *, uint16_t *, int);
+extern int qla28xx_secure_flash_update(scsi_qla_host_t *, uint16_t, uint16_t,
+ uint32_t, dma_addr_t, uint32_t);
+
+extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t,
+ uint32_t *);
+extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t,
+ uint32_t);
+
/*
* Global Function Prototypes in qla_isr.c source file.
*/
@@ -542,19 +555,20 @@ fc_port_t *qla2x00_find_fcport_by_nportid(scsi_qla_host_t *, port_id_t *, u8);
*/
extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
- uint32_t, uint32_t);
-extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
-extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
-extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
-extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
-extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
-extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
- uint32_t);
+ uint32_t, uint32_t);
+extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, void *, uint32_t,
+ uint32_t);
+extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, void *, uint32_t,
+ uint32_t);
+extern int qla2x00_write_nvram_data(scsi_qla_host_t *, void *, uint32_t,
+ uint32_t);
+extern int qla24xx_write_nvram_data(scsi_qla_host_t *, void *, uint32_t,
+ uint32_t);
+extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, void *, uint32_t,
+ uint32_t);
+extern int qla25xx_write_nvram_data(scsi_qla_host_t *, void *, uint32_t,
+ uint32_t);
+
extern int qla2x00_is_a_vp_did(scsi_qla_host_t *, uint32_t);
bool qla2x00_check_reg32_for_disconnect(scsi_qla_host_t *, uint32_t);
bool qla2x00_check_reg16_for_disconnect(scsi_qla_host_t *, uint16_t);
@@ -574,18 +588,18 @@ extern int qla83xx_restart_nic_firmware(scsi_qla_host_t *);
extern int qla83xx_access_control(scsi_qla_host_t *, uint16_t, uint32_t,
uint32_t, uint16_t *);
-extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
+extern void *qla2x00_read_optrom_data(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
-extern int qla2x00_write_optrom_data(struct scsi_qla_host *, uint8_t *,
+extern int qla2x00_write_optrom_data(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
-extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
+extern void *qla24xx_read_optrom_data(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
-extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
+extern int qla24xx_write_optrom_data(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
-extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
+extern void *qla25xx_read_optrom_data(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
-extern uint8_t *qla8044_read_optrom_data(struct scsi_qla_host *,
- uint8_t *, uint32_t, uint32_t);
+extern void *qla8044_read_optrom_data(struct scsi_qla_host *,
+ void *, uint32_t, uint32_t);
extern void qla8044_watchdog(struct scsi_qla_host *vha);
extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
@@ -610,20 +624,13 @@ extern void qla82xx_fw_dump(scsi_qla_host_t *, int);
extern void qla8044_fw_dump(scsi_qla_host_t *, int);
extern void qla27xx_fwdump(scsi_qla_host_t *, int);
-extern ulong qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *);
+extern ulong qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *, void *);
extern int qla27xx_fwdt_template_valid(void *);
extern ulong qla27xx_fwdt_template_size(void *);
-extern const void *qla27xx_fwdt_template_default(void);
-extern ulong qla27xx_fwdt_template_default_size(void);
-
-extern void qla2x00_dump_regs(scsi_qla_host_t *);
-extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
-extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
-extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t);
-extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t,
- uint8_t *, uint32_t);
-extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int);
+extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int);
+extern void ql_dump_regs(uint, scsi_qla_host_t *, uint);
+extern void ql_dump_buffer(uint, scsi_qla_host_t *, uint, void *, uint);
/*
* Global Function Prototypes in qla_gs.c source file.
*/
@@ -722,7 +729,7 @@ extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
/* qlafx00 related functions */
extern int qlafx00_pci_config(struct scsi_qla_host *);
extern int qlafx00_initialize_adapter(struct scsi_qla_host *);
-extern void qlafx00_soft_reset(scsi_qla_host_t *);
+extern int qlafx00_soft_reset(scsi_qla_host_t *);
extern int qlafx00_chip_diag(scsi_qla_host_t *);
extern void qlafx00_config_rings(struct scsi_qla_host *);
extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *);
@@ -765,16 +772,16 @@ extern int qla82xx_pci_region_offset(struct pci_dev *, int);
extern int qla82xx_iospace_config(struct qla_hw_data *);
/* Initialization related functions */
-extern void qla82xx_reset_chip(struct scsi_qla_host *);
+extern int qla82xx_reset_chip(struct scsi_qla_host *);
extern void qla82xx_config_rings(struct scsi_qla_host *);
extern void qla82xx_watchdog(scsi_qla_host_t *);
extern int qla82xx_start_firmware(scsi_qla_host_t *);
/* Firmware and flash related functions */
extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *);
-extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
+extern void *qla82xx_read_optrom_data(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
-extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
+extern int qla82xx_write_optrom_data(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
/* Mailbox related functions */
@@ -870,7 +877,7 @@ extern void qla8044_clear_drv_active(struct qla_hw_data *);
void qla8044_get_minidump(struct scsi_qla_host *vha);
int qla8044_collect_md_data(struct scsi_qla_host *vha);
extern int qla8044_md_get_template(scsi_qla_host_t *);
-extern int qla8044_write_optrom_data(struct scsi_qla_host *, uint8_t *,
+extern int qla8044_write_optrom_data(struct scsi_qla_host *, void *,
uint32_t, uint32_t);
extern irqreturn_t qla8044_intr_handler(int, void *);
extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t);
@@ -901,4 +908,6 @@ void qlt_clr_qp_table(struct scsi_qla_host *vha);
void qlt_set_mode(struct scsi_qla_host *);
int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode);
+/* nvme.c */
+void qla_nvme_unregister_remote_port(struct fc_port *fcport);
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index c6fdad12428e..9f58e591666d 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -45,13 +45,11 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg)
ms_pkt->rsp_bytecount = cpu_to_le32(arg->rsp_size);
ms_pkt->req_bytecount = cpu_to_le32(arg->req_size);
- ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(arg->req_dma));
- ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(arg->req_dma));
- ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
+ put_unaligned_le64(arg->req_dma, &ms_pkt->req_dsd.address);
+ ms_pkt->req_dsd.length = ms_pkt->req_bytecount;
- ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(arg->rsp_dma));
- ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(arg->rsp_dma));
- ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
+ put_unaligned_le64(arg->rsp_dma, &ms_pkt->rsp_dsd.address);
+ ms_pkt->rsp_dsd.length = ms_pkt->rsp_bytecount;
vha->qla_stats.control_requests++;
@@ -83,13 +81,11 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg)
ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size);
ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size);
- ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(arg->req_dma));
- ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(arg->req_dma));
- ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
+ put_unaligned_le64(arg->req_dma, &ct_pkt->dsd[0].address);
+ ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
- ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(arg->rsp_dma));
- ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(arg->rsp_dma));
- ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+ put_unaligned_le64(arg->rsp_dma, &ct_pkt->dsd[1].address);
+ ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
ct_pkt->vp_index = vha->vp_idx;
vha->qla_stats.control_requests++;
@@ -152,8 +148,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
vha->d_id.b.area, vha->d_id.b.al_pa,
comp_status, ct_rsp->header.response);
ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha,
- 0x2078, (uint8_t *)&ct_rsp->header,
- sizeof(struct ct_rsp_hdr));
+ 0x2078, ct_rsp,
+ offsetof(typeof(*ct_rsp), rsp));
rval = QLA_INVALID_COMMAND;
} else
rval = QLA_SUCCESS;
@@ -1000,8 +996,7 @@ qla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len,
memset(sns_cmd, 0, sizeof(struct sns_cmd_pkt));
wc = data_size / 2; /* Size in 16bit words. */
sns_cmd->p.cmd.buffer_length = cpu_to_le16(wc);
- sns_cmd->p.cmd.buffer_address[0] = cpu_to_le32(LSD(ha->sns_cmd_dma));
- sns_cmd->p.cmd.buffer_address[1] = cpu_to_le32(MSD(ha->sns_cmd_dma));
+ put_unaligned_le64(ha->sns_cmd_dma, &sns_cmd->p.cmd.buffer_address);
sns_cmd->p.cmd.subcommand_length = cpu_to_le16(scmd_len);
sns_cmd->p.cmd.subcommand = cpu_to_le16(cmd);
wc = (data_size - 16) / 4; /* Size in 32bit words. */
@@ -1385,6 +1380,7 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *vha)
int ret, rval;
uint16_t mb[MAILBOX_REGISTER_COUNT];
struct qla_hw_data *ha = vha->hw;
+
ret = QLA_SUCCESS;
if (vha->flags.management_server_logged_in)
return ret;
@@ -1423,6 +1419,7 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size,
{
ms_iocb_entry_t *ms_pkt;
struct qla_hw_data *ha = vha->hw;
+
ms_pkt = ha->ms_iocb;
memset(ms_pkt, 0, sizeof(ms_iocb_entry_t));
@@ -1436,13 +1433,11 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size,
ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
ms_pkt->req_bytecount = cpu_to_le32(req_size);
- ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
- ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
- ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
+ put_unaligned_le64(ha->ct_sns_dma, &ms_pkt->req_dsd.address);
+ ms_pkt->req_dsd.length = ms_pkt->req_bytecount;
- ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
- ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
- ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
+ put_unaligned_le64(ha->ct_sns_dma, &ms_pkt->rsp_dsd.address);
+ ms_pkt->rsp_dsd.length = ms_pkt->rsp_bytecount;
return ms_pkt;
}
@@ -1474,13 +1469,11 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size,
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
- ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
- ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
- ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
+ put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[0].address);
+ ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
- ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
- ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
- ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+ put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[1].address);
+ ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
ct_pkt->vp_index = vha->vp_idx;
return ct_pkt;
@@ -1495,10 +1488,10 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size)
if (IS_FWI2_CAPABLE(ha)) {
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
- ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
+ ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
} else {
ms_pkt->req_bytecount = cpu_to_le32(req_size);
- ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
+ ms_pkt->req_dsd.length = ms_pkt->req_bytecount;
}
return ms_pkt;
@@ -1794,7 +1787,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
if (IS_CNA_CAPABLE(ha))
eiter->a.sup_speed = cpu_to_be32(
FDMI_PORT_SPEED_10GB);
- else if (IS_QLA27XX(ha))
+ else if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
eiter->a.sup_speed = cpu_to_be32(
FDMI_PORT_SPEED_32GB|
FDMI_PORT_SPEED_16GB|
@@ -2373,7 +2366,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha)
if (IS_CNA_CAPABLE(ha))
eiter->a.sup_speed = cpu_to_be32(
FDMI_PORT_SPEED_10GB);
- else if (IS_QLA27XX(ha))
+ else if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
eiter->a.sup_speed = cpu_to_be32(
FDMI_PORT_SPEED_32GB|
FDMI_PORT_SPEED_16GB|
@@ -2446,7 +2439,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha)
eiter->type = cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
eiter->len = cpu_to_be16(4 + 4);
eiter->a.max_frame_size = IS_FWI2_CAPABLE(ha) ?
- le16_to_cpu(icb24->frame_payload_size):
+ le16_to_cpu(icb24->frame_payload_size) :
le16_to_cpu(ha->init_cb->frame_payload_size);
eiter->a.max_frame_size = cpu_to_be32(eiter->a.max_frame_size);
size += 4 + 4;
@@ -2783,6 +2776,31 @@ qla24xx_prep_ct_fm_req(struct ct_sns_pkt *p, uint16_t cmd,
return &p->p.req;
}
+static uint16_t
+qla2x00_port_speed_capability(uint16_t speed)
+{
+ switch (speed) {
+ case BIT_15:
+ return PORT_SPEED_1GB;
+ case BIT_14:
+ return PORT_SPEED_2GB;
+ case BIT_13:
+ return PORT_SPEED_4GB;
+ case BIT_12:
+ return PORT_SPEED_10GB;
+ case BIT_11:
+ return PORT_SPEED_8GB;
+ case BIT_10:
+ return PORT_SPEED_16GB;
+ case BIT_8:
+ return PORT_SPEED_32GB;
+ case BIT_7:
+ return PORT_SPEED_64GB;
+ default:
+ return PORT_SPEED_UNKNOWN;
+ }
+}
+
/**
* qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query.
* @vha: HA context
@@ -2855,31 +2873,8 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
}
rval = QLA_FUNCTION_FAILED;
} else {
- /* Save port-speed */
- switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) {
- case BIT_15:
- list[i].fp_speed = PORT_SPEED_1GB;
- break;
- case BIT_14:
- list[i].fp_speed = PORT_SPEED_2GB;
- break;
- case BIT_13:
- list[i].fp_speed = PORT_SPEED_4GB;
- break;
- case BIT_12:
- list[i].fp_speed = PORT_SPEED_10GB;
- break;
- case BIT_11:
- list[i].fp_speed = PORT_SPEED_8GB;
- break;
- case BIT_10:
- list[i].fp_speed = PORT_SPEED_16GB;
- break;
- case BIT_8:
- list[i].fp_speed = PORT_SPEED_32GB;
- break;
- }
-
+ list->fp_speed = qla2x00_port_speed_capability(
+ be16_to_cpu(ct_rsp->rsp.gpsc.speed));
ql_dbg(ql_dbg_disc, vha, 0x205b,
"GPSC ext entry - fpn "
"%8phN speeds=%04x speed=%04x.\n",
@@ -3031,6 +3026,8 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res)
"Async done-%s res %x, WWPN %8phC \n",
sp->name, res, fcport->port_name);
+ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
+
if (res == QLA_FUNCTION_TIMEOUT)
return;
@@ -3048,29 +3045,8 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res)
goto done;
}
} else {
- switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) {
- case BIT_15:
- fcport->fp_speed = PORT_SPEED_1GB;
- break;
- case BIT_14:
- fcport->fp_speed = PORT_SPEED_2GB;
- break;
- case BIT_13:
- fcport->fp_speed = PORT_SPEED_4GB;
- break;
- case BIT_12:
- fcport->fp_speed = PORT_SPEED_10GB;
- break;
- case BIT_11:
- fcport->fp_speed = PORT_SPEED_8GB;
- break;
- case BIT_10:
- fcport->fp_speed = PORT_SPEED_16GB;
- break;
- case BIT_8:
- fcport->fp_speed = PORT_SPEED_32GB;
- break;
- }
+ fcport->fp_speed = qla2x00_port_speed_capability(
+ be16_to_cpu(ct_rsp->rsp.gpsc.speed));
ql_dbg(ql_dbg_disc, vha, 0x2054,
"Async-%s OUT WWPN %8phC speeds=%04x speed=%04x.\n",
@@ -4370,6 +4346,7 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport)
done_free_sp:
sp->free(sp);
+ fcport->flags &= ~FCF_ASYNC_SENT;
done:
return rval;
}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 0c700b140ce7..4059655639d9 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -95,6 +95,79 @@ qla2x00_get_async_timeout(struct scsi_qla_host *vha)
return tmo;
}
+static void qla24xx_abort_iocb_timeout(void *data)
+{
+ srb_t *sp = data;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ abt->u.abt.comp_status = CS_TIMEOUT;
+ sp->done(sp, QLA_FUNCTION_TIMEOUT);
+}
+
+static void qla24xx_abort_sp_done(void *ptr, int res)
+{
+ srb_t *sp = ptr;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ if (del_timer(&sp->u.iocb_cmd.timer)) {
+ if (sp->flags & SRB_WAKEUP_ON_COMP)
+ complete(&abt->u.abt.comp);
+ else
+ sp->free(sp);
+ }
+}
+
+static int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
+{
+ scsi_qla_host_t *vha = cmd_sp->vha;
+ struct srb_iocb *abt_iocb;
+ srb_t *sp;
+ int rval = QLA_FUNCTION_FAILED;
+
+ sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport,
+ GFP_ATOMIC);
+ if (!sp)
+ goto done;
+
+ abt_iocb = &sp->u.iocb_cmd;
+ sp->type = SRB_ABT_CMD;
+ sp->name = "abort";
+ sp->qpair = cmd_sp->qpair;
+ if (wait)
+ sp->flags = SRB_WAKEUP_ON_COMP;
+
+ abt_iocb->timeout = qla24xx_abort_iocb_timeout;
+ init_completion(&abt_iocb->u.abt.comp);
+ /* FW can send 2 x ABTS's timeout/20s */
+ qla2x00_init_timer(sp, 42);
+
+ abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
+ abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id);
+
+ sp->done = qla24xx_abort_sp_done;
+
+ ql_dbg(ql_dbg_async, vha, 0x507c,
+ "Abort command issued - hdl=%x, type=%x\n", cmd_sp->handle,
+ cmd_sp->type);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ if (wait) {
+ wait_for_completion(&abt_iocb->u.abt.comp);
+ rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
+ } else {
+ goto done;
+ }
+
+done_free_sp:
+ sp->free(sp);
+done:
+ return rval;
+}
+
void
qla2x00_async_iocb_timeout(void *data)
{
@@ -514,6 +587,72 @@ done:
return rval;
}
+static bool qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (IS_FWI2_CAPABLE(ha))
+ return loop_id > NPH_LAST_HANDLE;
+
+ return (loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
+ loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST;
+}
+
+/**
+ * qla2x00_find_new_loop_id - scan through our port list and find a new usable loop ID
+ * @vha: adapter state pointer.
+ * @dev: port structure pointer.
+ *
+ * Returns:
+ * qla2x00 local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+static int qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
+{
+ int rval;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags = 0;
+
+ rval = QLA_SUCCESS;
+
+ spin_lock_irqsave(&ha->vport_slock, flags);
+
+ dev->loop_id = find_first_zero_bit(ha->loop_id_map, LOOPID_MAP_SIZE);
+ if (dev->loop_id >= LOOPID_MAP_SIZE ||
+ qla2x00_is_reserved_id(vha, dev->loop_id)) {
+ dev->loop_id = FC_NO_LOOP_ID;
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ set_bit(dev->loop_id, ha->loop_id_map);
+ }
+ spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+ if (rval == QLA_SUCCESS)
+ ql_dbg(ql_dbg_disc, dev->vha, 0x2086,
+ "Assigning new loopid=%x, portid=%x.\n",
+ dev->loop_id, dev->d_id.b24);
+ else
+ ql_log(ql_log_warn, dev->vha, 0x2087,
+ "No loop_id's available, portid=%x.\n",
+ dev->d_id.b24);
+
+ return rval;
+}
+
+void qla2x00_clear_loop_id(fc_port_t *fcport)
+{
+ struct qla_hw_data *ha = fcport->vha->hw;
+
+ if (fcport->loop_id == FC_NO_LOOP_ID ||
+ qla2x00_is_reserved_id(fcport->vha, fcport->loop_id))
+ return;
+
+ clear_bit(fcport->loop_id, ha->loop_id_map);
+ fcport->loop_id = FC_NO_LOOP_ID;
+}
+
static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
struct event_arg *ea)
{
@@ -1482,6 +1621,7 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id,
u8 *port_name, u8 *node_name, void *pla, u8 fc4_type)
{
struct qla_work_evt *e;
+
e = qla2x00_alloc_work(vha, QLA_EVT_NEW_SESS);
if (!e)
return QLA_FUNCTION_FAILED;
@@ -1558,6 +1698,7 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
return;
{
unsigned long flags;
+
fcport = qla2x00_find_fcport_by_nportid
(vha, &ea->id, 1);
if (fcport) {
@@ -1620,21 +1761,21 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
*/
void qla_rscn_replay(fc_port_t *fcport)
{
- struct event_arg ea;
+ struct event_arg ea;
- switch (fcport->disc_state) {
- case DSC_DELETE_PEND:
- return;
- default:
- break;
- }
+ switch (fcport->disc_state) {
+ case DSC_DELETE_PEND:
+ return;
+ default:
+ break;
+ }
- if (fcport->scan_needed) {
- memset(&ea, 0, sizeof(ea));
- ea.event = FCME_RSCN;
- ea.id = fcport->d_id;
- ea.id.b.rsvd_1 = RSCN_PORT_ADDR;
- qla2x00_fcport_event_handler(fcport->vha, &ea);
+ if (fcport->scan_needed) {
+ memset(&ea, 0, sizeof(ea));
+ ea.event = FCME_RSCN;
+ ea.id = fcport->d_id;
+ ea.id.b.rsvd_1 = RSCN_PORT_ADDR;
+ qla2x00_fcport_event_handler(fcport->vha, &ea);
}
}
@@ -1717,82 +1858,6 @@ done:
return rval;
}
-static void
-qla24xx_abort_iocb_timeout(void *data)
-{
- srb_t *sp = data;
- struct srb_iocb *abt = &sp->u.iocb_cmd;
-
- abt->u.abt.comp_status = CS_TIMEOUT;
- sp->done(sp, QLA_FUNCTION_TIMEOUT);
-}
-
-static void
-qla24xx_abort_sp_done(void *ptr, int res)
-{
- srb_t *sp = ptr;
- struct srb_iocb *abt = &sp->u.iocb_cmd;
-
- if (del_timer(&sp->u.iocb_cmd.timer)) {
- if (sp->flags & SRB_WAKEUP_ON_COMP)
- complete(&abt->u.abt.comp);
- else
- sp->free(sp);
- }
-}
-
-int
-qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
-{
- scsi_qla_host_t *vha = cmd_sp->vha;
- struct srb_iocb *abt_iocb;
- srb_t *sp;
- int rval = QLA_FUNCTION_FAILED;
-
- sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport,
- GFP_ATOMIC);
- if (!sp)
- goto done;
-
- abt_iocb = &sp->u.iocb_cmd;
- sp->type = SRB_ABT_CMD;
- sp->name = "abort";
- sp->qpair = cmd_sp->qpair;
- if (wait)
- sp->flags = SRB_WAKEUP_ON_COMP;
-
- abt_iocb->timeout = qla24xx_abort_iocb_timeout;
- init_completion(&abt_iocb->u.abt.comp);
- /* FW can send 2 x ABTS's timeout/20s */
- qla2x00_init_timer(sp, 42);
-
- abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
- abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id);
-
- sp->done = qla24xx_abort_sp_done;
-
- ql_dbg(ql_dbg_async, vha, 0x507c,
- "Abort command issued - hdl=%x, type=%x\n",
- cmd_sp->handle, cmd_sp->type);
-
- rval = qla2x00_start_sp(sp);
- if (rval != QLA_SUCCESS)
- goto done_free_sp;
-
- if (wait) {
- wait_for_completion(&abt_iocb->u.abt.comp);
- rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
- QLA_SUCCESS : QLA_FUNCTION_FAILED;
- } else {
- goto done;
- }
-
-done_free_sp:
- sp->free(sp);
-done:
- return rval;
-}
-
int
qla24xx_async_abort_command(srb_t *sp)
{
@@ -2102,6 +2167,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
int rval;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
memset(&vha->qla_stats, 0, sizeof(vha->qla_stats));
memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
@@ -2136,6 +2202,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
ha->isp_ops->reset_chip(vha);
+ /* Check for secure flash support */
+ if (IS_QLA28XX(ha)) {
+ if (RD_REG_DWORD(&reg->mailbox12) & BIT_0) {
+ ql_log(ql_log_info, vha, 0xffff, "Adapter is Secure\n");
+ ha->flags.secure_adapter = 1;
+ }
+ }
+
+
rval = qla2xxx_get_flash_info(vha);
if (rval) {
ql_log(ql_log_fatal, vha, 0x004f,
@@ -2452,7 +2527,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
*
* Returns 0 on success.
*/
-void
+int
qla2x00_reset_chip(scsi_qla_host_t *vha)
{
unsigned long flags = 0;
@@ -2460,9 +2535,10 @@ qla2x00_reset_chip(scsi_qla_host_t *vha)
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
uint32_t cnt;
uint16_t cmd;
+ int rval = QLA_FUNCTION_FAILED;
if (unlikely(pci_channel_offline(ha->pdev)))
- return;
+ return rval;
ha->isp_ops->disable_intrs(ha);
@@ -2588,6 +2664,8 @@ qla2x00_reset_chip(scsi_qla_host_t *vha)
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_SUCCESS;
}
/**
@@ -2828,14 +2906,15 @@ acquired:
*
* Returns 0 on success.
*/
-void
+int
qla24xx_reset_chip(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+ int rval = QLA_FUNCTION_FAILED;
if (pci_channel_offline(ha->pdev) &&
ha->flags.pci_channel_io_perm_failure) {
- return;
+ return rval;
}
ha->isp_ops->disable_intrs(ha);
@@ -2843,7 +2922,9 @@ qla24xx_reset_chip(scsi_qla_host_t *vha)
qla25xx_manipulate_risc_semaphore(vha);
/* Perform RISC reset. */
- qla24xx_reset_risc(vha);
+ rval = qla24xx_reset_risc(vha);
+
+ return rval;
}
/**
@@ -3018,7 +3099,7 @@ qla2x00_alloc_offload_mem(scsi_qla_host_t *vha)
if (IS_FWI2_CAPABLE(ha)) {
/* Allocate memory for Fibre Channel Event Buffer. */
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
- !IS_QLA27XX(ha))
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
goto try_eft;
if (ha->fce)
@@ -3089,12 +3170,15 @@ eft_err:
void
qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
{
+ int rval;
uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
eft_size, fce_size, mq_size;
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];
struct qla2xxx_fw_dump *fw_dump;
+ dma_addr_t tc_dma;
+ void *tc;
dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
req_q_size = rsp_q_size = 0;
@@ -3106,7 +3190,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
mem_size = (ha->fw_memory_size - 0x11000 + 1) *
sizeof(uint16_t);
} else if (IS_FWI2_CAPABLE(ha)) {
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem);
else if (IS_QLA81XX(ha))
fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
@@ -3118,40 +3202,72 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
sizeof(uint32_t);
if (ha->mqenable) {
- if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) &&
+ !IS_QLA28XX(ha))
mq_size = sizeof(struct qla2xxx_mq_chain);
/*
- * Allocate maximum buffer size for all queues.
+ * Allocate maximum buffer size for all queues - Q0.
* Resizing must be done at end-of-dump processing.
*/
- mq_size += ha->max_req_queues *
+ mq_size += (ha->max_req_queues - 1) *
(req->length * sizeof(request_t));
- mq_size += ha->max_rsp_queues *
+ mq_size += (ha->max_rsp_queues - 1) *
(rsp->length * sizeof(response_t));
}
if (ha->tgt.atio_ring)
mq_size += ha->tgt.atio_q_length * sizeof(request_t);
/* Allocate memory for Fibre Channel Event Buffer. */
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
- !IS_QLA27XX(ha))
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
goto try_eft;
fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
try_eft:
+ if (ha->eft)
+ dma_free_coherent(&ha->pdev->dev,
+ EFT_SIZE, ha->eft, ha->eft_dma);
+
+ /* Allocate memory for Extended Trace Buffer. */
+ tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
+ GFP_KERNEL);
+ if (!tc) {
+ ql_log(ql_log_warn, vha, 0x00c1,
+ "Unable to allocate (%d KB) for EFT.\n",
+ EFT_SIZE / 1024);
+ goto allocate;
+ }
+
+ rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
+ if (rval) {
+ ql_log(ql_log_warn, vha, 0x00c2,
+ "Unable to initialize EFT (%d).\n", rval);
+ dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
+ tc_dma);
+ }
ql_dbg(ql_dbg_init, vha, 0x00c3,
"Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024);
eft_size = EFT_SIZE;
}
- if (IS_QLA27XX(ha)) {
- if (!ha->fw_dump_template) {
- ql_log(ql_log_warn, vha, 0x00ba,
- "Failed missing fwdump template\n");
- return;
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+ struct fwdt *fwdt = ha->fwdt;
+ uint j;
+
+ for (j = 0; j < 2; j++, fwdt++) {
+ if (!fwdt->template) {
+ ql_log(ql_log_warn, vha, 0x00ba,
+ "-> fwdt%u no template\n", j);
+ continue;
+ }
+ ql_dbg(ql_dbg_init, vha, 0x00fa,
+ "-> fwdt%u calculating fwdump size...\n", j);
+ fwdt->dump_size = qla27xx_fwdt_calculate_dump_size(
+ vha, fwdt->template);
+ ql_dbg(ql_dbg_init, vha, 0x00fa,
+ "-> fwdt%u calculated fwdump size = %#lx bytes\n",
+ j, fwdt->dump_size);
+ dump_size += fwdt->dump_size;
}
- dump_size = qla27xx_fwdt_calculate_dump_size(vha);
- ql_dbg(ql_dbg_init, vha, 0x00fa,
- "-> allocating fwdump (%x bytes)...\n", dump_size);
goto allocate;
}
@@ -3170,42 +3286,66 @@ try_eft:
ha->exlogin_size;
allocate:
- if (!ha->fw_dump_len || dump_size != ha->fw_dump_len) {
+ if (!ha->fw_dump_len || dump_size > ha->fw_dump_alloc_len) {
+
+ ql_dbg(ql_dbg_init, vha, 0x00c5,
+ "%s dump_size %d fw_dump_len %d fw_dump_alloc_len %d\n",
+ __func__, dump_size, ha->fw_dump_len,
+ ha->fw_dump_alloc_len);
+
fw_dump = vmalloc(dump_size);
if (!fw_dump) {
ql_log(ql_log_warn, vha, 0x00c4,
"Unable to allocate (%d KB) for firmware dump.\n",
dump_size / 1024);
} else {
- if (ha->fw_dump)
+ mutex_lock(&ha->optrom_mutex);
+ if (ha->fw_dumped) {
+ memcpy(fw_dump, ha->fw_dump, ha->fw_dump_len);
vfree(ha->fw_dump);
- ha->fw_dump = fw_dump;
-
- ha->fw_dump_len = dump_size;
- ql_dbg(ql_dbg_init, vha, 0x00c5,
- "Allocated (%d KB) for firmware dump.\n",
- dump_size / 1024);
-
- if (IS_QLA27XX(ha))
- return;
-
- ha->fw_dump->signature[0] = 'Q';
- ha->fw_dump->signature[1] = 'L';
- ha->fw_dump->signature[2] = 'G';
- ha->fw_dump->signature[3] = 'C';
- ha->fw_dump->version = htonl(1);
-
- ha->fw_dump->fixed_size = htonl(fixed_size);
- ha->fw_dump->mem_size = htonl(mem_size);
- ha->fw_dump->req_q_size = htonl(req_q_size);
- ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
-
- ha->fw_dump->eft_size = htonl(eft_size);
- ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
- ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
+ ha->fw_dump = fw_dump;
+ ha->fw_dump_alloc_len = dump_size;
+ ql_dbg(ql_dbg_init, vha, 0x00c5,
+ "Re-Allocated (%d KB) and save firmware dump.\n",
+ dump_size / 1024);
+ } else {
+ if (ha->fw_dump)
+ vfree(ha->fw_dump);
+ ha->fw_dump = fw_dump;
+
+ ha->fw_dump_len = ha->fw_dump_alloc_len =
+ dump_size;
+ ql_dbg(ql_dbg_init, vha, 0x00c5,
+ "Allocated (%d KB) for firmware dump.\n",
+ dump_size / 1024);
+
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+ mutex_unlock(&ha->optrom_mutex);
+ return;
+ }
- ha->fw_dump->header_size =
- htonl(offsetof(struct qla2xxx_fw_dump, isp));
+ ha->fw_dump->signature[0] = 'Q';
+ ha->fw_dump->signature[1] = 'L';
+ ha->fw_dump->signature[2] = 'G';
+ ha->fw_dump->signature[3] = 'C';
+ ha->fw_dump->version = htonl(1);
+
+ ha->fw_dump->fixed_size = htonl(fixed_size);
+ ha->fw_dump->mem_size = htonl(mem_size);
+ ha->fw_dump->req_q_size = htonl(req_q_size);
+ ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
+
+ ha->fw_dump->eft_size = htonl(eft_size);
+ ha->fw_dump->eft_addr_l =
+ htonl(LSD(ha->eft_dma));
+ ha->fw_dump->eft_addr_h =
+ htonl(MSD(ha->eft_dma));
+
+ ha->fw_dump->header_size =
+ htonl(offsetof
+ (struct qla2xxx_fw_dump, isp));
+ }
+ mutex_unlock(&ha->optrom_mutex);
}
}
}
@@ -3498,7 +3638,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
if (rval == QLA_SUCCESS) {
qla24xx_detect_sfp(vha);
- if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
+ if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) &&
(ha->zio_mode == QLA_ZIO_MODE_6))
qla27xx_set_zio_threshold(vha,
ha->last_zio_threshold);
@@ -3570,7 +3711,7 @@ enable_82xx_npiv:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
- if (IS_QLA27XX(ha))
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
ha->flags.fac_supported = 1;
else if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
uint32_t size;
@@ -3585,7 +3726,8 @@ enable_82xx_npiv:
ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version);
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
ha->flags.fac_supported = 0;
rval = QLA_SUCCESS;
}
@@ -3647,8 +3789,7 @@ qla2x00_update_fw_options(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0115,
"Serial link options.\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0109,
- (uint8_t *)&ha->fw_seriallink_options,
- sizeof(ha->fw_seriallink_options));
+ ha->fw_seriallink_options, sizeof(ha->fw_seriallink_options));
ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
if (ha->fw_seriallink_options[3] & BIT_2) {
@@ -3738,7 +3879,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
/* Move PUREX, ABTS RX & RIDA to ATIOQ */
if (ql2xmvasynctoatio &&
- (IS_QLA83XX(ha) || IS_QLA27XX(ha))) {
+ (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))) {
if (qla_tgt_mode_enabled(vha) ||
qla_dual_mode_enabled(vha))
ha->fw_options[2] |= BIT_11;
@@ -3746,7 +3887,8 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
ha->fw_options[2] &= ~BIT_11;
}
- if (IS_QLA25XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA25XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
/*
* Tell FW to track each exchange to prevent
* driver from using stale exchange.
@@ -3799,10 +3941,8 @@ qla2x00_config_rings(struct scsi_qla_host *vha)
ha->init_cb->response_q_inpointer = cpu_to_le16(0);
ha->init_cb->request_q_length = cpu_to_le16(req->length);
ha->init_cb->response_q_length = cpu_to_le16(rsp->length);
- ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
- ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
- ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
- ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
+ put_unaligned_le64(req->dma, &ha->init_cb->request_q_address);
+ put_unaligned_le64(rsp->dma, &ha->init_cb->response_q_address);
WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0);
WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0);
@@ -3829,21 +3969,19 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
icb->response_q_inpointer = cpu_to_le16(0);
icb->request_q_length = cpu_to_le16(req->length);
icb->response_q_length = cpu_to_le16(rsp->length);
- icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
- icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
- icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
- icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
+ put_unaligned_le64(req->dma, &icb->request_q_address);
+ put_unaligned_le64(rsp->dma, &icb->response_q_address);
/* Setup ATIO queue dma pointers for target mode */
icb->atio_q_inpointer = cpu_to_le16(0);
icb->atio_q_length = cpu_to_le16(ha->tgt.atio_q_length);
- icb->atio_q_address[0] = cpu_to_le32(LSD(ha->tgt.atio_dma));
- icb->atio_q_address[1] = cpu_to_le32(MSD(ha->tgt.atio_dma));
+ put_unaligned_le64(ha->tgt.atio_dma, &icb->atio_q_address);
if (IS_SHADOW_REG_CAPABLE(ha))
icb->firmware_options_2 |= cpu_to_le32(BIT_30|BIT_29);
- if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
icb->qos = cpu_to_le16(QLA_DEFAULT_QUE_QOS);
icb->rid = cpu_to_le16(rid);
if (ha->flags.msix_enabled) {
@@ -4266,11 +4404,14 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
{
char *st, *en;
uint16_t index;
+ uint64_t zero[2] = { 0 };
struct qla_hw_data *ha = vha->hw;
int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
!IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha);
- if (memcmp(model, BINZERO, len) != 0) {
+ if (len > sizeof(zero))
+ len = sizeof(zero);
+ if (memcmp(model, &zero, len) != 0) {
strncpy(ha->model_number, model, len);
st = en = ha->model_number;
en += len - 1;
@@ -4357,7 +4498,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
rval = QLA_SUCCESS;
/* Determine NVRAM starting address. */
- ha->nvram_size = sizeof(nvram_t);
+ ha->nvram_size = sizeof(*nv);
ha->nvram_base = 0;
if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
if ((RD_REG_WORD(&reg->ctrl_status) >> 14) == 1)
@@ -4371,16 +4512,15 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010f,
"Contents of NVRAM.\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0110,
- (uint8_t *)nv, ha->nvram_size);
+ nv, ha->nvram_size);
/* Bad NVRAM data, set defaults parameters. */
- if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
- nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
+ if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
+ nv->nvram_version < 1) {
/* Reset NVRAM data. */
ql_log(ql_log_warn, vha, 0x0064,
- "Inconsistent NVRAM "
- "detected: checksum=0x%x id=%c version=0x%x.\n",
- chksum, nv->id[0], nv->nvram_version);
+ "Inconsistent NVRAM detected: checksum=%#x id=%.4s version=%#x.\n",
+ chksum, nv->id, nv->nvram_version);
ql_log(ql_log_warn, vha, 0x0065,
"Falling back to "
"functioning (yet invalid -- WWPN) defaults.\n");
@@ -4629,7 +4769,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
ha->zio_mode = icb->add_firmware_options[0] &
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
ha->zio_timer = icb->interrupt_delay_timer ?
- icb->interrupt_delay_timer: 2;
+ icb->interrupt_delay_timer : 2;
}
icb->add_firmware_options[0] &=
~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
@@ -4662,7 +4802,7 @@ qla2x00_rport_del(void *data)
unsigned long flags;
spin_lock_irqsave(fcport->vha->host->host_lock, flags);
- rport = fcport->drport ? fcport->drport: fcport->rport;
+ rport = fcport->drport ? fcport->drport : fcport->rport;
fcport->drport = NULL;
spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
if (rport) {
@@ -4675,6 +4815,23 @@ qla2x00_rport_del(void *data)
}
}
+void qla2x00_set_fcport_state(fc_port_t *fcport, int state)
+{
+ int old_state;
+
+ old_state = atomic_read(&fcport->state);
+ atomic_set(&fcport->state, state);
+
+ /* Don't print state transitions during initial allocation of fcport */
+ if (old_state && old_state != state) {
+ ql_dbg(ql_dbg_disc, fcport->vha, 0x207d,
+ "FCPort %8phC state transitioned from %s to %s - portid=%02x%02x%02x.\n",
+ fcport->port_name, port_state_str[old_state],
+ port_state_str[state], fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+ }
+}
+
/**
* qla2x00_alloc_fcport() - Allocate a generic fcport.
* @vha: HA context
@@ -4741,6 +4898,8 @@ qla2x00_free_fcport(fc_port_t *fcport)
fcport->ct_desc.ct_sns = NULL;
}
+ list_del(&fcport->list);
+ qla2x00_clear_loop_id(fcport);
kfree(fcport);
}
@@ -4762,6 +4921,7 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
int rval;
unsigned long flags, save_flags;
struct qla_hw_data *ha = vha->hw;
+
rval = QLA_SUCCESS;
/* Get Initiator ID */
@@ -4943,8 +5103,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_disc, vha, 0x2011,
"Entries in ID list (%d).\n", entries);
ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075,
- (uint8_t *)ha->gid_list,
- entries * sizeof(struct gid_list_info));
+ ha->gid_list, entries * sizeof(*ha->gid_list));
if (entries == 0) {
spin_lock_irqsave(&vha->work_lock, flags);
@@ -5194,16 +5353,23 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
rport->supported_classes = fcport->supported_classes;
- rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
+ rport_ids.roles = FC_PORT_ROLE_UNKNOWN;
if (fcport->port_type == FCT_INITIATOR)
- rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+ rport_ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
if (fcport->port_type == FCT_TARGET)
- rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
+ rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET;
+ if (fcport->port_type & FCT_NVME_INITIATOR)
+ rport_ids.roles |= FC_PORT_ROLE_NVME_INITIATOR;
+ if (fcport->port_type & FCT_NVME_TARGET)
+ rport_ids.roles |= FC_PORT_ROLE_NVME_TARGET;
+ if (fcport->port_type & FCT_NVME_DISCOVERY)
+ rport_ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY;
ql_dbg(ql_dbg_disc, vha, 0x20ee,
"%s %8phN. rport %p is %s mode\n",
__func__, fcport->port_name, rport,
- (fcport->port_type == FCT_TARGET) ? "tgt" : "ini");
+ (fcport->port_type == FCT_TARGET) ? "tgt" :
+ ((fcport->port_type & FCT_NVME) ? "nvme" :"ini"));
fc_remote_port_rolechg(rport, rport_ids.roles);
}
@@ -5237,7 +5403,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
fcport->deleted = 0;
fcport->logout_on_delete = 1;
- fcport->login_retry = vha->hw->login_retry_count;
fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0;
switch (vha->hw->current_topology) {
@@ -5778,55 +5943,6 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
return (rval);
}
-/*
- * qla2x00_find_new_loop_id
- * Scan through our port list and find a new usable loop ID.
- *
- * Input:
- * ha: adapter state pointer.
- * dev: port structure pointer.
- *
- * Returns:
- * qla2x00 local function return status code.
- *
- * Context:
- * Kernel context.
- */
-int
-qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
-{
- int rval;
- struct qla_hw_data *ha = vha->hw;
- unsigned long flags = 0;
-
- rval = QLA_SUCCESS;
-
- spin_lock_irqsave(&ha->vport_slock, flags);
-
- dev->loop_id = find_first_zero_bit(ha->loop_id_map,
- LOOPID_MAP_SIZE);
- if (dev->loop_id >= LOOPID_MAP_SIZE ||
- qla2x00_is_reserved_id(vha, dev->loop_id)) {
- dev->loop_id = FC_NO_LOOP_ID;
- rval = QLA_FUNCTION_FAILED;
- } else
- set_bit(dev->loop_id, ha->loop_id_map);
-
- spin_unlock_irqrestore(&ha->vport_slock, flags);
-
- if (rval == QLA_SUCCESS)
- ql_dbg(ql_dbg_disc, dev->vha, 0x2086,
- "Assigning new loopid=%x, portid=%x.\n",
- dev->loop_id, dev->d_id.b24);
- else
- ql_log(ql_log_warn, dev->vha, 0x2087,
- "No loop_id's available, portid=%x.\n",
- dev->d_id.b24);
-
- return (rval);
-}
-
-
/* FW does not set aside Loop id for MGMT Server/FFFFFAh */
int
qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *vha)
@@ -6318,6 +6434,7 @@ qla83xx_initiating_reset(scsi_qla_host_t *vha)
qla83xx_idc_audit(vha, IDC_AUDIT_TIMESTAMP);
} else {
const char *state = qla83xx_dev_state_to_string(dev_state);
+
ql_log(ql_log_info, vha, 0xb057, "HW State: %s.\n", state);
/* SV: XXX: Is timeout required here? */
@@ -6639,6 +6756,14 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
if (vha->flags.online) {
qla2x00_abort_isp_cleanup(vha);
+ if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) {
+ ha->flags.chip_reset_done = 1;
+ vha->flags.online = 1;
+ status = 0;
+ clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
+ return status;
+ }
+
if (IS_QLA8031(ha)) {
ql_dbg(ql_dbg_p3p, vha, 0xb05c,
"Clearing fcoe driver presence.\n");
@@ -6879,7 +7004,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
* Input:
* ha = adapter block pointer.
*/
-void
+int
qla2x00_reset_adapter(scsi_qla_host_t *vha)
{
unsigned long flags = 0;
@@ -6895,17 +7020,20 @@ qla2x00_reset_adapter(scsi_qla_host_t *vha)
WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
RD_REG_WORD(&reg->hccr); /* PCI Posting. */
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_SUCCESS;
}
-void
+int
qla24xx_reset_adapter(scsi_qla_host_t *vha)
{
unsigned long flags = 0;
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ int rval = QLA_SUCCESS;
if (IS_P3P_TYPE(ha))
- return;
+ return rval;
vha->flags.online = 0;
ha->isp_ops->disable_intrs(ha);
@@ -6919,6 +7047,8 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha)
if (IS_NOPOLLING_TYPE(ha))
ha->isp_ops->enable_intrs(ha);
+
+ return rval;
}
/* On sparc systems, obtain port and node WWN from firmware
@@ -6969,34 +7099,33 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
ha->vpd_base = FA_NVRAM_VPD1_ADDR;
}
- ha->nvram_size = sizeof(struct nvram_24xx);
+ ha->nvram_size = sizeof(*nv);
ha->vpd_size = FA_NVRAM_VPD_SIZE;
/* Get VPD data into cache */
ha->vpd = ha->nvram + VPD_OFFSET;
- ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd,
+ ha->isp_ops->read_nvram(vha, ha->vpd,
ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
/* Get NVRAM data into cache and calculate checksum. */
dptr = (uint32_t *)nv;
- ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
- ha->nvram_size);
+ ha->isp_ops->read_nvram(vha, dptr, ha->nvram_base, ha->nvram_size);
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");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010d,
- (uint8_t *)nv, ha->nvram_size);
+ nv, ha->nvram_size);
/* Bad NVRAM data, set defaults parameters. */
- if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
- || nv->id[3] != ' ' ||
- nv->nvram_version < cpu_to_le16(ICB_VERSION)) {
+ if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
+ le16_to_cpu(nv->nvram_version) < ICB_VERSION) {
/* Reset NVRAM data. */
ql_log(ql_log_warn, vha, 0x006b,
- "Inconsistent NVRAM detected: checksum=0x%x id=%c "
- "version=0x%x.\n", chksum, nv->id[0], nv->nvram_version);
+ "Inconsistent NVRAM checksum=%#x id=%.4s version=%#x.\n",
+ chksum, nv->id, nv->nvram_version);
+ ql_dump_buffer(ql_dbg_init, vha, 0x006b, nv, sizeof(*nv));
ql_log(ql_log_warn, vha, 0x006c,
"Falling back to functioning (yet invalid -- WWPN) "
"defaults.\n");
@@ -7104,11 +7233,11 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
ha->flags.disable_risc_code_load = 0;
ha->flags.enable_lip_reset = 0;
ha->flags.enable_lip_full_login =
- le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
+ le32_to_cpu(nv->host_p) & BIT_10 ? 1 : 0;
ha->flags.enable_target_reset =
- le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
+ le32_to_cpu(nv->host_p) & BIT_11 ? 1 : 0;
ha->flags.enable_led_scheme = 0;
- ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
+ ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1 : 0;
ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
(BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -7182,7 +7311,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
- le16_to_cpu(icb->interrupt_delay_timer): 2;
+ le16_to_cpu(icb->interrupt_delay_timer) : 2;
}
icb->firmware_options_2 &= cpu_to_le32(
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
@@ -7205,128 +7334,311 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
return (rval);
}
-uint8_t qla27xx_find_valid_image(struct scsi_qla_host *vha)
+static void
+qla27xx_print_image(struct scsi_qla_host *vha, char *name,
+ struct qla27xx_image_status *image_status)
+{
+ ql_dbg(ql_dbg_init, vha, 0x018b,
+ "%s %s: mask=%#02x gen=%#04x ver=%u.%u map=%#01x sum=%#08x sig=%#08x\n",
+ name, "status",
+ image_status->image_status_mask,
+ le16_to_cpu(image_status->generation),
+ image_status->ver_major,
+ image_status->ver_minor,
+ image_status->bitmap,
+ le32_to_cpu(image_status->checksum),
+ le32_to_cpu(image_status->signature));
+}
+
+static bool
+qla28xx_check_aux_image_status_signature(
+ struct qla27xx_image_status *image_status)
+{
+ ulong signature = le32_to_cpu(image_status->signature);
+
+ return signature != QLA28XX_AUX_IMG_STATUS_SIGN;
+}
+
+static bool
+qla27xx_check_image_status_signature(struct qla27xx_image_status *image_status)
+{
+ ulong signature = le32_to_cpu(image_status->signature);
+
+ return
+ signature != QLA27XX_IMG_STATUS_SIGN &&
+ signature != QLA28XX_IMG_STATUS_SIGN;
+}
+
+static ulong
+qla27xx_image_status_checksum(struct qla27xx_image_status *image_status)
+{
+ uint32_t *p = (void *)image_status;
+ uint n = sizeof(*image_status) / sizeof(*p);
+ uint32_t sum = 0;
+
+ for ( ; n--; p++)
+ sum += le32_to_cpup(p);
+
+ return sum;
+}
+
+static inline uint
+qla28xx_component_bitmask(struct qla27xx_image_status *aux, uint bitmask)
+{
+ return aux->bitmap & bitmask ?
+ QLA27XX_SECONDARY_IMAGE : QLA27XX_PRIMARY_IMAGE;
+}
+
+static void
+qla28xx_component_status(
+ struct active_regions *active_regions, struct qla27xx_image_status *aux)
+{
+ active_regions->aux.board_config =
+ qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_BOARD_CONFIG);
+
+ active_regions->aux.vpd_nvram =
+ qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_VPD_NVRAM);
+
+ active_regions->aux.npiv_config_0_1 =
+ qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_NPIV_CONFIG_0_1);
+
+ active_regions->aux.npiv_config_2_3 =
+ qla28xx_component_bitmask(aux, QLA28XX_AUX_IMG_NPIV_CONFIG_2_3);
+}
+
+static int
+qla27xx_compare_image_generation(
+ struct qla27xx_image_status *pri_image_status,
+ struct qla27xx_image_status *sec_image_status)
+{
+ /* calculate generation delta as uint16 (this accounts for wrap) */
+ int16_t delta =
+ le16_to_cpu(pri_image_status->generation) -
+ le16_to_cpu(sec_image_status->generation);
+
+ ql_dbg(ql_dbg_init, NULL, 0x0180, "generation delta = %d\n", delta);
+
+ return delta;
+}
+
+void
+qla28xx_get_aux_images(
+ struct scsi_qla_host *vha, struct active_regions *active_regions)
{
- 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;
+ struct qla27xx_image_status pri_aux_image_status, sec_aux_image_status;
+ bool valid_pri_image = false, valid_sec_image = false;
+ bool active_pri_image = false, active_sec_image = false;
- valid_pri_image = valid_sec_image = 1;
- ha->active_image = 0;
- size = sizeof(struct qla27xx_image_status) / sizeof(uint32_t);
+ if (!ha->flt_region_aux_img_status_pri) {
+ ql_dbg(ql_dbg_init, vha, 0x018a, "Primary aux image not addressed\n");
+ goto check_sec_image;
+ }
- if (!ha->flt_region_img_status_pri) {
- valid_pri_image = 0;
+ qla24xx_read_flash_data(vha, (void *)&pri_aux_image_status,
+ ha->flt_region_aux_img_status_pri,
+ sizeof(pri_aux_image_status) >> 2);
+ qla27xx_print_image(vha, "Primary aux image", &pri_aux_image_status);
+
+ if (qla28xx_check_aux_image_status_signature(&pri_aux_image_status)) {
+ ql_dbg(ql_dbg_init, vha, 0x018b,
+ "Primary aux image signature (%#x) not valid\n",
+ le32_to_cpu(pri_aux_image_status.signature));
+ goto check_sec_image;
+ }
+
+ if (qla27xx_image_status_checksum(&pri_aux_image_status)) {
+ ql_dbg(ql_dbg_init, vha, 0x018c,
+ "Primary aux image checksum failed\n");
goto check_sec_image;
}
- qla24xx_read_flash_data(vha, (uint32_t *)(&pri_image_status),
- ha->flt_region_img_status_pri, size);
+ valid_pri_image = true;
+
+ if (pri_aux_image_status.image_status_mask & 1) {
+ ql_dbg(ql_dbg_init, vha, 0x018d,
+ "Primary aux image is active\n");
+ active_pri_image = true;
+ }
+
+check_sec_image:
+ if (!ha->flt_region_aux_img_status_sec) {
+ ql_dbg(ql_dbg_init, vha, 0x018a,
+ "Secondary aux image not addressed\n");
+ goto check_valid_image;
+ }
- if (pri_image_status.signature != QLA27XX_IMG_STATUS_SIGN) {
+ qla24xx_read_flash_data(vha, (void *)&sec_aux_image_status,
+ ha->flt_region_aux_img_status_sec,
+ sizeof(sec_aux_image_status) >> 2);
+ qla27xx_print_image(vha, "Secondary aux image", &sec_aux_image_status);
+
+ if (qla28xx_check_aux_image_status_signature(&sec_aux_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018b,
- "Primary image signature (0x%x) not valid\n",
- pri_image_status.signature);
- valid_pri_image = 0;
+ "Secondary aux image signature (%#x) not valid\n",
+ le32_to_cpu(sec_aux_image_status.signature));
+ goto check_valid_image;
+ }
+
+ if (qla27xx_image_status_checksum(&sec_aux_image_status)) {
+ ql_dbg(ql_dbg_init, vha, 0x018c,
+ "Secondary aux image checksum failed\n");
+ goto check_valid_image;
+ }
+
+ valid_sec_image = true;
+
+ if (sec_aux_image_status.image_status_mask & 1) {
+ ql_dbg(ql_dbg_init, vha, 0x018d,
+ "Secondary aux image is active\n");
+ active_sec_image = true;
+ }
+
+check_valid_image:
+ if (valid_pri_image && active_pri_image &&
+ valid_sec_image && active_sec_image) {
+ if (qla27xx_compare_image_generation(&pri_aux_image_status,
+ &sec_aux_image_status) >= 0) {
+ qla28xx_component_status(active_regions,
+ &pri_aux_image_status);
+ } else {
+ qla28xx_component_status(active_regions,
+ &sec_aux_image_status);
+ }
+ } else if (valid_pri_image && active_pri_image) {
+ qla28xx_component_status(active_regions, &pri_aux_image_status);
+ } else if (valid_sec_image && active_sec_image) {
+ qla28xx_component_status(active_regions, &sec_aux_image_status);
+ }
+
+ ql_dbg(ql_dbg_init, vha, 0x018f,
+ "aux images active: BCFG=%u VPD/NVR=%u NPIV0/1=%u NPIV2/3=%u\n",
+ active_regions->aux.board_config,
+ active_regions->aux.vpd_nvram,
+ active_regions->aux.npiv_config_0_1,
+ active_regions->aux.npiv_config_2_3);
+}
+
+void
+qla27xx_get_active_image(struct scsi_qla_host *vha,
+ struct active_regions *active_regions)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct qla27xx_image_status pri_image_status, sec_image_status;
+ bool valid_pri_image = false, valid_sec_image = false;
+ bool active_pri_image = false, active_sec_image = false;
+
+ if (!ha->flt_region_img_status_pri) {
+ ql_dbg(ql_dbg_init, vha, 0x018a, "Primary image not addressed\n");
goto check_sec_image;
}
- wptr = (uint32_t *)(&pri_image_status);
- cnt = size;
+ qla24xx_read_flash_data(vha, (void *)(&pri_image_status),
+ ha->flt_region_img_status_pri, sizeof(pri_image_status) >> 2);
+ qla27xx_print_image(vha, "Primary image", &pri_image_status);
- for (chksum = 0; cnt--; wptr++)
- chksum += le32_to_cpu(*wptr);
+ if (qla27xx_check_image_status_signature(&pri_image_status)) {
+ ql_dbg(ql_dbg_init, vha, 0x018b,
+ "Primary image signature (%#x) not valid\n",
+ le32_to_cpu(pri_image_status.signature));
+ goto check_sec_image;
+ }
- if (chksum) {
+ if (qla27xx_image_status_checksum(&pri_image_status)) {
ql_dbg(ql_dbg_init, vha, 0x018c,
- "Checksum validation failed for primary image (0x%x)\n",
- chksum);
- valid_pri_image = 0;
+ "Primary image checksum failed\n");
+ goto check_sec_image;
+ }
+
+ valid_pri_image = true;
+
+ if (pri_image_status.image_status_mask & 1) {
+ ql_dbg(ql_dbg_init, vha, 0x018d,
+ "Primary image is active\n");
+ active_pri_image = true;
}
check_sec_image:
if (!ha->flt_region_img_status_sec) {
- valid_sec_image = 0;
+ ql_dbg(ql_dbg_init, vha, 0x018a, "Secondary image not addressed\n");
goto check_valid_image;
}
qla24xx_read_flash_data(vha, (uint32_t *)(&sec_image_status),
- ha->flt_region_img_status_sec, size);
+ ha->flt_region_img_status_sec, sizeof(sec_image_status) >> 2);
+ qla27xx_print_image(vha, "Secondary image", &sec_image_status);
- 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;
+ if (qla27xx_check_image_status_signature(&sec_image_status)) {
+ ql_dbg(ql_dbg_init, vha, 0x018b,
+ "Secondary image signature (%#x) not valid\n",
+ le32_to_cpu(sec_image_status.signature));
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;
+ if (qla27xx_image_status_checksum(&sec_image_status)) {
+ ql_dbg(ql_dbg_init, vha, 0x018c,
+ "Secondary image checksum failed\n");
+ goto check_valid_image;
+ }
+
+ valid_sec_image = true;
+
+ if (sec_image_status.image_status_mask & 1) {
+ ql_dbg(ql_dbg_init, vha, 0x018d,
+ "Secondary image is active\n");
+ active_sec_image = true;
}
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;
+ if (valid_pri_image && active_pri_image)
+ active_regions->global = QLA27XX_PRIMARY_IMAGE;
+
+ if (valid_sec_image && active_sec_image) {
+ if (!active_regions->global ||
+ qla27xx_compare_image_generation(
+ &pri_image_status, &sec_image_status) < 0) {
+ active_regions->global = QLA27XX_SECONDARY_IMAGE;
+ }
}
- ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x018f, "%s image\n",
- ha->active_image == 0 ? "default bootld and fw" :
- ha->active_image == 1 ? "primary" :
- ha->active_image == 2 ? "secondary" :
- "Invalid");
+ ql_dbg(ql_dbg_init, vha, 0x018f, "active image %s (%u)\n",
+ active_regions->global == QLA27XX_DEFAULT_IMAGE ?
+ "default (boot/fw)" :
+ active_regions->global == QLA27XX_PRIMARY_IMAGE ?
+ "primary" :
+ active_regions->global == QLA27XX_SECONDARY_IMAGE ?
+ "secondary" : "invalid",
+ active_regions->global);
+}
- return ha->active_image;
+bool qla24xx_risc_firmware_invalid(uint32_t *dword)
+{
+ return
+ !(dword[4] | dword[5] | dword[6] | dword[7]) ||
+ !(~dword[4] | ~dword[5] | ~dword[6] | ~dword[7]);
}
static int
qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
uint32_t faddr)
{
- int rval = QLA_SUCCESS;
- int segments, fragment;
- uint32_t *dcode, dlen;
- uint32_t risc_addr;
- uint32_t risc_size;
- uint32_t i;
+ int rval;
+ uint templates, segments, fragment;
+ ulong i;
+ uint j;
+ ulong dlen;
+ uint32_t *dcode;
+ uint32_t risc_addr, risc_size, risc_attr = 0;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
+ struct fwdt *fwdt = ha->fwdt;
ql_dbg(ql_dbg_init, vha, 0x008b,
"FW: Loading firmware from flash (%x).\n", faddr);
- rval = QLA_SUCCESS;
-
- segments = FA_RISC_CODE_SEGMENTS;
- 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++)
- dcode[i] = be32_to_cpu(dcode[i]);
- if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
- dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
- (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
- dcode[3] == 0)) {
+ dcode = (void *)req->ring;
+ qla24xx_read_flash_data(vha, dcode, faddr, 8);
+ if (qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_fatal, vha, 0x008c,
"Unable to verify the integrity of flash firmware "
"image.\n");
@@ -7337,34 +7649,36 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
return QLA_FUNCTION_FAILED;
}
- while (segments && rval == QLA_SUCCESS) {
- /* Read segment's load information. */
- qla24xx_read_flash_data(vha, dcode, faddr, 4);
-
+ dcode = (void *)req->ring;
+ *srisc_addr = 0;
+ segments = FA_RISC_CODE_SEGMENTS;
+ for (j = 0; j < segments; j++) {
+ ql_dbg(ql_dbg_init, vha, 0x008d,
+ "-> Loading segment %u...\n", j);
+ qla24xx_read_flash_data(vha, dcode, faddr, 10);
risc_addr = be32_to_cpu(dcode[2]);
- *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
risc_size = be32_to_cpu(dcode[3]);
+ if (!*srisc_addr) {
+ *srisc_addr = risc_addr;
+ risc_attr = be32_to_cpu(dcode[9]);
+ }
- fragment = 0;
- while (risc_size > 0 && rval == QLA_SUCCESS) {
- dlen = (uint32_t)(ha->fw_transfer_size >> 2);
+ dlen = ha->fw_transfer_size >> 2;
+ for (fragment = 0; risc_size; fragment++) {
if (dlen > risc_size)
dlen = risc_size;
ql_dbg(ql_dbg_init, vha, 0x008e,
- "Loading risc segment@ risc addr %x "
- "number of dwords 0x%x offset 0x%x.\n",
- risc_addr, dlen, faddr);
-
+ "-> Loading fragment %u: %#x <- %#x (%#lx dwords)...\n",
+ fragment, risc_addr, faddr, dlen);
qla24xx_read_flash_data(vha, dcode, faddr, dlen);
for (i = 0; i < dlen; i++)
dcode[i] = swab32(dcode[i]);
- rval = qla2x00_load_ram(vha, req->dma, risc_addr,
- dlen);
+ rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
if (rval) {
ql_log(ql_log_fatal, vha, 0x008f,
- "Failed to load segment %d of firmware.\n",
+ "-> Failed load firmware fragment %u.\n",
fragment);
return QLA_FUNCTION_FAILED;
}
@@ -7372,107 +7686,82 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
faddr += dlen;
risc_addr += dlen;
risc_size -= dlen;
- fragment++;
}
-
- /* Next segment. */
- segments--;
}
- if (!IS_QLA27XX(ha))
- return rval;
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+ return QLA_SUCCESS;
- if (ha->fw_dump_template)
- vfree(ha->fw_dump_template);
- ha->fw_dump_template = NULL;
- ha->fw_dump_template_len = 0;
-
- ql_dbg(ql_dbg_init, vha, 0x0161,
- "Loading fwdump template from %x\n", faddr);
- qla24xx_read_flash_data(vha, dcode, faddr, 7);
- risc_size = be32_to_cpu(dcode[2]);
- ql_dbg(ql_dbg_init, vha, 0x0162,
- "-> array size %x dwords\n", risc_size);
- if (risc_size == 0 || risc_size == ~0)
- goto default_template;
-
- dlen = (risc_size - 8) * sizeof(*dcode);
- ql_dbg(ql_dbg_init, vha, 0x0163,
- "-> template allocating %x bytes...\n", dlen);
- ha->fw_dump_template = vmalloc(dlen);
- if (!ha->fw_dump_template) {
- ql_log(ql_log_warn, vha, 0x0164,
- "Failed fwdump template allocate %x bytes.\n", risc_size);
- goto default_template;
- }
-
- faddr += 7;
- risc_size -= 8;
- dcode = ha->fw_dump_template;
- qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
- for (i = 0; i < risc_size; i++)
- dcode[i] = le32_to_cpu(dcode[i]);
-
- if (!qla27xx_fwdt_template_valid(dcode)) {
- ql_log(ql_log_warn, vha, 0x0165,
- "Failed fwdump template validate\n");
- goto default_template;
- }
-
- dlen = qla27xx_fwdt_template_size(dcode);
- ql_dbg(ql_dbg_init, vha, 0x0166,
- "-> template size %x bytes\n", dlen);
- if (dlen > risc_size * sizeof(*dcode)) {
- ql_log(ql_log_warn, vha, 0x0167,
- "Failed fwdump template exceeds array by %zx bytes\n",
- (size_t)(dlen - risc_size * sizeof(*dcode)));
- goto default_template;
- }
- ha->fw_dump_template_len = dlen;
- return rval;
+ templates = (risc_attr & BIT_9) ? 2 : 1;
+ ql_dbg(ql_dbg_init, vha, 0x0160, "-> templates = %u\n", templates);
+ for (j = 0; j < templates; j++, fwdt++) {
+ if (fwdt->template)
+ vfree(fwdt->template);
+ fwdt->template = NULL;
+ fwdt->length = 0;
+
+ dcode = (void *)req->ring;
+ qla24xx_read_flash_data(vha, dcode, faddr, 7);
+ risc_size = be32_to_cpu(dcode[2]);
+ ql_dbg(ql_dbg_init, vha, 0x0161,
+ "-> fwdt%u template array at %#x (%#x dwords)\n",
+ j, faddr, risc_size);
+ if (!risc_size || !~risc_size) {
+ ql_dbg(ql_dbg_init, vha, 0x0162,
+ "-> fwdt%u failed to read array\n", j);
+ goto failed;
+ }
-default_template:
- ql_log(ql_log_warn, vha, 0x0168, "Using default fwdump template\n");
- if (ha->fw_dump_template)
- vfree(ha->fw_dump_template);
- ha->fw_dump_template = NULL;
- ha->fw_dump_template_len = 0;
-
- dlen = qla27xx_fwdt_template_default_size();
- ql_dbg(ql_dbg_init, vha, 0x0169,
- "-> template allocating %x bytes...\n", dlen);
- ha->fw_dump_template = vmalloc(dlen);
- if (!ha->fw_dump_template) {
- ql_log(ql_log_warn, vha, 0x016a,
- "Failed fwdump template allocate %x bytes.\n", risc_size);
- goto failed_template;
- }
-
- dcode = ha->fw_dump_template;
- risc_size = dlen / sizeof(*dcode);
- memcpy(dcode, qla27xx_fwdt_template_default(), dlen);
- for (i = 0; i < risc_size; i++)
- dcode[i] = be32_to_cpu(dcode[i]);
-
- if (!qla27xx_fwdt_template_valid(ha->fw_dump_template)) {
- ql_log(ql_log_warn, vha, 0x016b,
- "Failed fwdump template validate\n");
- goto failed_template;
- }
-
- dlen = qla27xx_fwdt_template_size(ha->fw_dump_template);
- ql_dbg(ql_dbg_init, vha, 0x016c,
- "-> template size %x bytes\n", dlen);
- ha->fw_dump_template_len = dlen;
- return rval;
+ /* skip header and ignore checksum */
+ faddr += 7;
+ risc_size -= 8;
+
+ ql_dbg(ql_dbg_init, vha, 0x0163,
+ "-> fwdt%u template allocate template %#x words...\n",
+ j, risc_size);
+ fwdt->template = vmalloc(risc_size * sizeof(*dcode));
+ if (!fwdt->template) {
+ ql_log(ql_log_warn, vha, 0x0164,
+ "-> fwdt%u failed allocate template.\n", j);
+ goto failed;
+ }
-failed_template:
- ql_log(ql_log_warn, vha, 0x016d, "Failed default fwdump template\n");
- if (ha->fw_dump_template)
- vfree(ha->fw_dump_template);
- ha->fw_dump_template = NULL;
- ha->fw_dump_template_len = 0;
- return rval;
+ dcode = fwdt->template;
+ qla24xx_read_flash_data(vha, dcode, faddr, risc_size);
+
+ if (!qla27xx_fwdt_template_valid(dcode)) {
+ ql_log(ql_log_warn, vha, 0x0165,
+ "-> fwdt%u failed template validate\n", j);
+ goto failed;
+ }
+
+ dlen = qla27xx_fwdt_template_size(dcode);
+ ql_dbg(ql_dbg_init, vha, 0x0166,
+ "-> fwdt%u template size %#lx bytes (%#lx words)\n",
+ j, dlen, dlen / sizeof(*dcode));
+ if (dlen > risc_size * sizeof(*dcode)) {
+ ql_log(ql_log_warn, vha, 0x0167,
+ "-> fwdt%u template exceeds array (%-lu bytes)\n",
+ j, dlen - risc_size * sizeof(*dcode));
+ goto failed;
+ }
+
+ fwdt->length = dlen;
+ ql_dbg(ql_dbg_init, vha, 0x0168,
+ "-> fwdt%u loaded template ok\n", j);
+
+ faddr += risc_size + 1;
+ }
+
+ return QLA_SUCCESS;
+
+failed:
+ if (fwdt->template)
+ vfree(fwdt->template);
+ fwdt->template = NULL;
+ fwdt->length = 0;
+
+ return QLA_SUCCESS;
}
#define QLA_FW_URL "http://ldriver.qlogic.com/firmware/"
@@ -7580,94 +7869,73 @@ static int
qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
{
int rval;
- int segments, fragment;
- uint32_t *dcode, dlen;
- uint32_t risc_addr;
- uint32_t risc_size;
- uint32_t i;
+ uint templates, segments, fragment;
+ uint32_t *dcode;
+ ulong dlen;
+ uint32_t risc_addr, risc_size, risc_attr = 0;
+ ulong i;
+ uint j;
struct fw_blob *blob;
- const uint32_t *fwcode;
- uint32_t fwclen;
+ uint32_t *fwcode;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
+ struct fwdt *fwdt = ha->fwdt;
+
+ ql_dbg(ql_dbg_init, vha, 0x0090,
+ "-> FW: Loading via request-firmware.\n");
- /* Load firmware blob. */
blob = qla2x00_request_firmware(vha);
if (!blob) {
- ql_log(ql_log_warn, vha, 0x0090,
- "Firmware image unavailable.\n");
- ql_log(ql_log_warn, vha, 0x0091,
- "Firmware images can be retrieved from: "
- QLA_FW_URL ".\n");
+ ql_log(ql_log_warn, vha, 0x0092,
+ "-> Firmware file not found.\n");
return QLA_FUNCTION_FAILED;
}
- ql_dbg(ql_dbg_init, vha, 0x0092,
- "FW: Loading via request-firmware.\n");
-
- rval = QLA_SUCCESS;
-
- segments = FA_RISC_CODE_SEGMENTS;
- dcode = (uint32_t *)req->ring;
- *srisc_addr = 0;
- fwcode = (uint32_t *)blob->fw->data;
- fwclen = 0;
-
- /* Validate firmware image by checking version. */
- if (blob->fw->size < 8 * sizeof(uint32_t)) {
+ fwcode = (void *)blob->fw->data;
+ dcode = fwcode;
+ if (qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_fatal, vha, 0x0093,
"Unable to verify integrity of firmware image (%zd).\n",
blob->fw->size);
- return QLA_FUNCTION_FAILED;
- }
- for (i = 0; i < 4; i++)
- dcode[i] = be32_to_cpu(fwcode[i + 4]);
- if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
- dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
- (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
- dcode[3] == 0)) {
- ql_log(ql_log_fatal, vha, 0x0094,
- "Unable to verify integrity of firmware image (%zd).\n",
- blob->fw->size);
ql_log(ql_log_fatal, vha, 0x0095,
"Firmware data: %08x %08x %08x %08x.\n",
dcode[0], dcode[1], dcode[2], dcode[3]);
return QLA_FUNCTION_FAILED;
}
- while (segments && rval == QLA_SUCCESS) {
+ dcode = (void *)req->ring;
+ *srisc_addr = 0;
+ segments = FA_RISC_CODE_SEGMENTS;
+ for (j = 0; j < segments; j++) {
+ ql_dbg(ql_dbg_init, vha, 0x0096,
+ "-> Loading segment %u...\n", j);
risc_addr = be32_to_cpu(fwcode[2]);
- *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
risc_size = be32_to_cpu(fwcode[3]);
- /* Validate firmware image size. */
- fwclen += risc_size * sizeof(uint32_t);
- if (blob->fw->size < fwclen) {
- ql_log(ql_log_fatal, vha, 0x0096,
- "Unable to verify integrity of firmware image "
- "(%zd).\n", blob->fw->size);
- return QLA_FUNCTION_FAILED;
+ if (!*srisc_addr) {
+ *srisc_addr = risc_addr;
+ risc_attr = be32_to_cpu(fwcode[9]);
}
- fragment = 0;
- while (risc_size > 0 && rval == QLA_SUCCESS) {
- dlen = (uint32_t)(ha->fw_transfer_size >> 2);
+ dlen = ha->fw_transfer_size >> 2;
+ for (fragment = 0; risc_size; fragment++) {
if (dlen > risc_size)
dlen = risc_size;
ql_dbg(ql_dbg_init, vha, 0x0097,
- "Loading risc segment@ risc addr %x "
- "number of dwords 0x%x.\n", risc_addr, dlen);
+ "-> Loading fragment %u: %#x <- %#x (%#lx words)...\n",
+ fragment, risc_addr,
+ (uint32_t)(fwcode - (typeof(fwcode))blob->fw->data),
+ dlen);
for (i = 0; i < dlen; i++)
dcode[i] = swab32(fwcode[i]);
- rval = qla2x00_load_ram(vha, req->dma, risc_addr,
- dlen);
+ rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
if (rval) {
ql_log(ql_log_fatal, vha, 0x0098,
- "Failed to load segment %d of firmware.\n",
+ "-> Failed load firmware fragment %u.\n",
fragment);
return QLA_FUNCTION_FAILED;
}
@@ -7675,106 +7943,82 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
fwcode += dlen;
risc_addr += dlen;
risc_size -= dlen;
- fragment++;
}
-
- /* Next segment. */
- segments--;
}
- if (!IS_QLA27XX(ha))
- return rval;
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+ return QLA_SUCCESS;
- if (ha->fw_dump_template)
- vfree(ha->fw_dump_template);
- ha->fw_dump_template = NULL;
- ha->fw_dump_template_len = 0;
-
- ql_dbg(ql_dbg_init, vha, 0x171,
- "Loading fwdump template from %x\n",
- (uint32_t)((void *)fwcode - (void *)blob->fw->data));
- risc_size = be32_to_cpu(fwcode[2]);
- ql_dbg(ql_dbg_init, vha, 0x172,
- "-> array size %x dwords\n", risc_size);
- if (risc_size == 0 || risc_size == ~0)
- goto default_template;
-
- dlen = (risc_size - 8) * sizeof(*fwcode);
- ql_dbg(ql_dbg_init, vha, 0x0173,
- "-> template allocating %x bytes...\n", dlen);
- ha->fw_dump_template = vmalloc(dlen);
- if (!ha->fw_dump_template) {
- ql_log(ql_log_warn, vha, 0x0174,
- "Failed fwdump template allocate %x bytes.\n", risc_size);
- goto default_template;
- }
-
- fwcode += 7;
- risc_size -= 8;
- dcode = ha->fw_dump_template;
- for (i = 0; i < risc_size; i++)
- dcode[i] = le32_to_cpu(fwcode[i]);
-
- if (!qla27xx_fwdt_template_valid(dcode)) {
- ql_log(ql_log_warn, vha, 0x0175,
- "Failed fwdump template validate\n");
- goto default_template;
- }
-
- dlen = qla27xx_fwdt_template_size(dcode);
- ql_dbg(ql_dbg_init, vha, 0x0176,
- "-> template size %x bytes\n", dlen);
- if (dlen > risc_size * sizeof(*fwcode)) {
- ql_log(ql_log_warn, vha, 0x0177,
- "Failed fwdump template exceeds array by %zx bytes\n",
- (size_t)(dlen - risc_size * sizeof(*fwcode)));
- goto default_template;
- }
- ha->fw_dump_template_len = dlen;
- return rval;
+ templates = (risc_attr & BIT_9) ? 2 : 1;
+ ql_dbg(ql_dbg_init, vha, 0x0170, "-> templates = %u\n", templates);
+ for (j = 0; j < templates; j++, fwdt++) {
+ if (fwdt->template)
+ vfree(fwdt->template);
+ fwdt->template = NULL;
+ fwdt->length = 0;
+
+ risc_size = be32_to_cpu(fwcode[2]);
+ ql_dbg(ql_dbg_init, vha, 0x0171,
+ "-> fwdt%u template array at %#x (%#x dwords)\n",
+ j, (uint32_t)((void *)fwcode - (void *)blob->fw->data),
+ risc_size);
+ if (!risc_size || !~risc_size) {
+ ql_dbg(ql_dbg_init, vha, 0x0172,
+ "-> fwdt%u failed to read array\n", j);
+ goto failed;
+ }
-default_template:
- ql_log(ql_log_warn, vha, 0x0178, "Using default fwdump template\n");
- if (ha->fw_dump_template)
- vfree(ha->fw_dump_template);
- ha->fw_dump_template = NULL;
- ha->fw_dump_template_len = 0;
-
- dlen = qla27xx_fwdt_template_default_size();
- ql_dbg(ql_dbg_init, vha, 0x0179,
- "-> template allocating %x bytes...\n", dlen);
- ha->fw_dump_template = vmalloc(dlen);
- if (!ha->fw_dump_template) {
- ql_log(ql_log_warn, vha, 0x017a,
- "Failed fwdump template allocate %x bytes.\n", risc_size);
- goto failed_template;
- }
-
- dcode = ha->fw_dump_template;
- risc_size = dlen / sizeof(*fwcode);
- fwcode = qla27xx_fwdt_template_default();
- for (i = 0; i < risc_size; i++)
- dcode[i] = be32_to_cpu(fwcode[i]);
-
- if (!qla27xx_fwdt_template_valid(ha->fw_dump_template)) {
- ql_log(ql_log_warn, vha, 0x017b,
- "Failed fwdump template validate\n");
- goto failed_template;
- }
-
- dlen = qla27xx_fwdt_template_size(ha->fw_dump_template);
- ql_dbg(ql_dbg_init, vha, 0x017c,
- "-> template size %x bytes\n", dlen);
- ha->fw_dump_template_len = dlen;
- return rval;
+ /* skip header and ignore checksum */
+ fwcode += 7;
+ risc_size -= 8;
+
+ ql_dbg(ql_dbg_init, vha, 0x0173,
+ "-> fwdt%u template allocate template %#x words...\n",
+ j, risc_size);
+ fwdt->template = vmalloc(risc_size * sizeof(*dcode));
+ if (!fwdt->template) {
+ ql_log(ql_log_warn, vha, 0x0174,
+ "-> fwdt%u failed allocate template.\n", j);
+ goto failed;
+ }
-failed_template:
- ql_log(ql_log_warn, vha, 0x017d, "Failed default fwdump template\n");
- if (ha->fw_dump_template)
- vfree(ha->fw_dump_template);
- ha->fw_dump_template = NULL;
- ha->fw_dump_template_len = 0;
- return rval;
+ dcode = fwdt->template;
+ for (i = 0; i < risc_size; i++)
+ dcode[i] = fwcode[i];
+
+ if (!qla27xx_fwdt_template_valid(dcode)) {
+ ql_log(ql_log_warn, vha, 0x0175,
+ "-> fwdt%u failed template validate\n", j);
+ goto failed;
+ }
+
+ dlen = qla27xx_fwdt_template_size(dcode);
+ ql_dbg(ql_dbg_init, vha, 0x0176,
+ "-> fwdt%u template size %#lx bytes (%#lx words)\n",
+ j, dlen, dlen / sizeof(*dcode));
+ if (dlen > risc_size * sizeof(*dcode)) {
+ ql_log(ql_log_warn, vha, 0x0177,
+ "-> fwdt%u template exceeds array (%-lu bytes)\n",
+ j, dlen - risc_size * sizeof(*dcode));
+ goto failed;
+ }
+
+ fwdt->length = dlen;
+ ql_dbg(ql_dbg_init, vha, 0x0178,
+ "-> fwdt%u loaded template ok\n", j);
+
+ fwcode += risc_size + 1;
+ }
+
+ return QLA_SUCCESS;
+
+failed:
+ if (fwdt->template)
+ vfree(fwdt->template);
+ fwdt->template = NULL;
+ fwdt->length = 0;
+
+ return QLA_SUCCESS;
}
int
@@ -7803,32 +8047,50 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
{
int rval;
struct qla_hw_data *ha = vha->hw;
+ struct active_regions active_regions = { };
if (ql2xfwloadbin == 2)
goto try_blob_fw;
- /*
- * FW Load priority:
+ /* FW Load priority:
* 1) Firmware residing in flash.
* 2) Firmware via request-firmware interface (.bin file).
- * 3) Golden-Firmware residing in flash -- limited operation.
+ * 3) Golden-Firmware residing in flash -- (limited operation).
*/
+
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+ goto try_primary_fw;
+
+ qla27xx_get_active_image(vha, &active_regions);
+
+ if (active_regions.global != QLA27XX_SECONDARY_IMAGE)
+ goto try_primary_fw;
+
+ ql_dbg(ql_dbg_init, vha, 0x008b,
+ "Loading secondary firmware image.\n");
+ rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw_sec);
+ if (!rval)
+ return rval;
+
+try_primary_fw:
+ ql_dbg(ql_dbg_init, vha, 0x008b,
+ "Loading primary firmware image.\n");
rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw);
- if (rval == QLA_SUCCESS)
+ if (!rval)
return rval;
try_blob_fw:
rval = qla24xx_load_risc_blob(vha, srisc_addr);
- if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw)
+ if (!rval || !ha->flt_region_gold_fw)
return rval;
ql_log(ql_log_info, vha, 0x0099,
"Attempting to fallback to golden firmware.\n");
rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw);
- if (rval != QLA_SUCCESS)
+ if (rval)
return rval;
- ql_log(ql_log_info, vha, 0x009a, "Update operational firmware.\n");
+ ql_log(ql_log_info, vha, 0x009a, "Need firmware flash update.\n");
ha->flags.running_gold_fw = 1;
return rval;
}
@@ -7963,6 +8225,7 @@ void
qla84xx_put_chip(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
+
if (ha->cs84xx)
kref_put(&ha->cs84xx->kref, __qla84xx_chip_release);
}
@@ -7980,7 +8243,7 @@ qla84xx_init_chip(scsi_qla_host_t *vha)
mutex_unlock(&ha->cs84xx->fw_update_mutex);
- return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED:
+ return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED :
QLA_SUCCESS;
}
@@ -7997,25 +8260,48 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
uint32_t chksum;
uint16_t cnt;
struct qla_hw_data *ha = vha->hw;
+ uint32_t faddr;
+ struct active_regions active_regions = { };
rval = QLA_SUCCESS;
icb = (struct init_cb_81xx *)ha->init_cb;
nv = ha->nvram;
/* Determine NVRAM starting address. */
- ha->nvram_size = sizeof(struct nvram_81xx);
+ ha->nvram_size = sizeof(*nv);
ha->vpd_size = FA_NVRAM_VPD_SIZE;
if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
ha->vpd_size = FA_VPD_SIZE_82XX;
+ if (IS_QLA28XX(ha) || IS_QLA27XX(ha))
+ qla28xx_get_aux_images(vha, &active_regions);
+
/* Get VPD data into cache */
ha->vpd = ha->nvram + VPD_OFFSET;
- ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2,
- ha->vpd_size);
+
+ faddr = ha->flt_region_vpd;
+ if (IS_QLA28XX(ha)) {
+ if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_vpd_sec;
+ ql_dbg(ql_dbg_init, vha, 0x0110,
+ "Loading %s nvram image.\n",
+ active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
+ "primary" : "secondary");
+ }
+ qla24xx_read_flash_data(vha, ha->vpd, faddr, ha->vpd_size >> 2);
/* Get NVRAM data into cache and calculate checksum. */
- ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
- ha->nvram_size);
+ faddr = ha->flt_region_nvram;
+ if (IS_QLA28XX(ha)) {
+ if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_nvram_sec;
+ }
+ ql_dbg(ql_dbg_init, vha, 0x0110,
+ "Loading %s nvram image.\n",
+ active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
+ "primary" : "secondary");
+ qla24xx_read_flash_data(vha, ha->nvram, faddr, ha->nvram_size >> 2);
+
dptr = (uint32_t *)nv;
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
chksum += le32_to_cpu(*dptr);
@@ -8023,17 +8309,16 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
"Contents of NVRAM:\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112,
- (uint8_t *)nv, ha->nvram_size);
+ nv, ha->nvram_size);
/* Bad NVRAM data, set defaults parameters. */
- if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
- || nv->id[3] != ' ' ||
- nv->nvram_version < cpu_to_le16(ICB_VERSION)) {
+ if (chksum || memcmp("ISP ", nv->id, sizeof(nv->id)) ||
+ le16_to_cpu(nv->nvram_version) < ICB_VERSION) {
/* Reset NVRAM data. */
ql_log(ql_log_info, vha, 0x0073,
- "Inconsistent NVRAM detected: checksum=0x%x id=%c "
- "version=0x%x.\n", chksum, nv->id[0],
- le16_to_cpu(nv->nvram_version));
+ "Inconsistent NVRAM checksum=%#x id=%.4s version=%#x.\n",
+ chksum, nv->id, le16_to_cpu(nv->nvram_version));
+ ql_dump_buffer(ql_dbg_init, vha, 0x0073, nv, sizeof(*nv));
ql_log(ql_log_info, vha, 0x0074,
"Falling back to functioning (yet invalid -- WWPN) "
"defaults.\n");
@@ -8154,11 +8439,11 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
ha->flags.disable_risc_code_load = 0;
ha->flags.enable_lip_reset = 0;
ha->flags.enable_lip_full_login =
- le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
+ le32_to_cpu(nv->host_p) & BIT_10 ? 1 : 0;
ha->flags.enable_target_reset =
- le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
+ le32_to_cpu(nv->host_p) & BIT_11 ? 1 : 0;
ha->flags.enable_led_scheme = 0;
- ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
+ ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1 : 0;
ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
(BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -8222,7 +8507,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
ha->login_retry_count = ql2xloginretrycount;
/* if not running MSI-X we need handshaking on interrupts */
- if (!vha->hw->flags.msix_enabled && (IS_QLA83XX(ha) || IS_QLA27XX(ha)))
+ if (!vha->hw->flags.msix_enabled &&
+ (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)))
icb->firmware_options_2 |= cpu_to_le32(BIT_22);
/* Enable ZIO. */
@@ -8230,7 +8516,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
- le16_to_cpu(icb->interrupt_delay_timer): 2;
+ le16_to_cpu(icb->interrupt_delay_timer) : 2;
}
icb->firmware_options_2 &= cpu_to_le32(
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
@@ -8255,12 +8541,6 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
/* N2N: driver will initiate Login instead of FW */
icb->firmware_options_3 |= BIT_8;
- if (IS_QLA27XX(ha)) {
- icb->firmware_options_3 |= BIT_8;
- ql_dbg(ql_log_info, vha, 0x0075,
- "Enabling direct connection.\n");
- }
-
if (rval) {
ql_log(ql_log_warn, vha, 0x0076,
"NVRAM configuration failed.\n");
@@ -8621,7 +8901,6 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos,
"Failed to allocate memory for queue pair.\n");
return NULL;
}
- memset(qpair, 0, sizeof(struct qla_qpair));
qpair->hw = vha->hw;
qpair->vha = vha;
@@ -8668,7 +8947,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos,
qpair->msix->in_use = 1;
list_add_tail(&qpair->qp_list_elem, &vha->qp_list);
qpair->pdev = ha->pdev;
- if (IS_QLA27XX(ha) || IS_QLA83XX(ha))
+ if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))
qpair->reqq_start_iocbs = qla_83xx_start_iocbs;
mutex_unlock(&ha->mq_lock);
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 512c3c37b447..bf063c664352 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -91,43 +91,6 @@ host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize)
}
static inline void
-qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha)
-{
- int i;
-
- if (IS_FWI2_CAPABLE(ha))
- return;
-
- for (i = 0; i < SNS_FIRST_LOOP_ID; i++)
- set_bit(i, ha->loop_id_map);
- set_bit(MANAGEMENT_SERVER, ha->loop_id_map);
- set_bit(BROADCAST, ha->loop_id_map);
-}
-
-static inline int
-qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id)
-{
- struct qla_hw_data *ha = vha->hw;
- if (IS_FWI2_CAPABLE(ha))
- return (loop_id > NPH_LAST_HANDLE);
-
- return ((loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
- loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST);
-}
-
-static inline void
-qla2x00_clear_loop_id(fc_port_t *fcport) {
- struct qla_hw_data *ha = fcport->vha->hw;
-
- if (fcport->loop_id == FC_NO_LOOP_ID ||
- qla2x00_is_reserved_id(fcport->vha, fcport->loop_id))
- return;
-
- clear_bit(fcport->loop_id, ha->loop_id_map);
- fcport->loop_id = FC_NO_LOOP_ID;
-}
-
-static inline void
qla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx)
{
struct dsd_dma *dsd, *tdsd;
@@ -142,25 +105,6 @@ qla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx)
INIT_LIST_HEAD(&ctx->dsd_list);
}
-static inline void
-qla2x00_set_fcport_state(fc_port_t *fcport, int state)
-{
- int old_state;
-
- old_state = atomic_read(&fcport->state);
- atomic_set(&fcport->state, state);
-
- /* Don't print state transitions during initial allocation of fcport */
- if (old_state && old_state != state) {
- ql_dbg(ql_dbg_disc, fcport->vha, 0x207d,
- "FCPort %8phC state transitioned from %s to %s - "
- "portid=%02x%02x%02x.\n", fcport->port_name,
- port_state_str[old_state], port_state_str[state],
- fcport->d_id.b.domain, fcport->d_id.b.area,
- fcport->d_id.b.al_pa);
- }
-}
-
static inline int
qla2x00_hba_err_chk_enabled(srb_t *sp)
{
@@ -240,6 +184,7 @@ done:
static inline void
qla2xxx_rel_qpair_sp(struct qla_qpair *qpair, srb_t *sp)
{
+ sp->qpair = NULL;
mempool_free(sp, qpair->srb_mempool);
QLA_QPAIR_MARK_NOT_BUSY(qpair);
}
@@ -274,18 +219,6 @@ qla2x00_rel_sp(srb_t *sp)
qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
-static inline void
-qla2x00_init_timer(srb_t *sp, unsigned long tmo)
-{
- timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0);
- sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ;
- sp->free = qla2x00_sp_free;
- init_completion(&sp->comp);
- if (IS_QLAFX00(sp->vha->hw) && (sp->type == SRB_FXIOCB_DCMD))
- init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
- add_timer(&sp->u.iocb_cmd.timer);
-}
-
static inline int
qla2x00_gid_list_size(struct qla_hw_data *ha)
{
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 456a41d2e2c6..9312b19ed708 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -107,7 +107,7 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha)
cont_pkt = (cont_entry_t *)req->ring_ptr;
/* Load packet defaults. */
- *((uint32_t *)(&cont_pkt->entry_type)) = cpu_to_le32(CONTINUE_TYPE);
+ put_unaligned_le32(CONTINUE_TYPE, &cont_pkt->entry_type);
return (cont_pkt);
}
@@ -136,9 +136,8 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req)
cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
/* Load packet defaults. */
- *((uint32_t *)(&cont_pkt->entry_type)) = IS_QLAFX00(vha->hw) ?
- cpu_to_le32(CONTINUE_A64_TYPE_FX00) :
- cpu_to_le32(CONTINUE_A64_TYPE);
+ put_unaligned_le32(IS_QLAFX00(vha->hw) ? CONTINUE_A64_TYPE_FX00 :
+ CONTINUE_A64_TYPE, &cont_pkt->entry_type);
return (cont_pkt);
}
@@ -193,7 +192,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
uint16_t tot_dsds)
{
uint16_t avail_dsds;
- uint32_t *cur_dsd;
+ struct dsd32 *cur_dsd;
scsi_qla_host_t *vha;
struct scsi_cmnd *cmd;
struct scatterlist *sg;
@@ -202,8 +201,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
cmd = GET_CMD_SP(sp);
/* Update entry type to indicate Command Type 2 IOCB */
- *((uint32_t *)(&cmd_pkt->entry_type)) =
- cpu_to_le32(COMMAND_TYPE);
+ put_unaligned_le32(COMMAND_TYPE, &cmd_pkt->entry_type);
/* No data transfer */
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
@@ -215,8 +213,8 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
/* Three DSDs are available in the Command Type 2 IOCB */
- avail_dsds = 3;
- cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
+ avail_dsds = ARRAY_SIZE(cmd_pkt->dsd32);
+ cur_dsd = cmd_pkt->dsd32;
/* Load data segments */
scsi_for_each_sg(cmd, sg, tot_dsds, i) {
@@ -229,12 +227,11 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
* Type 0 IOCB.
*/
cont_pkt = qla2x00_prep_cont_type0_iocb(vha);
- cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
- avail_dsds = 7;
+ cur_dsd = cont_pkt->dsd;
+ avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
}
- *cur_dsd++ = cpu_to_le32(sg_dma_address(sg));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd32(&cur_dsd, sg);
avail_dsds--;
}
}
@@ -251,7 +248,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
uint16_t tot_dsds)
{
uint16_t avail_dsds;
- uint32_t *cur_dsd;
+ struct dsd64 *cur_dsd;
scsi_qla_host_t *vha;
struct scsi_cmnd *cmd;
struct scatterlist *sg;
@@ -260,7 +257,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
cmd = GET_CMD_SP(sp);
/* Update entry type to indicate Command Type 3 IOCB */
- *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_A64_TYPE);
+ put_unaligned_le32(COMMAND_A64_TYPE, &cmd_pkt->entry_type);
/* No data transfer */
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
@@ -272,12 +269,11 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
/* Two DSDs are available in the Command Type 3 IOCB */
- avail_dsds = 2;
- cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
+ avail_dsds = ARRAY_SIZE(cmd_pkt->dsd64);
+ cur_dsd = cmd_pkt->dsd64;
/* Load data segments */
scsi_for_each_sg(cmd, sg, tot_dsds, i) {
- dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
@@ -287,14 +283,11 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
* Type 1 IOCB.
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
- cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
- avail_dsds = 5;
+ cur_dsd = cont_pkt->dsd;
+ avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
}
@@ -467,7 +460,7 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
req->ring_ptr++;
/* Set chip new ring index. */
- if (ha->mqenable || IS_QLA27XX(ha)) {
+ if (ha->mqenable || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
WRT_REG_DWORD(req->req_q_in, req->ring_index);
} else if (IS_QLA83XX(ha)) {
WRT_REG_DWORD(req->req_q_in, req->ring_index);
@@ -580,13 +573,11 @@ static inline int
qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
uint16_t tot_dsds)
{
- uint32_t *cur_dsd = NULL;
+ struct dsd64 *cur_dsd = NULL, *next_dsd;
scsi_qla_host_t *vha;
struct qla_hw_data *ha;
struct scsi_cmnd *cmd;
struct scatterlist *cur_seg;
- uint32_t *dsd_seg;
- void *next_dsd;
uint8_t avail_dsds;
uint8_t first_iocb = 1;
uint32_t dsd_list_len;
@@ -596,7 +587,7 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
cmd = GET_CMD_SP(sp);
/* Update entry type to indicate Command Type 3 IOCB */
- *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_6);
+ put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type);
/* No data transfer */
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
@@ -638,32 +629,27 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
if (first_iocb) {
first_iocb = 0;
- dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address;
- *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
- *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
- cmd_pkt->fcp_data_dseg_len = cpu_to_le32(dsd_list_len);
+ put_unaligned_le64(dsd_ptr->dsd_list_dma,
+ &cmd_pkt->fcp_dsd.address);
+ cmd_pkt->fcp_dsd.length = cpu_to_le32(dsd_list_len);
} else {
- *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ = cpu_to_le32(dsd_list_len);
+ put_unaligned_le64(dsd_ptr->dsd_list_dma,
+ &cur_dsd->address);
+ cur_dsd->length = cpu_to_le32(dsd_list_len);
+ cur_dsd++;
}
- cur_dsd = (uint32_t *)next_dsd;
+ cur_dsd = next_dsd;
while (avail_dsds) {
- dma_addr_t sle_dma;
-
- sle_dma = sg_dma_address(cur_seg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
+ append_dsd64(&cur_dsd, cur_seg);
cur_seg = sg_next(cur_seg);
avail_dsds--;
}
}
/* Null termination */
- *cur_dsd++ = 0;
- *cur_dsd++ = 0;
- *cur_dsd++ = 0;
+ cur_dsd->address = 0;
+ cur_dsd->length = 0;
+ cur_dsd++;
cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE;
return 0;
}
@@ -702,7 +688,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
uint16_t tot_dsds, struct req_que *req)
{
uint16_t avail_dsds;
- uint32_t *cur_dsd;
+ struct dsd64 *cur_dsd;
scsi_qla_host_t *vha;
struct scsi_cmnd *cmd;
struct scatterlist *sg;
@@ -711,7 +697,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
cmd = GET_CMD_SP(sp);
/* Update entry type to indicate Command Type 3 IOCB */
- *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_7);
+ put_unaligned_le32(COMMAND_TYPE_7, &cmd_pkt->entry_type);
/* No data transfer */
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
@@ -734,12 +720,11 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
/* One DSD is available in the Command Type 3 IOCB */
avail_dsds = 1;
- cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
+ cur_dsd = &cmd_pkt->dsd;
/* Load data segments */
scsi_for_each_sg(cmd, sg, tot_dsds, i) {
- dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
@@ -749,14 +734,11 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
* Type 1 IOCB.
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req);
- cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
- avail_dsds = 5;
+ cur_dsd = cont_pkt->dsd;
+ avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
}
@@ -892,14 +874,14 @@ qla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx,
int
qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp,
- uint32_t *dsd, uint16_t tot_dsds, struct qla_tc_param *tc)
+ struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc)
{
void *next_dsd;
uint8_t avail_dsds = 0;
uint32_t dsd_list_len;
struct dsd_dma *dsd_ptr;
struct scatterlist *sg_prot;
- uint32_t *cur_dsd = dsd;
+ struct dsd64 *cur_dsd = dsd;
uint16_t used_dsds = tot_dsds;
uint32_t prot_int; /* protection interval */
uint32_t partial;
@@ -973,14 +955,14 @@ alloc_and_fill:
/* add new list to cmd iocb or last list */
- *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ = dsd_list_len;
- cur_dsd = (uint32_t *)next_dsd;
+ put_unaligned_le64(dsd_ptr->dsd_list_dma,
+ &cur_dsd->address);
+ cur_dsd->length = cpu_to_le32(dsd_list_len);
+ cur_dsd = next_dsd;
}
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sle_dma_len);
+ put_unaligned_le64(sle_dma, &cur_dsd->address);
+ cur_dsd->length = cpu_to_le32(sle_dma_len);
+ cur_dsd++;
avail_dsds--;
if (partial == 0) {
@@ -999,22 +981,22 @@ alloc_and_fill:
}
}
/* Null termination */
- *cur_dsd++ = 0;
- *cur_dsd++ = 0;
- *cur_dsd++ = 0;
+ cur_dsd->address = 0;
+ cur_dsd->length = 0;
+ cur_dsd++;
return 0;
}
int
-qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
- uint16_t tot_dsds, struct qla_tc_param *tc)
+qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp,
+ struct dsd64 *dsd, uint16_t tot_dsds, struct qla_tc_param *tc)
{
void *next_dsd;
uint8_t avail_dsds = 0;
uint32_t dsd_list_len;
struct dsd_dma *dsd_ptr;
struct scatterlist *sg, *sgl;
- uint32_t *cur_dsd = dsd;
+ struct dsd64 *cur_dsd = dsd;
int i;
uint16_t used_dsds = tot_dsds;
struct scsi_cmnd *cmd;
@@ -1031,8 +1013,6 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
for_each_sg(sgl, sg, tot_dsds, i) {
- dma_addr_t sle_dma;
-
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
@@ -1072,29 +1052,25 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
}
/* add new list to cmd iocb or last list */
- *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ = dsd_list_len;
- cur_dsd = (uint32_t *)next_dsd;
+ put_unaligned_le64(dsd_ptr->dsd_list_dma,
+ &cur_dsd->address);
+ cur_dsd->length = cpu_to_le32(dsd_list_len);
+ cur_dsd = next_dsd;
}
- sle_dma = sg_dma_address(sg);
-
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
/* Null termination */
- *cur_dsd++ = 0;
- *cur_dsd++ = 0;
- *cur_dsd++ = 0;
+ cur_dsd->address = 0;
+ cur_dsd->length = 0;
+ cur_dsd++;
return 0;
}
int
qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
- uint32_t *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc)
+ struct dsd64 *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc)
{
struct dsd_dma *dsd_ptr = NULL, *dif_dsd, *nxt_dsd;
struct scatterlist *sg, *sgl;
@@ -1109,6 +1085,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
if (sp) {
struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+
sgl = scsi_prot_sglist(cmd);
vha = sp->vha;
difctx = sp->u.scmd.ctx;
@@ -1314,16 +1291,15 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
}
/* add new list to cmd iocb or last list */
- *cur_dsd++ =
- cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ =
- cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ = dsd_list_len;
+ put_unaligned_le64(dsd_ptr->dsd_list_dma,
+ &cur_dsd->address);
+ cur_dsd->length = cpu_to_le32(dsd_list_len);
cur_dsd = dsd_ptr->dsd_addr;
}
- *cur_dsd++ = cpu_to_le32(LSD(dif_dsd->dsd_list_dma));
- *cur_dsd++ = cpu_to_le32(MSD(dif_dsd->dsd_list_dma));
- *cur_dsd++ = cpu_to_le32(sglen);
+ put_unaligned_le64(dif_dsd->dsd_list_dma,
+ &cur_dsd->address);
+ cur_dsd->length = cpu_to_le32(sglen);
+ cur_dsd++;
avail_dsds--;
difctx->dif_bundl_len -= sglen;
track_difbundl_buf--;
@@ -1334,8 +1310,6 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
difctx->no_ldif_dsd, difctx->no_dif_bundl);
} else {
for_each_sg(sgl, sg, tot_dsds, i) {
- dma_addr_t sle_dma;
-
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
@@ -1375,24 +1349,19 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
}
/* add new list to cmd iocb or last list */
- *cur_dsd++ =
- cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ =
- cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
- *cur_dsd++ = dsd_list_len;
+ put_unaligned_le64(dsd_ptr->dsd_list_dma,
+ &cur_dsd->address);
+ cur_dsd->length = cpu_to_le32(dsd_list_len);
cur_dsd = dsd_ptr->dsd_addr;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
}
/* Null termination */
- *cur_dsd++ = 0;
- *cur_dsd++ = 0;
- *cur_dsd++ = 0;
+ cur_dsd->address = 0;
+ cur_dsd->length = 0;
+ cur_dsd++;
return 0;
}
/**
@@ -1405,11 +1374,12 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
* @tot_prot_dsds: Total number of segments with protection information
* @fw_prot_opts: Protection options to be passed to firmware
*/
-inline int
+static inline int
qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts)
{
- uint32_t *cur_dsd, *fcp_dl;
+ struct dsd64 *cur_dsd;
+ uint32_t *fcp_dl;
scsi_qla_host_t *vha;
struct scsi_cmnd *cmd;
uint32_t total_bytes = 0;
@@ -1427,7 +1397,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
cmd = GET_CMD_SP(sp);
/* Update entry type to indicate Command Type CRC_2 IOCB */
- *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_CRC_2);
+ put_unaligned_le32(COMMAND_TYPE_CRC_2, &cmd_pkt->entry_type);
vha = sp->vha;
ha = vha->hw;
@@ -1475,8 +1445,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *)
&crc_ctx_pkt->ref_tag, tot_prot_dsds);
- cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma));
- cmd_pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma));
+ put_unaligned_le64(crc_ctx_dma, &cmd_pkt->crc_context_address);
cmd_pkt->crc_context_len = CRC_CONTEXT_LEN_FW;
/* Determine SCSI command length -- align to 4 byte boundary */
@@ -1503,10 +1472,8 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
int_to_scsilun(cmd->device->lun, &fcp_cmnd->lun);
memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
- cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32(
- LSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF));
- cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32(
- MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF));
+ put_unaligned_le64(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF,
+ &cmd_pkt->fcp_cmnd_dseg_address);
fcp_cmnd->task_management = 0;
fcp_cmnd->task_attribute = TSK_SIMPLE;
@@ -1520,18 +1487,18 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
switch (scsi_get_prot_op(GET_CMD_SP(sp))) {
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
- total_bytes = data_bytes;
- data_bytes += dif_bytes;
- break;
+ total_bytes = data_bytes;
+ data_bytes += dif_bytes;
+ break;
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_WRITE_INSERT:
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
- total_bytes = data_bytes + dif_bytes;
- break;
+ total_bytes = data_bytes + dif_bytes;
+ break;
default:
- BUG();
+ BUG();
}
if (!qla2x00_hba_err_chk_enabled(sp))
@@ -1548,7 +1515,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
}
if (!bundling) {
- cur_dsd = (uint32_t *) &crc_ctx_pkt->u.nobundling.data_address;
+ cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd;
} else {
/*
* Configure Bundling if we need to fetch interlaving
@@ -1558,7 +1525,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes);
crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds -
tot_prot_dsds);
- cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.data_address;
+ cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd;
}
/* Finish the common fields of CRC pkt */
@@ -1591,7 +1558,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
if (bundling && tot_prot_dsds) {
/* Walks dif segments */
cmd_pkt->control_flags |= cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE);
- cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address;
+ cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd;
if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd,
tot_prot_dsds, NULL))
goto crc_queuing_error;
@@ -2325,7 +2292,8 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp)
if (req->cnt < req_cnt + 2) {
if (qpair->use_shadow_reg)
cnt = *req->out_ptr;
- else if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ else if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha))
cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
else if (IS_P3P_TYPE(ha))
cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
@@ -2494,7 +2462,7 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
mbx->mb1 = HAS_EXTENDED_IDS(ha) ?
- cpu_to_le16(sp->fcport->loop_id):
+ cpu_to_le16(sp->fcport->loop_id) :
cpu_to_le16(sp->fcport->loop_id << 8);
mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain);
mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 |
@@ -2565,6 +2533,16 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
}
}
+void qla2x00_init_timer(srb_t *sp, unsigned long tmo)
+{
+ timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0);
+ sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ;
+ sp->free = qla2x00_sp_free;
+ if (IS_QLAFX00(sp->vha->hw) && sp->type == SRB_FXIOCB_DCMD)
+ init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
+ add_timer(&sp->u.iocb_cmd.timer);
+}
+
static void
qla2x00_els_dcmd_sp_free(void *data)
{
@@ -2726,18 +2704,13 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) {
els_iocb->tx_byte_count = els_iocb->tx_len =
sizeof(struct els_plogi_payload);
- els_iocb->tx_address[0] =
- cpu_to_le32(LSD(elsio->u.els_plogi.els_plogi_pyld_dma));
- els_iocb->tx_address[1] =
- cpu_to_le32(MSD(elsio->u.els_plogi.els_plogi_pyld_dma));
-
+ put_unaligned_le64(elsio->u.els_plogi.els_plogi_pyld_dma,
+ &els_iocb->tx_address);
els_iocb->rx_dsd_count = 1;
els_iocb->rx_byte_count = els_iocb->rx_len =
sizeof(struct els_plogi_payload);
- els_iocb->rx_address[0] =
- cpu_to_le32(LSD(elsio->u.els_plogi.els_resp_pyld_dma));
- els_iocb->rx_address[1] =
- cpu_to_le32(MSD(elsio->u.els_plogi.els_resp_pyld_dma));
+ put_unaligned_le64(elsio->u.els_plogi.els_resp_pyld_dma,
+ &els_iocb->rx_address);
ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073,
"PLOGI ELS IOCB:\n");
@@ -2745,15 +2718,12 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
(uint8_t *)els_iocb, 0x70);
} else {
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));
+ put_unaligned_le64(elsio->u.els_logo.els_logo_pyld_dma,
+ &els_iocb->tx_address);
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_address = 0;
els_iocb->rx_len = 0;
}
@@ -2976,17 +2946,13 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
els_iocb->tx_byte_count =
cpu_to_le32(bsg_job->request_payload.payload_len);
- els_iocb->tx_address[0] = cpu_to_le32(LSD(sg_dma_address
- (bsg_job->request_payload.sg_list)));
- els_iocb->tx_address[1] = cpu_to_le32(MSD(sg_dma_address
- (bsg_job->request_payload.sg_list)));
+ put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list),
+ &els_iocb->tx_address);
els_iocb->tx_len = cpu_to_le32(sg_dma_len
(bsg_job->request_payload.sg_list));
- els_iocb->rx_address[0] = cpu_to_le32(LSD(sg_dma_address
- (bsg_job->reply_payload.sg_list)));
- els_iocb->rx_address[1] = cpu_to_le32(MSD(sg_dma_address
- (bsg_job->reply_payload.sg_list)));
+ put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list),
+ &els_iocb->rx_address);
els_iocb->rx_len = cpu_to_le32(sg_dma_len
(bsg_job->reply_payload.sg_list));
@@ -2997,14 +2963,13 @@ static void
qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
{
uint16_t avail_dsds;
- uint32_t *cur_dsd;
+ struct dsd64 *cur_dsd;
struct scatterlist *sg;
int index;
uint16_t tot_dsds;
scsi_qla_host_t *vha = sp->vha;
struct qla_hw_data *ha = vha->hw;
struct bsg_job *bsg_job = sp->u.bsg_job;
- int loop_iterartion = 0;
int entry_count = 1;
memset(ct_iocb, 0, sizeof(ms_iocb_entry_t));
@@ -3024,25 +2989,20 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
ct_iocb->rsp_bytecount =
cpu_to_le32(bsg_job->reply_payload.payload_len);
- ct_iocb->dseg_req_address[0] = cpu_to_le32(LSD(sg_dma_address
- (bsg_job->request_payload.sg_list)));
- ct_iocb->dseg_req_address[1] = cpu_to_le32(MSD(sg_dma_address
- (bsg_job->request_payload.sg_list)));
- ct_iocb->dseg_req_length = ct_iocb->req_bytecount;
+ put_unaligned_le64(sg_dma_address(bsg_job->request_payload.sg_list),
+ &ct_iocb->req_dsd.address);
+ ct_iocb->req_dsd.length = ct_iocb->req_bytecount;
- ct_iocb->dseg_rsp_address[0] = cpu_to_le32(LSD(sg_dma_address
- (bsg_job->reply_payload.sg_list)));
- ct_iocb->dseg_rsp_address[1] = cpu_to_le32(MSD(sg_dma_address
- (bsg_job->reply_payload.sg_list)));
- ct_iocb->dseg_rsp_length = ct_iocb->rsp_bytecount;
+ put_unaligned_le64(sg_dma_address(bsg_job->reply_payload.sg_list),
+ &ct_iocb->rsp_dsd.address);
+ ct_iocb->rsp_dsd.length = ct_iocb->rsp_bytecount;
avail_dsds = 1;
- cur_dsd = (uint32_t *)ct_iocb->dseg_rsp_address;
+ cur_dsd = &ct_iocb->rsp_dsd;
index = 0;
tot_dsds = bsg_job->reply_payload.sg_cnt;
for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) {
- dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
@@ -3053,16 +3013,12 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
vha->hw->req_q_map[0]);
- cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+ cur_dsd = cont_pkt->dsd;
avail_dsds = 5;
entry_count++;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
- loop_iterartion++;
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
ct_iocb->entry_count = entry_count;
@@ -3074,7 +3030,7 @@ static void
qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
{
uint16_t avail_dsds;
- uint32_t *cur_dsd;
+ struct dsd64 *cur_dsd;
struct scatterlist *sg;
int index;
uint16_t cmd_dsds, rsp_dsds;
@@ -3103,12 +3059,10 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
cpu_to_le32(bsg_job->request_payload.payload_len);
avail_dsds = 2;
- cur_dsd = (uint32_t *)ct_iocb->dseg_0_address;
+ cur_dsd = ct_iocb->dsd;
index = 0;
for_each_sg(bsg_job->request_payload.sg_list, sg, cmd_dsds, index) {
- dma_addr_t sle_dma;
-
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
@@ -3117,23 +3071,18 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(
vha, ha->req_q_map[0]);
- cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+ cur_dsd = cont_pkt->dsd;
avail_dsds = 5;
entry_count++;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
index = 0;
for_each_sg(bsg_job->reply_payload.sg_list, sg, rsp_dsds, index) {
- dma_addr_t sle_dma;
-
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
@@ -3142,15 +3091,12 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
ha->req_q_map[0]);
- cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+ cur_dsd = cont_pkt->dsd;
avail_dsds = 5;
entry_count++;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
ct_iocb->entry_count = entry_count;
@@ -3371,10 +3317,8 @@ sufficient_dsds:
*fcp_dl = htonl((uint32_t)scsi_bufflen(cmd));
cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
- cmd_pkt->fcp_cmnd_dseg_address[0] =
- cpu_to_le32(LSD(ctx->fcp_cmnd_dma));
- cmd_pkt->fcp_cmnd_dseg_address[1] =
- cpu_to_le32(MSD(ctx->fcp_cmnd_dma));
+ put_unaligned_le64(ctx->fcp_cmnd_dma,
+ &cmd_pkt->fcp_cmnd_dseg_address);
sp->flags |= SRB_FCP_CMND_DMA_VALID;
cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
@@ -3386,6 +3330,7 @@ sufficient_dsds:
cmd_pkt->entry_status = (uint8_t) rsp->id;
} else {
struct cmd_type_7 *cmd_pkt;
+
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
if (req->cnt < (req_cnt + 2)) {
cnt = (uint16_t)RD_REG_DWORD_RELAXED(
@@ -3590,15 +3535,13 @@ qla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt)
cmd_pkt->tx_dseg_count = 1;
cmd_pkt->tx_byte_count = nvme->u.nvme.cmd_len;
- cmd_pkt->dseg0_len = nvme->u.nvme.cmd_len;
- cmd_pkt->dseg0_address[0] = cpu_to_le32(LSD(nvme->u.nvme.cmd_dma));
- cmd_pkt->dseg0_address[1] = cpu_to_le32(MSD(nvme->u.nvme.cmd_dma));
+ cmd_pkt->dsd[0].length = nvme->u.nvme.cmd_len;
+ put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address);
cmd_pkt->rx_dseg_count = 1;
cmd_pkt->rx_byte_count = nvme->u.nvme.rsp_len;
- cmd_pkt->dseg1_len = nvme->u.nvme.rsp_len;
- cmd_pkt->dseg1_address[0] = cpu_to_le32(LSD(nvme->u.nvme.rsp_dma));
- cmd_pkt->dseg1_address[1] = cpu_to_le32(MSD(nvme->u.nvme.rsp_dma));
+ cmd_pkt->dsd[1].length = nvme->u.nvme.rsp_len;
+ put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address);
return rval;
}
@@ -3737,7 +3680,7 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
struct cmd_bidir *cmd_pkt, uint32_t tot_dsds)
{
uint16_t avail_dsds;
- uint32_t *cur_dsd;
+ struct dsd64 *cur_dsd;
uint32_t req_data_len = 0;
uint32_t rsp_data_len = 0;
struct scatterlist *sg;
@@ -3746,8 +3689,7 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
struct bsg_job *bsg_job = sp->u.bsg_job;
/*Update entry type to indicate bidir command */
- *((uint32_t *)(&cmd_pkt->entry_type)) =
- cpu_to_le32(COMMAND_BIDIRECTIONAL);
+ put_unaligned_le32(COMMAND_BIDIRECTIONAL, &cmd_pkt->entry_type);
/* Set the transfer direction, in this set both flags
* Also set the BD_WRAP_BACK flag, firmware will take care
@@ -3773,13 +3715,12 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
* are bundled in continuation iocb
*/
avail_dsds = 1;
- cur_dsd = (uint32_t *)&cmd_pkt->fcp_data_dseg_address;
+ cur_dsd = &cmd_pkt->fcp_dsd;
index = 0;
for_each_sg(bsg_job->request_payload.sg_list, sg,
bsg_job->request_payload.sg_cnt, index) {
- dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets */
@@ -3788,14 +3729,11 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
* 5 DSDS
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
- cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+ cur_dsd = cont_pkt->dsd;
avail_dsds = 5;
entry_count++;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
/* For read request DSD will always goes to continuation IOCB
@@ -3805,7 +3743,6 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
*/
for_each_sg(bsg_job->reply_payload.sg_list, sg,
bsg_job->reply_payload.sg_cnt, index) {
- dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets */
@@ -3814,14 +3751,11 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
* 5 DSDS
*/
cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req);
- cur_dsd = (uint32_t *) cont_pkt->dseg_0_address;
+ cur_dsd = cont_pkt->dsd;
avail_dsds = 5;
entry_count++;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
/* This value should be same as number of IOCB required for this cmd */
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 69bbea9239cc..78aec50abe0f 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -23,6 +23,14 @@ static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
sts_entry_t *);
+const char *const port_state_str[] = {
+ "Unknown",
+ "UNCONFIGURED",
+ "DEAD",
+ "LOST",
+ "ONLINE"
+};
+
/**
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
* @irq: interrupt number
@@ -41,7 +49,7 @@ qla2100_intr_handler(int irq, void *dev_id)
int status;
unsigned long iter;
uint16_t hccr;
- uint16_t mb[4];
+ uint16_t mb[8];
struct rsp_que *rsp;
unsigned long flags;
@@ -160,7 +168,7 @@ qla2300_intr_handler(int irq, void *dev_id)
unsigned long iter;
uint32_t stat;
uint16_t hccr;
- uint16_t mb[4];
+ uint16_t mb[8];
struct rsp_que *rsp;
struct qla_hw_data *ha;
unsigned long flags;
@@ -366,7 +374,7 @@ qla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed)
static const char *const link_speeds[] = {
"1", "2", "?", "4", "8", "16", "32", "10"
};
-#define QLA_LAST_SPEED 7
+#define QLA_LAST_SPEED (ARRAY_SIZE(link_speeds) - 1)
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return link_speeds[0];
@@ -708,12 +716,15 @@ skip_rio:
break;
case MBA_SYSTEM_ERR: /* System Error */
- mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) ?
+ mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) ?
RD_REG_WORD(&reg24->mailbox7) : 0;
ql_log(ql_log_warn, vha, 0x5003,
"ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
"mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
-
+ ha->fw_dump_mpi =
+ (IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&
+ RD_REG_WORD(&reg24->mailbox7) & BIT_8;
ha->isp_ops->fw_dump(vha, 1);
ha->flags.fw_init_done = 0;
QLA_FW_STOPPED(ha);
@@ -837,6 +848,7 @@ skip_rio:
if (ha->flags.fawwpn_enabled &&
(ha->current_topology == ISP_CFG_F)) {
void *wwpn = ha->init_cb->port_name;
+
memcpy(vha->port_name, wwpn, WWN_SIZE);
fc_host_port_name(vha->host) =
wwn_to_u64(vha->port_name);
@@ -1372,7 +1384,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
le16_to_cpu(mbx->status_flags));
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029,
- (uint8_t *)mbx, sizeof(*mbx));
+ mbx, sizeof(*mbx));
goto logio_done;
}
@@ -1516,7 +1528,7 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
bsg_reply->reply_payload_rcv_len = 0;
}
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035,
- (uint8_t *)pkt, sizeof(*pkt));
+ pkt, sizeof(*pkt));
} else {
res = DID_OK << 16;
bsg_reply->reply_payload_rcv_len =
@@ -1591,8 +1603,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
}
comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
- fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1);
- fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2);
+ fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_1);
+ fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_2);
if (iocb_type == ELS_IOCB_TYPE) {
els = &sp->u.iocb_cmd;
@@ -1613,7 +1625,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
res = DID_ERROR << 16;
}
}
- ql_log(ql_log_info, vha, 0x503f,
+ ql_dbg(ql_dbg_user, vha, 0x503f,
"ELS IOCB Done -%s error hdl=%x comp_status=0x%x error subcode 1=0x%x error subcode 2=0x%x total_byte=0x%x\n",
type, sp->handle, comp_status, fw_status[1], fw_status[2],
le16_to_cpu(((struct els_sts_entry_24xx *)
@@ -1656,7 +1668,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply),
fw_status, sizeof(fw_status));
ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
- (uint8_t *)pkt, sizeof(*pkt));
+ pkt, sizeof(*pkt));
}
else {
res = DID_OK << 16;
@@ -1700,7 +1712,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
fcport->d_id.b.area, fcport->d_id.b.al_pa,
logio->entry_status);
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d,
- (uint8_t *)logio, sizeof(*logio));
+ logio, sizeof(*logio));
goto logio_done;
}
@@ -1846,8 +1858,8 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
}
if (iocb->u.tmf.data != QLA_SUCCESS)
- ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
- (uint8_t *)sts, sizeof(*sts));
+ ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055,
+ sts, sizeof(*sts));
sp->done(sp, 0);
}
@@ -1969,6 +1981,52 @@ static void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req,
sp->done(sp, rval);
}
+/* Process a single response queue entry. */
+static void qla2x00_process_response_entry(struct scsi_qla_host *vha,
+ struct rsp_que *rsp,
+ sts_entry_t *pkt)
+{
+ sts21_entry_t *sts21_entry;
+ sts22_entry_t *sts22_entry;
+ uint16_t handle_cnt;
+ uint16_t cnt;
+
+ switch (pkt->entry_type) {
+ case STATUS_TYPE:
+ qla2x00_status_entry(vha, rsp, pkt);
+ break;
+ case STATUS_TYPE_21:
+ sts21_entry = (sts21_entry_t *)pkt;
+ handle_cnt = sts21_entry->handle_count;
+ for (cnt = 0; cnt < handle_cnt; cnt++)
+ qla2x00_process_completed_request(vha, rsp->req,
+ sts21_entry->handle[cnt]);
+ break;
+ case STATUS_TYPE_22:
+ sts22_entry = (sts22_entry_t *)pkt;
+ handle_cnt = sts22_entry->handle_count;
+ for (cnt = 0; cnt < handle_cnt; cnt++)
+ qla2x00_process_completed_request(vha, rsp->req,
+ sts22_entry->handle[cnt]);
+ break;
+ case STATUS_CONT_TYPE:
+ qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
+ break;
+ case MBX_IOCB_TYPE:
+ qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt);
+ break;
+ case CT_IOCB_TYPE:
+ qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
+ break;
+ default:
+ /* Type Not Supported. */
+ ql_log(ql_log_warn, vha, 0x504a,
+ "Received unknown response pkt type %x entry status=%x.\n",
+ pkt->entry_type, pkt->entry_status);
+ break;
+ }
+}
+
/**
* qla2x00_process_response_queue() - Process response queue entries.
* @rsp: response queue
@@ -1980,8 +2038,6 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
struct qla_hw_data *ha = rsp->hw;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
sts_entry_t *pkt;
- uint16_t handle_cnt;
- uint16_t cnt;
vha = pci_get_drvdata(ha->pdev);
@@ -2006,42 +2062,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
continue;
}
- switch (pkt->entry_type) {
- case STATUS_TYPE:
- qla2x00_status_entry(vha, rsp, pkt);
- break;
- case STATUS_TYPE_21:
- handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
- for (cnt = 0; cnt < handle_cnt; cnt++) {
- qla2x00_process_completed_request(vha, rsp->req,
- ((sts21_entry_t *)pkt)->handle[cnt]);
- }
- break;
- case STATUS_TYPE_22:
- handle_cnt = ((sts22_entry_t *)pkt)->handle_count;
- for (cnt = 0; cnt < handle_cnt; cnt++) {
- qla2x00_process_completed_request(vha, rsp->req,
- ((sts22_entry_t *)pkt)->handle[cnt]);
- }
- break;
- case STATUS_CONT_TYPE:
- qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
- break;
- case MBX_IOCB_TYPE:
- qla2x00_mbx_iocb_entry(vha, rsp->req,
- (struct mbx_entry *)pkt);
- break;
- case CT_IOCB_TYPE:
- qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
- break;
- default:
- /* Type Not Supported. */
- ql_log(ql_log_warn, vha, 0x504a,
- "Received unknown response pkt type %x "
- "entry status=%x.\n",
- pkt->entry_type, pkt->entry_status);
- break;
- }
+ qla2x00_process_response_entry(vha, rsp, pkt);
((response_t *)pkt)->signature = RESPONSE_PROCESSED;
wmb();
}
@@ -2238,6 +2259,7 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
struct fc_bsg_reply *bsg_reply;
sts_entry_t *sts;
struct sts_entry_24xx *sts24;
+
sts = (sts_entry_t *) pkt;
sts24 = (struct sts_entry_24xx *) pkt;
@@ -3014,7 +3036,8 @@ process_err:
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
break;
case ABTS_RECV_24XX:
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
/* ensure that the ATIO queue is empty */
qlt_handle_abts_recv(vha, rsp,
(response_t *)pkt);
@@ -3072,6 +3095,7 @@ process_err:
/* Adjust ring index */
if (IS_P3P_TYPE(ha)) {
struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
+
WRT_REG_DWORD(&reg->rsp_q_out[0], rsp->ring_index);
} else {
WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
@@ -3087,7 +3111,7 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha)
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
- !IS_QLA27XX(ha))
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return;
rval = QLA_SUCCESS;
@@ -3475,7 +3499,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
ql_log(ql_log_fatal, vha, 0x00c8,
"Failed to allocate memory for ha->msix_entries.\n");
ret = -ENOMEM;
- goto msix_out;
+ goto free_irqs;
}
ha->flags.msix_enabled = 1;
@@ -3539,7 +3563,7 @@ msix_register_fail:
}
/* Enable MSI-X vector for response queue update for queue 0 */
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
if (ha->msixbase && ha->mqiobase &&
(ha->max_rsp_queues > 1 || ha->max_req_queues > 1 ||
ql2xmqsupport))
@@ -3558,6 +3582,10 @@ msix_register_fail:
msix_out:
return ret;
+
+free_irqs:
+ pci_free_irq_vectors(ha->pdev);
+ goto msix_out;
}
int
@@ -3570,7 +3598,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
/* If possible, enable MSI-X. */
if (ql2xenablemsix == 0 || (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
!IS_QLA8432(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
- !IS_QLAFX00(ha) && !IS_QLA27XX(ha)))
+ !IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)))
goto skip_msi;
if (ql2xenablemsix == 2)
@@ -3609,7 +3637,7 @@ skip_msix:
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
!IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
- !IS_QLA27XX(ha))
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
goto skip_msi;
ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 5400696e1f6b..133f5f6270ff 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -567,9 +567,9 @@ mbx_done:
mcp->mb[0]);
} else if (rval) {
if (ql2xextended_error_logging & (ql_dbg_disc|ql_dbg_mbx)) {
- pr_warn("%s [%s]-%04x:%ld: **** Failed", QL_MSGHDR,
+ pr_warn("%s [%s]-%04x:%ld: **** Failed=%x", QL_MSGHDR,
dev_name(&ha->pdev->dev), 0x1020+0x800,
- vha->host_no);
+ vha->host_no, rval);
mboxes = mcp->in_mb;
cnt = 4;
for (i = 0; i < ha->mbx_count && cnt; i++, mboxes >>= 1)
@@ -634,14 +634,15 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
mcp->out_mb |= MBX_4;
}
- mcp->in_mb = MBX_0;
+ mcp->in_mb = MBX_1|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, 0x1023,
- "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ "Failed=%x mb[0]=%x mb[1]=%x.\n",
+ rval, mcp->mb[0], mcp->mb[1]);
} else {
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1024,
"Done %s.\n", __func__);
@@ -656,7 +657,7 @@ static inline uint16_t qla25xx_set_sfp_lr_dist(struct qla_hw_data *ha)
{
uint16_t mb4 = BIT_0;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
mb4 |= ha->long_range_distance << LR_DIST_FW_POS;
return mb4;
@@ -666,7 +667,7 @@ static inline uint16_t qla25xx_set_nvr_lr_dist(struct qla_hw_data *ha)
{
uint16_t mb4 = BIT_0;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
struct nvram_81xx *nv = ha->nvram;
mb4 |= LR_DIST_FW_FIELD(nv->enhanced_features);
@@ -711,7 +712,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
mcp->mb[4] = 0;
ha->flags.using_lr_setting = 0;
if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
- IS_QLA27XX(ha)) {
+ IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
if (ql2xautodetectsfp) {
if (ha->flags.detected_lr_sfp) {
mcp->mb[4] |=
@@ -730,19 +731,20 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
}
}
- if (ql2xnvmeenable && IS_QLA27XX(ha))
+ if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha)))
mcp->mb[4] |= NVME_ENABLE_FLAG;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
struct nvram_81xx *nv = ha->nvram;
/* set minimum speed if specified in nvram */
- if (nv->min_link_speed >= 2 &&
- nv->min_link_speed <= 5) {
+ if (nv->min_supported_speed >= 2 &&
+ nv->min_supported_speed <= 5) {
mcp->mb[4] |= BIT_4;
- mcp->mb[11] = nv->min_link_speed;
+ mcp->mb[11] |= nv->min_supported_speed & 0xF;
mcp->out_mb |= MBX_11;
mcp->in_mb |= BIT_5;
- vha->min_link_speed_feat = nv->min_link_speed;
+ vha->min_supported_speed =
+ nv->min_supported_speed;
}
}
@@ -770,34 +772,39 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_mbx, vha, 0x1026,
"Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
- } else {
- if (IS_FWI2_CAPABLE(ha)) {
- ha->fw_ability_mask = mcp->mb[3] << 16 | mcp->mb[2];
- ql_dbg(ql_dbg_mbx, vha, 0x119a,
- "fw_ability_mask=%x.\n", ha->fw_ability_mask);
- ql_dbg(ql_dbg_mbx, vha, 0x1027,
- "exchanges=%x.\n", mcp->mb[1]);
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
- ha->max_speed_sup = mcp->mb[2] & BIT_0;
- ql_dbg(ql_dbg_mbx, vha, 0x119b,
- "Maximum speed supported=%s.\n",
- ha->max_speed_sup ? "32Gps" : "16Gps");
- if (vha->min_link_speed_feat) {
- ha->min_link_speed = mcp->mb[5];
- ql_dbg(ql_dbg_mbx, vha, 0x119c,
- "Minimum speed set=%s.\n",
- mcp->mb[5] == 5 ? "32Gps" :
- mcp->mb[5] == 4 ? "16Gps" :
- mcp->mb[5] == 3 ? "8Gps" :
- mcp->mb[5] == 2 ? "4Gps" :
- "unknown");
- }
- }
+ return rval;
+ }
+
+ if (!IS_FWI2_CAPABLE(ha))
+ goto done;
+
+ ha->fw_ability_mask = mcp->mb[3] << 16 | mcp->mb[2];
+ ql_dbg(ql_dbg_mbx, vha, 0x119a,
+ "fw_ability_mask=%x.\n", ha->fw_ability_mask);
+ ql_dbg(ql_dbg_mbx, vha, 0x1027, "exchanges=%x.\n", mcp->mb[1]);
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+ ha->max_supported_speed = mcp->mb[2] & (BIT_0|BIT_1);
+ ql_dbg(ql_dbg_mbx, vha, 0x119b, "max_supported_speed=%s.\n",
+ ha->max_supported_speed == 0 ? "16Gps" :
+ ha->max_supported_speed == 1 ? "32Gps" :
+ ha->max_supported_speed == 2 ? "64Gps" : "unknown");
+ if (vha->min_supported_speed) {
+ ha->min_supported_speed = mcp->mb[5] &
+ (BIT_0 | BIT_1 | BIT_2);
+ ql_dbg(ql_dbg_mbx, vha, 0x119c,
+ "min_supported_speed=%s.\n",
+ ha->min_supported_speed == 6 ? "64Gps" :
+ ha->min_supported_speed == 5 ? "32Gps" :
+ ha->min_supported_speed == 4 ? "16Gps" :
+ ha->min_supported_speed == 3 ? "8Gps" :
+ ha->min_supported_speed == 2 ? "4Gps" : "unknown");
}
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1028,
- "Done.\n");
}
+done:
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1028,
+ "Done %s.\n", __func__);
+
return rval;
}
@@ -1053,10 +1060,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8;
if (IS_FWI2_CAPABLE(ha))
mcp->in_mb |= MBX_17|MBX_16|MBX_15;
- if (IS_QLA27XX(ha))
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->in_mb |=
MBX_25|MBX_24|MBX_23|MBX_22|MBX_21|MBX_20|MBX_19|MBX_18|
- MBX_14|MBX_13|MBX_11|MBX_10|MBX_9|MBX_8;
+ MBX_14|MBX_13|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7;
mcp->flags = 0;
mcp->tov = MBX_TOV_SECONDS;
@@ -1122,7 +1129,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
}
}
- if (IS_QLA27XX(ha)) {
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+ ha->serdes_version[0] = mcp->mb[7] & 0xff;
+ ha->serdes_version[1] = mcp->mb[8] >> 8;
+ ha->serdes_version[2] = mcp->mb[8] & 0xff;
ha->mpi_version[0] = mcp->mb[10] & 0xff;
ha->mpi_version[1] = mcp->mb[11] >> 8;
ha->mpi_version[2] = mcp->mb[11] & 0xff;
@@ -1133,6 +1143,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20];
ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22];
ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24];
+ if (IS_QLA28XX(ha)) {
+ if (mcp->mb[16] & BIT_10) {
+ ql_log(ql_log_info, vha, 0xffff,
+ "FW support secure flash updates\n");
+ ha->flags.secure_fw = 1;
+ }
+ }
}
failed:
@@ -1638,7 +1655,7 @@ 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))
+ if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
mcp->in_mb |= MBX_15;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
@@ -1692,7 +1709,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
}
}
- if (IS_QLA27XX(vha->hw))
+ if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
vha->bbcr = mcp->mb[15];
}
@@ -1808,7 +1825,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
}
/* 1 and 2 should normally be captured. */
mcp->in_mb = MBX_2|MBX_1|MBX_0;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
/* mb3 is additional info about the installed SFP. */
mcp->in_mb |= MBX_3;
mcp->buf_size = size;
@@ -1819,10 +1836,20 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
ql_dbg(ql_dbg_mbx, vha, 0x104d,
- "Failed=%x mb[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x,.\n",
+ "Failed=%x mb[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x.\n",
rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
+ if (ha->init_cb) {
+ ql_dbg(ql_dbg_mbx, vha, 0x104d, "init_cb:\n");
+ ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha,
+ 0x0104d, ha->init_cb, sizeof(*ha->init_cb));
+ }
+ if (ha->ex_init_cb && ha->ex_init_cb->ex_version) {
+ ql_dbg(ql_dbg_mbx, vha, 0x104d, "ex_init_cb:\n");
+ ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha,
+ 0x0104d, ha->ex_init_cb, sizeof(*ha->ex_init_cb));
+ }
} else {
- if (IS_QLA27XX(ha)) {
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
if (mcp->mb[2] == 6 || mcp->mb[3] == 2)
ql_dbg(ql_dbg_mbx, vha, 0x119d,
"Invalid SFP/Validation Failed\n");
@@ -2006,7 +2033,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
/* Passback COS information. */
fcport->supported_classes = (pd->options & BIT_4) ?
- FC_COS_CLASS2: FC_COS_CLASS3;
+ FC_COS_CLASS2 : FC_COS_CLASS3;
}
gpd_error_out:
@@ -2076,7 +2103,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
/*EMPTY*/
ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval);
} else {
- if (IS_QLA27XX(ha)) {
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
if (mcp->mb[2] == 6 || mcp->mb[3] == 2)
ql_dbg(ql_dbg_mbx, vha, 0x119e,
"Invalid SFP/Validation Failed\n");
@@ -2859,7 +2886,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
- if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) || IS_QLA27XX(vha->hw))
+ if (IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
+ IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->in_mb |= MBX_12;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
@@ -2884,7 +2912,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
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))
+ if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha))
ha->fw_max_fcf_count = mcp->mb[12];
}
@@ -3248,7 +3277,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
/* Issue marker IOCB. */
rval2 = qla2x00_marker(vha, ha->base_qpair, fcport->loop_id, l,
- type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID);
+ type == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
if (rval2 != QLA_SUCCESS) {
ql_dbg(ql_dbg_mbx, vha, 0x1099,
"Failed to issue marker IOCB (%x).\n", rval2);
@@ -3323,7 +3352,7 @@ qla2x00_write_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t data)
mbx_cmd_t *mcp = &mc;
if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) &&
- !IS_QLA27XX(vha->hw))
+ !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1182,
@@ -3362,7 +3391,7 @@ qla2x00_read_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t *data)
mbx_cmd_t *mcp = &mc;
if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) &&
- !IS_QLA27XX(vha->hw))
+ !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1185,
@@ -3631,7 +3660,8 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
"Entered %s.\n", __func__);
if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) &&
- !IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw))
+ !IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
+ !IS_QLA28XX(vha->hw))
return QLA_FUNCTION_FAILED;
if (unlikely(pci_channel_offline(vha->hw->pdev)))
@@ -3744,7 +3774,7 @@ qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
rval = qla2x00_mailbox_command(vha, mcp);
/* Return mailbox statuses. */
- if (mb != NULL) {
+ if (mb) {
mb[0] = mcp->mb[0];
mb[1] = mcp->mb[1];
mb[3] = mcp->mb[3];
@@ -3779,7 +3809,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
mcp->mb[0] = MBC_PORT_PARAMS;
mcp->mb[1] = loop_id;
mcp->mb[2] = BIT_0;
- mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
+ mcp->mb[3] = port_speed & 0x3F;
mcp->mb[9] = vha->vp_idx;
mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
mcp->in_mb = MBX_3|MBX_1|MBX_0;
@@ -3788,7 +3818,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
rval = qla2x00_mailbox_command(vha, mcp);
/* Return mailbox statuses. */
- if (mb != NULL) {
+ if (mb) {
mb[0] = mcp->mb[0];
mb[1] = mcp->mb[1];
mb[3] = mcp->mb[3];
@@ -4230,7 +4260,7 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status)
ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111c,
"Dump of Verify Request.\n");
ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111e,
- (uint8_t *)mn, sizeof(*mn));
+ mn, sizeof(*mn));
rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);
if (rval != QLA_SUCCESS) {
@@ -4242,7 +4272,7 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status)
ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1110,
"Dump of Verify Response.\n");
ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1118,
- (uint8_t *)mn, sizeof(*mn));
+ mn, sizeof(*mn));
status[0] = le16_to_cpu(mn->p.rsp.comp_status);
status[1] = status[0] == CS_VCS_CHIP_FAILURE ?
@@ -4318,7 +4348,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
mcp->mb[12] = req->qos;
mcp->mb[11] = req->vp_idx;
mcp->mb[13] = req->rid;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->mb[15] = 0;
mcp->mb[4] = req->id;
@@ -4332,9 +4362,10 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
mcp->flags = MBX_DMA_OUT;
mcp->tov = MBX_TOV_SECONDS * 2;
- if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha))
mcp->in_mb |= MBX_1;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
mcp->out_mb |= MBX_15;
/* debug q create issue in SR-IOV */
mcp->in_mb |= MBX_9 | MBX_8 | MBX_7;
@@ -4343,7 +4374,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
spin_lock_irqsave(&ha->hardware_lock, flags);
if (!(req->options & BIT_0)) {
WRT_REG_DWORD(req->req_q_in, 0);
- if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
WRT_REG_DWORD(req->req_q_out, 0);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -4387,7 +4418,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
mcp->mb[5] = rsp->length;
mcp->mb[14] = rsp->msix->entry;
mcp->mb[13] = rsp->rid;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->mb[15] = 0;
mcp->mb[4] = rsp->id;
@@ -4404,7 +4435,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
if (IS_QLA81XX(ha)) {
mcp->out_mb |= MBX_12|MBX_11|MBX_10;
mcp->in_mb |= MBX_1;
- } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ } else if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
mcp->out_mb |= MBX_15|MBX_12|MBX_11|MBX_10;
mcp->in_mb |= MBX_1;
/* debug q create issue in SR-IOV */
@@ -4414,7 +4445,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
spin_lock_irqsave(&ha->hardware_lock, flags);
if (!(rsp->options & BIT_0)) {
WRT_REG_DWORD(rsp->rsp_q_out, 0);
- if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
WRT_REG_DWORD(rsp->rsp_q_in, 0);
}
@@ -4472,7 +4503,7 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size)
"Entered %s.\n", __func__);
if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
- !IS_QLA27XX(vha->hw))
+ !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
@@ -4504,7 +4535,7 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable)
mbx_cmd_t *mcp = &mc;
if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
- !IS_QLA27XX(vha->hw))
+ !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10df,
@@ -4539,7 +4570,7 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
mbx_cmd_t *mcp = &mc;
if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw) &&
- !IS_QLA27XX(vha->hw))
+ !IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2,
@@ -4570,6 +4601,42 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
}
int
+qla81xx_fac_semaphore_access(scsi_qla_host_t *vha, int lock)
+{
+ int rval = QLA_SUCCESS;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+ return rval;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
+ mcp->mb[1] = (lock ? FAC_OPT_CMD_LOCK_SEMAPHORE :
+ FAC_OPT_CMD_UNLOCK_SEMAPHORE);
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|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, 0x10e3,
+ "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+ rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e4,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+int
qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
{
int rval = 0;
@@ -4818,10 +4885,10 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_mbx, vha, 0x10e9,
"Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
- if (mcp->mb[0] == MBS_COMMAND_ERROR &&
- mcp->mb[1] == 0x22)
+ if (mcp->mb[0] == MBS_COMMAND_ERROR && mcp->mb[1] == 0x22) {
/* sfp is not there */
rval = QLA_INTERFACE_ERROR;
+ }
} else {
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea,
"Done %s.\n", __func__);
@@ -5161,13 +5228,14 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
mcp->mb[3] = MSW(data);
mcp->mb[8] = MSW(risc_addr);
mcp->out_mb = MBX_8|MBX_3|MBX_2|MBX_1|MBX_0;
- mcp->in_mb = MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
mcp->tov = 30;
mcp->flags = 0;
rval = qla2x00_mailbox_command(vha, mcp);
if (rval != QLA_SUCCESS) {
ql_dbg(ql_dbg_mbx, vha, 0x1101,
- "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ "Failed=%x mb[0]=%x mb[1]=%x.\n",
+ rval, mcp->mb[0], mcp->mb[1]);
} else {
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1102,
"Done %s.\n", __func__);
@@ -5278,7 +5346,7 @@ qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode)
mcp->out_mb = MBX_2|MBX_1|MBX_0;
mcp->in_mb = MBX_2|MBX_1|MBX_0;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->in_mb |= MBX_4|MBX_3;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
@@ -5316,7 +5384,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
mcp->mb[1] = QLA_GET_DATA_RATE;
mcp->out_mb = MBX_1|MBX_0;
mcp->in_mb = MBX_2|MBX_1|MBX_0;
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
mcp->in_mb |= MBX_3;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
@@ -5346,7 +5414,7 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
"Entered %s.\n", __func__);
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA8044(ha) &&
- !IS_QLA27XX(ha))
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_GET_PORT_CONFIG;
mcp->out_mb = MBX_0;
@@ -5662,6 +5730,7 @@ qla8044_md_get_template(scsi_qla_host_t *vha)
mbx_cmd_t *mcp = &mc;
int rval = QLA_FUNCTION_FAILED;
int offset = 0, size = MINIDUMP_SIZE_36K;
+
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xb11f,
"Entered %s.\n", __func__);
@@ -5842,7 +5911,7 @@ qla83xx_wr_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1130,
@@ -5917,7 +5986,7 @@ qla83xx_rd_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t *data)
struct qla_hw_data *ha = vha->hw;
unsigned long retry_max_time = jiffies + (2 * HZ);
- if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx, vha, 0x114b, "Entered %s.\n", __func__);
@@ -5967,7 +6036,7 @@ qla83xx_restart_nic_firmware(scsi_qla_host_t *vha)
mbx_cmd_t *mcp = &mc;
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA83XX(ha))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx, vha, 0x1143, "Entered %s.\n", __func__);
@@ -6101,7 +6170,8 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha,
mbx_cmd_t *mcp = &mc;
dma_addr_t dd_dma;
- if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw))
+ if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
+ !IS_QLA28XX(vha->hw))
return QLA_FUNCTION_FAILED;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x119f,
@@ -6318,7 +6388,13 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport,
fcport->d_id.b.rsvd_1 = 0;
if (fcport->fc4f_nvme) {
- fcport->port_type = FCT_NVME;
+ fcport->port_type = 0;
+ if ((pd->prli_svc_param_word_3[0] & BIT_5) == 0)
+ fcport->port_type |= FCT_NVME_INITIATOR;
+ if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0)
+ fcport->port_type |= FCT_NVME_TARGET;
+ if ((pd->prli_svc_param_word_3[0] & BIT_3) == 0)
+ fcport->port_type |= FCT_NVME_DISCOVERY;
} else {
/* If not target must be initiator or unknown type. */
if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0)
@@ -6507,3 +6583,101 @@ int qla24xx_res_count_wait(struct scsi_qla_host *vha,
done:
return rval;
}
+
+int qla28xx_secure_flash_update(scsi_qla_host_t *vha, uint16_t opts,
+ uint16_t region, uint32_t len, dma_addr_t sfub_dma_addr,
+ uint32_t sfub_len)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ mcp->mb[0] = MBC_SECURE_FLASH_UPDATE;
+ mcp->mb[1] = opts;
+ mcp->mb[2] = region;
+ mcp->mb[3] = MSW(len);
+ mcp->mb[4] = LSW(len);
+ mcp->mb[5] = MSW(sfub_dma_addr);
+ mcp->mb[6] = LSW(sfub_dma_addr);
+ mcp->mb[7] = MSW(MSD(sfub_dma_addr));
+ mcp->mb[8] = LSW(MSD(sfub_dma_addr));
+ mcp->mb[9] = sfub_len;
+ mcp->out_mb =
+ MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_2|MBX_1|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, 0xffff, "%s(%ld): failed rval 0x%x, %x %x %x",
+ __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1],
+ mcp->mb[2]);
+ }
+
+ return rval;
+}
+
+int qla2xxx_write_remote_register(scsi_qla_host_t *vha, uint32_t addr,
+ uint32_t data)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_WRITE_REMOTE_REG;
+ mcp->mb[1] = LSW(addr);
+ mcp->mb[2] = MSW(addr);
+ mcp->mb[3] = LSW(data);
+ mcp->mb[4] = MSW(data);
+ mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|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, 0x10e9,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+int qla2xxx_read_remote_register(scsi_qla_host_t *vha, uint32_t addr,
+ uint32_t *data)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_READ_REMOTE_REG;
+ mcp->mb[1] = LSW(addr);
+ mcp->mb[2] = MSW(addr);
+ mcp->out_mb = MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ *data = (uint32_t)((((uint32_t)mcp->mb[4]) << 16) | mcp->mb[3]);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x10e9,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 099d8e9851cb..b2977e49356b 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -905,7 +905,8 @@ static void qla_ctrlvp_sp_done(void *s, int res)
{
struct srb *sp = s;
- complete(&sp->comp);
+ if (sp->comp)
+ complete(sp->comp);
/* don't free sp here. Let the caller do the free */
}
@@ -922,6 +923,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
struct qla_hw_data *ha = vha->hw;
int vp_index = vha->vp_idx;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
+ DECLARE_COMPLETION_ONSTACK(comp);
srb_t *sp;
ql_dbg(ql_dbg_vport, vha, 0x10c1,
@@ -936,6 +938,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
sp->type = SRB_CTRL_VP;
sp->name = "ctrl_vp";
+ sp->comp = &comp;
sp->done = qla_ctrlvp_sp_done;
sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
@@ -953,7 +956,9 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
ql_dbg(ql_dbg_vport, vha, 0x113f, "%s hndl %x submitted\n",
sp->name, sp->handle);
- wait_for_completion(&sp->comp);
+ wait_for_completion(&comp);
+ sp->comp = NULL;
+
rval = sp->rc;
switch (rval) {
case QLA_FUNCTION_TIMEOUT:
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index 60f964c53c01..942ee13b96a4 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -273,9 +273,9 @@ premature_exit:
if (rval) {
ql_log(ql_log_warn, base_vha, 0x1163,
- "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, "
- "mb[3]=%x, cmd=%x ****.\n",
- mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command);
+ "**** Failed=%x mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n",
+ rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3],
+ command);
} else {
ql_dbg(ql_dbg_mbx, base_vha, 0x1164, "Done %s.\n", __func__);
}
@@ -629,17 +629,20 @@ qlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
*
* Returns 0 on success.
*/
-void
+int
qlafx00_soft_reset(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+ int rval = QLA_FUNCTION_FAILED;
if (unlikely(pci_channel_offline(ha->pdev) &&
ha->flags.pci_channel_io_perm_failure))
- return;
+ return rval;
ha->isp_ops->disable_intrs(ha);
qlafx00_soc_cpu_reset(vha);
+
+ return QLA_SUCCESS;
}
/**
@@ -1138,8 +1141,8 @@ qlafx00_find_all_targets(scsi_qla_host_t *vha,
ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x2088,
"Listing Target bit map...\n");
- ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha,
- 0x2089, (uint8_t *)ha->gid_list, 32);
+ ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha, 0x2089,
+ ha->gid_list, 32);
/* Allocate temporary rmtport for any new rmtports discovered. */
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
@@ -1320,6 +1323,7 @@ qlafx00_configure_devices(scsi_qla_host_t *vha)
{
int rval;
unsigned long flags;
+
rval = QLA_SUCCESS;
flags = vha->dpc_flags;
@@ -1913,8 +1917,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
phost_info->domainname,
phost_info->hostdriver);
ql_dump_buffer(ql_dbg_init + ql_dbg_disc, vha, 0x014d,
- (uint8_t *)phost_info,
- sizeof(struct host_system_info));
+ phost_info, sizeof(*phost_info));
}
}
@@ -1968,7 +1971,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
vha->d_id.b.al_pa = pinfo->port_id[2];
qlafx00_update_host_attr(vha, pinfo);
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0141,
- (uint8_t *)pinfo, 16);
+ pinfo, 16);
} else if (fx_type == FXDISC_GET_TGT_NODE_INFO) {
struct qlafx00_tgt_node_info *pinfo =
(struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
@@ -1976,12 +1979,12 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
memcpy(fcport->port_name, pinfo->tgt_node_wwpn, WWN_SIZE);
fcport->port_type = FCT_TARGET;
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0144,
- (uint8_t *)pinfo, 16);
+ pinfo, 16);
} else if (fx_type == FXDISC_GET_TGT_NODE_LIST) {
struct qlafx00_tgt_node_info *pinfo =
(struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0146,
- (uint8_t *)pinfo, 16);
+ pinfo, 16);
memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
} else if (fx_type == FXDISC_ABORT_IOCTL)
fdisc->u.fxiocb.result =
@@ -2248,18 +2251,16 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
fw_sts_ptr = bsg_job->reply + sizeof(struct fc_bsg_reply);
- memcpy(fw_sts_ptr, (uint8_t *)&fstatus,
- sizeof(struct qla_mt_iocb_rsp_fx00));
+ memcpy(fw_sts_ptr, &fstatus, sizeof(fstatus));
bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
sizeof(struct qla_mt_iocb_rsp_fx00) + sizeof(uint8_t);
ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
- sp->fcport->vha, 0x5080,
- (uint8_t *)pkt, sizeof(struct ioctl_iocb_entry_fx00));
+ sp->vha, 0x5080, pkt, sizeof(*pkt));
ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
- sp->fcport->vha, 0x5074,
- (uint8_t *)fw_sts_ptr, sizeof(struct qla_mt_iocb_rsp_fx00));
+ sp->vha, 0x5074,
+ fw_sts_ptr, sizeof(fstatus));
res = bsg_reply->result = DID_OK << 16;
bsg_reply->reply_payload_rcv_len =
@@ -2597,7 +2598,7 @@ qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
/* Move sense data. */
ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304e,
- (uint8_t *)pkt, sizeof(sts_cont_entry_t));
+ pkt, sizeof(*pkt));
memcpy(sense_ptr, pkt->data, sense_sz);
ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304a,
sense_ptr, sense_sz);
@@ -2992,7 +2993,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt)
{
uint16_t avail_dsds;
- __le32 *cur_dsd;
+ struct dsd64 *cur_dsd;
scsi_qla_host_t *vha;
struct scsi_cmnd *cmd;
struct scatterlist *sg;
@@ -3028,12 +3029,10 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
/* One DSD is available in the Command Type 3 IOCB */
avail_dsds = 1;
- cur_dsd = (__le32 *)&lcmd_pkt->dseg_0_address;
+ cur_dsd = &lcmd_pkt->dsd;
/* Load data segments */
scsi_for_each_sg(cmd, sg, tot_dsds, i) {
- dma_addr_t sle_dma;
-
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
@@ -3043,26 +3042,23 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE);
cont_pkt =
qlafx00_prep_cont_type1_iocb(req, &lcont_pkt);
- cur_dsd = (__le32 *)lcont_pkt.dseg_0_address;
+ cur_dsd = lcont_pkt.dsd;
avail_dsds = 5;
cont = 1;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
if (avail_dsds == 0 && cont == 1) {
cont = 0;
memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
- REQUEST_ENTRY_SIZE);
+ sizeof(lcont_pkt));
}
}
if (avail_dsds != 0 && cont == 1) {
memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
- REQUEST_ENTRY_SIZE);
+ sizeof(lcont_pkt));
}
}
@@ -3172,9 +3168,9 @@ qlafx00_start_scsi(srb_t *sp)
lcmd_pkt.entry_status = (uint8_t) rsp->id;
ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e,
- (uint8_t *)cmd->cmnd, cmd->cmd_len);
+ cmd->cmnd, cmd->cmd_len);
ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3032,
- (uint8_t *)&lcmd_pkt, REQUEST_ENTRY_SIZE);
+ &lcmd_pkt, sizeof(lcmd_pkt));
memcpy_toio((void __iomem *)cmd_pkt, &lcmd_pkt, REQUEST_ENTRY_SIZE);
wmb();
@@ -3282,11 +3278,9 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
fx_iocb.req_dsdcnt = cpu_to_le16(1);
fx_iocb.req_xfrcnt =
cpu_to_le16(fxio->u.fxiocb.req_len);
- fx_iocb.dseg_rq_address[0] =
- cpu_to_le32(LSD(fxio->u.fxiocb.req_dma_handle));
- fx_iocb.dseg_rq_address[1] =
- cpu_to_le32(MSD(fxio->u.fxiocb.req_dma_handle));
- fx_iocb.dseg_rq_len =
+ put_unaligned_le64(fxio->u.fxiocb.req_dma_handle,
+ &fx_iocb.dseg_rq.address);
+ fx_iocb.dseg_rq.length =
cpu_to_le32(fxio->u.fxiocb.req_len);
}
@@ -3294,11 +3288,9 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
fx_iocb.rsp_dsdcnt = cpu_to_le16(1);
fx_iocb.rsp_xfrcnt =
cpu_to_le16(fxio->u.fxiocb.rsp_len);
- fx_iocb.dseg_rsp_address[0] =
- cpu_to_le32(LSD(fxio->u.fxiocb.rsp_dma_handle));
- fx_iocb.dseg_rsp_address[1] =
- cpu_to_le32(MSD(fxio->u.fxiocb.rsp_dma_handle));
- fx_iocb.dseg_rsp_len =
+ put_unaligned_le64(fxio->u.fxiocb.rsp_dma_handle,
+ &fx_iocb.dseg_rsp.address);
+ fx_iocb.dseg_rsp.length =
cpu_to_le32(fxio->u.fxiocb.rsp_len);
}
@@ -3308,6 +3300,7 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
fx_iocb.flags = fxio->u.fxiocb.flags;
} else {
struct scatterlist *sg;
+
bsg_job = sp->u.bsg_job;
bsg_request = bsg_job->request;
piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
@@ -3327,19 +3320,17 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
int avail_dsds, tot_dsds;
cont_a64_entry_t lcont_pkt;
cont_a64_entry_t *cont_pkt = NULL;
- __le32 *cur_dsd;
+ struct dsd64 *cur_dsd;
int index = 0, cont = 0;
fx_iocb.req_dsdcnt =
cpu_to_le16(bsg_job->request_payload.sg_cnt);
tot_dsds =
bsg_job->request_payload.sg_cnt;
- cur_dsd = (__le32 *)&fx_iocb.dseg_rq_address[0];
+ cur_dsd = &fx_iocb.dseg_rq;
avail_dsds = 1;
for_each_sg(bsg_job->request_payload.sg_list, sg,
tot_dsds, index) {
- dma_addr_t sle_dma;
-
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
@@ -3351,17 +3342,13 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
cont_pkt =
qlafx00_prep_cont_type1_iocb(
sp->vha->req, &lcont_pkt);
- cur_dsd = (__le32 *)
- lcont_pkt.dseg_0_address;
+ cur_dsd = lcont_pkt.dsd;
avail_dsds = 5;
cont = 1;
entry_cnt++;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
if (avail_dsds == 0 && cont == 1) {
@@ -3389,19 +3376,17 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
int avail_dsds, tot_dsds;
cont_a64_entry_t lcont_pkt;
cont_a64_entry_t *cont_pkt = NULL;
- __le32 *cur_dsd;
+ struct dsd64 *cur_dsd;
int index = 0, cont = 0;
fx_iocb.rsp_dsdcnt =
cpu_to_le16(bsg_job->reply_payload.sg_cnt);
tot_dsds = bsg_job->reply_payload.sg_cnt;
- cur_dsd = (__le32 *)&fx_iocb.dseg_rsp_address[0];
+ cur_dsd = &fx_iocb.dseg_rsp;
avail_dsds = 1;
for_each_sg(bsg_job->reply_payload.sg_list, sg,
tot_dsds, index) {
- dma_addr_t sle_dma;
-
/* Allocate additional continuation packets? */
if (avail_dsds == 0) {
/*
@@ -3413,17 +3398,13 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
cont_pkt =
qlafx00_prep_cont_type1_iocb(
sp->vha->req, &lcont_pkt);
- cur_dsd = (__le32 *)
- lcont_pkt.dseg_0_address;
+ cur_dsd = lcont_pkt.dsd;
avail_dsds = 5;
cont = 1;
entry_cnt++;
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
if (avail_dsds == 0 && cont == 1) {
@@ -3454,10 +3435,8 @@ qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
}
ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
- sp->vha, 0x3047,
- (uint8_t *)&fx_iocb, sizeof(struct fxdisc_entry_fx00));
+ sp->vha, 0x3047, &fx_iocb, sizeof(fx_iocb));
- memcpy_toio((void __iomem *)pfxiocb, &fx_iocb,
- sizeof(struct fxdisc_entry_fx00));
+ memcpy_toio((void __iomem *)pfxiocb, &fx_iocb, sizeof(fx_iocb));
wmb();
}
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
index aeaa1b40b1fc..4567f0c42486 100644
--- a/drivers/scsi/qla2xxx/qla_mr.h
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -7,6 +7,8 @@
#ifndef __QLA_MR_H
#define __QLA_MR_H
+#include "qla_dsd.h"
+
/*
* The PCI VendorID and DeviceID for our board.
*/
@@ -46,8 +48,7 @@ struct cmd_type_7_fx00 {
uint8_t fcp_cdb[MAX_CMDSZ]; /* SCSI command words. */
__le32 byte_count; /* Total byte count. */
- uint32_t dseg_0_address[2]; /* Data segment 0 address. */
- uint32_t dseg_0_len; /* Data segment 0 length. */
+ struct dsd64 dsd;
};
#define STATUS_TYPE_FX00 0x01 /* Status entry. */
@@ -176,10 +177,8 @@ struct fxdisc_entry_fx00 {
uint8_t flags;
uint8_t reserved_1;
- __le32 dseg_rq_address[2]; /* Data segment 0 address. */
- __le32 dseg_rq_len; /* Data segment 0 length. */
- __le32 dseg_rsp_address[2]; /* Data segment 1 address. */
- __le32 dseg_rsp_len; /* Data segment 1 length. */
+ struct dsd64 dseg_rq;
+ struct dsd64 dseg_rsp;
__le32 dataword;
__le32 adapid;
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index 41c85da3ab32..963094b3c300 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -12,8 +12,6 @@
static struct nvme_fc_port_template qla_nvme_fc_transport;
-static void qla_nvme_unregister_remote_port(struct work_struct *);
-
int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
{
struct qla_nvme_rport *rport;
@@ -38,7 +36,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
(fcport->nvme_flag & NVME_FLAG_REGISTERED))
return 0;
- INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port);
fcport->nvme_flag &= ~NVME_FLAG_RESETTING;
memset(&req, 0, sizeof(struct nvme_fc_port_info));
@@ -74,7 +71,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
rport = fcport->nvme_remote_port->private;
rport->fcport = fcport;
- list_add_tail(&rport->list, &vha->nvme_rport_list);
fcport->nvme_flag |= NVME_FLAG_REGISTERED;
return 0;
@@ -124,54 +120,91 @@ static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport,
return 0;
}
-static void qla_nvme_sp_ls_done(void *ptr, int res)
+static void qla_nvme_release_fcp_cmd_kref(struct kref *kref)
{
- srb_t *sp = ptr;
+ struct srb *sp = container_of(kref, struct srb, cmd_kref);
+ struct nvme_private *priv = (struct nvme_private *)sp->priv;
+ struct nvmefc_fcp_req *fd;
struct srb_iocb *nvme;
- struct nvmefc_ls_req *fd;
- struct nvme_private *priv;
+ unsigned long flags;
- if (atomic_read(&sp->ref_count) == 0) {
- ql_log(ql_log_warn, sp->fcport->vha, 0x2123,
- "SP reference-count to ZERO on LS_done -- sp=%p.\n", sp);
- return;
+ if (!priv)
+ goto out;
+
+ nvme = &sp->u.iocb_cmd;
+ fd = nvme->u.nvme.desc;
+
+ spin_lock_irqsave(&priv->cmd_lock, flags);
+ priv->sp = NULL;
+ sp->priv = NULL;
+ if (priv->comp_status == QLA_SUCCESS) {
+ fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
+ } else {
+ fd->rcv_rsplen = 0;
+ fd->transferred_length = 0;
}
+ fd->status = 0;
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+
+ fd->done(fd);
+out:
+ qla2xxx_rel_qpair_sp(sp->qpair, sp);
+}
+
+static void qla_nvme_release_ls_cmd_kref(struct kref *kref)
+{
+ struct srb *sp = container_of(kref, struct srb, cmd_kref);
+ struct nvme_private *priv = (struct nvme_private *)sp->priv;
+ struct nvmefc_ls_req *fd;
+ unsigned long flags;
+
+ if (!priv)
+ goto out;
+
+ spin_lock_irqsave(&priv->cmd_lock, flags);
+ priv->sp = NULL;
+ sp->priv = NULL;
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+
+ fd = priv->fd;
+ fd->done(fd, priv->comp_status);
+out:
+ qla2x00_rel_sp(sp);
+}
+
+static void qla_nvme_ls_complete(struct work_struct *work)
+{
+ struct nvme_private *priv =
+ container_of(work, struct nvme_private, ls_work);
+
+ kref_put(&priv->sp->cmd_kref, qla_nvme_release_ls_cmd_kref);
+}
- if (!atomic_dec_and_test(&sp->ref_count))
+static void qla_nvme_sp_ls_done(void *ptr, int res)
+{
+ srb_t *sp = ptr;
+ struct nvme_private *priv;
+
+ if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0))
return;
if (res)
res = -EINVAL;
- nvme = &sp->u.iocb_cmd;
- fd = nvme->u.nvme.desc;
- priv = fd->private;
+ priv = (struct nvme_private *)sp->priv;
priv->comp_status = res;
+ INIT_WORK(&priv->ls_work, qla_nvme_ls_complete);
schedule_work(&priv->ls_work);
- /* work schedule doesn't need the sp */
- qla2x00_rel_sp(sp);
}
+/* it assumed that QPair lock is held. */
static void qla_nvme_sp_done(void *ptr, int res)
{
srb_t *sp = ptr;
- struct srb_iocb *nvme;
- struct nvmefc_fcp_req *fd;
+ struct nvme_private *priv = (struct nvme_private *)sp->priv;
- nvme = &sp->u.iocb_cmd;
- fd = nvme->u.nvme.desc;
-
- if (!atomic_dec_and_test(&sp->ref_count))
- return;
-
- if (res == QLA_SUCCESS)
- fd->status = 0;
- else
- fd->status = NVME_SC_INTERNAL;
-
- fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
- fd->done(fd);
- qla2xxx_rel_qpair_sp(sp->qpair, sp);
+ priv->comp_status = res;
+ kref_put(&sp->cmd_kref, qla_nvme_release_fcp_cmd_kref);
return;
}
@@ -185,13 +218,20 @@ static void qla_nvme_abort_work(struct work_struct *work)
struct qla_hw_data *ha = fcport->vha->hw;
int rval;
- if (fcport)
- ql_dbg(ql_dbg_io, fcport->vha, 0xffff,
- "%s called for sp=%p, hndl=%x on fcport=%p deleted=%d\n",
- __func__, sp, sp->handle, fcport, fcport->deleted);
+ ql_dbg(ql_dbg_io, fcport->vha, 0xffff,
+ "%s called for sp=%p, hndl=%x on fcport=%p deleted=%d\n",
+ __func__, sp, sp->handle, fcport, fcport->deleted);
if (!ha->flags.fw_started && (fcport && fcport->deleted))
- return;
+ goto out;
+
+ if (ha->flags.host_shutting_down) {
+ ql_log(ql_log_info, sp->fcport->vha, 0xffff,
+ "%s Calling done on sp: %p, type: 0x%x, sp->ref_count: 0x%x\n",
+ __func__, sp, sp->type, atomic_read(&sp->ref_count));
+ sp->done(sp, 0);
+ goto out;
+ }
rval = ha->isp_ops->abort_command(sp);
@@ -199,25 +239,34 @@ static void qla_nvme_abort_work(struct work_struct *work)
"%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n",
__func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted",
sp, sp->handle, fcport, rval);
+
+out:
+ /* kref_get was done before work was schedule. */
+ kref_put(&sp->cmd_kref, sp->put_fn);
}
static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
{
struct nvme_private *priv = fd->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->cmd_lock, flags);
+ if (!priv->sp) {
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+ return;
+ }
+
+ if (!kref_get_unless_zero(&priv->sp->cmd_kref)) {
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
schedule_work(&priv->abort_work);
}
-static void qla_nvme_ls_complete(struct work_struct *work)
-{
- struct nvme_private *priv =
- container_of(work, struct nvme_private, ls_work);
- struct nvmefc_ls_req *fd = priv->fd;
-
- fd->done(fd, priv->comp_status);
-}
static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
@@ -231,8 +280,16 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
struct qla_hw_data *ha;
srb_t *sp;
+
+ if (!fcport || (fcport && fcport->deleted))
+ return rval;
+
vha = fcport->vha;
ha = vha->hw;
+
+ if (!ha->flags.fw_started)
+ return rval;
+
/* Alloc SRB structure */
sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
if (!sp)
@@ -241,11 +298,13 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
sp->type = SRB_NVME_LS;
sp->name = "nvme_ls";
sp->done = qla_nvme_sp_ls_done;
- atomic_set(&sp->ref_count, 1);
- nvme = &sp->u.iocb_cmd;
+ sp->put_fn = qla_nvme_release_ls_cmd_kref;
+ sp->priv = (void *)priv;
priv->sp = sp;
+ kref_init(&sp->cmd_kref);
+ spin_lock_init(&priv->cmd_lock);
+ nvme = &sp->u.iocb_cmd;
priv->fd = fd;
- INIT_WORK(&priv->ls_work, qla_nvme_ls_complete);
nvme->u.nvme.desc = fd;
nvme->u.nvme.dir = 0;
nvme->u.nvme.dl = 0;
@@ -262,8 +321,10 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x700e,
"qla2x00_start_sp failed = %d\n", rval);
- atomic_dec(&sp->ref_count);
wake_up(&sp->nvme_ls_waitq);
+ sp->priv = NULL;
+ priv->sp = NULL;
+ qla2x00_rel_sp(sp);
return rval;
}
@@ -275,6 +336,18 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
struct nvmefc_fcp_req *fd)
{
struct nvme_private *priv = fd->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->cmd_lock, flags);
+ if (!priv->sp) {
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+ return;
+ }
+ if (!kref_get_unless_zero(&priv->sp->cmd_kref)) {
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&priv->cmd_lock, flags);
INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
schedule_work(&priv->abort_work);
@@ -291,7 +364,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
uint16_t req_cnt;
uint16_t tot_dsds;
uint16_t avail_dsds;
- uint32_t *cur_dsd;
+ struct dsd64 *cur_dsd;
struct req_que *req = NULL;
struct scsi_qla_host *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
@@ -340,6 +413,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
if (unlikely(!fd->sqid)) {
struct nvme_fc_cmd_iu *cmd = fd->cmdaddr;
+
if (cmd->sqe.common.opcode == nvme_admin_async_event) {
nvme->u.nvme.aen_op = 1;
atomic_inc(&ha->nvme_active_aen_cnt);
@@ -395,25 +469,22 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
/* NVME RSP IU */
cmd_pkt->nvme_rsp_dsd_len = cpu_to_le16(fd->rsplen);
- cmd_pkt->nvme_rsp_dseg_address[0] = cpu_to_le32(LSD(fd->rspdma));
- cmd_pkt->nvme_rsp_dseg_address[1] = cpu_to_le32(MSD(fd->rspdma));
+ put_unaligned_le64(fd->rspdma, &cmd_pkt->nvme_rsp_dseg_address);
/* NVME CNMD IU */
cmd_pkt->nvme_cmnd_dseg_len = cpu_to_le16(fd->cmdlen);
- cmd_pkt->nvme_cmnd_dseg_address[0] = cpu_to_le32(LSD(fd->cmddma));
- cmd_pkt->nvme_cmnd_dseg_address[1] = cpu_to_le32(MSD(fd->cmddma));
+ cmd_pkt->nvme_cmnd_dseg_address = cpu_to_le64(fd->cmddma);
cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
cmd_pkt->byte_count = cpu_to_le32(fd->payload_length);
/* One DSD is available in the Command Type NVME IOCB */
avail_dsds = 1;
- cur_dsd = (uint32_t *)&cmd_pkt->nvme_data_dseg_address[0];
+ cur_dsd = &cmd_pkt->nvme_dsd;
sgl = fd->first_sgl;
/* Load data segments */
for_each_sg(sgl, sg, tot_dsds, i) {
- dma_addr_t sle_dma;
cont_a64_entry_t *cont_pkt;
/* Allocate additional continuation packets? */
@@ -432,17 +503,14 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
req->ring_ptr++;
}
cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
- *((uint32_t *)(&cont_pkt->entry_type)) =
- cpu_to_le32(CONTINUE_A64_TYPE);
+ put_unaligned_le32(CONTINUE_A64_TYPE,
+ &cont_pkt->entry_type);
- cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
- avail_dsds = 5;
+ cur_dsd = cont_pkt->dsd;
+ avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
}
- sle_dma = sg_dma_address(sg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ append_dsd64(&cur_dsd, sg);
avail_dsds--;
}
@@ -483,11 +551,11 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
fcport = qla_rport->fcport;
- vha = fcport->vha;
-
- if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
+ if (!qpair || !fcport || (qpair && !qpair->fw_started) ||
+ (fcport && fcport->deleted))
return rval;
+ vha = fcport->vha;
/*
* If we know the dev is going away while the transport is still sending
* IO's return busy back to stall the IO Q. This happens when the
@@ -503,12 +571,15 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
if (!sp)
return -EBUSY;
- atomic_set(&sp->ref_count, 1);
init_waitqueue_head(&sp->nvme_ls_waitq);
+ kref_init(&sp->cmd_kref);
+ spin_lock_init(&priv->cmd_lock);
+ sp->priv = (void *)priv;
priv->sp = sp;
sp->type = SRB_NVME_CMD;
sp->name = "nvme_cmd";
sp->done = qla_nvme_sp_done;
+ sp->put_fn = qla_nvme_release_fcp_cmd_kref;
sp->qpair = qpair;
sp->vha = vha;
nvme = &sp->u.iocb_cmd;
@@ -518,8 +589,10 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
if (rval != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x212d,
"qla2x00_start_nvme_mq failed = %d\n", rval);
- atomic_dec(&sp->ref_count);
wake_up(&sp->nvme_ls_waitq);
+ sp->priv = NULL;
+ priv->sp = NULL;
+ qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
return rval;
@@ -538,29 +611,16 @@ static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport)
static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
{
fc_port_t *fcport;
- struct qla_nvme_rport *qla_rport = rport->private, *trport;
+ struct qla_nvme_rport *qla_rport = rport->private;
fcport = qla_rport->fcport;
fcport->nvme_remote_port = NULL;
fcport->nvme_flag &= ~NVME_FLAG_REGISTERED;
-
- list_for_each_entry_safe(qla_rport, trport,
- &fcport->vha->nvme_rport_list, list) {
- if (qla_rport->fcport == fcport) {
- list_del(&qla_rport->list);
- break;
- }
- }
- complete(&fcport->nvme_del_done);
-
- if (!test_bit(UNLOADING, &fcport->vha->dpc_flags)) {
- INIT_WORK(&fcport->free_work, qlt_free_session_done);
- schedule_work(&fcport->free_work);
- }
-
fcport->nvme_flag &= ~NVME_FLAG_DELETING;
ql_log(ql_log_info, fcport->vha, 0x2110,
- "remoteport_delete of %p completed.\n", fcport);
+ "remoteport_delete of %p %8phN completed.\n",
+ fcport, fcport->port_name);
+ complete(&fcport->nvme_del_done);
}
static struct nvme_fc_port_template qla_nvme_fc_transport = {
@@ -573,7 +633,7 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = {
.fcp_io = qla_nvme_post_cmd,
.fcp_abort = qla_nvme_fcp_abort,
.max_hw_queues = 8,
- .max_sgl_segments = 128,
+ .max_sgl_segments = 1024,
.max_dif_sgl_segments = 64,
.dma_boundary = 0xFFFFFFFF,
.local_priv_sz = 8,
@@ -582,68 +642,25 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = {
.fcprqst_priv_sz = sizeof(struct nvme_private),
};
-#define NVME_ABORT_POLLING_PERIOD 2
-static int qla_nvme_wait_on_command(srb_t *sp)
-{
- int ret = QLA_SUCCESS;
-
- wait_event_timeout(sp->nvme_ls_waitq, (atomic_read(&sp->ref_count) > 1),
- NVME_ABORT_POLLING_PERIOD*HZ);
-
- if (atomic_read(&sp->ref_count) > 1)
- ret = QLA_FUNCTION_FAILED;
-
- return ret;
-}
-
-void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp, int res)
-{
- int rval;
-
- if (ha->flags.fw_started) {
- rval = ha->isp_ops->abort_command(sp);
- if (!rval && !qla_nvme_wait_on_command(sp))
- ql_log(ql_log_warn, NULL, 0x2112,
- "timed out waiting on sp=%p\n", sp);
- } else {
- sp->done(sp, res);
- }
-}
-
-static void qla_nvme_unregister_remote_port(struct work_struct *work)
+void qla_nvme_unregister_remote_port(struct fc_port *fcport)
{
- struct fc_port *fcport = container_of(work, struct fc_port,
- nvme_del_work);
- struct qla_nvme_rport *qla_rport, *trport;
- scsi_qla_host_t *base_vha;
+ int ret;
if (!IS_ENABLED(CONFIG_NVME_FC))
return;
ql_log(ql_log_warn, NULL, 0x2112,
- "%s: unregister remoteport on %p\n",__func__, fcport);
-
- base_vha = pci_get_drvdata(fcport->vha->hw->pdev);
- if (test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags)) {
- ql_dbg(ql_dbg_disc, fcport->vha, 0x2114,
- "%s: Notify FC-NVMe transport, set devloss=0\n",
- __func__);
-
- nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0);
- }
-
- list_for_each_entry_safe(qla_rport, trport,
- &fcport->vha->nvme_rport_list, list) {
- if (qla_rport->fcport == fcport) {
- ql_log(ql_log_info, fcport->vha, 0x2113,
- "%s: fcport=%p\n", __func__, fcport);
- init_completion(&fcport->nvme_del_done);
- nvme_fc_unregister_remoteport(
- fcport->nvme_remote_port);
- wait_for_completion(&fcport->nvme_del_done);
- break;
- }
- }
+ "%s: unregister remoteport on %p %8phN\n",
+ __func__, fcport, fcport->port_name);
+
+ nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0);
+ init_completion(&fcport->nvme_del_done);
+ ret = nvme_fc_unregister_remoteport(fcport->nvme_remote_port);
+ if (ret)
+ ql_log(ql_log_info, fcport->vha, 0x2114,
+ "%s: Failed to unregister nvme_remote_port (%d)\n",
+ __func__, ret);
+ wait_for_completion(&fcport->nvme_del_done);
}
void qla_nvme_delete(struct scsi_qla_host *vha)
diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h
index da8dad5ad693..67bb4a2a3742 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.h
+++ b/drivers/scsi/qla2xxx/qla_nvme.h
@@ -13,6 +13,7 @@
#include <linux/nvme-fc-driver.h>
#include "qla_def.h"
+#include "qla_dsd.h"
/* default dev loss time (seconds) before transport tears down ctrl */
#define NVME_FC_DEV_LOSS_TMO 30
@@ -33,10 +34,10 @@ struct nvme_private {
struct work_struct ls_work;
struct work_struct abort_work;
int comp_status;
+ spinlock_t cmd_lock;
};
struct qla_nvme_rport {
- struct list_head list;
struct fc_port *fcport;
};
@@ -64,16 +65,15 @@ struct cmd_nvme {
#define CF_WRITE_DATA BIT_0
uint16_t nvme_cmnd_dseg_len; /* Data segment length. */
- uint32_t nvme_cmnd_dseg_address[2]; /* Data segment address. */
- uint32_t nvme_rsp_dseg_address[2]; /* Data segment address. */
+ __le64 nvme_cmnd_dseg_address __packed;/* Data segment address. */
+ __le64 nvme_rsp_dseg_address __packed; /* Data segment address. */
uint32_t byte_count; /* Total byte count. */
uint8_t port_id[3]; /* PortID of destination port. */
uint8_t vp_index;
- uint32_t nvme_data_dseg_address[2]; /* Data segment address. */
- uint32_t nvme_data_dseg_len; /* Data segment length. */
+ struct dsd64 nvme_dsd;
};
#define PT_LS4_REQUEST 0x89 /* Link Service pass-through IOCB (request) */
@@ -101,10 +101,7 @@ struct pt_ls4_request {
uint32_t rsvd3;
uint32_t rx_byte_count;
uint32_t tx_byte_count;
- uint32_t dseg0_address[2];
- uint32_t dseg0_len;
- uint32_t dseg1_address[2];
- uint32_t dseg1_len;
+ struct dsd64 dsd[2];
};
#define PT_LS4_UNSOL 0x56 /* pass-up unsolicited rec FC-NVMe request */
@@ -145,7 +142,6 @@ struct pt_ls4_rx_unsol {
int qla_nvme_register_hba(struct scsi_qla_host *);
int qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *);
void qla_nvme_delete(struct scsi_qla_host *);
-void qla_nvme_abort(struct qla_hw_data *, struct srb *sp, int res);
void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *, struct pt_ls4_request *,
struct req_que *);
void qla24xx_async_gffid_sp_done(void *, int);
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index f2f54806f4da..c760ae354174 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -6,6 +6,7 @@
*/
#include "qla_def.h"
#include <linux/delay.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/pci.h>
#include <linux/ratelimit.h>
#include <linux/vmalloc.h>
@@ -608,6 +609,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
} else if (addr_in_range(addr, QLA82XX_ADDR_OCM0,
QLA82XX_ADDR_OCM0_MAX)) {
unsigned int temp1;
+
if ((addr & 0x00ff800) == 0xff800) {
ql_log(ql_log_warn, vha, 0xb004,
"%s: QM access not handled.\n", __func__);
@@ -990,6 +992,7 @@ static int
qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val)
{
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR);
qla82xx_wait_rom_busy(ha);
if (qla82xx_wait_rom_done(ha)) {
@@ -1030,6 +1033,7 @@ static int
qla82xx_flash_set_write_enable(struct qla_hw_data *ha)
{
uint32_t val;
+
qla82xx_wait_rom_busy(ha);
qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WREN);
@@ -1047,6 +1051,7 @@ static int
qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
{
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
if (qla82xx_flash_set_write_enable(ha))
return -1;
qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val);
@@ -1063,6 +1068,7 @@ static int
qla82xx_write_disable_flash(struct qla_hw_data *ha)
{
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI);
if (qla82xx_wait_rom_done(ha)) {
ql_log(ql_log_warn, vha, 0xb00f,
@@ -1435,6 +1441,7 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha)
long memaddr = BOOTLD_START;
u64 data;
u32 high, low;
+
size = (IMAGE_START - BOOTLD_START) / 8;
for (i = 0; i < size; i++) {
@@ -1757,11 +1764,14 @@ qla82xx_pci_config(scsi_qla_host_t *vha)
*
* Returns 0 on success.
*/
-void
+int
qla82xx_reset_chip(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+
ha->isp_ops->disable_intrs(ha);
+
+ return QLA_SUCCESS;
}
void qla82xx_config_rings(struct scsi_qla_host *vha)
@@ -1778,10 +1788,8 @@ void qla82xx_config_rings(struct scsi_qla_host *vha)
icb->response_q_inpointer = cpu_to_le16(0);
icb->request_q_length = cpu_to_le16(req->length);
icb->response_q_length = cpu_to_le16(rsp->length);
- icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
- icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
- icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
- icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
+ put_unaligned_le64(req->dma, &icb->request_q_address);
+ put_unaligned_le64(rsp->dma, &icb->response_q_address);
WRT_REG_DWORD(&reg->req_q_out[0], 0);
WRT_REG_DWORD(&reg->rsp_q_in[0], 0);
@@ -1992,6 +2000,7 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
uint16_t __iomem *wptr;
struct qla_hw_data *ha = vha->hw;
struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
+
wptr = (uint16_t __iomem *)&reg->mailbox_out[1];
/* Load return mailbox registers. */
@@ -2028,7 +2037,7 @@ qla82xx_intr_handler(int irq, void *dev_id)
unsigned long flags;
unsigned long iter;
uint32_t stat = 0;
- uint16_t mb[4];
+ uint16_t mb[8];
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -2112,7 +2121,7 @@ qla82xx_msix_default(int irq, void *dev_id)
unsigned long flags;
uint32_t stat = 0;
uint32_t host_int = 0;
- uint16_t mb[4];
+ uint16_t mb[8];
rsp = (struct rsp_que *) dev_id;
if (!rsp) {
@@ -2208,7 +2217,7 @@ qla82xx_poll(int irq, void *dev_id)
int status = 0;
uint32_t stat;
uint32_t host_int = 0;
- uint16_t mb[4];
+ uint16_t mb[8];
unsigned long flags;
rsp = (struct rsp_que *) dev_id;
@@ -2262,6 +2271,7 @@ void
qla82xx_enable_intrs(struct qla_hw_data *ha)
{
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
qla82xx_mbx_intr_enable(vha);
spin_lock_irq(&ha->hardware_lock);
if (IS_QLA8044(ha))
@@ -2276,6 +2286,7 @@ void
qla82xx_disable_intrs(struct qla_hw_data *ha)
{
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
qla82xx_mbx_intr_disable(vha);
spin_lock_irq(&ha->hardware_lock);
if (IS_QLA8044(ha))
@@ -2658,8 +2669,8 @@ done:
/*
* Address and length are byte address
*/
-uint8_t *
-qla82xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+void *
+qla82xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
scsi_block_requests(vha->host);
@@ -2767,15 +2778,14 @@ write_done:
}
int
-qla82xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+qla82xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
int rval;
/* Suspend HBA. */
scsi_block_requests(vha->host);
- rval = qla82xx_write_flash_data(vha, (uint32_t *)buf, offset,
- length >> 2);
+ rval = qla82xx_write_flash_data(vha, buf, offset, length >> 2);
scsi_unblock_requests(vha->host);
/* Convert return ISP82xx to generic */
@@ -4464,6 +4474,7 @@ qla82xx_beacon_on(struct scsi_qla_host *vha)
int rval;
struct qla_hw_data *ha = vha->hw;
+
qla82xx_idc_lock(ha);
rval = qla82xx_mbx_beacon_ctl(vha, 1);
@@ -4484,6 +4495,7 @@ qla82xx_beacon_off(struct scsi_qla_host *vha)
int rval;
struct qla_hw_data *ha = vha->hw;
+
qla82xx_idc_lock(ha);
rval = qla82xx_mbx_beacon_ctl(vha, 0);
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index 71a41093530e..3c7beef92c35 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -7,7 +7,7 @@
#ifndef __QLA_NX_H
#define __QLA_NX_H
-#include <linux/io-64-nonatomic-lo-hi.h>
+#include <scsi/scsi.h>
/*
* Following are the states of the Phantom. Phantom will set them and
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
index fe856b602e03..369ac04d0454 100644
--- a/drivers/scsi/qla2xxx/qla_nx2.c
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -559,12 +559,12 @@ exit_lock_error:
/*
* Address and length are byte address
*/
-uint8_t *
-qla8044_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+void *
+qla8044_read_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
scsi_block_requests(vha->host);
- if (qla8044_read_flash_data(vha, (uint8_t *)buf, offset, length / 4)
+ if (qla8044_read_flash_data(vha, buf, offset, length / 4)
!= QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0xb08d,
"%s: Failed to read from flash\n",
@@ -3007,10 +3007,9 @@ qla8044_minidump_process_rddfe(struct scsi_qla_host *vha,
uint16_t count;
uint32_t poll, mask, modify_mask;
uint32_t wait_count = 0;
-
uint32_t *data_ptr = *d_ptr;
-
struct qla8044_minidump_entry_rddfe *rddfe;
+
rddfe = (struct qla8044_minidump_entry_rddfe *) entry_hdr;
addr1 = rddfe->addr_1;
@@ -3797,7 +3796,7 @@ qla8044_write_flash_dword_mode(scsi_qla_host_t *vha, uint32_t *dwptr,
}
int
-qla8044_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+qla8044_write_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
int rval = QLA_FUNCTION_FAILED, i, burst_iter_count;
@@ -3896,7 +3895,7 @@ qla8044_intr_handler(int irq, void *dev_id)
unsigned long flags;
unsigned long iter;
uint32_t stat;
- uint16_t mb[4];
+ uint16_t mb[8];
uint32_t leg_int_ptr = 0, pf_bit;
rsp = (struct rsp_que *) dev_id;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 91f576d743fe..2e58cff9d200 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -42,7 +42,7 @@ static struct kmem_cache *ctx_cachep;
/*
* error level for logging
*/
-int ql_errlev = ql_log_all;
+uint ql_errlev = 0x8001;
static int ql2xenableclass2;
module_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR);
@@ -108,7 +108,7 @@ MODULE_PARM_DESC(ql2xshiftctondsd,
"Set to control shifting of command type processing "
"based on total number of SG elements.");
-int ql2xfdmienable=1;
+int ql2xfdmienable = 1;
module_param(ql2xfdmienable, int, S_IRUGO|S_IWUSR);
module_param_named(fdmi, ql2xfdmienable, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xfdmienable,
@@ -154,7 +154,7 @@ MODULE_PARM_DESC(ql2xenablehba_err_chk,
" 1 -- Error isolation enabled only for DIX Type 0\n"
" 2 -- Error isolation enabled for all Types\n");
-int ql2xiidmaenable=1;
+int ql2xiidmaenable = 1;
module_param(ql2xiidmaenable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xiidmaenable,
"Enables iIDMA settings "
@@ -285,14 +285,14 @@ MODULE_PARM_DESC(qla2xuseresexchforels,
"Reserve 1/2 of emergency exchanges for ELS.\n"
" 0 (default): disabled");
-int ql2xprotmask;
+static int ql2xprotmask;
module_param(ql2xprotmask, int, 0644);
MODULE_PARM_DESC(ql2xprotmask,
"Override DIF/DIX protection capabilities mask\n"
"Default is 0 which sets protection mask based on "
"capabilities reported by HBA firmware.\n");
-int ql2xprotguard;
+static int ql2xprotguard;
module_param(ql2xprotguard, int, 0644);
MODULE_PARM_DESC(ql2xprotguard, "Override choice of DIX checksum\n"
" 0 -- Let HBA firmware decide\n"
@@ -306,58 +306,12 @@ MODULE_PARM_DESC(ql2xdifbundlinginternalbuffers,
"0 (Default). Based on check.\n"
"1 Force using internal buffers\n");
-/*
- * SCSI host template entry points
- */
-static int qla2xxx_slave_configure(struct scsi_device * device);
-static int qla2xxx_slave_alloc(struct scsi_device *);
-static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
-static void qla2xxx_scan_start(struct Scsi_Host *);
-static void qla2xxx_slave_destroy(struct scsi_device *);
-static int qla2xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
-static int qla2xxx_eh_abort(struct scsi_cmnd *);
-static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
-static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
-static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
-static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
-
static void qla2x00_clear_drv_active(struct qla_hw_data *);
static void qla2x00_free_device(scsi_qla_host_t *);
static int qla2xxx_map_queues(struct Scsi_Host *shost);
static void qla2x00_destroy_deferred_work(struct qla_hw_data *);
-struct scsi_host_template qla2xxx_driver_template = {
- .module = THIS_MODULE,
- .name = QLA2XXX_DRIVER_NAME,
- .queuecommand = qla2xxx_queuecommand,
-
- .eh_timed_out = fc_eh_timed_out,
- .eh_abort_handler = qla2xxx_eh_abort,
- .eh_device_reset_handler = qla2xxx_eh_device_reset,
- .eh_target_reset_handler = qla2xxx_eh_target_reset,
- .eh_bus_reset_handler = qla2xxx_eh_bus_reset,
- .eh_host_reset_handler = qla2xxx_eh_host_reset,
-
- .slave_configure = qla2xxx_slave_configure,
-
- .slave_alloc = qla2xxx_slave_alloc,
- .slave_destroy = qla2xxx_slave_destroy,
- .scan_finished = qla2xxx_scan_finished,
- .scan_start = qla2xxx_scan_start,
- .change_queue_depth = scsi_change_queue_depth,
- .map_queues = qla2xxx_map_queues,
- .this_id = -1,
- .cmd_per_lun = 3,
- .sg_tablesize = SG_ALL,
-
- .max_sectors = 0xFFFF,
- .shost_attrs = qla2x00_host_attrs,
-
- .supported_mode = MODE_INITIATOR,
- .track_queue_depth = 1,
-};
-
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
@@ -411,6 +365,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req,
struct rsp_que *rsp)
{
struct qla_hw_data *ha = vha->hw;
+
rsp->qpair = ha->base_qpair;
rsp->req = req;
ha->base_qpair->hw = ha;
@@ -427,7 +382,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req,
qla_cpu_update(rsp->qpair, raw_smp_processor_id());
ha->base_qpair->pdev = ha->pdev;
- if (IS_QLA27XX(ha) || IS_QLA83XX(ha))
+ if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))
ha->base_qpair->reqq_start_iocbs = qla_83xx_start_iocbs;
}
@@ -435,6 +390,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
struct rsp_que *rsp)
{
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
ha->req_q_map = kcalloc(ha->max_req_queues, sizeof(struct req_que *),
GFP_KERNEL);
if (!ha->req_q_map) {
@@ -726,7 +682,7 @@ qla2x00_sp_free_dma(void *ptr)
}
if (!ctx)
- goto end;
+ return;
if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
/* List assured to be having elements */
@@ -751,12 +707,6 @@ qla2x00_sp_free_dma(void *ptr)
ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
mempool_free(ctx1, ha->ctx_mempool);
}
-
-end:
- if (sp->type != SRB_NVME_CMD && sp->type != SRB_NVME_LS) {
- CMD_SP(cmd) = NULL;
- qla2x00_rel_sp(sp);
- }
}
void
@@ -764,22 +714,20 @@ qla2x00_sp_compl(void *ptr, int res)
{
srb_t *sp = ptr;
struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+ struct completion *comp = sp->comp;
- cmd->result = res;
-
- if (atomic_read(&sp->ref_count) == 0) {
- ql_dbg(ql_dbg_io, sp->vha, 0x3015,
- "SP reference-count to ZERO -- sp=%p cmd=%p.\n",
- sp, GET_CMD_SP(sp));
- if (ql2xextended_error_logging & ql_dbg_io)
- WARN_ON(atomic_read(&sp->ref_count) == 0);
- return;
- }
- if (!atomic_dec_and_test(&sp->ref_count))
+ if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
return;
+ atomic_dec(&sp->ref_count);
+
sp->free(sp);
+ cmd->result = res;
+ CMD_SP(cmd) = NULL;
cmd->scsi_done(cmd);
+ if (comp)
+ complete(comp);
+ qla2x00_rel_sp(sp);
}
void
@@ -802,7 +750,7 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
}
if (!ctx)
- goto end;
+ return;
if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
/* List assured to be having elements */
@@ -810,25 +758,8 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
}
- if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
- struct crc_context *ctx0 = ctx;
-
- dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma);
- sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
- }
-
- if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
- struct ct6_dsd *ctx1 = ctx;
- dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
- ctx1->fcp_cmnd_dma);
- list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
- ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
- ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
- mempool_free(ctx1, ha->ctx_mempool);
- sp->flags &= ~SRB_FCP_CMND_DMA_VALID;
- }
if (sp->flags & SRB_DIF_BUNDL_DMA_VALID) {
- struct crc_context *difctx = sp->u.scmd.ctx;
+ struct crc_context *difctx = ctx;
struct dsd_dma *dif_dsd, *nxt_dsd;
list_for_each_entry_safe(dif_dsd, nxt_dsd,
@@ -863,9 +794,24 @@ qla2xxx_qpair_sp_free_dma(void *ptr)
sp->flags &= ~SRB_DIF_BUNDL_DMA_VALID;
}
-end:
- CMD_SP(cmd) = NULL;
- qla2xxx_rel_qpair_sp(sp->qpair, sp);
+ if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
+ struct ct6_dsd *ctx1 = ctx;
+
+ dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd,
+ ctx1->fcp_cmnd_dma);
+ list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list);
+ ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt;
+ ha->gbl_dsd_avail += ctx1->dsd_use_cnt;
+ mempool_free(ctx1, ha->ctx_mempool);
+ sp->flags &= ~SRB_FCP_CMND_DMA_VALID;
+ }
+
+ if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
+ struct crc_context *ctx0 = ctx;
+
+ dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma);
+ sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
+ }
}
void
@@ -873,27 +819,22 @@ qla2xxx_qpair_sp_compl(void *ptr, int res)
{
srb_t *sp = ptr;
struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+ struct completion *comp = sp->comp;
- cmd->result = res;
-
- if (atomic_read(&sp->ref_count) == 0) {
- ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3079,
- "SP reference-count to ZERO -- sp=%p cmd=%p.\n",
- sp, GET_CMD_SP(sp));
- if (ql2xextended_error_logging & ql_dbg_io)
- WARN_ON(atomic_read(&sp->ref_count) == 0);
- return;
- }
- if (!atomic_dec_and_test(&sp->ref_count))
+ if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0))
return;
+ atomic_dec(&sp->ref_count);
+
sp->free(sp);
+ cmd->result = res;
+ CMD_SP(cmd) = NULL;
cmd->scsi_done(cmd);
+ if (comp)
+ complete(comp);
+ qla2xxx_rel_qpair_sp(sp->qpair, sp);
}
-/* If we are SP1 here, we need to still take and release the host_lock as SP1
- * does not have the changes necessary to avoid taking host->host_lock.
- */
static int
qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
@@ -908,7 +849,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
uint32_t tag;
uint16_t hwq;
- if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags))) {
+ if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags)) ||
+ WARN_ON_ONCE(!rport)) {
cmd->result = DID_NO_CONNECT << 16;
goto qc24_fail_command;
}
@@ -1031,7 +973,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
srb_t *sp;
int rval;
- rval = fc_remote_port_chkready(rport);
+ rval = rport ? fc_remote_port_chkready(rport) : FC_PORTSTATE_OFFLINE;
if (rval) {
cmd->result = rval;
ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3076,
@@ -1272,7 +1214,7 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)
static int
sp_get(struct srb *sp)
{
- if (!refcount_inc_not_zero((refcount_t*)&sp->ref_count))
+ if (!refcount_inc_not_zero((refcount_t *)&sp->ref_count))
/* kref get fail */
return ENXIO;
else
@@ -1332,7 +1274,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
unsigned int id;
uint64_t lun;
unsigned long flags;
- int rval, wait = 0;
+ int rval;
struct qla_hw_data *ha = vha->hw;
struct qla_qpair *qpair;
@@ -1345,7 +1287,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
ret = fc_block_scsi_eh(cmd);
if (ret != 0)
return ret;
- ret = SUCCESS;
sp = (srb_t *) CMD_SP(cmd);
if (!sp)
@@ -1356,7 +1297,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
return SUCCESS;
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
- if (!CMD_SP(cmd)) {
+ if (sp->type != SRB_SCSI_CMD || GET_CMD_SP(sp) != cmd) {
/* there's a chance an interrupt could clear
the ptr as part of done & free */
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
@@ -1377,58 +1318,31 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
"Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n",
vha->host_no, id, lun, sp, cmd, sp->handle);
- /* Get a reference to the sp and drop the lock.*/
-
rval = ha->isp_ops->abort_command(sp);
- if (rval) {
- if (rval == QLA_FUNCTION_PARAMETER_ERROR)
- ret = SUCCESS;
- else
- ret = FAILED;
+ ql_dbg(ql_dbg_taskm, vha, 0x8003,
+ "Abort command mbx cmd=%p, rval=%x.\n", cmd, rval);
- ql_dbg(ql_dbg_taskm, vha, 0x8003,
- "Abort command mbx failed cmd=%p, rval=%x.\n", cmd, rval);
- } else {
- ql_dbg(ql_dbg_taskm, vha, 0x8004,
- "Abort command mbx success cmd=%p.\n", cmd);
- wait = 1;
- }
-
- spin_lock_irqsave(qpair->qp_lock_ptr, flags);
- /*
- * Clear the slot in the oustanding_cmds array if we can't find the
- * command to reclaim the resources.
- */
- if (rval == QLA_FUNCTION_PARAMETER_ERROR)
- vha->req->outstanding_cmds[sp->handle] = NULL;
-
- /*
- * sp->done will do ref_count--
- * sp_get() took an extra count above
- */
- sp->done(sp, DID_RESET << 16);
-
- /* Did the command return during mailbox execution? */
- if (ret == FAILED && !CMD_SP(cmd))
+ switch (rval) {
+ case QLA_SUCCESS:
+ /*
+ * The command has been aborted. That means that the firmware
+ * won't report a completion.
+ */
+ sp->done(sp, DID_ABORT << 16);
ret = SUCCESS;
-
- if (!CMD_SP(cmd))
- wait = 0;
-
- spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
-
- /* Wait for the command to be returned. */
- if (wait) {
- if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) {
- ql_log(ql_log_warn, vha, 0x8006,
- "Abort handler timed out cmd=%p.\n", cmd);
- ret = FAILED;
- }
+ break;
+ default:
+ /*
+ * Either abort failed or abort and completion raced. Let
+ * the SCSI core retry the abort in the former case.
+ */
+ ret = FAILED;
+ break;
}
ql_log(ql_log_info, vha, 0x801c,
- "Abort command issued nexus=%ld:%d:%llu -- %d %x.\n",
- vha->host_no, id, lun, wait, ret);
+ "Abort command issued nexus=%ld:%d:%llu -- %x.\n",
+ vha->host_no, id, lun, ret);
return ret;
}
@@ -1804,42 +1718,34 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res,
__releases(qp->qp_lock_ptr)
__acquires(qp->qp_lock_ptr)
{
+ DECLARE_COMPLETION_ONSTACK(comp);
scsi_qla_host_t *vha = qp->vha;
struct qla_hw_data *ha = vha->hw;
+ int rval;
- if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS) {
- if (!sp_get(sp)) {
- /* got sp */
- spin_unlock_irqrestore(qp->qp_lock_ptr, *flags);
- qla_nvme_abort(ha, sp, res);
- spin_lock_irqsave(qp->qp_lock_ptr, *flags);
- }
- } else if (GET_CMD_SP(sp) && !ha->flags.eeh_busy &&
- !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
- !qla2x00_isp_reg_stat(ha) && sp->type == SRB_SCSI_CMD) {
- /*
- * Don't abort commands in adapter during EEH recovery as it's
- * not accessible/responding.
- *
- * Get a reference to the sp and drop the lock. The reference
- * ensures this sp->done() call and not the call in
- * qla2xxx_eh_abort() ends the SCSI cmd (with result 'res').
- */
- if (!sp_get(sp)) {
- int status;
+ if (sp_get(sp))
+ return;
- spin_unlock_irqrestore(qp->qp_lock_ptr, *flags);
- status = qla2xxx_eh_abort(GET_CMD_SP(sp));
- spin_lock_irqsave(qp->qp_lock_ptr, *flags);
- /*
- * Get rid of extra reference caused
- * by early exit from qla2xxx_eh_abort
- */
- if (status == FAST_IO_FAIL)
- atomic_dec(&sp->ref_count);
+ if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS ||
+ (sp->type == SRB_SCSI_CMD && !ha->flags.eeh_busy &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !qla2x00_isp_reg_stat(ha))) {
+ sp->comp = &comp;
+ spin_unlock_irqrestore(qp->qp_lock_ptr, *flags);
+ rval = ha->isp_ops->abort_command(sp);
+
+ switch (rval) {
+ case QLA_SUCCESS:
+ sp->done(sp, res);
+ break;
+ case QLA_FUNCTION_PARAMETER_ERROR:
+ wait_for_completion(&comp);
+ break;
}
+
+ spin_lock_irqsave(qp->qp_lock_ptr, *flags);
+ sp->comp = NULL;
}
- sp->done(sp, res);
}
static void
@@ -1875,15 +1781,10 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
continue;
}
cmd = (struct qla_tgt_cmd *)sp;
- qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
+ cmd->aborted = 1;
break;
case TYPE_TGT_TMCMD:
- /*
- * Currently, only ABTS response gets on the
- * outstanding_cmds[]
- */
- ha->tgt.tgt_ops->free_mcmd(
- (struct qla_tgt_mgmt_cmd *)sp);
+ /* Skip task management functions. */
break;
default:
break;
@@ -2753,6 +2654,24 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
+ case PCI_DEVICE_ID_QLOGIC_ISP2081:
+ case PCI_DEVICE_ID_QLOGIC_ISP2089:
+ ha->isp_type |= DT_ISP2081;
+ 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_ISP2281:
+ case PCI_DEVICE_ID_QLOGIC_ISP2289:
+ ha->isp_type |= DT_ISP2281;
+ 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;
}
if (IS_QLA82XX(ha))
@@ -2760,7 +2679,8 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
else {
/* Get adapter physical port no from interrupt pin register. */
pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
- if (IS_QLA27XX(ha))
+ if (IS_QLA25XX(ha) || IS_QLA2031(ha) ||
+ IS_QLA27XX(ha) || IS_QLA28XX(ha))
ha->port_no--;
else
ha->port_no = !(ha->port_no & 1);
@@ -2857,7 +2777,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2071 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2271 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2261) {
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2261 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2081 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2281 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2089 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2289) {
bars = pci_select_bars(pdev, IORESOURCE_MEM);
mem_only = 1;
ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2877,6 +2801,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* This may fail but that's ok */
pci_enable_pcie_error_reporting(pdev);
+ /* Turn off T10-DIF when FC-NVMe is enabled */
+ if (ql2xnvmeenable)
+ ql2xenabledif = 0;
+
ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL);
if (!ha) {
ql_log_pci(ql_log_fatal, pdev, 0x0009,
@@ -2906,7 +2834,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* Set EEH reset type to fundamental if required by hba */
if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha) ||
- IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
pdev->needs_freset = 1;
ha->prev_topology = 0;
@@ -3085,6 +3013,23 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
ha->nvram_conf_off = ~0;
ha->nvram_data_off = ~0;
+ } else if (IS_QLA28XX(ha)) {
+ 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;
+ 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);
+ ha->gid_list_info_size = 8;
+ ha->optrom_size = OPTROM_SIZE_28XX;
+ ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
+ ha->isp_ops = &qla27xx_isp_ops;
+ ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_28XX;
+ ha->flash_data_off = FARX_ACCESS_FLASH_DATA_28XX;
+ ha->nvram_conf_off = ~0;
+ ha->nvram_data_off = ~0;
}
ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
@@ -3250,7 +3195,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
req->req_q_out = &ha->iobase->isp24.req_q_out;
rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in;
rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out;
- if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
req->req_q_in = &ha->mqiobase->isp25mq.req_q_in;
req->req_q_out = &ha->mqiobase->isp25mq.req_q_out;
rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in;
@@ -3395,6 +3341,7 @@ skip_dpc:
if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
int prot = 0, guard;
+
base_vha->flags.difdix_supported = 1;
ql_dbg(ql_dbg_init, base_vha, 0x00f1,
"Registering for DIF/DIX type 1 and 3 protection.\n");
@@ -3576,7 +3523,8 @@ qla2x00_shutdown(struct pci_dev *pdev)
if (ha->eft)
qla2x00_disable_eft_trace(vha);
- if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
if (ha->flags.fw_started)
qla2x00_abort_isp_cleanup(vha);
} else {
@@ -3681,7 +3629,8 @@ qla2x00_unmap_iobases(struct qla_hw_data *ha)
if (ha->mqiobase)
iounmap(ha->mqiobase);
- if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) && ha->msixbase)
+ if ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&
+ ha->msixbase)
iounmap(ha->msixbase);
}
}
@@ -3732,7 +3681,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
}
qla2x00_wait_for_hba_ready(base_vha);
- if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
if (ha->flags.fw_started)
qla2x00_abort_isp_cleanup(base_vha);
} else if (!IS_QLAFX00(ha)) {
@@ -3770,8 +3720,6 @@ qla2x00_remove_one(struct pci_dev *pdev)
qla2x00_delete_all_vps(ha, base_vha);
- qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
-
qla2x00_dfs_remove(base_vha);
qla84xx_put_chip(base_vha);
@@ -3860,11 +3808,8 @@ void qla2x00_free_fcports(struct scsi_qla_host *vha)
{
fc_port_t *fcport, *tfcport;
- list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) {
- list_del(&fcport->list);
- qla2x00_clear_loop_id(fcport);
- kfree(fcport);
- }
+ list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list)
+ qla2x00_free_fcport(fcport);
}
static inline void
@@ -3889,6 +3834,7 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
qla2xxx_wake_dpc(base_vha);
} else {
int now;
+
if (rport) {
ql_dbg(ql_dbg_disc, fcport->vha, 0x2109,
"%s %8phN. rport %p roles %x\n",
@@ -3980,6 +3926,19 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer)
}
}
+static void qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha)
+{
+ int i;
+
+ if (IS_FWI2_CAPABLE(ha))
+ return;
+
+ for (i = 0; i < SNS_FIRST_LOOP_ID; i++)
+ set_bit(i, ha->loop_id_map);
+ set_bit(MANAGEMENT_SERVER, ha->loop_id_map);
+ set_bit(BROADCAST, ha->loop_id_map);
+}
+
/*
* qla2x00_mem_alloc
* Allocates adapter memory.
@@ -4222,7 +4181,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
ha->npiv_info = NULL;
/* Get consistent memory allocated for EX-INIT-CB. */
- if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha)) {
+ if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
&ha->ex_init_cb_dma);
if (!ha->ex_init_cb)
@@ -4265,8 +4225,20 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
goto fail_sfp_data;
}
+ ha->flt = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, &ha->flt_dma,
+ GFP_KERNEL);
+ if (!ha->flt) {
+ ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
+ "Unable to allocate memory for FLT.\n");
+ goto fail_flt_buffer;
+ }
+
return 0;
+fail_flt_buffer:
+ dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE,
+ ha->sfp_data, ha->sfp_data_dma);
fail_sfp_data:
kfree(ha->loop_id_map);
fail_loop_id_map:
@@ -4602,6 +4574,9 @@ qla2x00_free_exchoffld_buffer(struct qla_hw_data *ha)
static void
qla2x00_free_fw_dump(struct qla_hw_data *ha)
{
+ struct fwdt *fwdt = ha->fwdt;
+ uint j;
+
if (ha->fce)
dma_free_coherent(&ha->pdev->dev,
FCE_SIZE, ha->fce, ha->fce_dma);
@@ -4612,8 +4587,6 @@ qla2x00_free_fw_dump(struct qla_hw_data *ha)
if (ha->fw_dump)
vfree(ha->fw_dump);
- if (ha->fw_dump_template)
- vfree(ha->fw_dump_template);
ha->fce = NULL;
ha->fce_dma = 0;
@@ -4624,8 +4597,13 @@ qla2x00_free_fw_dump(struct qla_hw_data *ha)
ha->fw_dump_reading = 0;
ha->fw_dump = NULL;
ha->fw_dump_len = 0;
- ha->fw_dump_template = NULL;
- ha->fw_dump_template_len = 0;
+
+ for (j = 0; j < 2; j++, fwdt++) {
+ if (fwdt->template)
+ vfree(fwdt->template);
+ fwdt->template = NULL;
+ fwdt->length = 0;
+ }
}
/*
@@ -4643,44 +4621,68 @@ qla2x00_mem_free(struct qla_hw_data *ha)
if (ha->mctp_dump)
dma_free_coherent(&ha->pdev->dev, MCTP_DUMP_SIZE, ha->mctp_dump,
ha->mctp_dump_dma);
+ ha->mctp_dump = NULL;
mempool_destroy(ha->srb_mempool);
+ ha->srb_mempool = NULL;
if (ha->dcbx_tlv)
dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
ha->dcbx_tlv, ha->dcbx_tlv_dma);
+ ha->dcbx_tlv = NULL;
if (ha->xgmac_data)
dma_free_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
ha->xgmac_data, ha->xgmac_data_dma);
+ ha->xgmac_data = NULL;
if (ha->sns_cmd)
dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
ha->sns_cmd, ha->sns_cmd_dma);
+ ha->sns_cmd = NULL;
+ ha->sns_cmd_dma = 0;
if (ha->ct_sns)
dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt),
ha->ct_sns, ha->ct_sns_dma);
+ ha->ct_sns = NULL;
+ ha->ct_sns_dma = 0;
if (ha->sfp_data)
dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, ha->sfp_data,
ha->sfp_data_dma);
+ ha->sfp_data = NULL;
+
+ if (ha->flt)
+ dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE,
+ ha->flt, ha->flt_dma);
+ ha->flt = NULL;
+ ha->flt_dma = 0;
if (ha->ms_iocb)
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
+ ha->ms_iocb = NULL;
+ ha->ms_iocb_dma = 0;
if (ha->ex_init_cb)
dma_pool_free(ha->s_dma_pool,
ha->ex_init_cb, ha->ex_init_cb_dma);
+ ha->ex_init_cb = NULL;
+ ha->ex_init_cb_dma = 0;
if (ha->async_pd)
dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
+ ha->async_pd = NULL;
+ ha->async_pd_dma = 0;
dma_pool_destroy(ha->s_dma_pool);
+ ha->s_dma_pool = NULL;
if (ha->gid_list)
dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
ha->gid_list, ha->gid_list_dma);
+ ha->gid_list = NULL;
+ ha->gid_list_dma = 0;
if (IS_QLA82XX(ha)) {
if (!list_empty(&ha->gbl_dsd_list)) {
@@ -4698,10 +4700,13 @@ qla2x00_mem_free(struct qla_hw_data *ha)
}
dma_pool_destroy(ha->dl_dma_pool);
+ ha->dl_dma_pool = NULL;
dma_pool_destroy(ha->fcp_cmnd_dma_pool);
+ ha->fcp_cmnd_dma_pool = NULL;
mempool_destroy(ha->ctx_mempool);
+ ha->ctx_mempool = NULL;
if (ql2xenabledif) {
struct dsd_dma *dsd, *nxt;
@@ -4728,53 +4733,26 @@ qla2x00_mem_free(struct qla_hw_data *ha)
if (ha->dif_bundl_pool)
dma_pool_destroy(ha->dif_bundl_pool);
+ ha->dif_bundl_pool = NULL;
qlt_mem_free(ha);
if (ha->init_cb)
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
ha->init_cb, ha->init_cb_dma);
+ ha->init_cb = NULL;
+ ha->init_cb_dma = 0;
vfree(ha->optrom_buffer);
+ ha->optrom_buffer = NULL;
kfree(ha->nvram);
+ ha->nvram = NULL;
kfree(ha->npiv_info);
+ ha->npiv_info = NULL;
kfree(ha->swl);
+ ha->swl = NULL;
kfree(ha->loop_id_map);
-
- ha->srb_mempool = NULL;
- ha->ctx_mempool = NULL;
- ha->sns_cmd = NULL;
- ha->sns_cmd_dma = 0;
- ha->ct_sns = NULL;
- ha->ct_sns_dma = 0;
- ha->ms_iocb = NULL;
- ha->ms_iocb_dma = 0;
- ha->init_cb = NULL;
- ha->init_cb_dma = 0;
- ha->ex_init_cb = NULL;
- ha->ex_init_cb_dma = 0;
- ha->async_pd = NULL;
- ha->async_pd_dma = 0;
ha->loop_id_map = NULL;
- ha->npiv_info = NULL;
- ha->optrom_buffer = NULL;
- ha->swl = NULL;
- ha->nvram = NULL;
- ha->mctp_dump = NULL;
- ha->dcbx_tlv = NULL;
- ha->xgmac_data = NULL;
- ha->sfp_data = NULL;
-
- ha->s_dma_pool = NULL;
- ha->dl_dma_pool = NULL;
- ha->fcp_cmnd_dma_pool = NULL;
-
- ha->gid_list = NULL;
- ha->gid_list_dma = 0;
-
- ha->tgt.atio_ring = NULL;
- ha->tgt.atio_dma = 0;
- ha->tgt.tgt_vp_map = NULL;
}
struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
@@ -4811,7 +4789,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
INIT_LIST_HEAD(&vha->plogi_ack_list);
INIT_LIST_HEAD(&vha->qp_list);
INIT_LIST_HEAD(&vha->gnl.fcports);
- INIT_LIST_HEAD(&vha->nvme_rport_list);
INIT_LIST_HEAD(&vha->gpnid_list);
INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn);
@@ -5608,6 +5585,7 @@ qla83xx_force_lock_recovery(scsi_qla_host_t *base_vha)
uint32_t idc_lck_rcvry_stage_mask = 0x3;
uint32_t idc_lck_rcvry_owner_mask = 0x3c;
struct qla_hw_data *ha = base_vha->hw;
+
ql_dbg(ql_dbg_p3p, base_vha, 0xb086,
"Trying force recovery of the IDC lock.\n");
@@ -6677,8 +6655,10 @@ qla2x00_timer(struct timer_list *t)
* FC-NVME
* see if the active AEN count has changed from what was last reported.
*/
- if (!vha->vp_idx && (atomic_read(&ha->nvme_active_aen_cnt) !=
- ha->nvme_last_rptd_aen) && ha->zio_mode == QLA_ZIO_MODE_6) {
+ if (!vha->vp_idx &&
+ (atomic_read(&ha->nvme_active_aen_cnt) != ha->nvme_last_rptd_aen) &&
+ ha->zio_mode == QLA_ZIO_MODE_6 &&
+ !ha->flags.host_shutting_down) {
ql_log(ql_log_info, vha, 0x3002,
"nvme: Sched: Set ZIO exchange threshold to %d.\n",
ha->nvme_last_rptd_aen);
@@ -6690,7 +6670,7 @@ qla2x00_timer(struct timer_list *t)
if (!vha->vp_idx &&
(atomic_read(&ha->zio_threshold) != ha->last_zio_threshold) &&
(ha->zio_mode == QLA_ZIO_MODE_6) &&
- (IS_QLA83XX(ha) || IS_QLA27XX(ha))) {
+ (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))) {
ql_log(ql_log_info, vha, 0x3002,
"Sched: Set ZIO exchange threshold to %d.\n",
ha->last_zio_threshold);
@@ -6736,7 +6716,6 @@ qla2x00_timer(struct timer_list *t)
/* Firmware interface routines. */
-#define FW_BLOBS 11
#define FW_ISP21XX 0
#define FW_ISP22XX 1
#define FW_ISP2300 2
@@ -6748,6 +6727,7 @@ qla2x00_timer(struct timer_list *t)
#define FW_ISP2031 8
#define FW_ISP8031 9
#define FW_ISP27XX 10
+#define FW_ISP28XX 11
#define FW_FILE_ISP21XX "ql2100_fw.bin"
#define FW_FILE_ISP22XX "ql2200_fw.bin"
@@ -6760,11 +6740,12 @@ qla2x00_timer(struct timer_list *t)
#define FW_FILE_ISP2031 "ql2600_fw.bin"
#define FW_FILE_ISP8031 "ql8300_fw.bin"
#define FW_FILE_ISP27XX "ql2700_fw.bin"
+#define FW_FILE_ISP28XX "ql2800_fw.bin"
static DEFINE_MUTEX(qla_fw_lock);
-static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
+static struct fw_blob qla_fw_blobs[] = {
{ .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, },
{ .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, },
{ .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
@@ -6776,6 +6757,8 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
{ .name = FW_FILE_ISP2031, },
{ .name = FW_FILE_ISP8031, },
{ .name = FW_FILE_ISP27XX, },
+ { .name = FW_FILE_ISP28XX, },
+ { .name = NULL, },
};
struct fw_blob *
@@ -6806,10 +6789,15 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
blob = &qla_fw_blobs[FW_ISP8031];
} else if (IS_QLA27XX(ha)) {
blob = &qla_fw_blobs[FW_ISP27XX];
+ } else if (IS_QLA28XX(ha)) {
+ blob = &qla_fw_blobs[FW_ISP28XX];
} else {
return NULL;
}
+ if (!blob->name)
+ return NULL;
+
mutex_lock(&qla_fw_lock);
if (blob->fw)
goto out;
@@ -6819,7 +6807,6 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
"Failed to load firmware image (%s).\n", blob->name);
blob->fw = NULL;
blob = NULL;
- goto out;
}
out:
@@ -6830,14 +6817,86 @@ out:
static void
qla2x00_release_firmware(void)
{
- int idx;
+ struct fw_blob *blob;
mutex_lock(&qla_fw_lock);
- for (idx = 0; idx < FW_BLOBS; idx++)
- release_firmware(qla_fw_blobs[idx].fw);
+ for (blob = qla_fw_blobs; blob->name; blob++)
+ release_firmware(blob->fw);
mutex_unlock(&qla_fw_lock);
}
+static void qla_pci_error_cleanup(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+ struct qla_qpair *qpair = NULL;
+ struct scsi_qla_host *vp;
+ fc_port_t *fcport;
+ int i;
+ unsigned long flags;
+
+ ha->chip_reset++;
+
+ ha->base_qpair->chip_reset = ha->chip_reset;
+ for (i = 0; i < ha->max_qpairs; i++) {
+ if (ha->queue_pair_map[i])
+ ha->queue_pair_map[i]->chip_reset =
+ ha->base_qpair->chip_reset;
+ }
+
+ /* purge MBox commands */
+ if (atomic_read(&ha->num_pend_mbx_stage3)) {
+ clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+ complete(&ha->mbx_intr_comp);
+ }
+
+ i = 0;
+
+ while (atomic_read(&ha->num_pend_mbx_stage3) ||
+ atomic_read(&ha->num_pend_mbx_stage2) ||
+ atomic_read(&ha->num_pend_mbx_stage1)) {
+ msleep(20);
+ i++;
+ if (i > 50)
+ break;
+ }
+
+ ha->flags.purge_mbox = 0;
+
+ mutex_lock(&ha->mq_lock);
+ list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem)
+ qpair->online = 0;
+ mutex_unlock(&ha->mq_lock);
+
+ qla2x00_mark_all_devices_lost(vha, 0);
+
+ spin_lock_irqsave(&ha->vport_slock, flags);
+ list_for_each_entry(vp, &ha->vp_list, list) {
+ atomic_inc(&vp->vref_count);
+ spin_unlock_irqrestore(&ha->vport_slock, flags);
+ qla2x00_mark_all_devices_lost(vp, 0);
+ spin_lock_irqsave(&ha->vport_slock, flags);
+ atomic_dec(&vp->vref_count);
+ }
+ spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+ /* Clear all async request states across all VPs. */
+ list_for_each_entry(fcport, &vha->vp_fcports, list)
+ fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
+
+ spin_lock_irqsave(&ha->vport_slock, flags);
+ list_for_each_entry(vp, &ha->vp_list, list) {
+ atomic_inc(&vp->vref_count);
+ spin_unlock_irqrestore(&ha->vport_slock, flags);
+ list_for_each_entry(fcport, &vp->vp_fcports, list)
+ fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
+ spin_lock_irqsave(&ha->vport_slock, flags);
+ atomic_dec(&vp->vref_count);
+ }
+ spin_unlock_irqrestore(&ha->vport_slock, flags);
+}
+
+
static pci_ers_result_t
qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
@@ -6863,20 +6922,7 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_frozen:
ha->flags.eeh_busy = 1;
- /* For ISP82XX complete any pending mailbox cmd */
- if (IS_QLA82XX(ha)) {
- ha->flags.isp82xx_fw_hung = 1;
- ql_dbg(ql_dbg_aer, vha, 0x9001, "Pci channel io frozen\n");
- qla82xx_clear_pending_mbx(vha);
- }
- qla2x00_free_irqs(vha);
- pci_disable_device(pdev);
- /* Return back all IOs */
- qla2x00_abort_all_cmds(vha, DID_RESET << 16);
- if (ql2xmqsupport || ql2xnvmeenable) {
- set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags);
- qla2xxx_wake_dpc(vha);
- }
+ qla_pci_error_cleanup(vha);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
ha->flags.pci_channel_io_perm_failure = 1;
@@ -6930,122 +6976,14 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
return PCI_ERS_RESULT_RECOVERED;
}
-static uint32_t
-qla82xx_error_recovery(scsi_qla_host_t *base_vha)
-{
- uint32_t rval = QLA_FUNCTION_FAILED;
- uint32_t drv_active = 0;
- struct qla_hw_data *ha = base_vha->hw;
- int fn;
- struct pci_dev *other_pdev = NULL;
-
- ql_dbg(ql_dbg_aer, base_vha, 0x9006,
- "Entered %s.\n", __func__);
-
- set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
-
- if (base_vha->flags.online) {
- /* Abort all outstanding commands,
- * so as to be requeued later */
- qla2x00_abort_isp_cleanup(base_vha);
- }
-
-
- fn = PCI_FUNC(ha->pdev->devfn);
- while (fn > 0) {
- fn--;
- ql_dbg(ql_dbg_aer, base_vha, 0x9007,
- "Finding pci device at function = 0x%x.\n", fn);
- other_pdev =
- pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
- ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
- fn));
-
- if (!other_pdev)
- continue;
- if (atomic_read(&other_pdev->enable_cnt)) {
- ql_dbg(ql_dbg_aer, base_vha, 0x9008,
- "Found PCI func available and enable at 0x%x.\n",
- fn);
- pci_dev_put(other_pdev);
- break;
- }
- pci_dev_put(other_pdev);
- }
-
- if (!fn) {
- /* Reset owner */
- ql_dbg(ql_dbg_aer, base_vha, 0x9009,
- "This devfn is reset owner = 0x%x.\n",
- ha->pdev->devfn);
- qla82xx_idc_lock(ha);
-
- qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
- QLA8XXX_DEV_INITIALIZING);
-
- qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
- QLA82XX_IDC_VERSION);
-
- drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
- ql_dbg(ql_dbg_aer, base_vha, 0x900a,
- "drv_active = 0x%x.\n", drv_active);
-
- qla82xx_idc_unlock(ha);
- /* Reset if device is not already reset
- * drv_active would be 0 if a reset has already been done
- */
- if (drv_active)
- rval = qla82xx_start_firmware(base_vha);
- else
- rval = QLA_SUCCESS;
- qla82xx_idc_lock(ha);
-
- if (rval != QLA_SUCCESS) {
- ql_log(ql_log_info, base_vha, 0x900b,
- "HW State: FAILED.\n");
- qla82xx_clear_drv_active(ha);
- qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
- QLA8XXX_DEV_FAILED);
- } else {
- ql_log(ql_log_info, base_vha, 0x900c,
- "HW State: READY.\n");
- qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
- QLA8XXX_DEV_READY);
- qla82xx_idc_unlock(ha);
- ha->flags.isp82xx_fw_hung = 0;
- rval = qla82xx_restart_isp(base_vha);
- qla82xx_idc_lock(ha);
- /* Clear driver state register */
- qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
- qla82xx_set_drv_active(base_vha);
- }
- qla82xx_idc_unlock(ha);
- } else {
- ql_dbg(ql_dbg_aer, base_vha, 0x900d,
- "This devfn is not reset owner = 0x%x.\n",
- ha->pdev->devfn);
- if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
- QLA8XXX_DEV_READY)) {
- ha->flags.isp82xx_fw_hung = 0;
- rval = qla82xx_restart_isp(base_vha);
- qla82xx_idc_lock(ha);
- qla82xx_set_drv_active(base_vha);
- qla82xx_idc_unlock(ha);
- }
- }
- clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
-
- return rval;
-}
-
static pci_ers_result_t
qla2xxx_pci_slot_reset(struct pci_dev *pdev)
{
pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
scsi_qla_host_t *base_vha = pci_get_drvdata(pdev);
struct qla_hw_data *ha = base_vha->hw;
- struct rsp_que *rsp;
- int rc, retries = 10;
+ int rc;
+ struct qla_qpair *qpair = NULL;
ql_dbg(ql_dbg_aer, base_vha, 0x9004,
"Slot Reset.\n");
@@ -7074,24 +7012,16 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
goto exit_slot_reset;
}
- rsp = ha->rsp_q_map[0];
- if (qla2x00_request_irqs(ha, rsp))
- goto exit_slot_reset;
if (ha->isp_ops->pci_config(base_vha))
goto exit_slot_reset;
- if (IS_QLA82XX(ha)) {
- if (qla82xx_error_recovery(base_vha) == QLA_SUCCESS) {
- ret = PCI_ERS_RESULT_RECOVERED;
- goto exit_slot_reset;
- } else
- goto exit_slot_reset;
- }
-
- while (ha->flags.mbox_busy && retries--)
- msleep(1000);
+ mutex_lock(&ha->mq_lock);
+ list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem)
+ qpair->online = 1;
+ mutex_unlock(&ha->mq_lock);
+ base_vha->flags.online = 1;
set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
if (ha->isp_ops->abort_isp(base_vha) == QLA_SUCCESS)
ret = PCI_ERS_RESULT_RECOVERED;
@@ -7115,13 +7045,13 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
ql_dbg(ql_dbg_aer, base_vha, 0x900f,
"pci_resume.\n");
+ ha->flags.eeh_busy = 0;
+
ret = qla2x00_wait_for_hba_online(base_vha);
if (ret != QLA_SUCCESS) {
ql_log(ql_log_fatal, base_vha, 0x9002,
"The device failed to resume I/O from slot/link_reset.\n");
}
-
- ha->flags.eeh_busy = 0;
}
static void
@@ -7179,7 +7109,7 @@ static int qla2xxx_map_queues(struct Scsi_Host *shost)
{
int rc;
scsi_qla_host_t *vha = (scsi_qla_host_t *)shost->hostdata;
- struct blk_mq_queue_map *qmap = &shost->tag_set.map[0];
+ struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
if (USER_CTRL_IRQ(vha->hw) || !vha->hw->mqiobase)
rc = blk_mq_map_queues(qmap);
@@ -7188,6 +7118,37 @@ static int qla2xxx_map_queues(struct Scsi_Host *shost)
return rc;
}
+struct scsi_host_template qla2xxx_driver_template = {
+ .module = THIS_MODULE,
+ .name = QLA2XXX_DRIVER_NAME,
+ .queuecommand = qla2xxx_queuecommand,
+
+ .eh_timed_out = fc_eh_timed_out,
+ .eh_abort_handler = qla2xxx_eh_abort,
+ .eh_device_reset_handler = qla2xxx_eh_device_reset,
+ .eh_target_reset_handler = qla2xxx_eh_target_reset,
+ .eh_bus_reset_handler = qla2xxx_eh_bus_reset,
+ .eh_host_reset_handler = qla2xxx_eh_host_reset,
+
+ .slave_configure = qla2xxx_slave_configure,
+
+ .slave_alloc = qla2xxx_slave_alloc,
+ .slave_destroy = qla2xxx_slave_destroy,
+ .scan_finished = qla2xxx_scan_finished,
+ .scan_start = qla2xxx_scan_start,
+ .change_queue_depth = scsi_change_queue_depth,
+ .map_queues = qla2xxx_map_queues,
+ .this_id = -1,
+ .cmd_per_lun = 3,
+ .sg_tablesize = SG_ALL,
+
+ .max_sectors = 0xFFFF,
+ .shost_attrs = qla2x00_host_attrs,
+
+ .supported_mode = MODE_INITIATOR,
+ .track_queue_depth = 1,
+};
+
static const struct pci_error_handlers qla2xxx_err_handler = {
.error_detected = qla2xxx_pci_error_detected,
.mmio_enabled = qla2xxx_pci_mmio_enabled,
@@ -7220,6 +7181,11 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2071) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2271) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2261) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2061) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2081) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2281) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2089) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2289) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -7249,6 +7215,30 @@ qla2x00_module_init(void)
{
int ret = 0;
+ BUILD_BUG_ON(sizeof(cmd_entry_t) != 64);
+ BUILD_BUG_ON(sizeof(cont_a64_entry_t) != 64);
+ BUILD_BUG_ON(sizeof(cont_entry_t) != 64);
+ BUILD_BUG_ON(sizeof(init_cb_t) != 96);
+ BUILD_BUG_ON(sizeof(ms_iocb_entry_t) != 64);
+ BUILD_BUG_ON(sizeof(request_t) != 64);
+ BUILD_BUG_ON(sizeof(struct access_chip_84xx) != 64);
+ BUILD_BUG_ON(sizeof(struct cmd_bidir) != 64);
+ BUILD_BUG_ON(sizeof(struct cmd_nvme) != 64);
+ BUILD_BUG_ON(sizeof(struct cmd_type_6) != 64);
+ BUILD_BUG_ON(sizeof(struct cmd_type_7) != 64);
+ BUILD_BUG_ON(sizeof(struct cmd_type_7_fx00) != 64);
+ BUILD_BUG_ON(sizeof(struct cmd_type_crc_2) != 64);
+ BUILD_BUG_ON(sizeof(struct ct_entry_24xx) != 64);
+ BUILD_BUG_ON(sizeof(struct ctio_crc2_to_fw) != 64);
+ BUILD_BUG_ON(sizeof(struct els_entry_24xx) != 64);
+ BUILD_BUG_ON(sizeof(struct fxdisc_entry_fx00) != 64);
+ BUILD_BUG_ON(sizeof(struct init_cb_24xx) != 128);
+ BUILD_BUG_ON(sizeof(struct init_cb_81xx) != 128);
+ BUILD_BUG_ON(sizeof(struct pt_ls4_request) != 64);
+ BUILD_BUG_ON(sizeof(struct sns_cmd_pkt) != 2064);
+ BUILD_BUG_ON(sizeof(struct verify_chip_entry_84xx) != 64);
+ BUILD_BUG_ON(sizeof(struct vf_evfp_entry_24xx) != 56);
+
/* Allocate cache for SRBs. */
srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
SLAB_HWCACHE_ALIGN, NULL);
@@ -7261,8 +7251,7 @@ qla2x00_module_init(void)
/* Initialize target kmem_cache and mem_pools */
ret = qlt_init();
if (ret < 0) {
- kmem_cache_destroy(srb_cachep);
- return ret;
+ goto destroy_cache;
} else if (ret > 0) {
/*
* If initiator mode is explictly disabled by qlt_init(),
@@ -7286,11 +7275,10 @@ qla2x00_module_init(void)
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
if (!qla2xxx_transport_template) {
- kmem_cache_destroy(srb_cachep);
ql_log(ql_log_fatal, NULL, 0x0002,
"fc_attach_transport failed...Failing load!.\n");
- qlt_exit();
- return -ENODEV;
+ ret = -ENODEV;
+ goto qlt_exit;
}
apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops);
@@ -7302,27 +7290,37 @@ qla2x00_module_init(void)
qla2xxx_transport_vport_template =
fc_attach_transport(&qla2xxx_transport_vport_functions);
if (!qla2xxx_transport_vport_template) {
- kmem_cache_destroy(srb_cachep);
- qlt_exit();
- fc_release_transport(qla2xxx_transport_template);
ql_log(ql_log_fatal, NULL, 0x0004,
"fc_attach_transport vport failed...Failing load!.\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto unreg_chrdev;
}
ql_log(ql_log_info, NULL, 0x0005,
"QLogic Fibre Channel HBA Driver: %s.\n",
qla2x00_version_str);
ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
- kmem_cache_destroy(srb_cachep);
- qlt_exit();
- fc_release_transport(qla2xxx_transport_template);
- fc_release_transport(qla2xxx_transport_vport_template);
ql_log(ql_log_fatal, NULL, 0x0006,
"pci_register_driver failed...ret=%d Failing load!.\n",
ret);
+ goto release_vport_transport;
}
return ret;
+
+release_vport_transport:
+ fc_release_transport(qla2xxx_transport_vport_template);
+
+unreg_chrdev:
+ if (apidev_major >= 0)
+ unregister_chrdev(apidev_major, QLA2XXX_APIDEV);
+ fc_release_transport(qla2xxx_transport_template);
+
+qlt_exit:
+ qlt_exit();
+
+destroy_cache:
+ kmem_cache_destroy(srb_cachep);
+ return ret;
}
/**
@@ -7331,14 +7329,15 @@ qla2x00_module_init(void)
static void __exit
qla2x00_module_exit(void)
{
- unregister_chrdev(apidev_major, QLA2XXX_APIDEV);
pci_unregister_driver(&qla2xxx_pci_driver);
qla2x00_release_firmware();
- kmem_cache_destroy(srb_cachep);
- qlt_exit();
kmem_cache_destroy(ctx_cachep);
- fc_release_transport(qla2xxx_transport_template);
fc_release_transport(qla2xxx_transport_vport_template);
+ if (apidev_major >= 0)
+ unregister_chrdev(apidev_major, QLA2XXX_APIDEV);
+ fc_release_transport(qla2xxx_transport_template);
+ qlt_exit();
+ kmem_cache_destroy(srb_cachep);
}
module_init(qla2x00_module_init);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 2a3055c799fb..1eb82384d933 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -429,66 +429,64 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
static inline uint32_t
flash_conf_addr(struct qla_hw_data *ha, uint32_t faddr)
{
- return ha->flash_conf_off | faddr;
+ return ha->flash_conf_off + faddr;
}
static inline uint32_t
flash_data_addr(struct qla_hw_data *ha, uint32_t faddr)
{
- return ha->flash_data_off | faddr;
+ return ha->flash_data_off + faddr;
}
static inline uint32_t
nvram_conf_addr(struct qla_hw_data *ha, uint32_t naddr)
{
- return ha->nvram_conf_off | naddr;
+ return ha->nvram_conf_off + naddr;
}
static inline uint32_t
nvram_data_addr(struct qla_hw_data *ha, uint32_t naddr)
{
- return ha->nvram_data_off | naddr;
+ return ha->nvram_data_off + naddr;
}
-static uint32_t
-qla24xx_read_flash_dword(struct qla_hw_data *ha, uint32_t addr)
+static int
+qla24xx_read_flash_dword(struct qla_hw_data *ha, uint32_t addr, uint32_t *data)
{
- int rval;
- uint32_t cnt, data;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ ulong cnt = 30000;
WRT_REG_DWORD(&reg->flash_addr, addr & ~FARX_DATA_FLAG);
- /* Wait for READ cycle to complete. */
- rval = QLA_SUCCESS;
- for (cnt = 3000;
- (RD_REG_DWORD(&reg->flash_addr) & FARX_DATA_FLAG) == 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(10);
- else
- rval = QLA_FUNCTION_TIMEOUT;
+
+ while (cnt--) {
+ if (RD_REG_DWORD(&reg->flash_addr) & FARX_DATA_FLAG) {
+ *data = RD_REG_DWORD(&reg->flash_data);
+ return QLA_SUCCESS;
+ }
+ udelay(10);
cond_resched();
}
- /* TODO: What happens if we time out? */
- data = 0xDEADDEAD;
- if (rval == QLA_SUCCESS)
- data = RD_REG_DWORD(&reg->flash_data);
-
- return data;
+ ql_log(ql_log_warn, pci_get_drvdata(ha->pdev), 0x7090,
+ "Flash read dword at %x timeout.\n", addr);
+ *data = 0xDEADDEAD;
+ return QLA_FUNCTION_TIMEOUT;
}
uint32_t *
qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
uint32_t dwords)
{
- uint32_t i;
+ ulong i;
struct qla_hw_data *ha = vha->hw;
/* Dword reads to flash. */
- for (i = 0; i < dwords; i++, faddr++)
- dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
- flash_data_addr(ha, faddr)));
+ faddr = flash_data_addr(ha, faddr);
+ for (i = 0; i < dwords; i++, faddr++, dwptr++) {
+ if (qla24xx_read_flash_dword(ha, faddr, dwptr))
+ break;
+ cpu_to_le32s(dwptr);
+ }
return dwptr;
}
@@ -496,35 +494,37 @@ qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
static int
qla24xx_write_flash_dword(struct qla_hw_data *ha, uint32_t addr, uint32_t data)
{
- int rval;
- uint32_t cnt;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ ulong cnt = 500000;
WRT_REG_DWORD(&reg->flash_data, data);
- RD_REG_DWORD(&reg->flash_data); /* PCI Posting. */
WRT_REG_DWORD(&reg->flash_addr, addr | FARX_DATA_FLAG);
- /* Wait for Write cycle to complete. */
- rval = QLA_SUCCESS;
- for (cnt = 500000; (RD_REG_DWORD(&reg->flash_addr) & FARX_DATA_FLAG) &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(10);
- else
- rval = QLA_FUNCTION_TIMEOUT;
+
+ while (cnt--) {
+ if (!(RD_REG_DWORD(&reg->flash_addr) & FARX_DATA_FLAG))
+ return QLA_SUCCESS;
+ udelay(10);
cond_resched();
}
- return rval;
+
+ ql_log(ql_log_warn, pci_get_drvdata(ha->pdev), 0x7090,
+ "Flash write dword at %x timeout.\n", addr);
+ return QLA_FUNCTION_TIMEOUT;
}
static void
qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id,
uint8_t *flash_id)
{
- uint32_t ids;
+ uint32_t faddr, ids = 0;
- ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x03ab));
- *man_id = LSB(ids);
- *flash_id = MSB(ids);
+ *man_id = *flash_id = 0;
+
+ faddr = flash_conf_addr(ha, 0x03ab);
+ if (!qla24xx_read_flash_dword(ha, faddr, &ids)) {
+ *man_id = LSB(ids);
+ *flash_id = MSB(ids);
+ }
/* Check if man_id and flash_id are valid. */
if (ids != 0xDEADDEAD && (*man_id == 0 || *flash_id == 0)) {
@@ -534,9 +534,11 @@ qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id,
* Example: ATMEL 0x00 01 45 1F
* Extract MFG and Dev ID from last two bytes.
*/
- ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x009f));
- *man_id = LSB(ids);
- *flash_id = MSB(ids);
+ faddr = flash_conf_addr(ha, 0x009f);
+ if (!qla24xx_read_flash_dword(ha, faddr, &ids)) {
+ *man_id = LSB(ids);
+ *flash_id = MSB(ids);
+ }
}
}
@@ -545,12 +547,12 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
{
const char *loc, *locations[] = { "DEF", "PCI" };
uint32_t pcihdr, pcids;
- uint32_t *dcode;
- uint8_t *buf, *bcode, last_image;
uint16_t cnt, chksum, *wptr;
- struct qla_flt_location *fltl;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
+ struct qla_flt_location *fltl = (void *)req->ring;
+ uint32_t *dcode = (void *)req->ring;
+ uint8_t *buf = (void *)req->ring, *bcode, last_image;
/*
* FLT-location structure resides after the last PCI region.
@@ -571,12 +573,13 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
} else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
*start = FA_FLASH_LAYOUT_ADDR_83;
goto end;
+ } else if (IS_QLA28XX(ha)) {
+ *start = FA_FLASH_LAYOUT_ADDR_28;
+ goto end;
}
+
/* Begin with first PCI expansion ROM header. */
- buf = (uint8_t *)req->ring;
- dcode = (uint32_t *)req->ring;
pcihdr = 0;
- last_image = 1;
do {
/* Verify PCI expansion ROM header. */
qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20);
@@ -601,22 +604,19 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
} while (!last_image);
/* Now verify FLT-location structure. */
- fltl = (struct qla_flt_location *)req->ring;
- qla24xx_read_flash_data(vha, dcode, pcihdr >> 2,
- sizeof(struct qla_flt_location) >> 2);
- if (fltl->sig[0] != 'Q' || fltl->sig[1] != 'F' ||
- fltl->sig[2] != 'L' || fltl->sig[3] != 'T')
+ qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, sizeof(*fltl) >> 2);
+ if (memcmp(fltl->sig, "QFLT", 4))
goto end;
- wptr = (uint16_t *)req->ring;
- cnt = sizeof(struct qla_flt_location) >> 1;
+ wptr = (void *)req->ring;
+ cnt = sizeof(*fltl) / sizeof(*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);
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010e,
- buf, sizeof(struct qla_flt_location));
+ fltl, sizeof(*fltl));
return QLA_FUNCTION_FAILED;
}
@@ -634,7 +634,7 @@ end:
static void
qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
{
- const char *loc, *locations[] = { "DEF", "FLT" };
+ const char *locations[] = { "DEF", "FLT" }, *loc = locations[1];
const uint32_t def_fw[] =
{ FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 };
const uint32_t def_boot[] =
@@ -664,20 +664,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
const uint32_t fcp_prio_cfg1[] =
{ FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25,
0 };
- uint32_t def;
- uint16_t *wptr;
- uint16_t cnt, chksum;
- uint32_t start;
- struct qla_flt_header *flt;
- struct qla_flt_region *region;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req = ha->req_q_map[0];
- def = 0;
- if (IS_QLA25XX(ha))
- def = 1;
- else if (IS_QLA81XX(ha))
- def = 2;
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t def = IS_QLA81XX(ha) ? 2 : IS_QLA25XX(ha) ? 1 : 0;
+ struct qla_flt_header *flt = (void *)ha->flt;
+ struct qla_flt_region *region = (void *)&flt[1];
+ uint16_t *wptr, cnt, chksum;
+ uint32_t start;
/* Assign FCP prio region since older adapters may not have FLT, or
FCP prio region in it's FLT.
@@ -686,12 +679,11 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
ha->flt_region_flt = flt_addr;
- wptr = (uint16_t *)req->ring;
- flt = (struct qla_flt_header *)req->ring;
- region = (struct qla_flt_region *)&flt[1];
- ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring,
- flt_addr << 2, OPTROM_BURST_SIZE);
- if (*wptr == cpu_to_le16(0xffff))
+ wptr = (uint16_t *)ha->flt;
+ qla24xx_read_flash_data(vha, (void *)flt, flt_addr,
+ (sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE) >> 2);
+
+ if (le16_to_cpu(*wptr) == 0xffff)
goto no_flash_data;
if (flt->version != cpu_to_le16(1)) {
ql_log(ql_log_warn, vha, 0x0047,
@@ -701,7 +693,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
goto no_flash_data;
}
- cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
+ cnt = (sizeof(*flt) + le16_to_cpu(flt->length)) / sizeof(*wptr);
for (chksum = 0; cnt--; wptr++)
chksum += le16_to_cpu(*wptr);
if (chksum) {
@@ -712,18 +704,20 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
goto no_flash_data;
}
- loc = locations[1];
- cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
+ cnt = le16_to_cpu(flt->length) / sizeof(*region);
for ( ; cnt; cnt--, region++) {
/* Store addresses as DWORD offsets. */
start = le32_to_cpu(region->start) >> 2;
ql_dbg(ql_dbg_init, vha, 0x0049,
- "FLT[%02x]: start=0x%x "
- "end=0x%x size=0x%x.\n", le32_to_cpu(region->code) & 0xff,
- start, le32_to_cpu(region->end) >> 2,
- le32_to_cpu(region->size));
-
- switch (le32_to_cpu(region->code) & 0xff) {
+ "FLT[%#x]: start=%#x end=%#x size=%#x.\n",
+ le16_to_cpu(region->code), start,
+ le32_to_cpu(region->end) >> 2,
+ le32_to_cpu(region->size) >> 2);
+ if (region->attribute)
+ ql_log(ql_dbg_init, vha, 0xffff,
+ "Region %x is secure\n", region->code);
+
+ switch (le16_to_cpu(region->code)) {
case FLT_REG_FCOE_FW:
if (!IS_QLA8031(ha))
break;
@@ -753,13 +747,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
ha->flt_region_vpd = start;
break;
case FLT_REG_VPD_2:
- if (!IS_QLA27XX(ha))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
break;
if (ha->port_no == 2)
ha->flt_region_vpd = start;
break;
case FLT_REG_VPD_3:
- if (!IS_QLA27XX(ha))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
break;
if (ha->port_no == 3)
ha->flt_region_vpd = start;
@@ -777,13 +771,13 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
ha->flt_region_nvram = start;
break;
case FLT_REG_NVRAM_2:
- if (!IS_QLA27XX(ha))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
break;
if (ha->port_no == 2)
ha->flt_region_nvram = start;
break;
case FLT_REG_NVRAM_3:
- if (!IS_QLA27XX(ha))
+ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
break;
if (ha->port_no == 3)
ha->flt_region_nvram = start;
@@ -847,36 +841,74 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
ha->flt_region_nvram = start;
break;
case FLT_REG_IMG_PRI_27XX:
- if (IS_QLA27XX(ha))
+ if (IS_QLA27XX(ha) && !IS_QLA28XX(ha))
ha->flt_region_img_status_pri = start;
break;
case FLT_REG_IMG_SEC_27XX:
- if (IS_QLA27XX(ha))
+ if (IS_QLA27XX(ha) && !IS_QLA28XX(ha))
ha->flt_region_img_status_sec = start;
break;
case FLT_REG_FW_SEC_27XX:
- if (IS_QLA27XX(ha))
+ if (IS_QLA27XX(ha) && !IS_QLA28XX(ha))
ha->flt_region_fw_sec = start;
break;
case FLT_REG_BOOTLOAD_SEC_27XX:
- if (IS_QLA27XX(ha))
+ if (IS_QLA27XX(ha) && !IS_QLA28XX(ha))
ha->flt_region_boot_sec = start;
break;
+ case FLT_REG_AUX_IMG_PRI_28XX:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ ha->flt_region_aux_img_status_pri = start;
+ break;
+ case FLT_REG_AUX_IMG_SEC_28XX:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ ha->flt_region_aux_img_status_sec = start;
+ break;
+ case FLT_REG_NVRAM_SEC_28XX_0:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ if (ha->port_no == 0)
+ ha->flt_region_nvram_sec = start;
+ break;
+ case FLT_REG_NVRAM_SEC_28XX_1:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ if (ha->port_no == 1)
+ ha->flt_region_nvram_sec = start;
+ break;
+ case FLT_REG_NVRAM_SEC_28XX_2:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ if (ha->port_no == 2)
+ ha->flt_region_nvram_sec = start;
+ break;
+ case FLT_REG_NVRAM_SEC_28XX_3:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ if (ha->port_no == 3)
+ ha->flt_region_nvram_sec = start;
+ break;
case FLT_REG_VPD_SEC_27XX_0:
- if (IS_QLA27XX(ha))
- ha->flt_region_vpd_sec = start;
+ case FLT_REG_VPD_SEC_28XX_0:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+ ha->flt_region_vpd_nvram_sec = start;
+ if (ha->port_no == 0)
+ ha->flt_region_vpd_sec = start;
+ }
break;
case FLT_REG_VPD_SEC_27XX_1:
- if (IS_QLA27XX(ha))
- ha->flt_region_vpd_sec = start;
+ case FLT_REG_VPD_SEC_28XX_1:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ if (ha->port_no == 1)
+ ha->flt_region_vpd_sec = start;
break;
case FLT_REG_VPD_SEC_27XX_2:
- if (IS_QLA27XX(ha))
- ha->flt_region_vpd_sec = start;
+ case FLT_REG_VPD_SEC_28XX_2:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ if (ha->port_no == 2)
+ ha->flt_region_vpd_sec = start;
break;
case FLT_REG_VPD_SEC_27XX_3:
- if (IS_QLA27XX(ha))
- ha->flt_region_vpd_sec = start;
+ case FLT_REG_VPD_SEC_28XX_3:
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ if (ha->port_no == 3)
+ ha->flt_region_vpd_sec = start;
break;
}
}
@@ -912,22 +944,19 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
#define FLASH_BLK_SIZE_32K 0x8000
#define FLASH_BLK_SIZE_64K 0x10000
const char *loc, *locations[] = { "MID", "FDT" };
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
uint16_t cnt, chksum;
- uint16_t *wptr;
- struct qla_fdt_layout *fdt;
+ uint16_t *wptr = (void *)req->ring;
+ struct qla_fdt_layout *fdt = (void *)req->ring;
uint8_t man_id, flash_id;
uint16_t mid = 0, fid = 0;
- struct qla_hw_data *ha = vha->hw;
- struct req_que *req = ha->req_q_map[0];
- wptr = (uint16_t *)req->ring;
- fdt = (struct qla_fdt_layout *)req->ring;
- ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring,
- ha->flt_region_fdt << 2, OPTROM_BURST_SIZE);
- if (*wptr == cpu_to_le16(0xffff))
+ qla24xx_read_flash_data(vha, (void *)fdt, ha->flt_region_fdt,
+ OPTROM_BURST_DWORDS);
+ if (le16_to_cpu(*wptr) == 0xffff)
goto no_flash_data;
- if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' ||
- fdt->sig[3] != 'D')
+ if (memcmp(fdt->sig, "QLID", 4))
goto no_flash_data;
for (cnt = 0, chksum = 0; cnt < sizeof(*fdt) >> 1; cnt++, wptr++)
@@ -938,7 +967,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
" checksum=0x%x id=%c version0x%x.\n", chksum,
fdt->sig[0], le16_to_cpu(fdt->version));
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113,
- (uint8_t *)fdt, sizeof(*fdt));
+ fdt, sizeof(*fdt));
goto no_flash_data;
}
@@ -958,7 +987,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0300 |
fdt->unprotect_sec_cmd);
ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ?
- flash_conf_addr(ha, 0x0300 | fdt->protect_sec_cmd):
+ flash_conf_addr(ha, 0x0300 | fdt->protect_sec_cmd) :
flash_conf_addr(ha, 0x0336);
}
goto done;
@@ -1019,8 +1048,7 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
return;
wptr = (uint32_t *)req->ring;
- ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring,
- QLA82XX_IDC_PARAM_ADDR , 8);
+ ha->isp_ops->read_optrom(vha, req->ring, QLA82XX_IDC_PARAM_ADDR, 8);
if (*wptr == cpu_to_le32(0xffffffff)) {
ha->fcoe_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
@@ -1045,7 +1073,8 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
- !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha))
+ !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
return QLA_SUCCESS;
ret = qla2xxx_find_flt_start(vha, &flt_addr);
@@ -1081,8 +1110,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
if (IS_QLA8044(ha))
return;
- ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr,
- ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header));
+ ha->isp_ops->read_optrom(vha, &hdr, ha->flt_region_npiv_conf << 2,
+ sizeof(struct qla_npiv_header));
if (hdr.version == cpu_to_le16(0xffff))
return;
if (hdr.version != cpu_to_le16(1)) {
@@ -1101,8 +1130,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
return;
}
- ha->isp_ops->read_optrom(vha, (uint8_t *)data,
- ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE);
+ ha->isp_ops->read_optrom(vha, data, ha->flt_region_npiv_conf << 2,
+ NPIV_CONFIG_SIZE);
cnt = (sizeof(hdr) + le16_to_cpu(hdr.entries) * sizeof(*entry)) >> 1;
for (wptr = data, chksum = 0; cnt--; wptr++)
@@ -1139,10 +1168,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
vid.node_name = wwn_to_u64(entry->node_name);
ql_dbg(ql_dbg_user, vha, 0x7093,
- "NPIV[%02x]: wwpn=%llx "
- "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt,
- (unsigned long long)vid.port_name,
- (unsigned long long)vid.node_name,
+ "NPIV[%02x]: wwpn=%llx wwnn=%llx vf_id=%#x Q_qos=%#x F_qos=%#x.\n",
+ cnt, vid.port_name, vid.node_name,
le16_to_cpu(entry->vf_id),
entry->q_qos, entry->f_qos);
@@ -1150,10 +1177,8 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
vport = fc_vport_create(vha->host, 0, &vid);
if (!vport)
ql_log(ql_log_warn, vha, 0x7094,
- "NPIV-Config Failed to create vport [%02x]: "
- "wwpn=%llx wwnn=%llx.\n", cnt,
- (unsigned long long)vid.port_name,
- (unsigned long long)vid.node_name);
+ "NPIV-Config Failed to create vport [%02x]: wwpn=%llx wwnn=%llx.\n",
+ cnt, vid.port_name, vid.node_name);
}
}
done:
@@ -1188,9 +1213,10 @@ done:
static int
qla24xx_protect_flash(scsi_qla_host_t *vha)
{
- uint32_t cnt;
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ ulong cnt = 300;
+ uint32_t faddr, dword;
if (ha->flags.fac_supported)
return qla81xx_fac_do_write_enable(vha, 0);
@@ -1199,11 +1225,14 @@ qla24xx_protect_flash(scsi_qla_host_t *vha)
goto skip_wrt_protect;
/* Enable flash write-protection and wait for completion. */
- qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101),
- ha->fdt_wrt_disable);
- for (cnt = 300; cnt &&
- qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x005)) & BIT_0;
- cnt--) {
+ faddr = flash_conf_addr(ha, 0x101);
+ qla24xx_write_flash_dword(ha, faddr, ha->fdt_wrt_disable);
+ faddr = flash_conf_addr(ha, 0x5);
+ while (cnt--) {
+ if (!qla24xx_read_flash_dword(ha, faddr, &dword)) {
+ if (!(dword & BIT_0))
+ break;
+ }
udelay(10);
}
@@ -1211,7 +1240,6 @@ skip_wrt_protect:
/* Disable flash write. */
WRT_REG_DWORD(&reg->ctrl_status,
RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
- RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
return QLA_SUCCESS;
}
@@ -1239,107 +1267,103 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
uint32_t dwords)
{
int ret;
- uint32_t liter;
- uint32_t sec_mask, rest_addr;
- uint32_t fdata;
+ ulong liter;
+ ulong dburst = OPTROM_BURST_DWORDS; /* burst size in dwords */
+ uint32_t sec_mask, rest_addr, fdata;
dma_addr_t optrom_dma;
void *optrom = NULL;
struct qla_hw_data *ha = vha->hw;
- /* Prepare burst-capable write on supported ISPs. */
- if ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
- IS_QLA27XX(ha)) &&
- !(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) {
- optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
- &optrom_dma, GFP_KERNEL);
- if (!optrom) {
- ql_log(ql_log_warn, vha, 0x7095,
- "Unable to allocate "
- "memory for optrom burst write (%x KB).\n",
- OPTROM_BURST_SIZE / 1024);
- }
- }
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
+ !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
+ goto next;
- rest_addr = (ha->fdt_block_size >> 2) - 1;
- sec_mask = ~rest_addr;
+ /* Allocate dma buffer for burst write */
+ optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+ &optrom_dma, GFP_KERNEL);
+ if (!optrom) {
+ ql_log(ql_log_warn, vha, 0x7095,
+ "Failed allocate burst (%x bytes)\n", OPTROM_BURST_SIZE);
+ }
+next:
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
+ "Unprotect flash...\n");
ret = qla24xx_unprotect_flash(vha);
- if (ret != QLA_SUCCESS) {
+ if (ret) {
ql_log(ql_log_warn, vha, 0x7096,
- "Unable to unprotect flash for update.\n");
+ "Failed to unprotect flash.\n");
goto done;
}
+ rest_addr = (ha->fdt_block_size >> 2) - 1;
+ sec_mask = ~rest_addr;
for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
fdata = (faddr & sec_mask) << 2;
/* Are we at the beginning of a sector? */
- if ((faddr & rest_addr) == 0) {
- /* Do sector unprotect. */
- if (ha->fdt_unprotect_sec_cmd)
- qla24xx_write_flash_dword(ha,
- ha->fdt_unprotect_sec_cmd,
- (fdata & 0xff00) | ((fdata << 16) &
- 0xff0000) | ((fdata >> 16) & 0xff));
+ if (!(faddr & rest_addr)) {
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
+ "Erase sector %#x...\n", faddr);
+
ret = qla24xx_erase_sector(vha, fdata);
- if (ret != QLA_SUCCESS) {
+ if (ret) {
ql_dbg(ql_dbg_user, vha, 0x7007,
- "Unable to erase erase sector: address=%x.\n",
- faddr);
+ "Failed to erase sector %x.\n", faddr);
break;
}
}
- /* Go with burst-write. */
- if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) {
- /* Copy data to DMA'ble buffer. */
- memcpy(optrom, dwptr, OPTROM_BURST_SIZE);
+ if (optrom) {
+ /* If smaller than a burst remaining */
+ if (dwords - liter < dburst)
+ dburst = dwords - liter;
+ /* Copy to dma buffer */
+ memcpy(optrom, dwptr, dburst << 2);
+
+ /* Burst write */
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
+ "Write burst (%#lx dwords)...\n", dburst);
ret = qla2x00_load_ram(vha, optrom_dma,
- flash_data_addr(ha, faddr),
- OPTROM_BURST_DWORDS);
- if (ret != QLA_SUCCESS) {
- ql_log(ql_log_warn, vha, 0x7097,
- "Unable to burst-write optrom segment "
- "(%x/%x/%llx).\n", ret,
- flash_data_addr(ha, faddr),
- (unsigned long long)optrom_dma);
- ql_log(ql_log_warn, vha, 0x7098,
- "Reverting to slow-write.\n");
-
- dma_free_coherent(&ha->pdev->dev,
- OPTROM_BURST_SIZE, optrom, optrom_dma);
- optrom = NULL;
- } else {
- liter += OPTROM_BURST_DWORDS - 1;
- faddr += OPTROM_BURST_DWORDS - 1;
- dwptr += OPTROM_BURST_DWORDS - 1;
+ flash_data_addr(ha, faddr), dburst);
+ if (!ret) {
+ liter += dburst - 1;
+ faddr += dburst - 1;
+ dwptr += dburst - 1;
continue;
}
+
+ ql_log(ql_log_warn, vha, 0x7097,
+ "Failed burst-write at %x (%p/%#llx)....\n",
+ flash_data_addr(ha, faddr), optrom,
+ (u64)optrom_dma);
+
+ dma_free_coherent(&ha->pdev->dev,
+ OPTROM_BURST_SIZE, optrom, optrom_dma);
+ optrom = NULL;
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
+ break;
+ ql_log(ql_log_warn, vha, 0x7098,
+ "Reverting to slow write...\n");
}
+ /* Slow write */
ret = qla24xx_write_flash_dword(ha,
flash_data_addr(ha, faddr), cpu_to_le32(*dwptr));
- if (ret != QLA_SUCCESS) {
+ if (ret) {
ql_dbg(ql_dbg_user, vha, 0x7006,
- "Unable to program flash address=%x data=%x.\n",
- faddr, *dwptr);
+ "Failed slopw write %x (%x)\n", faddr, *dwptr);
break;
}
-
- /* Do sector protect. */
- if (ha->fdt_unprotect_sec_cmd &&
- ((faddr & rest_addr) == rest_addr))
- qla24xx_write_flash_dword(ha,
- ha->fdt_protect_sec_cmd,
- (fdata & 0xff00) | ((fdata << 16) &
- 0xff0000) | ((fdata >> 16) & 0xff));
}
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
+ "Protect flash...\n");
ret = qla24xx_protect_flash(vha);
- if (ret != QLA_SUCCESS)
+ if (ret)
ql_log(ql_log_warn, vha, 0x7099,
- "Unable to protect flash after update.\n");
+ "Failed to protect flash\n");
done:
if (optrom)
dma_free_coherent(&ha->pdev->dev,
@@ -1349,7 +1373,7 @@ done:
}
uint8_t *
-qla2x00_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
+qla2x00_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
uint32_t bytes)
{
uint32_t i;
@@ -1368,27 +1392,30 @@ qla2x00_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
}
uint8_t *
-qla24xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
+qla24xx_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
uint32_t bytes)
{
- uint32_t i;
- uint32_t *dwptr;
struct qla_hw_data *ha = vha->hw;
+ uint32_t *dwptr = buf;
+ uint32_t i;
if (IS_P3P_TYPE(ha))
return buf;
/* Dword reads to flash. */
- dwptr = (uint32_t *)buf;
- for (i = 0; i < bytes >> 2; i++, naddr++)
- dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
- nvram_data_addr(ha, naddr)));
+ naddr = nvram_data_addr(ha, naddr);
+ bytes >>= 2;
+ for (i = 0; i < bytes; i++, naddr++, dwptr++) {
+ if (qla24xx_read_flash_dword(ha, naddr, dwptr))
+ break;
+ cpu_to_le32s(dwptr);
+ }
return buf;
}
int
-qla2x00_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
+qla2x00_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
uint32_t bytes)
{
int ret, stat;
@@ -1422,14 +1449,14 @@ qla2x00_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
}
int
-qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
+qla24xx_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
uint32_t bytes)
{
- int ret;
- uint32_t i;
- uint32_t *dwptr;
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ uint32_t *dwptr = buf;
+ uint32_t i;
+ int ret;
ret = QLA_SUCCESS;
@@ -1446,11 +1473,10 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0);
/* Dword writes to flash. */
- dwptr = (uint32_t *)buf;
- for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) {
- ret = qla24xx_write_flash_dword(ha,
- nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr));
- if (ret != QLA_SUCCESS) {
+ naddr = nvram_data_addr(ha, naddr);
+ bytes >>= 2;
+ for (i = 0; i < bytes; i++, naddr++, dwptr++) {
+ if (qla24xx_write_flash_dword(ha, naddr, cpu_to_le32(*dwptr))) {
ql_dbg(ql_dbg_user, vha, 0x709a,
"Unable to program nvram address=%x data=%x.\n",
naddr, *dwptr);
@@ -1470,31 +1496,34 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
}
uint8_t *
-qla25xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
+qla25xx_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
uint32_t bytes)
{
- uint32_t i;
- uint32_t *dwptr;
struct qla_hw_data *ha = vha->hw;
+ uint32_t *dwptr = buf;
+ uint32_t i;
/* Dword reads to flash. */
- dwptr = (uint32_t *)buf;
- for (i = 0; i < bytes >> 2; i++, naddr++)
- dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
- flash_data_addr(ha, ha->flt_region_vpd_nvram | naddr)));
+ naddr = flash_data_addr(ha, ha->flt_region_vpd_nvram | naddr);
+ bytes >>= 2;
+ for (i = 0; i < bytes; i++, naddr++, dwptr++) {
+ if (qla24xx_read_flash_dword(ha, naddr, dwptr))
+ break;
+
+ cpu_to_le32s(dwptr);
+ }
return buf;
}
+#define RMW_BUFFER_SIZE (64 * 1024)
int
-qla25xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
+qla25xx_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
uint32_t bytes)
{
struct qla_hw_data *ha = vha->hw;
-#define RMW_BUFFER_SIZE (64 * 1024)
- uint8_t *dbuf;
+ uint8_t *dbuf = vmalloc(RMW_BUFFER_SIZE);
- dbuf = vmalloc(RMW_BUFFER_SIZE);
if (!dbuf)
return QLA_MEMORY_ALLOC_FAILED;
ha->isp_ops->read_optrom(vha, dbuf, ha->flt_region_vpd_nvram << 2,
@@ -1728,7 +1757,7 @@ qla83xx_select_led_port(struct qla_hw_data *ha)
{
uint32_t led_select_value = 0;
- if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
goto out;
if (ha->port_no == 0)
@@ -1749,13 +1778,14 @@ qla83xx_beacon_blink(struct scsi_qla_host *vha)
uint16_t orig_led_cfg[6];
uint32_t led_10_value, led_43_value;
- if (!IS_QLA83XX(ha) && !IS_QLA81XX(ha) && !IS_QLA27XX(ha))
+ if (!IS_QLA83XX(ha) && !IS_QLA81XX(ha) && !IS_QLA27XX(ha) &&
+ !IS_QLA28XX(ha))
return;
if (!ha->beacon_blink_led)
return;
- if (IS_QLA27XX(ha)) {
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
qla2x00_write_ram_word(vha, 0x1003, 0x40000230);
qla2x00_write_ram_word(vha, 0x1004, 0x40000230);
} else if (IS_QLA2031(ha)) {
@@ -1845,7 +1875,7 @@ qla24xx_beacon_on(struct scsi_qla_host *vha)
return QLA_FUNCTION_FAILED;
}
- if (IS_QLA2031(ha) || IS_QLA27XX(ha))
+ if (IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
goto skip_gpio;
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1885,7 +1915,7 @@ qla24xx_beacon_off(struct scsi_qla_host *vha)
ha->beacon_blink_led = 0;
- if (IS_QLA2031(ha) || IS_QLA27XX(ha))
+ if (IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
goto set_fw_options;
if (IS_QLA8031(ha) || IS_QLA81XX(ha))
@@ -2314,8 +2344,8 @@ qla2x00_resume_hba(struct scsi_qla_host *vha)
scsi_unblock_requests(vha->host);
}
-uint8_t *
-qla2x00_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+void *
+qla2x00_read_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
uint32_t addr, midpoint;
@@ -2349,12 +2379,12 @@ qla2x00_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
}
int
-qla2x00_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+qla2x00_write_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
int rval;
- uint8_t man_id, flash_id, sec_number, data;
+ uint8_t man_id, flash_id, sec_number, *data;
uint16_t wd;
uint32_t addr, liter, sec_mask, rest_addr;
struct qla_hw_data *ha = vha->hw;
@@ -2483,7 +2513,7 @@ update_flash:
for (addr = offset, liter = 0; liter < length; liter++,
addr++) {
- data = buf[liter];
+ data = buf + liter;
/* Are we at the beginning of a sector? */
if ((addr & rest_addr) == 0) {
if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
@@ -2551,7 +2581,7 @@ update_flash:
}
}
- if (qla2x00_program_flash_address(ha, addr, data,
+ if (qla2x00_program_flash_address(ha, addr, *data,
man_id, flash_id)) {
rval = QLA_FUNCTION_FAILED;
break;
@@ -2567,8 +2597,8 @@ update_flash:
return rval;
}
-uint8_t *
-qla24xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+void *
+qla24xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
struct qla_hw_data *ha = vha->hw;
@@ -2578,7 +2608,7 @@ qla24xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with read. */
- qla24xx_read_flash_data(vha, (uint32_t *)buf, offset >> 2, length >> 2);
+ qla24xx_read_flash_data(vha, (void *)buf, offset >> 2, length >> 2);
/* Resume HBA. */
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
@@ -2587,8 +2617,340 @@ qla24xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
return buf;
}
+static int
+qla28xx_extract_sfub_and_verify(struct scsi_qla_host *vha, uint32_t *buf,
+ uint32_t len, uint32_t buf_size_without_sfub, uint8_t *sfub_buf)
+{
+ uint32_t *p, check_sum = 0;
+ int i;
+
+ p = buf + buf_size_without_sfub;
+
+ /* Extract SFUB from end of file */
+ memcpy(sfub_buf, (uint8_t *)p,
+ sizeof(struct secure_flash_update_block));
+
+ for (i = 0; i < (sizeof(struct secure_flash_update_block) >> 2); i++)
+ check_sum += p[i];
+
+ check_sum = (~check_sum) + 1;
+
+ if (check_sum != p[i]) {
+ ql_log(ql_log_warn, vha, 0x7097,
+ "SFUB checksum failed, 0x%x, 0x%x\n",
+ check_sum, p[i]);
+ return QLA_COMMAND_ERROR;
+ }
+
+ return QLA_SUCCESS;
+}
+
+static int
+qla28xx_get_flash_region(struct scsi_qla_host *vha, uint32_t start,
+ struct qla_flt_region *region)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct qla_flt_header *flt;
+ struct qla_flt_region *flt_reg;
+ uint16_t cnt;
+ int rval = QLA_FUNCTION_FAILED;
+
+ if (!ha->flt)
+ return QLA_FUNCTION_FAILED;
+
+ flt = (struct qla_flt_header *)ha->flt;
+ flt_reg = (struct qla_flt_region *)&flt[1];
+ cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
+
+ for (; cnt; cnt--, flt_reg++) {
+ if (flt_reg->start == start) {
+ memcpy((uint8_t *)region, flt_reg,
+ sizeof(struct qla_flt_region));
+ rval = QLA_SUCCESS;
+ break;
+ }
+ }
+
+ return rval;
+}
+
+static int
+qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
+ uint32_t dwords)
+{
+ struct qla_hw_data *ha = vha->hw;
+ ulong liter;
+ ulong dburst = OPTROM_BURST_DWORDS; /* burst size in dwords */
+ uint32_t sec_mask, rest_addr, fdata;
+ void *optrom = NULL;
+ dma_addr_t optrom_dma;
+ int rval;
+ struct secure_flash_update_block *sfub;
+ dma_addr_t sfub_dma;
+ uint32_t offset = faddr << 2;
+ uint32_t buf_size_without_sfub = 0;
+ struct qla_flt_region region;
+ bool reset_to_rom = false;
+ uint32_t risc_size, risc_attr = 0;
+ uint32_t *fw_array = NULL;
+
+ /* Retrieve region info - must be a start address passed in */
+ rval = qla28xx_get_flash_region(vha, offset, &region);
+
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Invalid address %x - not a region start address\n",
+ offset);
+ goto done;
+ }
+
+ /* Allocate dma buffer for burst write */
+ optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+ &optrom_dma, GFP_KERNEL);
+ if (!optrom) {
+ ql_log(ql_log_warn, vha, 0x7095,
+ "Failed allocate burst (%x bytes)\n", OPTROM_BURST_SIZE);
+ rval = QLA_COMMAND_ERROR;
+ goto done;
+ }
+
+ /*
+ * If adapter supports secure flash and region is secure
+ * extract secure flash update block (SFUB) and verify
+ */
+ if (ha->flags.secure_adapter && region.attribute) {
+
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
+ "Region %x is secure\n", region.code);
+
+ if (region.code == FLT_REG_FW ||
+ region.code == FLT_REG_FW_SEC_27XX) {
+ fw_array = dwptr;
+
+ /* 1st fw array */
+ risc_size = be32_to_cpu(fw_array[3]);
+ risc_attr = be32_to_cpu(fw_array[9]);
+
+ buf_size_without_sfub = risc_size;
+ fw_array += risc_size;
+
+ /* 2nd fw array */
+ risc_size = be32_to_cpu(fw_array[3]);
+
+ buf_size_without_sfub += risc_size;
+ fw_array += risc_size;
+
+ /* 1st dump template */
+ risc_size = be32_to_cpu(fw_array[2]);
+
+ /* skip header and ignore checksum */
+ buf_size_without_sfub += risc_size;
+ fw_array += risc_size;
+
+ if (risc_attr & BIT_9) {
+ /* 2nd dump template */
+ risc_size = be32_to_cpu(fw_array[2]);
+
+ /* skip header and ignore checksum */
+ buf_size_without_sfub += risc_size;
+ fw_array += risc_size;
+ }
+ } else {
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
+ "Secure region %x not supported\n",
+ region.code);
+ rval = QLA_COMMAND_ERROR;
+ goto done;
+ }
+
+ sfub = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct secure_flash_update_block), &sfub_dma,
+ GFP_KERNEL);
+ if (!sfub) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to allocate memory for SFUB\n");
+ rval = QLA_COMMAND_ERROR;
+ goto done;
+ }
+
+ rval = qla28xx_extract_sfub_and_verify(vha, dwptr, dwords,
+ buf_size_without_sfub, (uint8_t *)sfub);
+
+ if (rval != QLA_SUCCESS)
+ goto done;
+
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
+ "SFUB extract and verify successful\n");
+ }
+
+ rest_addr = (ha->fdt_block_size >> 2) - 1;
+ sec_mask = ~rest_addr;
+
+ /* Lock semaphore */
+ rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to lock flash semaphore.");
+ goto done;
+ }
+
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
+ "Unprotect flash...\n");
+ rval = qla24xx_unprotect_flash(vha);
+ if (rval) {
+ qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
+ ql_log(ql_log_warn, vha, 0x7096, "Failed unprotect flash\n");
+ goto done;
+ }
+
+ for (liter = 0; liter < dwords; liter++, faddr++) {
+ fdata = (faddr & sec_mask) << 2;
+
+ /* If start of sector */
+ if (!(faddr & rest_addr)) {
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
+ "Erase sector %#x...\n", faddr);
+ rval = qla24xx_erase_sector(vha, fdata);
+ if (rval) {
+ ql_dbg(ql_dbg_user, vha, 0x7007,
+ "Failed erase sector %#x\n", faddr);
+ goto write_protect;
+ }
+ }
+ }
+
+ if (ha->flags.secure_adapter) {
+ /*
+ * If adapter supports secure flash but FW doesn't,
+ * disable write protect, release semaphore and reset
+ * chip to execute ROM code in order to update region securely
+ */
+ if (!ha->flags.secure_fw) {
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
+ "Disable Write and Release Semaphore.");
+ rval = qla24xx_protect_flash(vha);
+ if (rval != QLA_SUCCESS) {
+ qla81xx_fac_semaphore_access(vha,
+ FAC_SEMAPHORE_UNLOCK);
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to protect flash.");
+ goto done;
+ }
+
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
+ "Reset chip to ROM.");
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ set_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ rval = qla2x00_wait_for_chip_reset(vha);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to reset to ROM code.");
+ goto done;
+ }
+ reset_to_rom = true;
+ ha->flags.fac_supported = 0;
+
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
+ "Lock Semaphore");
+ rval = qla2xxx_write_remote_register(vha,
+ FLASH_SEMAPHORE_REGISTER_ADDR, 0x00020002);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to lock flash semaphore.");
+ goto done;
+ }
+
+ /* Unprotect flash */
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
+ "Enable Write.");
+ rval = qla2x00_write_ram_word(vha, 0x7ffd0101, 0);
+ if (rval) {
+ ql_log(ql_log_warn, vha, 0x7096,
+ "Failed unprotect flash\n");
+ goto done;
+ }
+ }
+
+ /* If region is secure, send Secure Flash MB Cmd */
+ if (region.attribute && buf_size_without_sfub) {
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
+ "Sending Secure Flash MB Cmd\n");
+ rval = qla28xx_secure_flash_update(vha, 0, region.code,
+ buf_size_without_sfub, sfub_dma,
+ sizeof(struct secure_flash_update_block));
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Secure Flash MB Cmd failed %x.", rval);
+ goto write_protect;
+ }
+ }
+
+ }
+
+ /* re-init flash offset */
+ faddr = offset >> 2;
+
+ for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
+ fdata = (faddr & sec_mask) << 2;
+
+ /* If smaller than a burst remaining */
+ if (dwords - liter < dburst)
+ dburst = dwords - liter;
+
+ /* Copy to dma buffer */
+ memcpy(optrom, dwptr, dburst << 2);
+
+ /* Burst write */
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
+ "Write burst (%#lx dwords)...\n", dburst);
+ rval = qla2x00_load_ram(vha, optrom_dma,
+ flash_data_addr(ha, faddr), dburst);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x7097,
+ "Failed burst write at %x (%p/%#llx)...\n",
+ flash_data_addr(ha, faddr), optrom,
+ (u64)optrom_dma);
+ break;
+ }
+
+ liter += dburst - 1;
+ faddr += dburst - 1;
+ dwptr += dburst - 1;
+ continue;
+ }
+
+write_protect:
+ ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
+ "Protect flash...\n");
+ rval = qla24xx_protect_flash(vha);
+ if (rval) {
+ qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
+ ql_log(ql_log_warn, vha, 0x7099,
+ "Failed protect flash\n");
+ }
+
+ if (reset_to_rom == true) {
+ /* Schedule DPC to restart the RISC */
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+
+ rval = qla2x00_wait_for_hba_online(vha);
+ if (rval != QLA_SUCCESS)
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Adapter did not come out of reset\n");
+ }
+
+done:
+ if (optrom)
+ dma_free_coherent(&ha->pdev->dev,
+ OPTROM_BURST_SIZE, optrom, optrom_dma);
+
+ return rval;
+}
+
int
-qla24xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+qla24xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
int rval;
@@ -2599,8 +2961,12 @@ qla24xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with write. */
- rval = qla24xx_write_flash_data(vha, (uint32_t *)buf, offset >> 2,
- length >> 2);
+ if (IS_QLA28XX(ha))
+ rval = qla28xx_write_flash_data(vha, (uint32_t *)buf,
+ offset >> 2, length >> 2);
+ else
+ rval = qla24xx_write_flash_data(vha, (uint32_t *)buf,
+ offset >> 2, length >> 2);
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
scsi_unblock_requests(vha->host);
@@ -2608,8 +2974,8 @@ qla24xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
return rval;
}
-uint8_t *
-qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+void *
+qla25xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
uint32_t offset, uint32_t length)
{
int rval;
@@ -2620,7 +2986,7 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
struct qla_hw_data *ha = vha->hw;
if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
- IS_QLA27XX(ha))
+ IS_QLA27XX(ha) || IS_QLA28XX(ha))
goto try_fast;
if (offset & 0xfff)
goto slow_read;
@@ -2628,6 +2994,8 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
goto slow_read;
try_fast:
+ if (offset & 0xff)
+ goto slow_read;
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
&optrom_dma, GFP_KERNEL);
if (!optrom) {
@@ -2874,7 +3242,7 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
"Dumping fw "
"ver from flash:.\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010b,
- (uint8_t *)dbyte, 8);
+ dbyte, 32);
if ((dcode[0] == 0xffff && dcode[1] == 0xffff &&
dcode[2] == 0xffff && dcode[3] == 0xffff) ||
@@ -2905,8 +3273,8 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
{
int ret = QLA_SUCCESS;
uint32_t pcihdr, pcids;
- uint32_t *dcode;
- uint8_t *bcode;
+ uint32_t *dcode = mbuf;
+ uint8_t *bcode = mbuf;
uint8_t code_type, last_image;
struct qla_hw_data *ha = vha->hw;
@@ -2918,17 +3286,14 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
- dcode = mbuf;
-
/* Begin with first PCI expansion ROM header. */
pcihdr = ha->flt_region_boot << 2;
last_image = 1;
do {
/* Verify PCI expansion ROM header. */
- ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, pcihdr,
- 0x20 * 4);
+ ha->isp_ops->read_optrom(vha, dcode, pcihdr, 0x20 * 4);
bcode = mbuf + (pcihdr % 4);
- if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {
+ if (memcmp(bcode, "\x55\xaa", 2)) {
/* No signature */
ql_log(ql_log_fatal, vha, 0x0154,
"No matching ROM signature.\n");
@@ -2939,13 +3304,11 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
/* Locate PCI data structure. */
pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
- ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, pcids,
- 0x20 * 4);
+ ha->isp_ops->read_optrom(vha, dcode, pcids, 0x20 * 4);
bcode = mbuf + (pcihdr % 4);
/* Validate signature of PCI data structure. */
- if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
- bcode[0x2] != 'I' || bcode[0x3] != 'R') {
+ if (memcmp(bcode, "PCIR", 4)) {
/* Incorrect header. */
ql_log(ql_log_fatal, vha, 0x0155,
"PCI data struct not found pcir_adr=%x.\n", pcids);
@@ -2996,8 +3359,7 @@ qla82xx_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;
- ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, ha->flt_region_fw << 2,
- 0x20);
+ ha->isp_ops->read_optrom(vha, dcode, ha->flt_region_fw << 2, 0x20);
bcode = mbuf + (pcihdr % 4);
/* Validate signature of PCI data structure. */
@@ -3019,15 +3381,14 @@ int
qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
{
int ret = QLA_SUCCESS;
- uint32_t pcihdr, pcids;
- uint32_t *dcode;
- uint8_t *bcode;
+ uint32_t pcihdr = 0, pcids = 0;
+ uint32_t *dcode = mbuf;
+ uint8_t *bcode = mbuf;
uint8_t code_type, last_image;
int i;
struct qla_hw_data *ha = vha->hw;
uint32_t faddr = 0;
-
- pcihdr = pcids = 0;
+ struct active_regions active_regions = { };
if (IS_P3P_TYPE(ha))
return ret;
@@ -3040,18 +3401,19 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
- dcode = mbuf;
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;
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+ qla27xx_get_active_image(vha, &active_regions);
+ if (active_regions.global == QLA27XX_SECONDARY_IMAGE) {
+ pcihdr = ha->flt_region_boot_sec << 2;
+ }
+ }
- last_image = 1;
do {
/* Verify PCI expansion ROM header. */
qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20);
bcode = mbuf + (pcihdr % 4);
- if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {
+ if (memcmp(bcode, "\x55\xaa", 2)) {
/* No signature */
ql_log(ql_log_fatal, vha, 0x0059,
"No matching ROM signature.\n");
@@ -3066,11 +3428,11 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
bcode = mbuf + (pcihdr % 4);
/* Validate signature of PCI data structure. */
- if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
- bcode[0x2] != 'I' || bcode[0x3] != 'R') {
+ if (memcmp(bcode, "PCIR", 4)) {
/* Incorrect header. */
ql_log(ql_log_fatal, vha, 0x005a,
"PCI data struct not found pcir_adr=%x.\n", pcids);
+ ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32);
ret = QLA_FUNCTION_FAILED;
break;
}
@@ -3117,30 +3479,24 @@ 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, faddr + 4, 4);
- for (i = 0; i < 4; i++)
- dcode[i] = be32_to_cpu(dcode[i]);
+ if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+ qla27xx_get_active_image(vha, &active_regions);
+ if (active_regions.global == QLA27XX_SECONDARY_IMAGE)
+ faddr = ha->flt_region_fw_sec;
+ }
- if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
- dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
- (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
- dcode[3] == 0)) {
+ qla24xx_read_flash_data(vha, dcode, faddr, 8);
+ if (qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_warn, vha, 0x005f,
"Unrecognized fw revision at %x.\n",
ha->flt_region_fw * 4);
+ ql_dump_buffer(ql_dbg_init, vha, 0x005f, dcode, 32);
} else {
- ha->fw_revision[0] = dcode[0];
- ha->fw_revision[1] = dcode[1];
- ha->fw_revision[2] = dcode[2];
- ha->fw_revision[3] = dcode[3];
+ for (i = 0; i < 4; i++)
+ ha->fw_revision[i] = be32_to_cpu(dcode[4+i]);
ql_dbg(ql_dbg_init, vha, 0x0060,
- "Firmware revision %d.%d.%d (%x).\n",
+ "Firmware revision (flash) %u.%u.%u (%x).\n",
ha->fw_revision[0], ha->fw_revision[1],
ha->fw_revision[2], ha->fw_revision[3]);
}
@@ -3152,20 +3508,17 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
}
memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version));
- dcode = mbuf;
- ha->isp_ops->read_optrom(vha, (uint8_t *)dcode,
- ha->flt_region_gold_fw << 2, 32);
-
- if (dcode[4] == 0xFFFFFFFF && dcode[5] == 0xFFFFFFFF &&
- dcode[6] == 0xFFFFFFFF && dcode[7] == 0xFFFFFFFF) {
+ faddr = ha->flt_region_gold_fw;
+ qla24xx_read_flash_data(vha, (void *)dcode, ha->flt_region_gold_fw, 8);
+ if (qla24xx_risc_firmware_invalid(dcode)) {
ql_log(ql_log_warn, vha, 0x0056,
- "Unrecognized golden fw at 0x%x.\n",
- ha->flt_region_gold_fw * 4);
+ "Unrecognized golden fw at %#x.\n", faddr);
+ ql_dump_buffer(ql_dbg_init, vha, 0x0056, dcode, 32);
return ret;
}
- for (i = 4; i < 8; i++)
- ha->gold_fw_version[i-4] = be32_to_cpu(dcode[i]);
+ for (i = 0; i < 4; i++)
+ ha->gold_fw_version[i] = be32_to_cpu(dcode[4+i]);
return ret;
}
@@ -3237,7 +3590,7 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
fcp_prio_addr = ha->flt_region_fcp_prio;
/* first read the fcp priority data header from flash */
- ha->isp_ops->read_optrom(vha, (uint8_t *)ha->fcp_prio_cfg,
+ ha->isp_ops->read_optrom(vha, ha->fcp_prio_cfg,
fcp_prio_addr << 2, FCP_PRIO_CFG_HDR_SIZE);
if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 0))
@@ -3248,7 +3601,7 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
len = ha->fcp_prio_cfg->num_entries * FCP_PRIO_CFG_ENTRY_SIZE;
max_len = FCP_PRIO_CFG_SIZE - FCP_PRIO_CFG_HDR_SIZE;
- ha->isp_ops->read_optrom(vha, (uint8_t *)&ha->fcp_prio_cfg->entry[0],
+ ha->isp_ops->read_optrom(vha, &ha->fcp_prio_cfg->entry[0],
fcp_prio_addr << 2, (len < max_len ? len : max_len));
/* revalidate the entire FCP priority config data, including entries */
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 582d1663f971..1c1f63be6eed 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* qla_target.c SCSI LLD infrastructure for QLogic 22xx/23xx/24xx/25xx
*
@@ -11,16 +12,6 @@
* Forward port and refactoring to modern qla2xxx and target/configfs
*
* Copyright (C) 2010-2013 Nicholas A. Bellinger <nab@kernel.org>
- *
- * 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, version 2
- * of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
@@ -184,6 +175,7 @@ static inline int qlt_issue_marker(struct scsi_qla_host *vha, int vha_locked)
/* Send marker if required */
if (unlikely(vha->marker_needed != 0)) {
int rc = qla2x00_issue_marker(vha, vha_locked);
+
if (rc != QLA_SUCCESS) {
ql_dbg(ql_dbg_tgt, vha, 0xe03d,
"qla_target(%d): issue_marker() failed\n",
@@ -557,6 +549,7 @@ static int qla24xx_post_nack_work(struct scsi_qla_host *vha, fc_port_t *fcport,
struct imm_ntfy_from_isp *ntfy, int type)
{
struct qla_work_evt *e;
+
e = qla2x00_alloc_work(vha, QLA_EVT_NACK);
if (!e)
return QLA_FUNCTION_FAILED;
@@ -680,7 +673,6 @@ done:
void qla24xx_do_nack_work(struct scsi_qla_host *vha, struct qla_work_evt *e)
{
fc_port_t *t;
- unsigned long flags;
switch (e->u.nack.type) {
case SRB_NACK_PRLI:
@@ -693,24 +685,19 @@ void qla24xx_do_nack_work(struct scsi_qla_host *vha, struct qla_work_evt *e)
if (t) {
ql_log(ql_log_info, vha, 0xd034,
"%s create sess success %p", __func__, t);
- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
/* create sess has an extra kref */
vha->hw->tgt.tgt_ops->put_sess(e->u.nack.fcport);
- spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
}
break;
}
qla24xx_async_notify_ack(vha, e->u.nack.fcport,
- (struct imm_ntfy_from_isp*)e->u.nack.iocb, e->u.nack.type);
+ (struct imm_ntfy_from_isp *)e->u.nack.iocb, e->u.nack.type);
}
void qla24xx_delete_sess_fn(struct work_struct *work)
{
fc_port_t *fcport = container_of(work, struct fc_port, del_work);
struct qla_hw_data *ha = fcport->vha->hw;
- unsigned long flags;
-
- spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (fcport->se_sess) {
ha->tgt.tgt_ops->shutdown_sess(fcport);
@@ -718,7 +705,6 @@ void qla24xx_delete_sess_fn(struct work_struct *work)
} else {
qlt_unreg_sess(fcport);
}
- spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
/*
@@ -787,8 +773,9 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
fcport->port_name, sess->loop_id);
sess->local = 0;
}
- ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
+ ha->tgt.tgt_ops->put_sess(sess);
}
/*
@@ -980,6 +967,8 @@ void qlt_free_session_done(struct work_struct *work)
sess->send_els_logo);
if (!IS_SW_RESV_ADDR(sess->d_id)) {
+ qla2x00_mark_device_lost(vha, sess, 0, 0);
+
if (sess->send_els_logo) {
qlt_port_logo_t logo;
@@ -1015,6 +1004,12 @@ void qlt_free_session_done(struct work_struct *work)
else
logout_started = true;
}
+ } /* if sess->logout_on_delete */
+
+ if (sess->nvme_flag & NVME_FLAG_REGISTERED &&
+ !(sess->nvme_flag & NVME_FLAG_DELETING)) {
+ sess->nvme_flag |= NVME_FLAG_DELETING;
+ qla_nvme_unregister_remote_port(sess);
}
}
@@ -1076,6 +1071,7 @@ void qlt_free_session_done(struct work_struct *work)
struct qlt_plogi_ack_t *con =
sess->plogi_link[QLT_PLOGI_LINK_CONFLICT];
struct imm_ntfy_from_isp *iocb;
+
own = sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
if (con) {
@@ -1160,21 +1156,13 @@ void qlt_unreg_sess(struct fc_port *sess)
if (sess->se_sess)
vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess);
- qla2x00_mark_device_lost(vha, sess, 0, 0);
-
sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
sess->disc_state = DSC_DELETE_PEND;
sess->last_rscn_gen = sess->rscn_gen;
sess->last_login_gen = sess->login_gen;
- if (sess->nvme_flag & NVME_FLAG_REGISTERED &&
- !(sess->nvme_flag & NVME_FLAG_DELETING)) {
- sess->nvme_flag |= NVME_FLAG_DELETING;
- schedule_work(&sess->nvme_del_work);
- } else {
- INIT_WORK(&sess->free_work, qlt_free_session_done);
- schedule_work(&sess->free_work);
- }
+ INIT_WORK(&sess->free_work, qlt_free_session_done);
+ schedule_work(&sess->free_work);
}
EXPORT_SYMBOL(qlt_unreg_sess);
@@ -1329,6 +1317,7 @@ static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id,
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]) &&
(gid->area == s_id[1]) &&
(gid->domain == s_id[0])) {
@@ -2331,14 +2320,14 @@ void qlt_send_resp_ctio(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd,
ctio->u.status1.scsi_status |=
cpu_to_le16(SS_RESIDUAL_UNDER);
- /* Response code and sense key */
- put_unaligned_le32(((0x70 << 24) | (sense_key << 8)),
- (&ctio->u.status1.sense_data)[0]);
+ /* Fixed format sense data. */
+ ctio->u.status1.sense_data[0] = 0x70;
+ ctio->u.status1.sense_data[2] = sense_key;
/* Additional sense length */
- put_unaligned_le32(0x0a, (&ctio->u.status1.sense_data)[1]);
+ ctio->u.status1.sense_data[7] = 0xa;
/* ASC and ASCQ */
- put_unaligned_le32(((asc << 24) | (ascq << 16)),
- (&ctio->u.status1.sense_data)[3]);
+ ctio->u.status1.sense_data[12] = asc;
+ ctio->u.status1.sense_data[13] = ascq;
/* Memory Barrier */
wmb();
@@ -2387,7 +2376,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
case ELS_PRLO:
case ELS_TPRLO:
ql_dbg(ql_dbg_disc, vha, 0x2106,
- "TM response logo %phC status %#x state %#x",
+ "TM response logo %8phC status %#x state %#x",
mcmd->sess->port_name, mcmd->fc_tm_rsp,
mcmd->flags);
qlt_schedule_sess_for_deletion(mcmd->sess);
@@ -2485,6 +2474,7 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
{
struct qla_hw_data *ha;
struct qla_qpair *qpair;
+
if (!cmd->sg_mapped)
return;
@@ -2635,7 +2625,7 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair,
static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
{
int cnt;
- uint32_t *dword_ptr;
+ struct dsd64 *cur_dsd;
/* Build continuation packets */
while (prm->seg_cnt > 0) {
@@ -2656,19 +2646,13 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
cont_pkt64->sys_define = 0;
cont_pkt64->entry_type = CONTINUE_A64_TYPE;
- dword_ptr = (uint32_t *)&cont_pkt64->dseg_0_address;
+ cur_dsd = cont_pkt64->dsd;
/* Load continuation entry data segments */
for (cnt = 0;
cnt < QLA_TGT_DATASEGS_PER_CONT_24XX && prm->seg_cnt;
cnt++, prm->seg_cnt--) {
- *dword_ptr++ =
- cpu_to_le32(lower_32_bits
- (sg_dma_address(prm->sg)));
- *dword_ptr++ = cpu_to_le32(upper_32_bits
- (sg_dma_address(prm->sg)));
- *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg));
-
+ append_dsd64(&cur_dsd, prm->sg);
prm->sg = sg_next(prm->sg);
}
}
@@ -2681,13 +2665,13 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
static void qlt_load_data_segments(struct qla_tgt_prm *prm)
{
int cnt;
- uint32_t *dword_ptr;
+ struct dsd64 *cur_dsd;
struct ctio7_to_24xx *pkt24 = (struct ctio7_to_24xx *)prm->pkt;
pkt24->u.status0.transfer_length = cpu_to_le32(prm->cmd->bufflen);
/* Setup packet address segment pointer */
- dword_ptr = pkt24->u.status0.dseg_0_address;
+ cur_dsd = &pkt24->u.status0.dsd;
/* Set total data segment count */
if (prm->seg_cnt)
@@ -2695,8 +2679,8 @@ static void qlt_load_data_segments(struct qla_tgt_prm *prm)
if (prm->seg_cnt == 0) {
/* No data transfer */
- *dword_ptr++ = 0;
- *dword_ptr = 0;
+ cur_dsd->address = 0;
+ cur_dsd->length = 0;
return;
}
@@ -2706,14 +2690,7 @@ static void qlt_load_data_segments(struct qla_tgt_prm *prm)
for (cnt = 0;
(cnt < QLA_TGT_DATASEGS_PER_CMD_24XX) && prm->seg_cnt;
cnt++, prm->seg_cnt--) {
- *dword_ptr++ =
- cpu_to_le32(lower_32_bits(sg_dma_address(prm->sg)));
-
- *dword_ptr++ = cpu_to_le32(upper_32_bits(
- sg_dma_address(prm->sg)));
-
- *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg));
-
+ append_dsd64(&cur_dsd, prm->sg);
prm->sg = sg_next(prm->sg);
}
@@ -3037,7 +3014,7 @@ qla_tgt_set_dif_tags(struct qla_tgt_cmd *cmd, struct crc_context *ctx,
static inline int
qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm)
{
- uint32_t *cur_dsd;
+ struct dsd64 *cur_dsd;
uint32_t transfer_length = 0;
uint32_t data_bytes;
uint32_t dif_bytes;
@@ -3183,12 +3160,11 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm)
qla_tgt_set_dif_tags(cmd, crc_ctx_pkt, &fw_prot_opts);
- pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma));
- pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma));
+ put_unaligned_le64(crc_ctx_dma, &pkt->crc_context_address);
pkt->crc_context_len = CRC_CONTEXT_LEN_FW;
if (!bundling) {
- cur_dsd = (uint32_t *) &crc_ctx_pkt->u.nobundling.data_address;
+ cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd;
} else {
/*
* Configure Bundling if we need to fetch interlaving
@@ -3198,7 +3174,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm)
crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes);
crc_ctx_pkt->u.bundling.dseg_count =
cpu_to_le16(prm->tot_dsds - prm->prot_seg_cnt);
- cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.data_address;
+ cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd;
}
/* Finish the common fields of CRC pkt */
@@ -3231,7 +3207,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm)
/* Walks dif segments */
pkt->add_flags |= CTIO_CRC2_AF_DIF_DSD_ENA;
- cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address;
+ cur_dsd = &crc_ctx_pkt->u.bundling.dif_dsd;
if (qla24xx_walk_and_build_prot_sglist(ha, NULL, cur_dsd,
prm->prot_seg_cnt, cmd))
goto crc_queuing_error;
@@ -3263,7 +3239,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) ||
(cmd->sess && cmd->sess->deleted)) {
cmd->state = QLA_TGT_STATE_PROCESSED;
- qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
return 0;
}
@@ -3292,7 +3267,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
* previous life, just abort the processing.
*/
cmd->state = QLA_TGT_STATE_PROCESSED;
- qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
ql_dbg_qp(ql_dbg_async, qpair, 0xe101,
"RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
vha->flags.online, qla2x00_reset_active(vha),
@@ -3384,9 +3358,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */
- spin_lock(&cmd->cmd_lock);
cmd->cmd_sent_to_fw = 1;
- spin_unlock(&cmd->cmd_lock);
cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags);
/* Memory Barrier */
@@ -3433,8 +3405,10 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
* 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);
+ cmd->aborted = 1;
+ cmd->write_data_transferred = 0;
+ cmd->state = QLA_TGT_STATE_DATA_IN;
+ vha->hw->tgt.tgt_ops->handle_data(cmd);
ql_dbg_qp(ql_dbg_async, qpair, 0xe102,
"RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
vha->flags.online, qla2x00_reset_active(vha),
@@ -3465,9 +3439,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
qlt_load_data_segments(&prm);
cmd->state = QLA_TGT_STATE_NEED_DATA;
- spin_lock(&cmd->cmd_lock);
cmd->cmd_sent_to_fw = 1;
- spin_unlock(&cmd->cmd_lock);
cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags);
/* Memory Barrier */
@@ -3646,33 +3618,11 @@ static int __qlt_send_term_imm_notif(struct scsi_qla_host *vha,
static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
struct imm_ntfy_from_isp *imm, int ha_locked)
{
- unsigned long flags = 0;
int rc;
- if (ha_locked) {
- rc = __qlt_send_term_imm_notif(vha, imm);
-
-#if 0 /* Todo */
- if (rc == -ENOMEM)
- qlt_alloc_qfull_cmd(vha, imm, 0, 0);
-#else
- if (rc) {
- }
-#endif
- goto done;
- }
-
- spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+ WARN_ON_ONCE(!ha_locked);
rc = __qlt_send_term_imm_notif(vha, imm);
-
-#if 0 /* Todo */
- if (rc == -ENOMEM)
- qlt_alloc_qfull_cmd(vha, imm, 0, 0);
-#endif
-
-done:
- if (!ha_locked)
- spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+ pr_debug("rc = %d\n", rc);
}
/*
@@ -3913,6 +3863,7 @@ static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio,
if (ctio != NULL) {
struct ctio7_from_24xx *c = (struct ctio7_from_24xx *)ctio;
+
term = !(c->flags &
cpu_to_le16(OF_TERM_EXCH));
} else
@@ -3977,39 +3928,6 @@ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha,
return cmd;
}
-/* hardware_lock should be held by caller. */
-void
-qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
-{
- struct qla_hw_data *ha = vha->hw;
-
- if (cmd->sg_mapped)
- qlt_unmap_sg(vha, cmd);
-
- /* TODO: fix debug message type and ids. */
- if (cmd->state == QLA_TGT_STATE_PROCESSED) {
- ql_dbg(ql_dbg_io, vha, 0xff00,
- "HOST-ABORT: state=PROCESSED.\n");
- } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) {
- cmd->write_data_transferred = 0;
- cmd->state = QLA_TGT_STATE_DATA_IN;
-
- ql_dbg(ql_dbg_io, vha, 0xff01,
- "HOST-ABORT: state=DATA_IN.\n");
-
- ha->tgt.tgt_ops->handle_data(cmd);
- return;
- } else {
- ql_dbg(ql_dbg_io, vha, 0xff03,
- "HOST-ABORT: state=BAD(%d).\n",
- cmd->state);
- dump_stack();
- }
-
- cmd->trc_flags |= TRC_FLUSH;
- ha->tgt.tgt_ops->free_cmd(cmd);
-}
-
/*
* ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
*/
@@ -4031,7 +3949,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha,
return;
}
- cmd = (struct qla_tgt_cmd *)qlt_ctio_to_cmd(vha, rsp, handle, ctio);
+ cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio);
if (cmd == NULL)
return;
@@ -4240,11 +4158,9 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
if (ret != 0)
goto out_term;
/*
- * Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
+ * Drop extra session reference from qlt_handle_cmd_for_atio().
*/
- spin_lock_irqsave(&ha->tgt.sess_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
out_term:
@@ -4261,9 +4177,7 @@ out_term:
target_free_tag(sess->se_sess, &cmd->se_cmd);
spin_unlock_irqrestore(qpair->qp_lock_ptr, 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)
@@ -4472,9 +4386,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
if (!cmd) {
ql_dbg(ql_dbg_io, vha, 0x3062,
"qla_target(%d): Allocation of cmd failed\n", vha->vp_idx);
- spin_lock_irqsave(&ha->tgt.sess_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return -EBUSY;
}
@@ -4773,6 +4685,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id)
list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) {
uint32_t op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id);
+
if (op_key == key) {
op->aborted = true;
count++;
@@ -4781,6 +4694,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->aborted = 1;
count++;
@@ -5051,6 +4965,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
if (sess != NULL) {
bool delete = false;
int sec;
+
spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
switch (sess->fw_login_state) {
case DSC_LS_PLOGI_PEND:
@@ -5203,6 +5118,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
case ELS_ADISC:
{
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
+
if (tgt->link_reinit_iocb_pending) {
qlt_send_notify_ack(ha->base_qpair,
&tgt->link_reinit_iocb, 0, 0, 0, 0, 0, 0);
@@ -5266,6 +5182,7 @@ static void qlt_handle_imm_notify(struct scsi_qla_host *vha,
case IMM_NTFY_LIP_LINK_REINIT:
{
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
+
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf033,
"qla_target(%d): LINK REINIT (loop %#x, "
"subcode %x)\n", vha->vp_idx,
@@ -5492,11 +5409,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
se_sess = sess->se_sess;
tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
- if (tag < 0)
- return;
-
- cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag];
- if (!cmd) {
+ if (tag < 0) {
ql_dbg(ql_dbg_io, vha, 0x3009,
"qla_target(%d): %s: Allocation of cmd failed\n",
vha->vp_idx, __func__);
@@ -5511,6 +5424,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
return;
}
+ cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag];
memset(cmd, 0, sizeof(struct qla_tgt_cmd));
qlt_incr_num_pend_cmds(vha);
@@ -5820,8 +5734,7 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha,
struct qla_tgt_mgmt_cmd *mcmd;
struct qla_hw_data *ha = vha->hw;
- mcmd = (struct qla_tgt_mgmt_cmd *)qlt_ctio_to_cmd(vha, rsp,
- pkt->handle, pkt);
+ mcmd = qlt_ctio_to_cmd(vha, rsp, pkt->handle, pkt);
if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) {
ql_dbg(ql_dbg_async, vha, 0xe064,
"qla_target(%d): ABTS Comp without mcmd\n",
@@ -5883,6 +5796,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha,
case CTIO_TYPE7:
{
struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt;
+
qlt_do_ctio_completion(vha, rsp, entry->handle,
le16_to_cpu(entry->status)|(pkt->entry_status << 16),
entry);
@@ -5893,6 +5807,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha,
{
struct atio_from_isp *atio = (struct atio_from_isp *)pkt;
int rc;
+
if (atio->u.isp2x.status !=
cpu_to_le16(ATIO_CDB_VALID)) {
ql_dbg(ql_dbg_tgt, vha, 0xe05e,
@@ -5941,6 +5856,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha,
case CONTINUE_TGT_IO_TYPE:
{
struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt;
+
qlt_do_ctio_completion(vha, rsp, entry->handle,
le16_to_cpu(entry->status)|(pkt->entry_status << 16),
entry);
@@ -5950,6 +5866,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha,
case CTIO_A64_TYPE:
{
struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt;
+
qlt_do_ctio_completion(vha, rsp, entry->handle,
le16_to_cpu(entry->status)|(pkt->entry_status << 16),
entry);
@@ -5964,6 +5881,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha,
case NOTIFY_ACK_TYPE:
if (tgt->notify_ack_expected > 0) {
struct nack_to_isp *entry = (struct nack_to_isp *)pkt;
+
ql_dbg(ql_dbg_tgt, vha, 0xe036,
"NOTIFY_ACK seq %08x status %x\n",
le16_to_cpu(entry->u.isp2x.seq_id),
@@ -6239,6 +6157,7 @@ retry:
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);
@@ -6318,17 +6237,19 @@ static void qlt_abort_work(struct qla_tgt *tgt,
}
rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
- ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
+ ha->tgt.tgt_ops->put_sess(sess);
+
if (rc != 0)
goto out_term;
return;
out_term2:
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
+
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
out_term:
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -6386,9 +6307,10 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
scsilun_to_int((struct scsi_lun *)&a->u.isp24.fcp_cmnd.lun);
rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0);
- ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+ ha->tgt.tgt_ops->put_sess(sess);
+
if (rc != 0)
goto out_term;
return;
@@ -6499,6 +6421,7 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha)
unsigned long flags;
struct qla_qpair *qpair = ha->queue_pair_map[i];
+
h = &tgt->qphints[i + 1];
INIT_LIST_HEAD(&h->hint_elem);
if (qpair) {
@@ -6937,7 +6860,7 @@ qlt_24xx_config_rings(struct scsi_qla_host *vha)
RD_REG_DWORD(ISP_ATIO_Q_OUT(vha));
if (ha->flags.msix_enabled) {
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
if (IS_QLA2071(ha)) {
/* 4 ports Baker: Enable Interrupt Handshake */
icb->msix_atio = 0;
@@ -6952,7 +6875,7 @@ qlt_24xx_config_rings(struct scsi_qla_host *vha)
}
} else {
/* INTx|MSI */
- if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
icb->msix_atio = 0;
icb->firmware_options_2 |= BIT_26;
ql_dbg(ql_dbg_init, vha, 0xf072,
@@ -7201,7 +7124,8 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha)
if (!QLA_TGT_MODE_ENABLED())
return;
- if ((ql2xenablemsix == 0) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ if ((ql2xenablemsix == 0) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
+ IS_QLA28XX(ha)) {
ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in;
ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out;
} else {
@@ -7329,7 +7253,10 @@ qlt_mem_free(struct qla_hw_data *ha)
sizeof(struct atio_from_isp), ha->tgt.atio_ring,
ha->tgt.atio_dma);
}
+ ha->tgt.atio_ring = NULL;
+ ha->tgt.atio_dma = 0;
kfree(ha->tgt.tgt_vp_map);
+ ha->tgt.tgt_vp_map = NULL;
}
/* vport_slock to be held by the caller */
@@ -7413,6 +7340,9 @@ int __init qlt_init(void)
{
int ret;
+ BUILD_BUG_ON(sizeof(struct ctio7_to_24xx) != 64);
+ BUILD_BUG_ON(sizeof(struct ctio_to_2xxx) != 64);
+
if (!qlt_parse_ini_mode()) {
ql_log(ql_log_fatal, NULL, 0xe06b,
"qlt_parse_ini_mode() failed\n");
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index f3de75000a08..b8d244f1e189 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2004 - 2010 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004 - 2005 Leonid Stoljar
@@ -9,16 +10,6 @@
* Copyright (C) 2010-2011 Nicholas A. Bellinger <nab@kernel.org>
*
* Additional file for the target driver support.
- *
- * 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.
*/
/*
* This is the global def file that is useful for including from the
@@ -29,6 +20,7 @@
#define __QLA_TARGET_H
#include "qla_def.h"
+#include "qla_dsd.h"
/*
* Must be changed on any change in any initiator visible interfaces or
@@ -224,12 +216,7 @@ struct ctio_to_2xxx {
uint16_t reserved_1[3];
uint16_t scsi_status;
uint32_t transfer_length;
- uint32_t dseg_0_address; /* Data segment 0 address. */
- uint32_t dseg_0_length; /* Data segment 0 length. */
- uint32_t dseg_1_address; /* Data segment 1 address. */
- uint32_t dseg_1_length; /* Data segment 1 length. */
- uint32_t dseg_2_address; /* Data segment 2 address. */
- uint32_t dseg_2_length; /* Data segment 2 length. */
+ struct dsd32 dsd[3];
} __packed;
#define ATIO_PATH_INVALID 0x07
#define ATIO_CANT_PROV_CAP 0x16
@@ -429,10 +416,7 @@ struct ctio7_to_24xx {
uint32_t reserved2;
uint32_t transfer_length;
uint32_t reserved3;
- /* Data segment 0 address. */
- uint32_t dseg_0_address[2];
- /* Data segment 0 length. */
- uint32_t dseg_0_length;
+ struct dsd64 dsd;
} status0;
struct {
uint16_t sense_length;
@@ -526,10 +510,10 @@ struct ctio_crc2_to_fw {
uint32_t reserved5;
__le32 transfer_length; /* total fc transfer length */
uint32_t reserved6;
- __le32 crc_context_address[2];/* Data segment address. */
+ __le64 crc_context_address __packed; /* Data segment address. */
uint16_t crc_context_len; /* Data segment length. */
uint16_t reserved_1; /* MUST be set to 0. */
-} __packed;
+};
/* CTIO Type CRC_x Status IOCB */
struct ctio_crc_from_fw {
@@ -855,7 +839,7 @@ enum trace_flags {
TRC_CTIO_ERR = BIT_11,
TRC_CTIO_DONE = BIT_12,
TRC_CTIO_ABORTED = BIT_13,
- TRC_CTIO_STRANGE= BIT_14,
+ TRC_CTIO_STRANGE = BIT_14,
TRC_CMD_DONE = BIT_15,
TRC_CMD_CHK_STOP = BIT_16,
TRC_CMD_FREE = BIT_17,
@@ -889,10 +873,14 @@ 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;
- unsigned int data_work:1;
- unsigned int data_work_free:1;
- unsigned int released:1;
+
+ /*
+ * This variable may be set from outside the LIO and I/O completion
+ * callback functions. Do not declare this member variable as a
+ * bitfield to avoid a read-modify-write operation when this variable
+ * is set.
+ */
+ unsigned int aborted;
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
@@ -1103,7 +1091,5 @@ extern void qlt_do_generation_tick(struct scsi_qla_host *, int *);
void qlt_send_resp_ctio(struct qla_qpair *, struct qla_tgt_cmd *, uint8_t,
uint8_t, uint8_t, uint8_t);
-extern void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *,
- struct qla_tgt_cmd *);
#endif /* __QLA_TARGET_H */
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c
index 9e52500caff0..de696a07532e 100644
--- a/drivers/scsi/qla2xxx/qla_tmpl.c
+++ b/drivers/scsi/qla2xxx/qla_tmpl.c
@@ -7,103 +7,9 @@
#include "qla_def.h"
#include "qla_tmpl.h"
-/* note default template is in big endian */
-static const uint32_t ql27xx_fwdt_default_template[] = {
- 0x63000000, 0xa4000000, 0x7c050000, 0x00000000,
- 0x30000000, 0x01000000, 0x00000000, 0xc0406eb4,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x04010000, 0x14000000, 0x00000000,
- 0x02000000, 0x44000000, 0x09010000, 0x10000000,
- 0x00000000, 0x02000000, 0x01010000, 0x1c000000,
- 0x00000000, 0x02000000, 0x00600000, 0x00000000,
- 0xc0000000, 0x01010000, 0x1c000000, 0x00000000,
- 0x02000000, 0x00600000, 0x00000000, 0xcc000000,
- 0x01010000, 0x1c000000, 0x00000000, 0x02000000,
- 0x10600000, 0x00000000, 0xd4000000, 0x01010000,
- 0x1c000000, 0x00000000, 0x02000000, 0x700f0000,
- 0x00000060, 0xf0000000, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x00700000, 0x041000c0,
- 0x00010000, 0x18000000, 0x00000000, 0x02000000,
- 0x10700000, 0x041000c0, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x40700000, 0x041000c0,
- 0x01010000, 0x1c000000, 0x00000000, 0x02000000,
- 0x007c0000, 0x01000000, 0xc0000000, 0x00010000,
- 0x18000000, 0x00000000, 0x02000000, 0x007c0000,
- 0x040300c4, 0x00010000, 0x18000000, 0x00000000,
- 0x02000000, 0x007c0000, 0x040100c0, 0x01010000,
- 0x1c000000, 0x00000000, 0x02000000, 0x007c0000,
- 0x00000000, 0xc0000000, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x007c0000, 0x04200000,
- 0x0b010000, 0x18000000, 0x00000000, 0x02000000,
- 0x0c000000, 0x00000000, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000000b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000010b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000020b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000030b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000040b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000050b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000060b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000070b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000080b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x000090b0, 0x02010000, 0x20000000,
- 0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
- 0xf0000000, 0x0000a0b0, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x0a000000, 0x040100c0,
- 0x00010000, 0x18000000, 0x00000000, 0x02000000,
- 0x0a000000, 0x04200080, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x00be0000, 0x041000c0,
- 0x00010000, 0x18000000, 0x00000000, 0x02000000,
- 0x10be0000, 0x041000c0, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x20be0000, 0x041000c0,
- 0x00010000, 0x18000000, 0x00000000, 0x02000000,
- 0x30be0000, 0x041000c0, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x00b00000, 0x041000c0,
- 0x00010000, 0x18000000, 0x00000000, 0x02000000,
- 0x10b00000, 0x041000c0, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x20b00000, 0x041000c0,
- 0x00010000, 0x18000000, 0x00000000, 0x02000000,
- 0x30b00000, 0x041000c0, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x00300000, 0x041000c0,
- 0x00010000, 0x18000000, 0x00000000, 0x02000000,
- 0x10300000, 0x041000c0, 0x00010000, 0x18000000,
- 0x00000000, 0x02000000, 0x20300000, 0x041000c0,
- 0x00010000, 0x18000000, 0x00000000, 0x02000000,
- 0x30300000, 0x041000c0, 0x0a010000, 0x10000000,
- 0x00000000, 0x02000000, 0x06010000, 0x1c000000,
- 0x00000000, 0x02000000, 0x01000000, 0x00000200,
- 0xff230200, 0x06010000, 0x1c000000, 0x00000000,
- 0x02000000, 0x02000000, 0x00001000, 0x00000000,
- 0x07010000, 0x18000000, 0x00000000, 0x02000000,
- 0x00000000, 0x01000000, 0x07010000, 0x18000000,
- 0x00000000, 0x02000000, 0x00000000, 0x02000000,
- 0x07010000, 0x18000000, 0x00000000, 0x02000000,
- 0x00000000, 0x03000000, 0x0d010000, 0x14000000,
- 0x00000000, 0x02000000, 0x00000000, 0xff000000,
- 0x10000000, 0x00000000, 0x00000080,
-};
-
-static inline void __iomem *
-qla27xx_isp_reg(struct scsi_qla_host *vha)
-{
- return &vha->hw->iobase->isp24;
-}
+#define ISPREG(vha) (&(vha)->hw->iobase->isp24)
+#define IOBAR(reg) offsetof(typeof(*(reg)), iobase_addr)
+#define IOBASE(vha) IOBAR(ISPREG(vha))
static inline void
qla27xx_insert16(uint16_t value, void *buf, ulong *len)
@@ -128,7 +34,6 @@ qla27xx_insert32(uint32_t value, void *buf, ulong *len)
static inline void
qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len)
{
-
if (buf && mem && size) {
buf += *len;
memcpy(buf, mem, size);
@@ -190,9 +95,9 @@ static inline void
qla27xx_write_reg(__iomem struct device_reg_24xx *reg,
uint offset, uint32_t data, void *buf)
{
- __iomem void *window = (void __iomem *)reg + offset;
-
if (buf) {
+ void __iomem *window = (void __iomem *)reg + offset;
+
WRT_REG_DWORD(window, data);
}
}
@@ -205,7 +110,7 @@ qla27xx_read_window(__iomem struct device_reg_24xx *reg,
void __iomem *window = (void __iomem *)reg + offset;
void (*readn)(void __iomem*, void *, ulong *) = qla27xx_read_vector(width);
- qla27xx_write_reg(reg, IOBASE_ADDR, addr, buf);
+ qla27xx_write_reg(reg, IOBAR(reg), addr, buf);
while (count--) {
qla27xx_insert32(addr, buf, len);
readn(window, buf, len);
@@ -224,7 +129,7 @@ qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf)
static inline struct qla27xx_fwdt_entry *
qla27xx_next_entry(struct qla27xx_fwdt_entry *ent)
{
- return (void *)ent + ent->hdr.size;
+ return (void *)ent + le32_to_cpu(ent->hdr.size);
}
static struct qla27xx_fwdt_entry *
@@ -254,12 +159,14 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ ulong addr = le32_to_cpu(ent->t256.base_addr);
+ uint offset = ent->t256.pci_offset;
+ ulong count = le16_to_cpu(ent->t256.reg_count);
+ uint width = ent->t256.reg_width;
ql_dbg(ql_dbg_misc, vha, 0xd200,
"%s: rdio t1 [%lx]\n", __func__, *len);
- qla27xx_read_window(reg, ent->t256.base_addr, ent->t256.pci_offset,
- ent->t256.reg_count, ent->t256.reg_width, buf, len);
+ qla27xx_read_window(ISPREG(vha), addr, offset, count, width, buf, len);
return qla27xx_next_entry(ent);
}
@@ -268,12 +175,14 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ ulong addr = le32_to_cpu(ent->t257.base_addr);
+ uint offset = ent->t257.pci_offset;
+ ulong data = le32_to_cpu(ent->t257.write_data);
ql_dbg(ql_dbg_misc, vha, 0xd201,
"%s: wrio t1 [%lx]\n", __func__, *len);
- qla27xx_write_reg(reg, IOBASE_ADDR, ent->t257.base_addr, buf);
- qla27xx_write_reg(reg, ent->t257.pci_offset, ent->t257.write_data, buf);
+ qla27xx_write_reg(ISPREG(vha), IOBASE(vha), addr, buf);
+ qla27xx_write_reg(ISPREG(vha), offset, data, buf);
return qla27xx_next_entry(ent);
}
@@ -282,13 +191,17 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ uint banksel = ent->t258.banksel_offset;
+ ulong bank = le32_to_cpu(ent->t258.bank);
+ ulong addr = le32_to_cpu(ent->t258.base_addr);
+ uint offset = ent->t258.pci_offset;
+ uint count = le16_to_cpu(ent->t258.reg_count);
+ uint width = ent->t258.reg_width;
ql_dbg(ql_dbg_misc, vha, 0xd202,
"%s: rdio t2 [%lx]\n", __func__, *len);
- qla27xx_write_reg(reg, ent->t258.banksel_offset, ent->t258.bank, buf);
- qla27xx_read_window(reg, ent->t258.base_addr, ent->t258.pci_offset,
- ent->t258.reg_count, ent->t258.reg_width, buf, len);
+ qla27xx_write_reg(ISPREG(vha), banksel, bank, buf);
+ qla27xx_read_window(ISPREG(vha), addr, offset, count, width, buf, len);
return qla27xx_next_entry(ent);
}
@@ -297,13 +210,17 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ ulong addr = le32_to_cpu(ent->t259.base_addr);
+ uint banksel = ent->t259.banksel_offset;
+ ulong bank = le32_to_cpu(ent->t259.bank);
+ uint offset = ent->t259.pci_offset;
+ ulong data = le32_to_cpu(ent->t259.write_data);
ql_dbg(ql_dbg_misc, vha, 0xd203,
"%s: wrio t2 [%lx]\n", __func__, *len);
- qla27xx_write_reg(reg, IOBASE_ADDR, ent->t259.base_addr, buf);
- qla27xx_write_reg(reg, ent->t259.banksel_offset, ent->t259.bank, buf);
- qla27xx_write_reg(reg, ent->t259.pci_offset, ent->t259.write_data, buf);
+ qla27xx_write_reg(ISPREG(vha), IOBASE(vha), addr, buf);
+ qla27xx_write_reg(ISPREG(vha), banksel, bank, buf);
+ qla27xx_write_reg(ISPREG(vha), offset, data, buf);
return qla27xx_next_entry(ent);
}
@@ -312,12 +229,12 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ uint offset = ent->t260.pci_offset;
ql_dbg(ql_dbg_misc, vha, 0xd204,
"%s: rdpci [%lx]\n", __func__, *len);
- qla27xx_insert32(ent->t260.pci_offset, buf, len);
- qla27xx_read_reg(reg, ent->t260.pci_offset, buf, len);
+ qla27xx_insert32(offset, buf, len);
+ qla27xx_read_reg(ISPREG(vha), offset, buf, len);
return qla27xx_next_entry(ent);
}
@@ -326,11 +243,12 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ uint offset = ent->t261.pci_offset;
+ ulong data = le32_to_cpu(ent->t261.write_data);
ql_dbg(ql_dbg_misc, vha, 0xd205,
"%s: wrpci [%lx]\n", __func__, *len);
- qla27xx_write_reg(reg, ent->t261.pci_offset, ent->t261.write_data, buf);
+ qla27xx_write_reg(ISPREG(vha), offset, data, buf);
return qla27xx_next_entry(ent);
}
@@ -339,51 +257,50 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
+ uint area = ent->t262.ram_area;
+ ulong start = le32_to_cpu(ent->t262.start_addr);
+ ulong end = le32_to_cpu(ent->t262.end_addr);
ulong dwords;
- ulong start;
- ulong end;
ql_dbg(ql_dbg_misc, vha, 0xd206,
"%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len);
- start = ent->t262.start_addr;
- end = ent->t262.end_addr;
- if (ent->t262.ram_area == T262_RAM_AREA_CRITICAL_RAM) {
+ if (area == T262_RAM_AREA_CRITICAL_RAM) {
;
- } else if (ent->t262.ram_area == T262_RAM_AREA_EXTERNAL_RAM) {
+ } else if (area == T262_RAM_AREA_EXTERNAL_RAM) {
end = vha->hw->fw_memory_size;
if (buf)
- ent->t262.end_addr = end;
- } else if (ent->t262.ram_area == T262_RAM_AREA_SHARED_RAM) {
+ ent->t262.end_addr = cpu_to_le32(end);
+ } else if (area == T262_RAM_AREA_SHARED_RAM) {
start = vha->hw->fw_shared_ram_start;
end = vha->hw->fw_shared_ram_end;
if (buf) {
- ent->t262.start_addr = start;
- ent->t262.end_addr = end;
+ ent->t262.start_addr = cpu_to_le32(start);
+ ent->t262.end_addr = cpu_to_le32(end);
}
- } else if (ent->t262.ram_area == T262_RAM_AREA_DDR_RAM) {
+ } else if (area == T262_RAM_AREA_DDR_RAM) {
start = vha->hw->fw_ddr_ram_start;
end = vha->hw->fw_ddr_ram_end;
if (buf) {
- ent->t262.start_addr = start;
- ent->t262.end_addr = end;
+ ent->t262.start_addr = cpu_to_le32(start);
+ ent->t262.end_addr = cpu_to_le32(end);
}
- } else if (ent->t262.ram_area == T262_RAM_AREA_MISC) {
+ } else if (area == T262_RAM_AREA_MISC) {
if (buf) {
- ent->t262.start_addr = start;
- ent->t262.end_addr = end;
+ ent->t262.start_addr = cpu_to_le32(start);
+ ent->t262.end_addr = cpu_to_le32(end);
}
} else {
ql_dbg(ql_dbg_misc, vha, 0xd022,
- "%s: unknown area %x\n", __func__, ent->t262.ram_area);
+ "%s: unknown area %x\n", __func__, area);
qla27xx_skip_entry(ent, buf);
goto done;
}
if (end < start || start == 0 || end == 0) {
ql_dbg(ql_dbg_misc, vha, 0xd023,
- "%s: unusable range (start=%x end=%x)\n", __func__,
- ent->t262.end_addr, ent->t262.start_addr);
+ "%s: unusable range (start=%lx end=%lx)\n",
+ __func__, start, end);
qla27xx_skip_entry(ent, buf);
goto done;
}
@@ -402,13 +319,14 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
+ uint type = ent->t263.queue_type;
uint count = 0;
uint i;
uint length;
- ql_dbg(ql_dbg_misc, vha, 0xd207,
- "%s: getq(%x) [%lx]\n", __func__, ent->t263.queue_type, *len);
- if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
+ ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd207,
+ "%s: getq(%x) [%lx]\n", __func__, type, *len);
+ if (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];
@@ -422,7 +340,7 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
count++;
}
}
- } else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
+ } else if (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];
@@ -450,7 +368,7 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
}
} else {
ql_dbg(ql_dbg_misc, vha, 0xd026,
- "%s: unknown queue %x\n", __func__, ent->t263.queue_type);
+ "%s: unknown queue %x\n", __func__, type);
qla27xx_skip_entry(ent, buf);
}
@@ -496,12 +414,10 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
-
- ql_dbg(ql_dbg_misc, vha, 0xd209,
+ ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd209,
"%s: pause risc [%lx]\n", __func__, *len);
if (buf)
- qla24xx_pause_risc(reg, vha->hw);
+ qla24xx_pause_risc(ISPREG(vha), vha->hw);
return qla27xx_next_entry(ent);
}
@@ -522,11 +438,12 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ uint offset = ent->t267.pci_offset;
+ ulong data = le32_to_cpu(ent->t267.data);
ql_dbg(ql_dbg_misc, vha, 0xd20b,
"%s: dis intr [%lx]\n", __func__, *len);
- qla27xx_write_reg(reg, ent->t267.pci_offset, ent->t267.data, buf);
+ qla27xx_write_reg(ISPREG(vha), offset, data, buf);
return qla27xx_next_entry(ent);
}
@@ -622,17 +539,16 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
- ulong dwords = ent->t270.count;
- ulong addr = ent->t270.addr;
+ ulong addr = le32_to_cpu(ent->t270.addr);
+ ulong dwords = le32_to_cpu(ent->t270.count);
ql_dbg(ql_dbg_misc, vha, 0xd20e,
"%s: rdremreg [%lx]\n", __func__, *len);
- qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
+ qla27xx_write_reg(ISPREG(vha), IOBASE_ADDR, 0x40, buf);
while (dwords--) {
- qla27xx_write_reg(reg, 0xc0, addr|0x80000000, buf);
+ qla27xx_write_reg(ISPREG(vha), 0xc0, addr|0x80000000, buf);
qla27xx_insert32(addr, buf, len);
- qla27xx_read_reg(reg, 0xc4, buf, len);
+ qla27xx_read_reg(ISPREG(vha), 0xc4, buf, len);
addr += sizeof(uint32_t);
}
@@ -643,15 +559,14 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
- ulong addr = ent->t271.addr;
- ulong data = ent->t271.data;
+ ulong addr = le32_to_cpu(ent->t271.addr);
+ ulong data = le32_to_cpu(ent->t271.data);
ql_dbg(ql_dbg_misc, vha, 0xd20f,
"%s: wrremreg [%lx]\n", __func__, *len);
- qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
- qla27xx_write_reg(reg, 0xc4, data, buf);
- qla27xx_write_reg(reg, 0xc0, addr, buf);
+ qla27xx_write_reg(ISPREG(vha), IOBASE(vha), 0x40, buf);
+ qla27xx_write_reg(ISPREG(vha), 0xc4, data, buf);
+ qla27xx_write_reg(ISPREG(vha), 0xc0, addr, buf);
return qla27xx_next_entry(ent);
}
@@ -660,8 +575,8 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- ulong dwords = ent->t272.count;
- ulong start = ent->t272.addr;
+ ulong dwords = le32_to_cpu(ent->t272.count);
+ ulong start = le32_to_cpu(ent->t272.addr);
ql_dbg(ql_dbg_misc, vha, 0xd210,
"%s: rdremram [%lx]\n", __func__, *len);
@@ -680,8 +595,8 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- ulong dwords = ent->t273.count;
- ulong addr = ent->t273.addr;
+ ulong dwords = le32_to_cpu(ent->t273.count);
+ ulong addr = le32_to_cpu(ent->t273.addr);
uint32_t value;
ql_dbg(ql_dbg_misc, vha, 0xd211,
@@ -703,12 +618,13 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
+ ulong type = ent->t274.queue_type;
uint count = 0;
uint i;
- ql_dbg(ql_dbg_misc, vha, 0xd212,
- "%s: getqsh(%x) [%lx]\n", __func__, ent->t274.queue_type, *len);
- if (ent->t274.queue_type == T274_QUEUE_TYPE_REQ_SHAD) {
+ ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd212,
+ "%s: getqsh(%lx) [%lx]\n", __func__, type, *len);
+ if (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];
@@ -720,7 +636,7 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
count++;
}
}
- } else if (ent->t274.queue_type == T274_QUEUE_TYPE_RSP_SHAD) {
+ } else if (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];
@@ -746,7 +662,7 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
}
} else {
ql_dbg(ql_dbg_misc, vha, 0xd02f,
- "%s: unknown queue %x\n", __func__, ent->t274.queue_type);
+ "%s: unknown queue %lx\n", __func__, type);
qla27xx_skip_entry(ent, buf);
}
@@ -765,23 +681,26 @@ qla27xx_fwdt_entry_t275(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
ulong offset = offsetof(typeof(*ent), t275.buffer);
+ ulong length = le32_to_cpu(ent->t275.length);
+ ulong size = le32_to_cpu(ent->hdr.size);
+ void *buffer = ent->t275.buffer;
- ql_dbg(ql_dbg_misc, vha, 0xd213,
- "%s: buffer(%x) [%lx]\n", __func__, ent->t275.length, *len);
- if (!ent->t275.length) {
+ ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd213,
+ "%s: buffer(%lx) [%lx]\n", __func__, length, *len);
+ if (!length) {
ql_dbg(ql_dbg_misc, vha, 0xd020,
"%s: buffer zero length\n", __func__);
qla27xx_skip_entry(ent, buf);
goto done;
}
- if (offset + ent->t275.length > ent->hdr.size) {
+ if (offset + length > size) {
+ length = size - offset;
ql_dbg(ql_dbg_misc, vha, 0xd030,
- "%s: buffer overflow\n", __func__);
- qla27xx_skip_entry(ent, buf);
- goto done;
+ "%s: buffer overflow, truncate [%lx]\n", __func__, length);
+ ent->t275.length = cpu_to_le32(length);
}
- qla27xx_insertbuf(ent->t275.buffer, ent->t275.length, buf, len);
+ qla27xx_insertbuf(buffer, length, buf, len);
done:
return qla27xx_next_entry(ent);
}
@@ -790,15 +709,22 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t276(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- uint type = vha->hw->pdev->device >> 4 & 0xf;
- uint func = vha->hw->port_no & 0x3;
-
ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd214,
"%s: cond [%lx]\n", __func__, *len);
- if (type != ent->t276.cond1 || func != ent->t276.cond2) {
- ent = qla27xx_next_entry(ent);
- qla27xx_skip_entry(ent, buf);
+ if (buf) {
+ ulong cond1 = le32_to_cpu(ent->t276.cond1);
+ ulong cond2 = le32_to_cpu(ent->t276.cond2);
+ uint type = vha->hw->pdev->device >> 4 & 0xf;
+ uint func = vha->hw->port_no & 0x3;
+
+ if (type != cond1 || func != cond2) {
+ struct qla27xx_fwdt_template *tmp = buf;
+
+ tmp->count--;
+ ent = qla27xx_next_entry(ent);
+ qla27xx_skip_entry(ent, buf);
+ }
}
return qla27xx_next_entry(ent);
@@ -808,13 +734,15 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t277(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ ulong cmd_addr = le32_to_cpu(ent->t277.cmd_addr);
+ ulong wr_cmd_data = le32_to_cpu(ent->t277.wr_cmd_data);
+ ulong data_addr = le32_to_cpu(ent->t277.data_addr);
ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd215,
"%s: rdpep [%lx]\n", __func__, *len);
- qla27xx_insert32(ent->t277.wr_cmd_data, buf, len);
- qla27xx_write_reg(reg, ent->t277.cmd_addr, ent->t277.wr_cmd_data, buf);
- qla27xx_read_reg(reg, ent->t277.data_addr, buf, len);
+ qla27xx_insert32(wr_cmd_data, buf, len);
+ qla27xx_write_reg(ISPREG(vha), cmd_addr, wr_cmd_data, buf);
+ qla27xx_read_reg(ISPREG(vha), data_addr, buf, len);
return qla27xx_next_entry(ent);
}
@@ -823,12 +751,15 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t278(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
- struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
+ ulong cmd_addr = le32_to_cpu(ent->t278.cmd_addr);
+ ulong wr_cmd_data = le32_to_cpu(ent->t278.wr_cmd_data);
+ ulong data_addr = le32_to_cpu(ent->t278.data_addr);
+ ulong wr_data = le32_to_cpu(ent->t278.wr_data);
ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd216,
"%s: wrpep [%lx]\n", __func__, *len);
- qla27xx_write_reg(reg, ent->t278.data_addr, ent->t278.wr_data, buf);
- qla27xx_write_reg(reg, ent->t278.cmd_addr, ent->t278.wr_cmd_data, buf);
+ qla27xx_write_reg(ISPREG(vha), data_addr, wr_data, buf);
+ qla27xx_write_reg(ISPREG(vha), cmd_addr, wr_cmd_data, buf);
return qla27xx_next_entry(ent);
}
@@ -837,8 +768,10 @@ static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_other(struct scsi_qla_host *vha,
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
{
+ ulong type = le32_to_cpu(ent->hdr.type);
+
ql_dbg(ql_dbg_misc, vha, 0xd2ff,
- "%s: type %x [%lx]\n", __func__, ent->hdr.type, *len);
+ "%s: other %lx [%lx]\n", __func__, type, *len);
qla27xx_skip_entry(ent, buf);
return qla27xx_next_entry(ent);
@@ -893,36 +826,27 @@ static void
qla27xx_walk_template(struct scsi_qla_host *vha,
struct qla27xx_fwdt_template *tmp, void *buf, ulong *len)
{
- struct qla27xx_fwdt_entry *ent = (void *)tmp + tmp->entry_offset;
- ulong count = tmp->entry_count;
+ struct qla27xx_fwdt_entry *ent = (void *)tmp +
+ le32_to_cpu(tmp->entry_offset);
+ ulong type;
+ tmp->count = le32_to_cpu(tmp->entry_count);
ql_dbg(ql_dbg_misc, vha, 0xd01a,
- "%s: entry count %lx\n", __func__, count);
- while (count--) {
- ent = qla27xx_find_entry(ent->hdr.type)(vha, ent, buf, len);
+ "%s: entry count %u\n", __func__, tmp->count);
+ while (ent && tmp->count--) {
+ type = le32_to_cpu(ent->hdr.type);
+ ent = qla27xx_find_entry(type)(vha, ent, buf, len);
if (!ent)
break;
}
- if (count)
+ if (tmp->count)
ql_dbg(ql_dbg_misc, vha, 0xd018,
- "%s: entry residual count (%lx)\n", __func__, count);
+ "%s: entry count residual=+%u\n", __func__, tmp->count);
if (ent)
ql_dbg(ql_dbg_misc, vha, 0xd019,
- "%s: missing end entry (%lx)\n", __func__, count);
-
- if (buf && *len != vha->hw->fw_dump_len)
- ql_dbg(ql_dbg_misc, vha, 0xd01b,
- "%s: length=%#lx residual=%+ld\n",
- __func__, *len, vha->hw->fw_dump_len - *len);
-
- if (buf) {
- ql_log(ql_log_warn, vha, 0xd015,
- "Firmware dump saved to temp buffer (%lu/%p)\n",
- vha->host_no, vha->hw->fw_dump);
- qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
- }
+ "%s: missing end entry\n", __func__);
}
static void
@@ -945,8 +869,8 @@ qla27xx_driver_info(struct qla27xx_fwdt_template *tmp)
}
static void
-qla27xx_firmware_info(struct qla27xx_fwdt_template *tmp,
- struct scsi_qla_host *vha)
+qla27xx_firmware_info(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_template *tmp)
{
tmp->firmware_version[0] = vha->hw->fw_major_version;
tmp->firmware_version[1] = vha->hw->fw_minor_version;
@@ -963,19 +887,19 @@ ql27xx_edit_template(struct scsi_qla_host *vha,
{
qla27xx_time_stamp(tmp);
qla27xx_driver_info(tmp);
- qla27xx_firmware_info(tmp, vha);
+ qla27xx_firmware_info(vha, tmp);
}
static inline uint32_t
qla27xx_template_checksum(void *p, ulong size)
{
- uint32_t *buf = p;
+ __le32 *buf = p;
uint64_t sum = 0;
size /= sizeof(*buf);
- while (size--)
- sum += *buf++;
+ for ( ; size--; buf++)
+ sum += le32_to_cpu(*buf);
sum = (sum & 0xffffffff) + (sum >> 32);
@@ -991,29 +915,29 @@ qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp)
static inline int
qla27xx_verify_template_header(struct qla27xx_fwdt_template *tmp)
{
- return tmp->template_type == TEMPLATE_TYPE_FWDUMP;
+ return le32_to_cpu(tmp->template_type) == TEMPLATE_TYPE_FWDUMP;
}
-static void
-qla27xx_execute_fwdt_template(struct scsi_qla_host *vha)
+static ulong
+qla27xx_execute_fwdt_template(struct scsi_qla_host *vha,
+ struct qla27xx_fwdt_template *tmp, void *buf)
{
- struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
- ulong len;
+ ulong len = 0;
if (qla27xx_fwdt_template_valid(tmp)) {
len = tmp->template_size;
- tmp = memcpy(vha->hw->fw_dump, tmp, len);
+ tmp = memcpy(buf, tmp, len);
ql27xx_edit_template(vha, tmp);
- qla27xx_walk_template(vha, tmp, tmp, &len);
- vha->hw->fw_dump_len = len;
- vha->hw->fw_dumped = 1;
+ qla27xx_walk_template(vha, tmp, buf, &len);
}
+
+ return len;
}
ulong
-qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha)
+qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha, void *p)
{
- struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
+ struct qla27xx_fwdt_template *tmp = p;
ulong len = 0;
if (qla27xx_fwdt_template_valid(tmp)) {
@@ -1032,18 +956,6 @@ qla27xx_fwdt_template_size(void *p)
return tmp->template_size;
}
-ulong
-qla27xx_fwdt_template_default_size(void)
-{
- return sizeof(ql27xx_fwdt_default_template);
-}
-
-const void *
-qla27xx_fwdt_template_default(void)
-{
- return ql27xx_fwdt_default_template;
-}
-
int
qla27xx_fwdt_template_valid(void *p)
{
@@ -1051,7 +963,8 @@ qla27xx_fwdt_template_valid(void *p)
if (!qla27xx_verify_template_header(tmp)) {
ql_log(ql_log_warn, NULL, 0xd01c,
- "%s: template type %x\n", __func__, tmp->template_type);
+ "%s: template type %x\n", __func__,
+ le32_to_cpu(tmp->template_type));
return false;
}
@@ -1074,17 +987,41 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
spin_lock_irqsave(&vha->hw->hardware_lock, flags);
#endif
- if (!vha->hw->fw_dump)
- ql_log(ql_log_warn, vha, 0xd01e, "fwdump buffer missing.\n");
- else if (!vha->hw->fw_dump_template)
- ql_log(ql_log_warn, vha, 0xd01f, "fwdump template missing.\n");
- else if (vha->hw->fw_dumped)
- ql_log(ql_log_warn, vha, 0xd300,
- "Firmware has been previously dumped (%p),"
- " -- ignoring request\n", vha->hw->fw_dump);
- else {
- QLA_FW_STOPPED(vha->hw);
- qla27xx_execute_fwdt_template(vha);
+ if (!vha->hw->fw_dump) {
+ ql_log(ql_log_warn, vha, 0xd01e, "-> fwdump no buffer\n");
+ } else if (vha->hw->fw_dumped) {
+ ql_log(ql_log_warn, vha, 0xd01f,
+ "-> Firmware already dumped (%p) -- ignoring request\n",
+ vha->hw->fw_dump);
+ } else {
+ struct fwdt *fwdt = vha->hw->fwdt;
+ uint j;
+ ulong len;
+ void *buf = vha->hw->fw_dump;
+
+ for (j = 0; j < 2; j++, fwdt++, buf += len) {
+ ql_log(ql_log_warn, vha, 0xd011,
+ "-> fwdt%u running...\n", j);
+ if (!fwdt->template) {
+ ql_log(ql_log_warn, vha, 0xd012,
+ "-> fwdt%u no template\n", j);
+ break;
+ }
+ len = qla27xx_execute_fwdt_template(vha,
+ fwdt->template, buf);
+ if (len != fwdt->dump_size) {
+ ql_log(ql_log_warn, vha, 0xd013,
+ "-> fwdt%u fwdump residual=%+ld\n",
+ j, fwdt->dump_size - len);
+ }
+ }
+ vha->hw->fw_dump_len = buf - (void *)vha->hw->fw_dump;
+ vha->hw->fw_dumped = 1;
+
+ ql_log(ql_log_warn, vha, 0xd015,
+ "-> Firmware dump saved to buffer (%lu/%p) <%lx>\n",
+ vha->host_no, vha->hw->fw_dump, vha->hw->fw_dump_cap_flags);
+ qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
}
#ifndef __CHECKER__
diff --git a/drivers/scsi/qla2xxx/qla_tmpl.h b/drivers/scsi/qla2xxx/qla_tmpl.h
index 5c2c2a8a19c4..d2a0014e8b21 100644
--- a/drivers/scsi/qla2xxx/qla_tmpl.h
+++ b/drivers/scsi/qla2xxx/qla_tmpl.h
@@ -11,12 +11,12 @@
#define IOBASE_ADDR offsetof(struct device_reg_24xx, iobase_addr)
struct __packed qla27xx_fwdt_template {
- uint32_t template_type;
- uint32_t entry_offset;
+ __le32 template_type;
+ __le32 entry_offset;
uint32_t template_size;
- uint32_t reserved_1;
+ uint32_t count; /* borrow field for running/residual count */
- uint32_t entry_count;
+ __le32 entry_count;
uint32_t template_version;
uint32_t capture_timestamp;
uint32_t template_checksum;
@@ -65,8 +65,8 @@ struct __packed qla27xx_fwdt_template {
struct __packed qla27xx_fwdt_entry {
struct __packed {
- uint32_t type;
- uint32_t size;
+ __le32 type;
+ __le32 size;
uint32_t reserved_1;
uint8_t capture_flags;
@@ -81,36 +81,36 @@ struct __packed qla27xx_fwdt_entry {
} t255;
struct __packed {
- uint32_t base_addr;
+ __le32 base_addr;
uint8_t reg_width;
- uint16_t reg_count;
+ __le16 reg_count;
uint8_t pci_offset;
} t256;
struct __packed {
- uint32_t base_addr;
- uint32_t write_data;
+ __le32 base_addr;
+ __le32 write_data;
uint8_t pci_offset;
uint8_t reserved[3];
} t257;
struct __packed {
- uint32_t base_addr;
+ __le32 base_addr;
uint8_t reg_width;
- uint16_t reg_count;
+ __le16 reg_count;
uint8_t pci_offset;
uint8_t banksel_offset;
uint8_t reserved[3];
- uint32_t bank;
+ __le32 bank;
} t258;
struct __packed {
- uint32_t base_addr;
- uint32_t write_data;
+ __le32 base_addr;
+ __le32 write_data;
uint8_t reserved[2];
uint8_t pci_offset;
uint8_t banksel_offset;
- uint32_t bank;
+ __le32 bank;
} t259;
struct __packed {
@@ -121,14 +121,14 @@ struct __packed qla27xx_fwdt_entry {
struct __packed {
uint8_t pci_offset;
uint8_t reserved[3];
- uint32_t write_data;
+ __le32 write_data;
} t261;
struct __packed {
uint8_t ram_area;
uint8_t reserved[3];
- uint32_t start_addr;
- uint32_t end_addr;
+ __le32 start_addr;
+ __le32 end_addr;
} t262;
struct __packed {
@@ -158,7 +158,7 @@ struct __packed qla27xx_fwdt_entry {
struct __packed {
uint8_t pci_offset;
uint8_t reserved[3];
- uint32_t data;
+ __le32 data;
} t267;
struct __packed {
@@ -173,23 +173,23 @@ struct __packed qla27xx_fwdt_entry {
} t269;
struct __packed {
- uint32_t addr;
- uint32_t count;
+ __le32 addr;
+ __le32 count;
} t270;
struct __packed {
- uint32_t addr;
- uint32_t data;
+ __le32 addr;
+ __le32 data;
} t271;
struct __packed {
- uint32_t addr;
- uint32_t count;
+ __le32 addr;
+ __le32 count;
} t272;
struct __packed {
- uint32_t addr;
- uint32_t count;
+ __le32 addr;
+ __le32 count;
} t273;
struct __packed {
@@ -199,26 +199,26 @@ struct __packed qla27xx_fwdt_entry {
} t274;
struct __packed {
- uint32_t length;
+ __le32 length;
uint8_t buffer[];
} t275;
struct __packed {
- uint32_t cond1;
- uint32_t cond2;
+ __le32 cond1;
+ __le32 cond2;
} t276;
struct __packed {
- uint32_t cmd_addr;
- uint32_t wr_cmd_data;
- uint32_t data_addr;
+ __le32 cmd_addr;
+ __le32 wr_cmd_data;
+ __le32 data_addr;
} t277;
struct __packed {
- uint32_t cmd_addr;
- uint32_t wr_cmd_data;
- uint32_t data_addr;
- uint32_t wr_data;
+ __le32 cmd_addr;
+ __le32 wr_cmd_data;
+ __le32 data_addr;
+ __le32 wr_data;
} t278;
};
};
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 0690dac24081..cd6bdf71e533 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "10.00.00.14-k"
+#define QLA2XXX_VERSION "10.01.00.16-k"
#define QLA_DRIVER_MAJOR_VER 10
-#define QLA_DRIVER_MINOR_VER 0
+#define QLA_DRIVER_MINOR_VER 1
#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 8a3075d17c63..d15412d3d9bd 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*******************************************************************************
* This file contains tcm implementation using v4 configfs fabric infrastructure
* for QLogic target mode HBAs
@@ -11,35 +12,20 @@
*
* Copyright (c) 2010 Cisco Systems, Inc
*
- * 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.
****************************************************************************/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/utsname.h>
#include <linux/vmalloc.h>
-#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>
-#include <linux/kthread.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/configfs.h>
#include <linux/ctype.h>
#include <asm/unaligned.h>
-#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_cmnd.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
@@ -267,25 +253,17 @@ static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd)
static void tcm_qla2xxx_complete_free(struct work_struct *work)
{
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
- bool released = false;
- unsigned long flags;
cmd->cmd_in_wq = 0;
WARN_ON(cmd->trc_flags & TRC_CMD_FREE);
- spin_lock_irqsave(&cmd->cmd_lock, flags);
+ /* To do: protect all tgt_counters manipulations with proper locking. */
cmd->qpair->tgt_counters.qla_core_ret_sta_ctio++;
cmd->trc_flags |= TRC_CMD_FREE;
cmd->cmd_sent_to_fw = 0;
- if (cmd->released)
- released = true;
- spin_unlock_irqrestore(&cmd->cmd_lock, flags);
- if (released)
- qlt_free_cmd(cmd);
- else
- transport_generic_free_cmd(&cmd->se_cmd, 0);
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
}
/*
@@ -326,7 +304,6 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd)
static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd)
{
struct qla_tgt_cmd *cmd;
- unsigned long flags;
if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) {
struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd,
@@ -336,14 +313,10 @@ static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd)
}
cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd);
- spin_lock_irqsave(&cmd->cmd_lock, flags);
- if (cmd->cmd_sent_to_fw) {
- cmd->released = 1;
- spin_unlock_irqrestore(&cmd->cmd_lock, flags);
- } else {
- spin_unlock_irqrestore(&cmd->cmd_lock, flags);
- qlt_free_cmd(cmd);
- }
+ if (WARN_ON(cmd->cmd_sent_to_fw))
+ return;
+
+ qlt_free_cmd(cmd);
}
static void tcm_qla2xxx_release_session(struct kref *kref)
@@ -359,7 +332,6 @@ static void tcm_qla2xxx_put_sess(struct fc_port *sess)
if (!sess)
return;
- assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
kref_put(&sess->sess_kref, tcm_qla2xxx_release_session);
}
@@ -374,8 +346,9 @@ static void tcm_qla2xxx_close_session(struct se_session *se_sess)
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
target_sess_cmd_list_set_waiting(se_sess);
- tcm_qla2xxx_put_sess(sess);
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+
+ tcm_qla2xxx_put_sess(sess);
}
static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess)
@@ -399,6 +372,8 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
cmd->se_cmd.transport_state,
cmd->se_cmd.t_state,
cmd->se_cmd.se_cmd_flags);
+ transport_generic_request_failure(&cmd->se_cmd,
+ TCM_CHECK_CONDITION_ABORT_CMD);
return 0;
}
cmd->trc_flags |= TRC_XFR_RDY;
@@ -488,32 +463,18 @@ 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;
-
- spin_lock_irqsave(&cmd->cmd_lock, flags);
cmd->cmd_sent_to_fw = 0;
-
- if (cmd->released) {
- spin_unlock_irqrestore(&cmd->cmd_lock, flags);
- qlt_free_cmd(cmd);
- return;
- }
-
- cmd->data_work = 1;
if (cmd->aborted) {
- cmd->data_work_free = 1;
- spin_unlock_irqrestore(&cmd->cmd_lock, flags);
-
- tcm_qla2xxx_free_cmd(cmd);
+ transport_generic_request_failure(&cmd->se_cmd,
+ TCM_CHECK_CONDITION_ABORT_CMD);
return;
}
- spin_unlock_irqrestore(&cmd->cmd_lock, flags);
cmd->qpair->tgt_counters.qla_core_ret_ctio++;
if (!cmd->write_data_transferred) {
@@ -829,7 +790,6 @@ static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct fc_port *sess)
static void tcm_qla2xxx_shutdown_sess(struct fc_port *sess)
{
- assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
target_sess_cmd_list_set_waiting(sess->se_sess);
}
@@ -1489,7 +1449,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
*/
tpg = lport->tpg_1;
if (!tpg) {
- pr_err("Unable to lcoate struct tcm_qla2xxx_lport->tpg_1\n");
+ pr_err("Unable to locate struct tcm_qla2xxx_lport->tpg_1\n");
return -EINVAL;
}
/*
diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
index e4dc7c733c29..4bdf31b1407a 100644
--- a/drivers/scsi/qla4xxx/Kconfig
+++ b/drivers/scsi/qla4xxx/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SCSI_QLA_ISCSI
tristate "QLogic ISP4XXX and ISP82XX host adapter family support"
depends on PCI && SCSI && NET
diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile
index 4230977748cf..1f8a9096c744 100644
--- a/drivers/scsi/qla4xxx/Makefile
+++ b/drivers/scsi/qla4xxx/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o ql4_83xx.o
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 6e4f4931ae17..8c674eca09f1 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -5930,7 +5930,7 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
val = rd_nvram_byte(ha, sec_addr);
if (val & BIT_7)
ddb_index[1] = (val & 0x7f);
-
+ goto exit_boot_info;
} else if (is_qla80XX(ha)) {
buf = dma_alloc_coherent(&ha->pdev->dev, size,
&buf_dma, GFP_KERNEL);
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
index 8b471a925b43..136681ad18a5 100644
--- a/drivers/scsi/qlogicfas408.c
+++ b/drivers/scsi/qlogicfas408.c
@@ -139,7 +139,7 @@ static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int
} else { /* out */
#if QL_TURBO_PDMA
rtrc(4)
- if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */
+ if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */
outsl(qbase + 4, request, 32);
reqlen -= 128;
request += 128;
@@ -240,7 +240,7 @@ static void ql_icmd(struct scsi_cmnd *cmd)
outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
outb(qlcfg7, qbase + 7);
outb(qlcfg6, qbase + 6);
- /**/ outb(qlcfg5, qbase + 5); /* select timer */
+ outb(qlcfg5, qbase + 5); /* select timer */
outb(qlcfg9 & 7, qbase + 9); /* prescaler */
/* outb(0x99, qbase + 5); */
outb(scmd_id(cmd), qbase + 4);
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 0e22512bd3e4..9335849f6bea 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
* Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net)
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index 5c3d6e1e0145..898a0bdf8df6 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* raid_class.c - implementation of a simple raid visualisation class
*
* Copyright (c) 2005 - James Bottomley <James.Bottomley@steeleye.com>
*
- * This file is licensed under GPLv2
- *
* This class is designed to allow raid attributes to be visualised and
* manipulated in a form independent of the underlying raid. Ultimately this
* should work for both hardware and software raids.
diff --git a/drivers/scsi/script_asm.pl b/drivers/scsi/script_asm.pl
index 7d651d99afcb..0300f4c5562e 100644
--- a/drivers/scsi/script_asm.pl
+++ b/drivers/scsi/script_asm.pl
@@ -1,4 +1,5 @@
#!/usr/bin/perl -s
+# SPDX-License-Identifier: GPL-2.0-or-later
# NCR 53c810 script assembler
# Sponsored by
@@ -13,20 +14,6 @@
# Support for 53c710 (via -ncr7x0_family switch) added by Richard
# Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
#
-# 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.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
# TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
#
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 99a7b9f520ae..1f5b5c8a7f72 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* scsi.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
@@ -85,15 +86,10 @@ unsigned int scsi_logging_level;
EXPORT_SYMBOL(scsi_logging_level);
#endif
-/* sd, scsi core and power management need to coordinate flushing async actions */
-ASYNC_DOMAIN(scsi_sd_probe_domain);
-EXPORT_SYMBOL(scsi_sd_probe_domain);
-
/*
- * Separate domain (from scsi_sd_probe_domain) to maximize the benefit of
- * asynchronous system resume operations. It is marked 'exclusive' to avoid
- * being included in the async_synchronize_full() that is invoked by
- * dpm_resume()
+ * Domain for asynchronous system resume operations. It is marked 'exclusive'
+ * to avoid being included in the async_synchronize_full() that is invoked by
+ * dpm_resume().
*/
ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
EXPORT_SYMBOL(scsi_sd_pm_domain);
@@ -820,7 +816,6 @@ static void __exit exit_scsi(void)
scsi_exit_devinfo();
scsi_exit_procfs();
scsi_exit_queue();
- async_unregister_domain(&scsi_sd_probe_domain);
}
subsys_initcall(init_scsi);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 2740a90501a0..d323523f5f9d 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
* Copyright (C) 1992 Eric Youngdale
@@ -8,13 +9,7 @@
*
* Copyright (C) 2001 - 2018 Douglas Gilbert
*
- * 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, or (at your option)
- * any later version.
- *
* For documentation see http://sg.danny.cz/sg/sdebug26.html
- *
*/
diff --git a/drivers/scsi/scsi_debugfs.h b/drivers/scsi/scsi_debugfs.h
index 951b043e82d0..d125d1bd4184 100644
--- a/drivers/scsi/scsi_debugfs.h
+++ b/drivers/scsi/scsi_debugfs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
struct request;
struct seq_file;
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index c14006ac98f9..42f0550d6b11 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SCSI device handler infrastruture.
*
- * 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.
- *
- * 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.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
* Copyright IBM Corporation, 2007
* Authors:
* Chandra Seetharaman <sekharan@us.ibm.com>
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 1b8378f36139..1c470e31ae81 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* scsi_error.c Copyright (C) 1997 Eric Youngdale
*
@@ -1054,7 +1055,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
struct scsi_device *sdev = scmd->device;
struct Scsi_Host *shost = sdev->host;
DECLARE_COMPLETION_ONSTACK(done);
- unsigned long timeleft = timeout;
+ unsigned long timeleft = timeout, delay;
struct scsi_eh_save ses;
const unsigned long stall_for = msecs_to_jiffies(100);
int rtn;
@@ -1065,7 +1066,29 @@ retry:
scsi_log_send(scmd);
scmd->scsi_done = scsi_eh_done;
- rtn = shost->hostt->queuecommand(shost, scmd);
+
+ /*
+ * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can
+ * change the SCSI device state after we have examined it and before
+ * .queuecommand() is called.
+ */
+ mutex_lock(&sdev->state_mutex);
+ while (sdev->sdev_state == SDEV_BLOCK && timeleft > 0) {
+ mutex_unlock(&sdev->state_mutex);
+ SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_DEBUG, sdev,
+ "%s: state %d <> %d\n", __func__, sdev->sdev_state,
+ SDEV_BLOCK));
+ delay = min(timeleft, stall_for);
+ timeleft -= delay;
+ msleep(jiffies_to_msecs(delay));
+ mutex_lock(&sdev->state_mutex);
+ }
+ if (sdev->sdev_state != SDEV_BLOCK)
+ rtn = shost->hostt->queuecommand(shost, scmd);
+ else
+ rtn = SCSI_MLQUEUE_DEVICE_BUSY;
+ mutex_unlock(&sdev->state_mutex);
+
if (rtn) {
if (timeleft > stall_for) {
scsi_eh_restore_cmnd(scmd, &ses);
@@ -2393,7 +2416,6 @@ out_put_autopm_host:
scsi_autopm_put_host(shost);
return error;
}
-EXPORT_SYMBOL(scsi_ioctl_reset);
bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
struct scsi_sense_hdr *sshdr)
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 840d96fe81bc..57bcd05605bf 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Changes:
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> 08/23/2000
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 07dfc17d4824..e1da8c70a266 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 1999 Eric Youngdale
* Copyright (C) 2014 Christoph Hellwig
@@ -39,6 +40,18 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
+/*
+ * Size of integrity metadata is usually small, 1 inline sg should
+ * cover normal cases.
+ */
+#ifdef CONFIG_ARCH_NO_SG_CHAIN
+#define SCSI_INLINE_PROT_SG_CNT 0
+#define SCSI_INLINE_SG_CNT 0
+#else
+#define SCSI_INLINE_PROT_SG_CNT 1
+#define SCSI_INLINE_SG_CNT 2
+#endif
+
static struct kmem_cache *scsi_sdb_cache;
static struct kmem_cache *scsi_sense_cache;
static struct kmem_cache *scsi_sense_isadma_cache;
@@ -141,8 +154,6 @@ scsi_set_blocked(struct scsi_cmnd *cmd, int reason)
static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd)
{
- struct scsi_device *sdev = cmd->device;
-
if (cmd->request->rq_flags & RQF_DONTPREP) {
cmd->request->rq_flags &= ~RQF_DONTPREP;
scsi_mq_uninit_cmd(cmd);
@@ -150,7 +161,6 @@ static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd)
WARN_ON_ONCE(true);
}
blk_mq_requeue_request(cmd->request, true);
- put_device(&sdev->sdev_gendev);
}
/**
@@ -189,19 +199,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy)
*/
cmd->result = 0;
- /*
- * Before a SCSI command is dispatched,
- * get_device(&sdev->sdev_gendev) is called and the host,
- * target and device busy counters are increased. Since
- * requeuing a request causes these actions to be repeated and
- * since scsi_device_unbusy() has already been called,
- * put_device(&device->sdev_gendev) must still be called. Call
- * put_device() after blk_mq_requeue_request() to avoid that
- * removal of the SCSI device can start before requeueing has
- * happened.
- */
blk_mq_requeue_request(cmd->request, true);
- put_device(&device->sdev_gendev);
}
/*
@@ -556,9 +554,11 @@ static void scsi_uninit_cmd(struct scsi_cmnd *cmd)
static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd)
{
if (cmd->sdb.table.nents)
- sg_free_table_chained(&cmd->sdb.table, true);
+ sg_free_table_chained(&cmd->sdb.table,
+ SCSI_INLINE_SG_CNT);
if (scsi_prot_sg_count(cmd))
- sg_free_table_chained(&cmd->prot_sdb->table, true);
+ sg_free_table_chained(&cmd->prot_sdb->table,
+ SCSI_INLINE_PROT_SG_CNT);
}
static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd)
@@ -619,7 +619,6 @@ static bool scsi_end_request(struct request *req, blk_status_t error,
blk_mq_run_hw_queues(q, true);
percpu_ref_put(&q->q_usage_counter);
- put_device(&sdev->sdev_gendev);
return false;
}
@@ -992,7 +991,8 @@ static blk_status_t scsi_init_sgtable(struct request *req,
* If sg table allocation fails, requeue request later.
*/
if (unlikely(sg_alloc_table_chained(&sdb->table,
- blk_rq_nr_phys_segments(req), sdb->table.sgl)))
+ blk_rq_nr_phys_segments(req), sdb->table.sgl,
+ SCSI_INLINE_SG_CNT)))
return BLK_STS_RESOURCE;
/*
@@ -1046,7 +1046,8 @@ blk_status_t scsi_init_io(struct scsi_cmnd *cmd)
ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio);
if (sg_alloc_table_chained(&prot_sdb->table, ivecs,
- prot_sdb->table.sgl)) {
+ prot_sdb->table.sgl,
+ SCSI_INLINE_PROT_SG_CNT)) {
ret = BLK_STS_RESOURCE;
goto out_free_sgtables;
}
@@ -1557,9 +1558,9 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
}
/* Size in bytes of the sg-list stored in the scsi-mq command-private data. */
-static unsigned int scsi_mq_sgl_size(struct Scsi_Host *shost)
+static unsigned int scsi_mq_inline_sgl_size(struct Scsi_Host *shost)
{
- return min_t(unsigned int, shost->sg_tablesize, SG_CHUNK_SIZE) *
+ return min_t(unsigned int, shost->sg_tablesize, SCSI_INLINE_SG_CNT) *
sizeof(struct scatterlist);
}
@@ -1613,7 +1614,6 @@ static void scsi_mq_put_budget(struct blk_mq_hw_ctx *hctx)
struct scsi_device *sdev = q->queuedata;
atomic_dec(&sdev->device_busy);
- put_device(&sdev->sdev_gendev);
}
static bool scsi_mq_get_budget(struct blk_mq_hw_ctx *hctx)
@@ -1621,16 +1621,9 @@ static bool scsi_mq_get_budget(struct blk_mq_hw_ctx *hctx)
struct request_queue *q = hctx->queue;
struct scsi_device *sdev = q->queuedata;
- if (!get_device(&sdev->sdev_gendev))
- goto out;
- if (!scsi_dev_queue_ready(q, sdev))
- goto out_put_device;
-
- return true;
+ if (scsi_dev_queue_ready(q, sdev))
+ return true;
-out_put_device:
- put_device(&sdev->sdev_gendev);
-out:
if (atomic_read(&sdev->device_busy) == 0 && !scsi_device_blocked(sdev))
blk_mq_delay_run_hw_queue(hctx, SCSI_QUEUE_DELAY);
return false;
@@ -1749,7 +1742,7 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
if (scsi_host_get_prot(shost)) {
sg = (void *)cmd + sizeof(struct scsi_cmnd) +
shost->hostt->cmd_size;
- cmd->prot_sdb = (void *)sg + scsi_mq_sgl_size(shost);
+ cmd->prot_sdb = (void *)sg + scsi_mq_inline_sgl_size(shost);
}
return 0;
@@ -1770,7 +1763,7 @@ static int scsi_map_queues(struct blk_mq_tag_set *set)
if (shost->hostt->map_queues)
return shost->hostt->map_queues(shost);
- return blk_mq_map_queues(&set->map[0]);
+ return blk_mq_map_queues(&set->map[HCTX_TYPE_DEFAULT]);
}
void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q)
@@ -1843,10 +1836,11 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
{
unsigned int cmd_size, sgl_size;
- sgl_size = scsi_mq_sgl_size(shost);
+ sgl_size = scsi_mq_inline_sgl_size(shost);
cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size + sgl_size;
if (scsi_host_get_prot(shost))
- cmd_size += sizeof(struct scsi_data_buffer) + sgl_size;
+ cmd_size += sizeof(struct scsi_data_buffer) +
+ sizeof(struct scatterlist) * SCSI_INLINE_PROT_SG_CNT;
memset(&shost->tag_set, 0, sizeof(shost->tag_set));
shost->tag_set.ops = &scsi_mq_ops;
@@ -2639,10 +2633,6 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block_nowait);
* a legal transition). When the device is in this state, command processing
* is paused until the device leaves the SDEV_BLOCK state. See also
* scsi_internal_device_unblock().
- *
- * To do: avoid that scsi_send_eh_cmnd() calls queuecommand() after
- * scsi_internal_device_block() has blocked a SCSI device and also
- * remove the rport mutex lock and unlock calls from srp_queuecommand().
*/
static int scsi_internal_device_block(struct scsi_device *sdev)
{
diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c
index bd70339c1242..39b8cc4574b4 100644
--- a/drivers/scsi/scsi_logging.c
+++ b/drivers/scsi/scsi_logging.c
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* scsi_logging.c
*
* Copyright (C) 2014 SUSE Linux Products GmbH
* Copyright (C) 2014 Hannes Reinecke <hare@suse.de>
- *
- * This file is released under the GPLv2
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 50e624fb8307..d7f76fd84256 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -1,22 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* scsi_netlink.c - SCSI Transport Netlink Interface
*
* Copyright (C) 2006 James Smart, Emulex 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
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/time.h>
#include <linux/jiffies.h>
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index 7639df91b110..74ded5f3c236 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* scsi_pm.c Copyright (C) 2010 Alan Stern
*
@@ -175,11 +176,7 @@ static int scsi_bus_resume_common(struct device *dev,
static int scsi_bus_prepare(struct device *dev)
{
- if (scsi_is_sdev_device(dev)) {
- /* sd probing uses async_schedule. Wait until it finishes. */
- async_synchronize_full_domain(&scsi_sd_probe_domain);
-
- } else if (scsi_is_host_device(dev)) {
+ if (scsi_is_host_device(dev)) {
/* Wait until async scanning is finished */
scsi_complete_async_scans();
}
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 5f21547b2ad2..cc2859d76d81 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -175,7 +175,6 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {}
#endif /* CONFIG_PM */
extern struct async_domain scsi_sd_pm_domain;
-extern struct async_domain scsi_sd_probe_domain;
/* scsi_dh.c */
#ifdef CONFIG_SCSI_DH
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 7f0ceb65c3f3..c074631086a4 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -372,7 +372,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
return err;
}
-static int always_match(struct device *dev, void *data)
+static int always_match(struct device *dev, const void *data)
{
return 1;
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 53380e07b40e..058079f915f1 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1129,7 +1129,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
* that no LUN is present, so don't add sdev in these cases.
* Two specific examples are:
* 1) NetApp targets: return PQ=1, PDT=0x1f
- * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved"
+ * 2) IBM/2145 targets: return PQ=1, PDT=0
+ * 3) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved"
* in the UFI 1.0 spec (we cannot rely on reserved bits).
*
* References:
@@ -1143,8 +1144,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
* PDT=00h Direct-access device (floppy)
* PDT=1Fh none (no FDD connected to the requested logical unit)
*/
- if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) &&
- (result[0] & 0x1f) == 0x1f &&
+ if (((result[0] >> 5) == 1 ||
+ (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f)) &&
!scsi_is_wlun(lun)) {
SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev,
"scsi scan: peripheral device type"
diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c
index 546f16299ef9..7259704a7f52 100644
--- a/drivers/scsi/scsi_sysctl.c
+++ b/drivers/scsi/scsi_sysctl.c
@@ -1,6 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2003 Christoph Hellwig.
- * Released under GPL v2.
*/
#include <linux/errno.h>
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 3b119ca0cc0c..64c96c7828ee 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* scsi_sysfs.c
*
@@ -766,8 +767,13 @@ store_state_field(struct device *dev, struct device_attribute *attr,
break;
}
}
- if (!state)
+ switch (state) {
+ case SDEV_RUNNING:
+ case SDEV_OFFLINE:
+ break;
+ default:
return -EINVAL;
+ }
mutex_lock(&sdev->state_mutex);
ret = scsi_device_set_state(sdev, state);
diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c
index 0ff083bbf5b1..0f17e7dac1b0 100644
--- a/drivers/scsi/scsi_trace.c
+++ b/drivers/scsi/scsi_trace.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010 FUJITSU LIMITED
* Copyright (C) 2010 Tomohiro Kusumi <kusumi.tomohiro@jp.fujitsu.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/kernel.h>
#include <linux/trace_seq.h>
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index d7035270d274..2732fa65119c 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1,29 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * ========
- *
* Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
* Add vports, etc
- *
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -147,6 +130,7 @@ static const struct {
{ FCH_EVT_PORT_OFFLINE, "port_offline" },
{ FCH_EVT_PORT_FABRIC, "port_fabric" },
{ FCH_EVT_LINK_UNKNOWN, "link_unknown" },
+ { FCH_EVT_LINK_FPIN, "link_FPIN" },
{ FCH_EVT_VENDOR_UNIQUE, "vendor_unique" },
};
fc_enum_name_search(host_event_code, fc_host_event_code,
@@ -295,6 +279,9 @@ static const struct {
{ FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" },
{ FC_PORT_ROLE_IP_PORT, "IP Port" },
{ FC_PORT_ROLE_FCP_DUMMY_INITIATOR, "FCP Dummy Initiator" },
+ { FC_PORT_ROLE_NVME_INITIATOR, "NVMe Initiator" },
+ { FC_PORT_ROLE_NVME_TARGET, "NVMe Target" },
+ { FC_PORT_ROLE_NVME_DISCOVERY, "NVMe Discovery" },
};
fc_bitfield_name_search(port_roles, fc_port_role_names)
@@ -523,20 +510,23 @@ fc_get_event_number(void)
}
EXPORT_SYMBOL(fc_get_event_number);
-
/**
- * fc_host_post_event - called to post an even on an fc_host.
+ * fc_host_post_fc_event - routine to do the work of posting an event
+ * on an fc_host.
* @shost: host the event occurred on
* @event_number: fc event number obtained from get_fc_event_number()
* @event_code: fc_host event being posted
- * @event_data: 32bits of data for the event being posted
+ * @data_len: amount, in bytes, of event data
+ * @data_buf: pointer to event data
+ * @vendor_id: value for Vendor id
*
* Notes:
* This routine assumes no locks are held on entry.
*/
void
-fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
- enum fc_host_event_code event_code, u32 event_data)
+fc_host_post_fc_event(struct Scsi_Host *shost, u32 event_number,
+ enum fc_host_event_code event_code,
+ u32 data_len, char *data_buf, u64 vendor_id)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
@@ -545,12 +535,15 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
u32 len;
int err;
+ if (!data_buf || data_len < 4)
+ data_len = 0;
+
if (!scsi_nl_sock) {
err = -ENOENT;
goto send_fail;
}
- len = FC_NL_MSGALIGN(sizeof(*event));
+ len = FC_NL_MSGALIGN(sizeof(*event) + data_len);
skb = nlmsg_new(len, GFP_KERNEL);
if (!skb) {
@@ -568,12 +561,13 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
FC_NL_ASYNC_EVENT, len);
event->seconds = ktime_get_real_seconds();
- event->vendor_id = 0;
+ event->vendor_id = vendor_id;
event->host_no = shost->host_no;
- event->event_datalen = sizeof(u32); /* bytes */
+ event->event_datalen = data_len; /* bytes */
event->event_num = event_number;
event->event_code = event_code;
- event->event_data = event_data;
+ if (data_len)
+ memcpy(&event->event_data, data_buf, data_len);
nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
GFP_KERNEL);
@@ -586,14 +580,35 @@ send_fail:
printk(KERN_WARNING
"%s: Dropped Event : host %d %s data 0x%08x - err %d\n",
__func__, shost->host_no,
- (name) ? name : "<unknown>", event_data, err);
+ (name) ? name : "<unknown>",
+ (data_len) ? *((u32 *)data_buf) : 0xFFFFFFFF, err);
return;
}
+EXPORT_SYMBOL(fc_host_post_fc_event);
+
+/**
+ * fc_host_post_event - called to post an even on an fc_host.
+ * @shost: host the event occurred on
+ * @event_number: fc event number obtained from get_fc_event_number()
+ * @event_code: fc_host event being posted
+ * @event_data: 32bits of data for the event being posted
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ */
+void
+fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
+ enum fc_host_event_code event_code, u32 event_data)
+{
+ fc_host_post_fc_event(shost, event_number, event_code,
+ (u32)sizeof(u32), (char *)&event_data, 0);
+}
EXPORT_SYMBOL(fc_host_post_event);
/**
- * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host
+ * fc_host_post_vendor_event - called to post a vendor unique event
+ * on an fc_host
* @shost: host the event occurred on
* @event_number: fc event number obtained from get_fc_event_number()
* @data_len: amount, in bytes, of vendor unique data
@@ -607,56 +622,27 @@ void
fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
u32 data_len, char * data_buf, u64 vendor_id)
{
- struct sk_buff *skb;
- struct nlmsghdr *nlh;
- struct fc_nl_event *event;
- u32 len;
- int err;
-
- if (!scsi_nl_sock) {
- err = -ENOENT;
- goto send_vendor_fail;
- }
-
- len = FC_NL_MSGALIGN(sizeof(*event) + data_len);
-
- skb = nlmsg_new(len, GFP_KERNEL);
- if (!skb) {
- err = -ENOBUFS;
- goto send_vendor_fail;
- }
-
- nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0);
- if (!nlh) {
- err = -ENOBUFS;
- goto send_vendor_fail_skb;
- }
- event = nlmsg_data(nlh);
-
- INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
- FC_NL_ASYNC_EVENT, len);
- event->seconds = ktime_get_real_seconds();
- event->vendor_id = vendor_id;
- event->host_no = shost->host_no;
- event->event_datalen = data_len; /* bytes */
- event->event_num = event_number;
- event->event_code = FCH_EVT_VENDOR_UNIQUE;
- memcpy(&event->event_data, data_buf, data_len);
-
- nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
- GFP_KERNEL);
- return;
-
-send_vendor_fail_skb:
- kfree_skb(skb);
-send_vendor_fail:
- printk(KERN_WARNING
- "%s: Dropped Event : host %d vendor_unique - err %d\n",
- __func__, shost->host_no, err);
- return;
+ fc_host_post_fc_event(shost, event_number, FCH_EVT_VENDOR_UNIQUE,
+ data_len, data_buf, vendor_id);
}
EXPORT_SYMBOL(fc_host_post_vendor_event);
+/**
+ * fc_host_rcv_fpin - routine to process a received FPIN.
+ * @shost: host the FPIN was received on
+ * @fpin_len: length of FPIN payload, in bytes
+ * @fpin_buf: pointer to FPIN payload
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ */
+void
+fc_host_fpin_rcv(struct Scsi_Host *shost, u32 fpin_len, char *fpin_buf)
+{
+ fc_host_post_fc_event(shost, fc_get_event_number(),
+ FCH_EVT_LINK_FPIN, fpin_len, fpin_buf, 0);
+}
+EXPORT_SYMBOL(fc_host_fpin_rcv);
static __init int fc_transport_init(void)
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 0a82e93566dc..417b868d8735 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* iSCSI transport class definitions
*
@@ -5,20 +6,6 @@
* Copyright (C) Mike Christie, 2004 - 2005
* Copyright (C) Dmitry Yusupov, 2004 - 2005
* Copyright (C) Alex Aizman, 2004 - 2005
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/mutex.h>
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 60f1a81d2034..ef138c57e2a6 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -1,6 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2005-2006 Dell Inc.
- * Released under GPL v2.
*
* Serial Attached SCSI (SAS) transport class.
*
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 40b85b752b79..f8661062ef95 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Parallel SCSI (SPI) transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
* Copyright (c) 2004, 2005 James Bottomley <James.Bottomley@SteelEye.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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/ctype.h>
#include <linux/init.h>
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
index 4e46fdb2d7c9..d4d1104fac99 100644
--- a/drivers/scsi/scsi_transport_srp.c
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -1,22 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCSI RDMA (SRP) transport class
*
* Copyright (C) 2007 FUJITA Tomonori <tomof@acm.org>
- *
- * 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, version 2 of the
- * License.
- *
- * 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.
- *
- * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
*/
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 2b2bc4b49d78..149d406aacc9 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* sd.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
@@ -567,6 +568,7 @@ static struct scsi_driver sd_template = {
.name = "sd",
.owner = THIS_MODULE,
.probe = sd_probe,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
.remove = sd_remove,
.shutdown = sd_shutdown,
.pm = &sd_pm_ops,
@@ -2256,22 +2258,6 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
#define READ_CAPACITY_RETRIES_ON_RESET 10
-/*
- * Ensure that we don't overflow sector_t when CONFIG_LBDAF is not set
- * and the reported logical block size is bigger than 512 bytes. Note
- * that last_sector is a u64 and therefore logical_to_sectors() is not
- * applicable.
- */
-static bool sd_addressable_capacity(u64 lba, unsigned int sector_size)
-{
- u64 last_sector = (lba + 1ULL) << (ilog2(sector_size) - 9);
-
- if (sizeof(sector_t) == 4 && last_sector > U32_MAX)
- return false;
-
- return true;
-}
-
static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
unsigned char *buffer)
{
@@ -2337,14 +2323,6 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
return -ENODEV;
}
- if (!sd_addressable_capacity(lba, sector_size)) {
- sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
- "kernel compiled with support for large block "
- "devices.\n");
- sdkp->capacity = 0;
- return -EOVERFLOW;
- }
-
/* Logical blocks per physical block exponent */
sdkp->physical_block_size = (1 << (buffer[13] & 0xf)) * sector_size;
@@ -2426,14 +2404,6 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
return sector_size;
}
- if (!sd_addressable_capacity(lba, sector_size)) {
- sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
- "kernel compiled with support for large block "
- "devices.\n");
- sdkp->capacity = 0;
- return -EOVERFLOW;
- }
-
sdkp->capacity = lba + 1;
sdkp->physical_block_size = sector_size;
return sector_size;
@@ -2603,7 +2573,6 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
int res;
struct scsi_device *sdp = sdkp->device;
struct scsi_mode_data data;
- int disk_ro = get_disk_ro(sdkp->disk);
int old_wp = sdkp->write_prot;
set_disk_ro(sdkp->disk, 0);
@@ -2644,7 +2613,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
"Test WP failed, assume Write Enabled\n");
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
- set_disk_ro(sdkp->disk, sdkp->write_prot || disk_ro);
+ set_disk_ro(sdkp->disk, sdkp->write_prot);
if (sdkp->first_scan || old_wp != sdkp->write_prot) {
sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
sdkp->write_prot ? "on" : "off");
@@ -3284,68 +3253,6 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
return 0;
}
-/*
- * The asynchronous part of sd_probe
- */
-static void sd_probe_async(void *data, async_cookie_t cookie)
-{
- struct scsi_disk *sdkp = data;
- struct scsi_device *sdp;
- struct gendisk *gd;
- u32 index;
- struct device *dev;
-
- sdp = sdkp->device;
- gd = sdkp->disk;
- index = sdkp->index;
- dev = &sdp->sdev_gendev;
-
- gd->major = sd_major((index & 0xf0) >> 4);
- gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
-
- gd->fops = &sd_fops;
- gd->private_data = &sdkp->driver;
- gd->queue = sdkp->device->request_queue;
-
- /* defaults, until the device tells us otherwise */
- sdp->sector_size = 512;
- sdkp->capacity = 0;
- sdkp->media_present = 1;
- sdkp->write_prot = 0;
- sdkp->cache_override = 0;
- sdkp->WCE = 0;
- sdkp->RCD = 0;
- sdkp->ATO = 0;
- sdkp->first_scan = 1;
- sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
-
- sd_revalidate_disk(gd);
-
- gd->flags = GENHD_FL_EXT_DEVT;
- if (sdp->removable) {
- gd->flags |= GENHD_FL_REMOVABLE;
- gd->events |= DISK_EVENT_MEDIA_CHANGE;
- }
-
- blk_pm_runtime_init(sdp->request_queue, dev);
- device_add_disk(dev, gd, NULL);
- if (sdkp->capacity)
- sd_dif_config_host(sdkp);
-
- sd_revalidate_disk(gd);
-
- if (sdkp->security) {
- sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit);
- if (sdkp->opal_dev)
- sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
- }
-
- sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
- sdp->removable ? "removable " : "");
- scsi_autopm_put_device(sdp);
- put_device(&sdkp->dev);
-}
-
/**
* sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
@@ -3435,8 +3342,50 @@ static int sd_probe(struct device *dev)
get_device(dev);
dev_set_drvdata(dev, sdkp);
- get_device(&sdkp->dev); /* prevent release before async_schedule */
- async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);
+ gd->major = sd_major((index & 0xf0) >> 4);
+ gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+
+ gd->fops = &sd_fops;
+ gd->private_data = &sdkp->driver;
+ gd->queue = sdkp->device->request_queue;
+
+ /* defaults, until the device tells us otherwise */
+ sdp->sector_size = 512;
+ sdkp->capacity = 0;
+ sdkp->media_present = 1;
+ sdkp->write_prot = 0;
+ sdkp->cache_override = 0;
+ sdkp->WCE = 0;
+ sdkp->RCD = 0;
+ sdkp->ATO = 0;
+ sdkp->first_scan = 1;
+ sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS;
+
+ sd_revalidate_disk(gd);
+
+ gd->flags = GENHD_FL_EXT_DEVT;
+ if (sdp->removable) {
+ gd->flags |= GENHD_FL_REMOVABLE;
+ gd->events |= DISK_EVENT_MEDIA_CHANGE;
+ gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
+ }
+
+ blk_pm_runtime_init(sdp->request_queue, dev);
+ device_add_disk(dev, gd, NULL);
+ if (sdkp->capacity)
+ sd_dif_config_host(sdkp);
+
+ sd_revalidate_disk(gd);
+
+ if (sdkp->security) {
+ sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit);
+ if (sdkp->opal_dev)
+ sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
+ }
+
+ sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
+ sdp->removable ? "removable " : "");
+ scsi_autopm_put_device(sdp);
return 0;
@@ -3472,7 +3421,6 @@ static int sd_remove(struct device *dev)
scsi_autopm_get_device(sdkp->device);
async_synchronize_full_domain(&scsi_sd_pm_domain);
- async_synchronize_full_domain(&scsi_sd_probe_domain);
device_del(&sdkp->dev);
del_gendisk(sdkp->disk);
sd_shutdown(dev);
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index db72c82486e3..4cadb26070a8 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -1,23 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* sd_dif.c - SCSI Data Integrity Field
*
* Copyright (C) 2007, 2008 Oracle Corporation
* Written by: Martin K. Petersen <martin.petersen@oracle.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
*/
#include <linux/blkdev.h>
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index a340af797a85..7334024b64f1 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCSI Zoned Block commands
*
@@ -5,21 +6,6 @@
* Written by: Hannes Reinecke <hare@suse.de>
* Modified by: Damien Le Moal <damien.lemoal@hgst.com>
* Modified by: Shaun Tancheff <shaun.tancheff@seagate.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
*/
#include <linux/blkdev.h>
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 0fc39224ce1e..c2afba2a5414 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -1,25 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* SCSI Enclosure Services
*
* Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
- *
-**-----------------------------------------------------------------------------
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** version 2 as published by the Free Software Foundation.
-**
-** 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.
-**
-** 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
-*/
+ */
#include <linux/slab.h>
#include <linux/module.h>
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index d3f15319b9b3..cce757506383 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* History:
* Started: Aug 9 by Lawrence Foard (entropy@world.std.com),
@@ -8,12 +9,6 @@
* Copyright (C) 1992 Lawrence Foard
* Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2014 Douglas Gilbert
- *
- * 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, or (at your option)
- * any later version.
- *
*/
static int sg_version_num = 30536; /* 2 digits for each component */
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 82ed99848378..22302612e032 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* sim710.c - Copyright (C) 1999 Richard Hirst <richard@sleepie.demon.co.uk>
*
*----------------------------------------------------------------------------
- * 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.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*----------------------------------------------------------------------------
*
* MCA card detection code by Trent McNair. (now deleted)
@@ -23,7 +11,6 @@
* Auto probing of EISA config space from Trevor Hemsley.
*
* Rewritten to use 53c700.c by James.Bottomley@SteelEye.com
- *
*/
#include <linux/module.h>
diff --git a/drivers/scsi/smartpqi/Makefile b/drivers/scsi/smartpqi/Makefile
index a03a6edb0060..28985e508b5c 100644
--- a/drivers/scsi/smartpqi/Makefile
+++ b/drivers/scsi/smartpqi/Makefile
@@ -1,2 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_SCSI_SMARTPQI) += smartpqi.o
smartpqi-objs := smartpqi_init.o smartpqi_sis.o smartpqi_sas_transport.o
diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index af962368818b..e8e768849c70 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -1,18 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016-2017 Microsemi Corporation
+ * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries
+ * Copyright (c) 2016-2018 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
- * 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; version 2 of the License.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
- *
- * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ * Questions/Comments/Bugfixes to storagedev@microchip.com
*
*/
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index 75ec43aa8df3..8fd5ffc55792 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1,18 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016-2017 Microsemi Corporation
+ * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries
+ * Copyright (c) 2016-2018 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
- * 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; version 2 of the License.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
- *
- * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ * Questions/Comments/Bugfixes to storagedev@microchip.com
*
*/
@@ -40,11 +33,11 @@
#define BUILD_TIMESTAMP
#endif
-#define DRIVER_VERSION "1.2.4-070"
+#define DRIVER_VERSION "1.2.6-015"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 2
-#define DRIVER_RELEASE 4
-#define DRIVER_REVISION 70
+#define DRIVER_RELEASE 6
+#define DRIVER_REVISION 15
#define DRIVER_NAME "Microsemi PQI Driver (v" \
DRIVER_VERSION BUILD_TIMESTAMP ")"
@@ -2762,16 +2755,25 @@ static void pqi_process_raid_io_error(struct pqi_io_request *io_request)
scsi_normalize_sense(error_info->data,
sense_data_length, &sshdr) &&
sshdr.sense_key == HARDWARE_ERROR &&
- sshdr.asc == 0x3e &&
- sshdr.ascq == 0x1) {
+ sshdr.asc == 0x3e) {
struct pqi_ctrl_info *ctrl_info = shost_to_hba(scmd->device->host);
struct pqi_scsi_dev *device = scmd->device->hostdata;
- if (printk_ratelimit())
- scmd_printk(KERN_ERR, scmd, "received 'logical unit failure' from controller for scsi %d:%d:%d:%d\n",
- ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun);
- pqi_take_device_offline(scmd->device, "RAID");
- host_byte = DID_NO_CONNECT;
+ switch (sshdr.ascq) {
+ case 0x1: /* LOGICAL UNIT FAILURE */
+ if (printk_ratelimit())
+ scmd_printk(KERN_ERR, scmd, "received 'logical unit failure' from controller for scsi %d:%d:%d:%d\n",
+ ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun);
+ pqi_take_device_offline(scmd->device, "RAID");
+ host_byte = DID_NO_CONNECT;
+ break;
+
+ default: /* See http://www.t10.org/lists/asc-num.htm#ASC_3E */
+ if (printk_ratelimit())
+ scmd_printk(KERN_ERR, scmd, "received unhandled error %d from controller for scsi %d:%d:%d:%d\n",
+ sshdr.ascq, ctrl_info->scsi_host->host_no, device->bus, device->target, device->lun);
+ break;
+ }
}
if (sense_data_length > SCSI_SENSE_BUFFERSIZE)
@@ -4044,8 +4046,10 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
return -ETIMEDOUT;
msecs_blocked =
jiffies_to_msecs(jiffies - start_jiffies);
- if (msecs_blocked >= timeout_msecs)
- return -ETIMEDOUT;
+ if (msecs_blocked >= timeout_msecs) {
+ rc = -ETIMEDOUT;
+ goto out;
+ }
timeout_msecs -= msecs_blocked;
}
}
@@ -5660,9 +5664,11 @@ static int pqi_lun_reset(struct pqi_ctrl_info *ctrl_info,
return rc;
}
+/* Performs a reset at the LUN level. */
+
#define PQI_LUN_RESET_RETRIES 3
#define PQI_LUN_RESET_RETRY_INTERVAL_MSECS 10000
-/* Performs a reset at the LUN level. */
+#define PQI_LUN_RESET_PENDING_IO_TIMEOUT_SECS 120
static int _pqi_device_reset(struct pqi_ctrl_info *ctrl_info,
struct pqi_scsi_dev *device)
@@ -5673,12 +5679,12 @@ static int _pqi_device_reset(struct pqi_ctrl_info *ctrl_info,
for (retries = 0;;) {
rc = pqi_lun_reset(ctrl_info, device);
- if (rc != -EAGAIN ||
- ++retries > PQI_LUN_RESET_RETRIES)
+ if (rc != -EAGAIN || ++retries > PQI_LUN_RESET_RETRIES)
break;
msleep(PQI_LUN_RESET_RETRY_INTERVAL_MSECS);
}
- timeout_secs = rc ? PQI_LUN_RESET_TIMEOUT_SECS : NO_TIMEOUT;
+
+ timeout_secs = rc ? PQI_LUN_RESET_PENDING_IO_TIMEOUT_SECS : NO_TIMEOUT;
rc |= pqi_device_wait_for_pending_io(ctrl_info, device, timeout_secs);
@@ -5707,6 +5713,7 @@ static int pqi_device_reset(struct pqi_ctrl_info *ctrl_info,
pqi_device_reset_done(device);
mutex_unlock(&ctrl_info->lun_reset_mutex);
+
return rc;
}
@@ -5737,6 +5744,7 @@ static int pqi_eh_device_reset_handler(struct scsi_cmnd *scmd)
pqi_wait_until_ofa_finished(ctrl_info);
rc = pqi_device_reset(ctrl_info, device);
+
out:
dev_err(&ctrl_info->pci_dev->dev,
"reset of scsi %d:%d:%d:%d: %s\n",
@@ -5795,7 +5803,7 @@ static int pqi_map_queues(struct Scsi_Host *shost)
{
struct pqi_ctrl_info *ctrl_info = shost_to_hba(shost);
- return blk_mq_pci_map_queues(&shost->tag_set.map[0],
+ return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
ctrl_info->pci_dev, 0);
}
@@ -7285,7 +7293,7 @@ static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info)
else
mask = DMA_BIT_MASK(32);
- rc = dma_set_mask(&ctrl_info->pci_dev->dev, mask);
+ rc = dma_set_mask_and_coherent(&ctrl_info->pci_dev->dev, mask);
if (rc) {
dev_err(&ctrl_info->pci_dev->dev, "failed to set DMA mask\n");
goto disable_device;
@@ -7948,6 +7956,22 @@ static const struct pci_device_id pqi_pci_id_table[] = {
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0x1104)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0x1105)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0x1106)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+ 0x193d, 0x1107)
+ },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
0x193d, 0x8460)
},
{
diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c
index 0e4ef215115f..5cca1b9ef1f1 100644
--- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c
+++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c
@@ -1,18 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016-2017 Microsemi Corporation
+ * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries
+ * Copyright (c) 2016-2018 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
- * 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; version 2 of the License.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
- *
- * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ * Questions/Comments/Bugfixes to storagedev@microchip.com
*
*/
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c b/drivers/scsi/smartpqi/smartpqi_sis.c
index dcd11c6418cc..f0d6e88ba2c1 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.c
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -1,18 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016-2017 Microsemi Corporation
+ * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries
+ * Copyright (c) 2016-2018 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
- * 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; version 2 of the License.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
- *
- * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ * Questions/Comments/Bugfixes to storagedev@microchip.com
*
*/
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h b/drivers/scsi/smartpqi/smartpqi_sis.h
index d018cb9c3f82..86b0e484d921 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.h
+++ b/drivers/scsi/smartpqi/smartpqi_sis.h
@@ -1,18 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* driver for Microsemi PQI-based storage controllers
- * Copyright (c) 2016-2017 Microsemi Corporation
+ * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries
+ * Copyright (c) 2016-2018 Microsemi Corporation
* Copyright (c) 2016 PMC-Sierra, Inc.
*
- * 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; version 2 of the License.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
- *
- * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
+ * Questions/Comments/Bugfixes to storagedev@microchip.com
*
*/
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
index 1f9a087daf69..aef4881d8e21 100644
--- a/drivers/scsi/sni_53c710.c
+++ b/drivers/scsi/sni_53c710.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* -*- mode: c; c-basic-offset: 8 -*- */
/* SNI RM driver
@@ -5,19 +6,6 @@
* Copyright (C) 2001 by James.Bottomley@HansenPartnership.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.
-**
-** 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., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**-----------------------------------------------------------------------------
*/
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 039c27c2d7b3..4664fdf75c0f 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* sr.c Copyright (C) 1992 David Giller
* Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
@@ -716,6 +717,7 @@ static int sr_probe(struct device *dev)
disk->fops = &sr_bdops;
disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST;
+ disk->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT;
blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 19c022e66d63..e3266a64a477 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
file Documentation/scsi/st.txt for more information.
@@ -227,7 +228,6 @@ static DEFINE_IDR(st_index_idr);
-#include "osst_detect.h"
#ifndef SIGS_FROM_OSST
#define SIGS_FROM_OSST \
{"OnStream", "SC-", "", "osst"}, \
@@ -4266,9 +4266,10 @@ static int st_probe(struct device *dev)
if (SDp->type != TYPE_TAPE)
return -ENODEV;
if ((stp = st_incompatible(SDp))) {
- sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n");
sdev_printk(KERN_INFO, SDp,
- "st: The suggested driver is %s.\n", stp);
+ "OnStream tapes are no longer supported;\n");
+ sdev_printk(KERN_INFO, SDp,
+ "please mail to linux-scsi@vger.kernel.org.\n");
return -ENODEV;
}
@@ -4922,7 +4923,8 @@ 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_fast(uaddr, nr_pages, rw == READ, pages);
+ res = get_user_pages_fast(uaddr, nr_pages, rw == READ ? FOLL_WRITE : 0,
+ pages);
/* Errors and no page mapped should return here */
if (res < nr_pages)
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index f6bef7ad65e7..33287b6bdf0e 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -1,16 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SuperTrak EX Series Storage Controller driver for Linux
*
* 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
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Written By:
* Ed Lin <promise_linux@promise.com>
- *
*/
#include <linux/init.h>
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 8472de1007ff..c2b6a0ca6933 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2009, Microsoft Corporation.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * 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., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
* Authors:
* Haiyang Zhang <haiyangz@microsoft.com>
* Hank Janssen <hjanssen@microsoft.com>
@@ -387,6 +375,7 @@ enum storvsc_request_type {
static int storvsc_ringbuffer_size = (128 * 1024);
static u32 max_outstanding_req_per_channel;
+static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth);
static int storvsc_vcpus_per_sub_channel = 4;
@@ -1711,6 +1700,7 @@ static struct scsi_host_template scsi_driver = {
.dma_boundary = PAGE_SIZE-1,
.no_write_same = 1,
.track_queue_depth = 1,
+ .change_queue_depth = storvsc_change_queue_depth,
};
enum {
@@ -1917,6 +1907,15 @@ err_out0:
return ret;
}
+/* Change a scsi target's queue depth */
+static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+ if (queue_depth > scsi_driver.can_queue)
+ queue_depth = scsi_driver.can_queue;
+
+ return scsi_change_queue_depth(sdev, queue_depth);
+}
+
static int storvsc_remove(struct hv_device *dev)
{
struct storvsc_device *stor_device = hv_get_drvdata(dev);
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 95a7ea7eefa0..3d80ab67a626 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
*
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index c9a55d0f076d..440a73eae647 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* sun3x_esp.c: ESP front-end for Sun3x systems.
*
* Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index c71bd01fef94..964130d2c8a6 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/* sun_esp.c: ESP front-end for Sparc SBUS systems.
*
* Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
diff --git a/drivers/scsi/sym53c8xx_2/Makefile b/drivers/scsi/sym53c8xx_2/Makefile
index 873e8ced8252..0751e2a0cd82 100644
--- a/drivers/scsi/sym53c8xx_2/Makefile
+++ b/drivers/scsi/sym53c8xx_2/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
# Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver.
sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_nvram.o
diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
index 62d29cfac9e4..11f5dc29aa59 100644
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYM53C8XX_H
diff --git a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h
index defccc477d1e..317289ee04a7 100644
--- a/drivers/scsi/sym53c8xx_2/sym_defs.h
+++ b/drivers/scsi/sym53c8xx_2/sym_defs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYM_DEFS_H
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c
index 91db17727963..6d7651a7847e 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw.c
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sym_glue.h"
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.h b/drivers/scsi/sym53c8xx_2/sym_fw.h
index ae7e0f9e93fc..bbba011e7612 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYM_FW_H
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw1.h b/drivers/scsi/sym53c8xx_2/sym_fw1.h
index 63952ee300b5..d98ec67f0aae 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw1.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw1.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h
index c87d72443a16..4d1779b2a409 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw2.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 57f6d63e4c40..2ca018ce796f 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -22,20 +23,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/ctype.h>
#include <linux/init.h>
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
index e34801ae5d69..7d5c9b988b5b 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYM_GLUE_H
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index 0a2a54517b15..a428cae4535b 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -22,20 +23,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/slab.h>
@@ -3072,6 +3059,7 @@ static void sym_sir_bad_scsi_status(struct sym_hcb *np, int num, struct sym_ccb
sym_print_addr(cp->cmd, "%s\n",
s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n");
}
+ /* fall through */
default: /* S_INT, S_INT_COND_MET, S_CONFLICT */
sym_complete_error (np, cp);
break;
@@ -4632,6 +4620,7 @@ static void sym_int_sir(struct sym_hcb *np)
* Negotiation failed.
* Target does not want answer message.
*/
+ /* fall through */
case SIR_NEGO_PROTO:
sym_nego_default(np, tp, cp);
goto out;
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h
index a141b1758033..9231a2899064 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.h
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/gfp.h>
diff --git a/drivers/scsi/sym53c8xx_2/sym_malloc.c b/drivers/scsi/sym53c8xx_2/sym_malloc.c
index 6f9af0de7ec3..eb5c045c7c59 100644
--- a/drivers/scsi/sym53c8xx_2/sym_malloc.c
+++ b/drivers/scsi/sym53c8xx_2/sym_malloc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sym_glue.h"
diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h
index 96c15145902c..ef419b7ec3e9 100644
--- a/drivers/scsi/sym53c8xx_2/sym_misc.h
+++ b/drivers/scsi/sym53c8xx_2/sym_misc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYM_MISC_H
diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c
index 5662fbb3ff60..dd3f07b31612 100644
--- a/drivers/scsi/sym53c8xx_2/sym_nvram.c
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sym_glue.h"
@@ -708,6 +695,7 @@ static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
data, len);
if (!x)
break;
+ /* fall through */
default:
x = sym_read_T93C46_nvram(np, nvram);
break;
diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.h b/drivers/scsi/sym53c8xx_2/sym_nvram.h
index bdfbbb083b69..d07da39cc240 100644
--- a/drivers/scsi/sym53c8xx_2/sym_nvram.h
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
@@ -21,20 +22,6 @@
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYM_NVRAM_H
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 6db37cf306b0..0b845ab7c3bf 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -99,6 +99,7 @@ config SCSI_UFS_DWC_TC_PLATFORM
config SCSI_UFS_QCOM
tristate "QCOM specific hooks to UFS controller platform driver"
depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
+ select RESET_CONTROLLER
help
This selects the QCOM specific additions to UFSHCD platform driver.
UFS host on QCOM needs some vendor specific configuration before
@@ -108,6 +109,20 @@ config SCSI_UFS_QCOM
Select this if you have UFS controller on QCOM chipset.
If unsure, say N.
+config SCSI_UFS_MEDIATEK
+ tristate "Mediatek specific hooks to UFS controller platform driver"
+ depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK
+ select PHY_MTK_UFS
+ help
+ This selects the Mediatek specific additions to UFSHCD platform driver.
+ UFS host on Mediatek needs some vendor specific configuration before
+ accessing the hardware which includes PHY configuration and vendor
+ specific registers.
+
+ Select this if you have UFS controller on Mediatek chipset.
+
+ If unsure, say N.
+
config SCSI_UFS_HISI
tristate "Hisilicon specific hooks to UFS controller platform driver"
depends on (ARCH_HISI || COMPILE_TEST) && SCSI_UFSHCD_PLATFORM
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index a3bd70c3652c..2a9097939bcb 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -10,3 +10,4 @@ ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o
+obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o
diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 4a37b4f57164..86dbb723f3ac 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -17,7 +17,8 @@
#include "ufshcd-pltfrm.h"
-#define CDNS_UFS_REG_HCLKDIV 0xFC
+#define CDNS_UFS_REG_HCLKDIV 0xFC
+#define CDNS_UFS_REG_PHY_XCFGD1 0x113C
/**
* Sets HCLKDIV register value based on the core_clk
@@ -77,11 +78,66 @@ static int cdns_ufs_setup_clocks(struct ufs_hba *hba, bool on,
return cdns_ufs_set_hclkdiv(hba);
}
-static struct ufs_hba_variant_ops cdns_pltfm_hba_vops = {
+/**
+ * cdns_ufs_init - performs additional ufs initialization
+ * @hba: host controller instance
+ *
+ * Returns status of initialization
+ */
+static int cdns_ufs_init(struct ufs_hba *hba)
+{
+ int status = 0;
+
+ if (hba->vops && hba->vops->phy_initialization)
+ status = hba->vops->phy_initialization(hba);
+
+ return status;
+}
+
+/**
+ * cdns_ufs_m31_16nm_phy_initialization - performs m31 phy initialization
+ * @hba: host controller instance
+ *
+ * Always returns 0
+ */
+static int cdns_ufs_m31_16nm_phy_initialization(struct ufs_hba *hba)
+{
+ u32 data;
+
+ /* Increase RX_Advanced_Min_ActivateTime_Capability */
+ data = ufshcd_readl(hba, CDNS_UFS_REG_PHY_XCFGD1);
+ data |= BIT(24);
+ ufshcd_writel(hba, data, CDNS_UFS_REG_PHY_XCFGD1);
+
+ return 0;
+}
+
+static const struct ufs_hba_variant_ops cdns_ufs_pltfm_hba_vops = {
+ .name = "cdns-ufs-pltfm",
+ .setup_clocks = cdns_ufs_setup_clocks,
+};
+
+static const struct ufs_hba_variant_ops cdns_ufs_m31_16nm_pltfm_hba_vops = {
.name = "cdns-ufs-pltfm",
+ .init = cdns_ufs_init,
.setup_clocks = cdns_ufs_setup_clocks,
+ .phy_initialization = cdns_ufs_m31_16nm_phy_initialization,
+};
+
+static const struct of_device_id cdns_ufs_of_match[] = {
+ {
+ .compatible = "cdns,ufshc",
+ .data = &cdns_ufs_pltfm_hba_vops,
+ },
+ {
+ .compatible = "cdns,ufshc-m31-16nm",
+ .data = &cdns_ufs_m31_16nm_pltfm_hba_vops,
+ },
+ { },
};
+MODULE_DEVICE_TABLE(of, cdns_ufs_of_match);
+
/**
* cdns_ufs_pltfrm_probe - probe routine of the driver
* @pdev: pointer to platform device handle
@@ -91,10 +147,15 @@ static struct ufs_hba_variant_ops cdns_pltfm_hba_vops = {
static int cdns_ufs_pltfrm_probe(struct platform_device *pdev)
{
int err;
+ const struct of_device_id *of_id;
+ struct ufs_hba_variant_ops *vops;
struct device *dev = &pdev->dev;
+ of_id = of_match_node(cdns_ufs_of_match, dev->of_node);
+ vops = (struct ufs_hba_variant_ops *)of_id->data;
+
/* Perform generic probe */
- err = ufshcd_pltfrm_init(pdev, &cdns_pltfm_hba_vops);
+ err = ufshcd_pltfrm_init(pdev, vops);
if (err)
dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
@@ -115,13 +176,6 @@ static int cdns_ufs_pltfrm_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id cdns_ufs_of_match[] = {
- { .compatible = "cdns,ufshc" },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, cdns_ufs_of_match);
-
static const struct dev_pm_ops cdns_ufs_dev_pm_ops = {
.suspend = ufshcd_pltfrm_suspend,
.resume = ufshcd_pltfrm_resume,
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 2f41722a8c28..67a6a61154b7 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synopsys G210 Test Chip driver
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include "ufshcd.h"
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
index 6dfe5a9206e9..a1268e4f44d6 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synopsys G210 Test Chip driver
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/kernel.h>
diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c
index 3a8bc6d9cb5b..f954a68f6b4c 100644
--- a/drivers/scsi/ufs/tc-dwc-g210.c
+++ b/drivers/scsi/ufs/tc-dwc-g210.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Synopsys G210 Test Chip driver
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include "ufshcd.h"
diff --git a/drivers/scsi/ufs/tc-dwc-g210.h b/drivers/scsi/ufs/tc-dwc-g210.h
index fb177db1227d..5a506da03f4a 100644
--- a/drivers/scsi/ufs/tc-dwc-g210.h
+++ b/drivers/scsi/ufs/tc-dwc-g210.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Synopsys G210 Test Chip driver
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _TC_DWC_G210_H
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index 0e855b5afe82..f4d1dca962c4 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -1,11 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* HiSilicon Hixxxx UFS Driver
*
* Copyright (c) 2016-2017 Linaro Ltd.
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
- *
- * Released under the GPLv2 only.
- * SPDX-License-Identifier: GPL-2.0
*/
#include <linux/time.h>
@@ -293,108 +291,7 @@ static int ufs_hisi_link_startup_notify(struct ufs_hba *hba,
return err;
}
-struct ufs_hisi_dev_params {
- u32 pwm_rx_gear; /* pwm rx gear to work in */
- u32 pwm_tx_gear; /* pwm tx gear to work in */
- u32 hs_rx_gear; /* hs rx gear to work in */
- u32 hs_tx_gear; /* hs tx gear to work in */
- u32 rx_lanes; /* number of rx lanes */
- u32 tx_lanes; /* number of tx lanes */
- u32 rx_pwr_pwm; /* rx pwm working pwr */
- u32 tx_pwr_pwm; /* tx pwm working pwr */
- u32 rx_pwr_hs; /* rx hs working pwr */
- u32 tx_pwr_hs; /* tx hs working pwr */
- u32 hs_rate; /* rate A/B to work in HS */
- u32 desired_working_mode;
-};
-
-static int ufs_hisi_get_pwr_dev_param(
- struct ufs_hisi_dev_params *hisi_param,
- struct ufs_pa_layer_attr *dev_max,
- struct ufs_pa_layer_attr *agreed_pwr)
-{
- int min_hisi_gear;
- int min_dev_gear;
- bool is_dev_sup_hs = false;
- bool is_hisi_max_hs = false;
-
- if (dev_max->pwr_rx == FASTAUTO_MODE || dev_max->pwr_rx == FAST_MODE)
- is_dev_sup_hs = true;
-
- if (hisi_param->desired_working_mode == FAST) {
- is_hisi_max_hs = true;
- min_hisi_gear = min_t(u32, hisi_param->hs_rx_gear,
- hisi_param->hs_tx_gear);
- } else {
- min_hisi_gear = min_t(u32, hisi_param->pwm_rx_gear,
- hisi_param->pwm_tx_gear);
- }
-
- /*
- * device doesn't support HS but
- * hisi_param->desired_working_mode is HS,
- * thus device and hisi_param don't agree
- */
- if (!is_dev_sup_hs && is_hisi_max_hs) {
- pr_err("%s: device not support HS\n", __func__);
- return -ENOTSUPP;
- } else if (is_dev_sup_hs && is_hisi_max_hs) {
- /*
- * since device supports HS, it supports FAST_MODE.
- * since hisi_param->desired_working_mode is also HS
- * then final decision (FAST/FASTAUTO) is done according
- * to hisi_params as it is the restricting factor
- */
- agreed_pwr->pwr_rx = agreed_pwr->pwr_tx =
- hisi_param->rx_pwr_hs;
- } else {
- /*
- * here hisi_param->desired_working_mode is PWM.
- * it doesn't matter whether device supports HS or PWM,
- * in both cases hisi_param->desired_working_mode will
- * determine the mode
- */
- agreed_pwr->pwr_rx = agreed_pwr->pwr_tx =
- hisi_param->rx_pwr_pwm;
- }
-
- /*
- * we would like tx to work in the minimum number of lanes
- * between device capability and vendor preferences.
- * the same decision will be made for rx
- */
- agreed_pwr->lane_tx =
- min_t(u32, dev_max->lane_tx, hisi_param->tx_lanes);
- agreed_pwr->lane_rx =
- min_t(u32, dev_max->lane_rx, hisi_param->rx_lanes);
-
- /* device maximum gear is the minimum between device rx and tx gears */
- min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx);
-
- /*
- * if both device capabilities and vendor pre-defined preferences are
- * both HS or both PWM then set the minimum gear to be the chosen
- * working gear.
- * if one is PWM and one is HS then the one that is PWM get to decide
- * what is the gear, as it is the one that also decided previously what
- * pwr the device will be configured to.
- */
- if ((is_dev_sup_hs && is_hisi_max_hs) ||
- (!is_dev_sup_hs && !is_hisi_max_hs))
- agreed_pwr->gear_rx = agreed_pwr->gear_tx =
- min_t(u32, min_dev_gear, min_hisi_gear);
- else
- agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_hisi_gear;
-
- agreed_pwr->hs_rate = hisi_param->hs_rate;
-
- pr_info("ufs final power mode: gear = %d, lane = %d, pwr = %d, rate = %d\n",
- agreed_pwr->gear_rx, agreed_pwr->lane_rx, agreed_pwr->pwr_rx,
- agreed_pwr->hs_rate);
- return 0;
-}
-
-static void ufs_hisi_set_dev_cap(struct ufs_hisi_dev_params *hisi_param)
+static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param)
{
hisi_param->rx_lanes = UFS_HISI_LIMIT_NUM_LANES_RX;
hisi_param->tx_lanes = UFS_HISI_LIMIT_NUM_LANES_TX;
@@ -477,7 +374,7 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
- struct ufs_hisi_dev_params ufs_hisi_cap;
+ struct ufs_dev_params ufs_hisi_cap;
int ret = 0;
if (!dev_req_params) {
@@ -490,8 +387,8 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba,
switch (status) {
case PRE_CHANGE:
ufs_hisi_set_dev_cap(&ufs_hisi_cap);
- ret = ufs_hisi_get_pwr_dev_param(
- &ufs_hisi_cap, dev_max_params, dev_req_params);
+ ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap,
+ dev_max_params, dev_req_params);
if (ret) {
dev_err(hba->dev,
"%s: failed to determine capabilities\n", __func__);
@@ -587,6 +484,10 @@ static int ufs_hisi_init_common(struct ufs_hba *hba)
ufshcd_set_variant(hba, host);
host->rst = devm_reset_control_get(dev, "rst");
+ if (IS_ERR(host->rst)) {
+ dev_err(dev, "%s: failed to get reset control\n", __func__);
+ return PTR_ERR(host->rst);
+ }
ufs_hisi_set_pm_lvl(hba);
diff --git a/drivers/scsi/ufs/ufs-hisi.h b/drivers/scsi/ufs/ufs-hisi.h
index 667dfe39b57e..3231d3d81c98 100644
--- a/drivers/scsi/ufs/ufs-hisi.h
+++ b/drivers/scsi/ufs/ufs-hisi.h
@@ -1,8 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017, HiSilicon. All rights reserved.
- *
- * Released under the GPLv2 only.
- * SPDX-License-Identifier: GPL-2.0
*/
#ifndef UFS_HISI_H_
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
new file mode 100644
index 000000000000..0f6ff33ce52e
--- /dev/null
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 MediaTek Inc.
+ * Authors:
+ * Stanley Chu <stanley.chu@mediatek.com>
+ * Peter Wang <peter.wang@mediatek.com>
+ */
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#include "ufshcd.h"
+#include "ufshcd-pltfrm.h"
+#include "unipro.h"
+#include "ufs-mediatek.h"
+
+static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
+{
+ u32 tmp;
+
+ if (enable) {
+ ufshcd_dme_get(hba,
+ UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+ tmp = tmp |
+ (1 << RX_SYMBOL_CLK_GATE_EN) |
+ (1 << SYS_CLK_GATE_EN) |
+ (1 << TX_CLK_GATE_EN);
+ ufshcd_dme_set(hba,
+ UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+
+ ufshcd_dme_get(hba,
+ UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
+ tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE);
+ ufshcd_dme_set(hba,
+ UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
+ } else {
+ ufshcd_dme_get(hba,
+ UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+ tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) |
+ (1 << SYS_CLK_GATE_EN) |
+ (1 << TX_CLK_GATE_EN));
+ ufshcd_dme_set(hba,
+ UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+
+ ufshcd_dme_get(hba,
+ UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
+ tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE);
+ ufshcd_dme_set(hba,
+ UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
+ }
+}
+
+static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+ struct device *dev = hba->dev;
+ struct device_node *np = dev->of_node;
+ int err = 0;
+
+ host->mphy = devm_of_phy_get_by_index(dev, np, 0);
+
+ if (host->mphy == ERR_PTR(-EPROBE_DEFER)) {
+ /*
+ * UFS driver might be probed before the phy driver does.
+ * In that case we would like to return EPROBE_DEFER code.
+ */
+ err = -EPROBE_DEFER;
+ dev_info(dev,
+ "%s: required phy hasn't probed yet. err = %d\n",
+ __func__, err);
+ } else if (IS_ERR(host->mphy)) {
+ err = PTR_ERR(host->mphy);
+ dev_info(dev, "%s: PHY get failed %d\n", __func__, err);
+ }
+
+ if (err)
+ host->mphy = NULL;
+
+ return err;
+}
+
+/**
+ * ufs_mtk_setup_clocks - enables/disable clocks
+ * @hba: host controller instance
+ * @on: If true, enable clocks else disable them.
+ * @status: PRE_CHANGE or POST_CHANGE notify
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
+ enum ufs_notify_change_status status)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+ int ret = -EINVAL;
+
+ /*
+ * In case ufs_mtk_init() is not yet done, simply ignore.
+ * This ufs_mtk_setup_clocks() shall be called from
+ * ufs_mtk_init() after init is done.
+ */
+ if (!host)
+ return 0;
+
+ switch (status) {
+ case PRE_CHANGE:
+ if (!on)
+ ret = phy_power_off(host->mphy);
+ break;
+ case POST_CHANGE:
+ if (on)
+ ret = phy_power_on(host->mphy);
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * ufs_mtk_init - find other essential mmio bases
+ * @hba: host controller instance
+ *
+ * Binds PHY with controller and powers up PHY enabling clocks
+ * and regulators.
+ *
+ * Returns -EPROBE_DEFER if binding fails, returns negative error
+ * on phy power up failure and returns zero on success.
+ */
+static int ufs_mtk_init(struct ufs_hba *hba)
+{
+ struct ufs_mtk_host *host;
+ struct device *dev = hba->dev;
+ int err = 0;
+
+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+ if (!host) {
+ err = -ENOMEM;
+ dev_info(dev, "%s: no memory for mtk ufs host\n", __func__);
+ goto out;
+ }
+
+ host->hba = hba;
+ ufshcd_set_variant(hba, host);
+
+ err = ufs_mtk_bind_mphy(hba);
+ if (err)
+ goto out_variant_clear;
+
+ /*
+ * ufshcd_vops_init() is invoked after
+ * ufshcd_setup_clock(true) in ufshcd_hba_init() thus
+ * phy clock setup is skipped.
+ *
+ * Enable phy clocks specifically here.
+ */
+ ufs_mtk_setup_clocks(hba, true, POST_CHANGE);
+
+ goto out;
+
+out_variant_clear:
+ ufshcd_set_variant(hba, NULL);
+out:
+ return err;
+}
+
+static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
+ struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ struct ufs_dev_params host_cap;
+ int ret;
+
+ host_cap.tx_lanes = UFS_MTK_LIMIT_NUM_LANES_TX;
+ host_cap.rx_lanes = UFS_MTK_LIMIT_NUM_LANES_RX;
+ host_cap.hs_rx_gear = UFS_MTK_LIMIT_HSGEAR_RX;
+ host_cap.hs_tx_gear = UFS_MTK_LIMIT_HSGEAR_TX;
+ host_cap.pwm_rx_gear = UFS_MTK_LIMIT_PWMGEAR_RX;
+ host_cap.pwm_tx_gear = UFS_MTK_LIMIT_PWMGEAR_TX;
+ host_cap.rx_pwr_pwm = UFS_MTK_LIMIT_RX_PWR_PWM;
+ host_cap.tx_pwr_pwm = UFS_MTK_LIMIT_TX_PWR_PWM;
+ host_cap.rx_pwr_hs = UFS_MTK_LIMIT_RX_PWR_HS;
+ host_cap.tx_pwr_hs = UFS_MTK_LIMIT_TX_PWR_HS;
+ host_cap.hs_rate = UFS_MTK_LIMIT_HS_RATE;
+ host_cap.desired_working_mode =
+ UFS_MTK_LIMIT_DESIRED_MODE;
+
+ ret = ufshcd_get_pwr_dev_param(&host_cap,
+ dev_max_params,
+ dev_req_params);
+ if (ret) {
+ pr_info("%s: failed to determine capabilities\n",
+ __func__);
+ }
+
+ return ret;
+}
+
+static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status stage,
+ struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ int ret = 0;
+
+ switch (stage) {
+ case PRE_CHANGE:
+ ret = ufs_mtk_pre_pwr_change(hba, dev_max_params,
+ dev_req_params);
+ break;
+ case POST_CHANGE:
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ufs_mtk_pre_link(struct ufs_hba *hba)
+{
+ int ret;
+ u32 tmp;
+
+ /* disable deep stall */
+ ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
+ if (ret)
+ return ret;
+
+ tmp &= ~(1 << 6);
+
+ ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
+
+ return ret;
+}
+
+static int ufs_mtk_post_link(struct ufs_hba *hba)
+{
+ /* disable device LCC */
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0);
+
+ /* enable unipro clock gating feature */
+ ufs_mtk_cfg_unipro_cg(hba, true);
+
+ return 0;
+}
+
+static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status stage)
+{
+ int ret = 0;
+
+ switch (stage) {
+ case PRE_CHANGE:
+ ret = ufs_mtk_pre_link(hba);
+ break;
+ case POST_CHANGE:
+ ret = ufs_mtk_post_link(hba);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+
+ if (ufshcd_is_link_hibern8(hba))
+ phy_power_off(host->mphy);
+
+ return 0;
+}
+
+static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+{
+ struct ufs_mtk_host *host = ufshcd_get_variant(hba);
+
+ if (ufshcd_is_link_hibern8(hba))
+ phy_power_on(host->mphy);
+
+ return 0;
+}
+
+/**
+ * struct ufs_hba_mtk_vops - UFS MTK specific variant operations
+ *
+ * The variant operations configure the necessary controller and PHY
+ * handshake during initialization.
+ */
+static struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
+ .name = "mediatek.ufshci",
+ .init = ufs_mtk_init,
+ .setup_clocks = ufs_mtk_setup_clocks,
+ .link_startup_notify = ufs_mtk_link_startup_notify,
+ .pwr_change_notify = ufs_mtk_pwr_change_notify,
+ .suspend = ufs_mtk_suspend,
+ .resume = ufs_mtk_resume,
+};
+
+/**
+ * ufs_mtk_probe - probe routine of the driver
+ * @pdev: pointer to Platform device handle
+ *
+ * Return zero for success and non-zero for failure
+ */
+static int ufs_mtk_probe(struct platform_device *pdev)
+{
+ int err;
+ struct device *dev = &pdev->dev;
+
+ /* perform generic probe */
+ err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
+ if (err)
+ dev_info(dev, "probe failed %d\n", err);
+
+ return err;
+}
+
+/**
+ * ufs_mtk_remove - set driver_data of the device to NULL
+ * @pdev: pointer to platform device handle
+ *
+ * Always return 0
+ */
+static int ufs_mtk_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_mtk_of_match[] = {
+ { .compatible = "mediatek,mt8183-ufshci"},
+ {},
+};
+
+static const struct dev_pm_ops ufs_mtk_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_mtk_pltform = {
+ .probe = ufs_mtk_probe,
+ .remove = ufs_mtk_remove,
+ .shutdown = ufshcd_pltfrm_shutdown,
+ .driver = {
+ .name = "ufshcd-mtk",
+ .pm = &ufs_mtk_pm_ops,
+ .of_match_table = ufs_mtk_of_match,
+ },
+};
+
+MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>");
+MODULE_AUTHOR("Peter Wang <peter.wang@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek UFS Host Driver");
+MODULE_LICENSE("GPL v2");
+
+module_platform_driver(ufs_mtk_pltform);
diff --git a/drivers/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h
new file mode 100644
index 000000000000..19f8c42fe06f
--- /dev/null
+++ b/drivers/scsi/ufs/ufs-mediatek.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 MediaTek Inc.
+ */
+
+#ifndef _UFS_MEDIATEK_H
+#define _UFS_MEDIATEK_H
+
+/*
+ * Vendor specific pre-defined parameters
+ */
+#define UFS_MTK_LIMIT_NUM_LANES_RX 1
+#define UFS_MTK_LIMIT_NUM_LANES_TX 1
+#define UFS_MTK_LIMIT_HSGEAR_RX UFS_HS_G3
+#define UFS_MTK_LIMIT_HSGEAR_TX UFS_HS_G3
+#define UFS_MTK_LIMIT_PWMGEAR_RX UFS_PWM_G4
+#define UFS_MTK_LIMIT_PWMGEAR_TX UFS_PWM_G4
+#define UFS_MTK_LIMIT_RX_PWR_PWM SLOW_MODE
+#define UFS_MTK_LIMIT_TX_PWR_PWM SLOW_MODE
+#define UFS_MTK_LIMIT_RX_PWR_HS FAST_MODE
+#define UFS_MTK_LIMIT_TX_PWR_HS FAST_MODE
+#define UFS_MTK_LIMIT_HS_RATE PA_HS_MODE_B
+#define UFS_MTK_LIMIT_DESIRED_MODE UFS_HS_MODE
+
+/*
+ * Other attributes
+ */
+#define VS_DEBUGCLOCKENABLE 0xD0A1
+#define VS_SAVEPOWERCONTROL 0xD0A6
+#define VS_UNIPROPOWERDOWNCONTROL 0xD0A8
+
+/*
+ * VS_DEBUGCLOCKENABLE
+ */
+enum {
+ TX_SYMBOL_CLK_REQ_FORCE = 5,
+};
+
+/*
+ * VS_SAVEPOWERCONTROL
+ */
+enum {
+ RX_SYMBOL_CLK_GATE_EN = 0,
+ SYS_CLK_GATE_EN = 2,
+ TX_CLK_GATE_EN = 3,
+};
+
+struct ufs_mtk_host {
+ struct ufs_hba *hba;
+ struct phy *mphy;
+};
+
+#endif /* !_UFS_MEDIATEK_H */
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 3aeadb14aae1..ee4b1da1e223 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1,21 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 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
- * 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.
- *
*/
+#include <linux/acpi.h>
#include <linux/time.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
+#include <linux/reset-controller.h>
#include "ufshcd.h"
#include "ufshcd-pltfrm.h"
@@ -49,6 +42,11 @@ 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 struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd)
+{
+ return container_of(rcd, struct ufs_qcom_host, rcdev);
+}
+
static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len,
const char *prefix, void *priv)
{
@@ -164,6 +162,9 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
int err = 0;
struct device *dev = host->hba->dev;
+ if (has_acpi_companion(dev))
+ return 0;
+
err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk",
&host->rx_l0_sync_clk, false);
if (err)
@@ -255,11 +256,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
if (is_rate_B)
phy_set_mode(phy, PHY_MODE_UFS_HS_B);
- /* Assert PHY reset and apply PHY calibration values */
- ufs_qcom_assert_reset(hba);
- /* provide 1ms delay to let the reset pulse propagate */
- usleep_range(1000, 1100);
-
/* phy initialization - calibrate the phy */
ret = phy_init(phy);
if (ret) {
@@ -268,15 +264,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
goto out;
}
- /* De-assert PHY reset and start serdes */
- ufs_qcom_deassert_reset(hba);
-
- /*
- * after reset deassertion, phy will need all ref clocks,
- * voltage, current to settle down before starting serdes.
- */
- usleep_range(1000, 1100);
-
/* power on phy - start serdes and phy's power and clocks */
ret = phy_power_on(phy);
if (ret) {
@@ -290,7 +277,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
return 0;
out_disable_phy:
- ufs_qcom_assert_reset(hba);
phy_exit(phy);
out:
return ret;
@@ -554,21 +540,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
ufs_qcom_disable_lane_clks(host);
phy_power_off(phy);
- /* Assert PHY soft reset */
- ufs_qcom_assert_reset(hba);
- goto out;
- }
-
- /*
- * 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)) {
+ } else if (!ufs_qcom_is_link_active(hba)) {
ufs_qcom_disable_lane_clks(host);
- phy_power_off(phy);
}
-out:
return ret;
}
@@ -578,118 +553,25 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
struct phy *phy = host->generic_phy;
int err;
- err = phy_power_on(phy);
- if (err) {
- dev_err(hba->dev, "%s: failed enabling regs, err = %d\n",
- __func__, err);
- goto out;
- }
-
- err = ufs_qcom_enable_lane_clks(host);
- if (err)
- goto out;
-
- hba->is_sys_suspended = false;
-
-out:
- return err;
-}
-
-struct ufs_qcom_dev_params {
- u32 pwm_rx_gear; /* pwm rx gear to work in */
- u32 pwm_tx_gear; /* pwm tx gear to work in */
- u32 hs_rx_gear; /* hs rx gear to work in */
- u32 hs_tx_gear; /* hs tx gear to work in */
- u32 rx_lanes; /* number of rx lanes */
- u32 tx_lanes; /* number of tx lanes */
- u32 rx_pwr_pwm; /* rx pwm working pwr */
- u32 tx_pwr_pwm; /* tx pwm working pwr */
- u32 rx_pwr_hs; /* rx hs working pwr */
- u32 tx_pwr_hs; /* tx hs working pwr */
- u32 hs_rate; /* rate A/B to work in HS */
- u32 desired_working_mode;
-};
+ if (ufs_qcom_is_link_off(hba)) {
+ err = phy_power_on(phy);
+ if (err) {
+ dev_err(hba->dev, "%s: failed PHY power on: %d\n",
+ __func__, err);
+ return err;
+ }
-static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param,
- struct ufs_pa_layer_attr *dev_max,
- struct ufs_pa_layer_attr *agreed_pwr)
-{
- int min_qcom_gear;
- int min_dev_gear;
- bool is_dev_sup_hs = false;
- bool is_qcom_max_hs = false;
-
- if (dev_max->pwr_rx == FAST_MODE)
- is_dev_sup_hs = true;
-
- if (qcom_param->desired_working_mode == FAST) {
- is_qcom_max_hs = true;
- min_qcom_gear = min_t(u32, qcom_param->hs_rx_gear,
- qcom_param->hs_tx_gear);
- } else {
- min_qcom_gear = min_t(u32, qcom_param->pwm_rx_gear,
- qcom_param->pwm_tx_gear);
- }
+ err = ufs_qcom_enable_lane_clks(host);
+ if (err)
+ return err;
- /*
- * device doesn't support HS but qcom_param->desired_working_mode is
- * HS, thus device and qcom_param don't agree
- */
- if (!is_dev_sup_hs && is_qcom_max_hs) {
- pr_err("%s: failed to agree on power mode (device doesn't support HS but requested power is HS)\n",
- __func__);
- return -ENOTSUPP;
- } else if (is_dev_sup_hs && is_qcom_max_hs) {
- /*
- * since device supports HS, it supports FAST_MODE.
- * since qcom_param->desired_working_mode is also HS
- * then final decision (FAST/FASTAUTO) is done according
- * to qcom_params as it is the restricting factor
- */
- agreed_pwr->pwr_rx = agreed_pwr->pwr_tx =
- qcom_param->rx_pwr_hs;
- } else {
- /*
- * here qcom_param->desired_working_mode is PWM.
- * it doesn't matter whether device supports HS or PWM,
- * in both cases qcom_param->desired_working_mode will
- * determine the mode
- */
- agreed_pwr->pwr_rx = agreed_pwr->pwr_tx =
- qcom_param->rx_pwr_pwm;
+ } else if (!ufs_qcom_is_link_active(hba)) {
+ err = ufs_qcom_enable_lane_clks(host);
+ if (err)
+ return err;
}
- /*
- * we would like tx to work in the minimum number of lanes
- * between device capability and vendor preferences.
- * the same decision will be made for rx
- */
- agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx,
- qcom_param->tx_lanes);
- agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx,
- qcom_param->rx_lanes);
-
- /* device maximum gear is the minimum between device rx and tx gears */
- min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx);
-
- /*
- * if both device capabilities and vendor pre-defined preferences are
- * both HS or both PWM then set the minimum gear to be the chosen
- * working gear.
- * if one is PWM and one is HS then the one that is PWM get to decide
- * what is the gear, as it is the one that also decided previously what
- * pwr the device will be configured to.
- */
- if ((is_dev_sup_hs && is_qcom_max_hs) ||
- (!is_dev_sup_hs && !is_qcom_max_hs))
- agreed_pwr->gear_rx = agreed_pwr->gear_tx =
- min_t(u32, min_dev_gear, min_qcom_gear);
- else if (!is_dev_sup_hs)
- agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_dev_gear;
- else
- agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_qcom_gear;
-
- agreed_pwr->hs_rate = qcom_param->hs_rate;
+ hba->is_sys_suspended = false;
return 0;
}
@@ -920,7 +802,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
{
u32 val;
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct ufs_qcom_dev_params ufs_qcom_cap;
+ struct ufs_dev_params ufs_qcom_cap;
int ret = 0;
if (!dev_req_params) {
@@ -959,9 +841,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
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);
+ ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap,
+ dev_max_params,
+ dev_req_params);
if (ret) {
pr_err("%s: failed to determine capabilities\n",
__func__);
@@ -1118,8 +1000,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
return 0;
if (on && (status == POST_CHANGE)) {
- phy_power_on(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);
@@ -1131,9 +1011,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
if (!ufs_qcom_is_link_active(hba)) {
/* disable device ref_clk */
ufs_qcom_dev_ref_clk_ctrl(host, false);
-
- /* powering off PHY during aggressive clk gating */
- phy_power_off(host->generic_phy);
}
vote = host->bus_vote.min_bw_vote;
@@ -1147,6 +1024,41 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
return err;
}
+static int
+ufs_qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct ufs_qcom_host *host = rcdev_to_ufs_host(rcdev);
+
+ /* Currently this code only knows about a single reset. */
+ WARN_ON(id);
+ ufs_qcom_assert_reset(host->hba);
+ /* provide 1ms delay to let the reset pulse propagate. */
+ usleep_range(1000, 1100);
+ return 0;
+}
+
+static int
+ufs_qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct ufs_qcom_host *host = rcdev_to_ufs_host(rcdev);
+
+ /* Currently this code only knows about a single reset. */
+ WARN_ON(id);
+ ufs_qcom_deassert_reset(host->hba);
+
+ /*
+ * after reset deassertion, phy will need all ref clocks,
+ * voltage, current to settle down before starting serdes.
+ */
+ usleep_range(1000, 1100);
+ return 0;
+}
+
+static const struct reset_control_ops ufs_qcom_reset_ops = {
+ .assert = ufs_qcom_reset_assert,
+ .deassert = ufs_qcom_reset_deassert,
+};
+
#define ANDROID_BOOT_DEV_MAX 30
static char android_boot_dev[ANDROID_BOOT_DEV_MAX];
@@ -1191,6 +1103,17 @@ static int ufs_qcom_init(struct ufs_hba *hba)
host->hba = hba;
ufshcd_set_variant(hba, host);
+ /* Fire up the reset controller. Failure here is non-fatal. */
+ host->rcdev.of_node = dev->of_node;
+ host->rcdev.ops = &ufs_qcom_reset_ops;
+ host->rcdev.owner = dev->driver->owner;
+ host->rcdev.nr_resets = 1;
+ err = devm_reset_controller_register(dev, &host->rcdev);
+ if (err) {
+ dev_warn(dev, "Failed to register reset controller\n");
+ err = 0;
+ }
+
/*
* voting/devoting device ref_clk source is time consuming hence
* skip devoting it during aggressive clock gating. This clock
@@ -1208,9 +1131,13 @@ static int ufs_qcom_init(struct ufs_hba *hba)
__func__, err);
goto out_variant_clear;
} else if (IS_ERR(host->generic_phy)) {
- err = PTR_ERR(host->generic_phy);
- dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
- goto out_variant_clear;
+ if (has_acpi_companion(dev)) {
+ host->generic_phy = NULL;
+ } else {
+ err = PTR_ERR(host->generic_phy);
+ dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
+ goto out_variant_clear;
+ }
}
err = ufs_qcom_bus_register(host);
@@ -1680,6 +1607,14 @@ static const struct of_device_id ufs_qcom_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ufs_qcom_of_match);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ufs_qcom_acpi_match[] = {
+ { "QCOM24A5" },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, ufs_qcom_acpi_match);
+#endif
+
static const struct dev_pm_ops ufs_qcom_pm_ops = {
.suspend = ufshcd_pltfrm_suspend,
.resume = ufshcd_pltfrm_resume,
@@ -1696,6 +1631,7 @@ static struct platform_driver ufs_qcom_pltform = {
.name = "ufshcd-qcom",
.pm = &ufs_qcom_pm_ops,
.of_match_table = of_match_ptr(ufs_qcom_of_match),
+ .acpi_match_table = ACPI_PTR(ufs_qcom_acpi_match),
},
};
module_platform_driver(ufs_qcom_pltform);
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index c114826316eb..001915d1e0e4 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -1,19 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2013-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 UFS_QCOM_H_
#define UFS_QCOM_H_
+#include <linux/reset-controller.h>
+
#define MAX_UFS_QCOM_HOSTS 1
#define MAX_U32 (~(u32)0)
#define MPHY_TX_FSM_STATE 0x41
@@ -237,6 +230,8 @@ struct ufs_qcom_host {
/* Bitmask for enabling debug prints */
u32 dbg_print_en;
struct ufs_qcom_testbus testbus;
+
+ struct reset_controller_dev rcdev;
};
static inline u32
diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index 8d9332bb7d0c..f478685122ff 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -122,7 +122,7 @@ static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
{
unsigned long flags;
- if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+ if (!ufshcd_is_auto_hibern8_supported(hba))
return;
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -164,7 +164,7 @@ static ssize_t auto_hibern8_show(struct device *dev,
{
struct ufs_hba *hba = dev_get_drvdata(dev);
- if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+ if (!ufshcd_is_auto_hibern8_supported(hba))
return -EOPNOTSUPP;
return snprintf(buf, PAGE_SIZE, "%d\n", ufshcd_ahit_to_us(hba->ahit));
@@ -177,7 +177,7 @@ static ssize_t auto_hibern8_store(struct device *dev,
struct ufs_hba *hba = dev_get_drvdata(dev);
unsigned int timer;
- if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+ if (!ufshcd_is_auto_hibern8_supported(hba))
return -EOPNOTSUPP;
if (kstrtouint(buf, 0, &timer))
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 21e4ccb5ba6e..99a9c4d16f6b 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -516,7 +516,6 @@ struct ufs_vreg {
bool enabled;
int min_uV;
int max_uV;
- int min_uA;
int max_uA;
};
diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
index 869e71f861d6..a9344eb4e047 100644
--- a/drivers/scsi/ufs/ufs_bsg.c
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -122,7 +122,7 @@ static int ufs_bsg_request(struct bsg_job *job)
memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE);
ret = ufshcd_send_uic_cmd(hba, &uc);
if (ret)
- dev_dbg(hba->dev,
+ dev_err(hba->dev,
"send uic cmd: error code %d\n", ret);
memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE);
@@ -149,7 +149,9 @@ static int ufs_bsg_request(struct bsg_job *job)
out:
bsg_reply->result = ret;
job->reply_len = sizeof(struct ufs_bsg_reply);
- bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
+ /* complete the job here only if no error */
+ if (ret == 0)
+ bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len);
return ret;
}
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index a9bbd34d6b16..fe6cad9b2a0d 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -1,15 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 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_
diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c
index 977b21871a5d..fb9e2ff4f8d2 100644
--- a/drivers/scsi/ufs/ufshcd-dwc.c
+++ b/drivers/scsi/ufs/ufshcd-dwc.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* UFS Host driver for Synopsys Designware Core
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include "ufshcd.h"
diff --git a/drivers/scsi/ufs/ufshcd-dwc.h b/drivers/scsi/ufs/ufshcd-dwc.h
index c8be295e0ebe..4268ca2eb64c 100644
--- a/drivers/scsi/ufs/ufshcd-dwc.h
+++ b/drivers/scsi/ufs/ufshcd-dwc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* UFS Host driver for Synopsys Designware Core
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _UFSHCD_DWC_H
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index ffe6f82182ba..3b19de3ae9a3 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -200,6 +200,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
static const struct pci_device_id ufshcd_pci_tbl[] = {
{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
+ { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
+ { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_cnl_hba_vops },
{ } /* terminate list */
};
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 27213676329c..d7d521b394c3 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -39,6 +39,7 @@
#include "ufshcd.h"
#include "ufshcd-pltfrm.h"
+#include "unipro.h"
#define UFSHCD_DEFAULT_LANES_PER_DIRECTION 2
@@ -151,20 +152,12 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
vreg->name = kstrdup(name, GFP_KERNEL);
- /* if fixed regulator no need further initialization */
- snprintf(prop_name, MAX_PROP_SIZE, "%s-fixed-regulator", name);
- if (of_property_read_bool(np, prop_name))
- goto out;
-
snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
- ret = of_property_read_u32(np, prop_name, &vreg->max_uA);
- if (ret) {
- dev_err(dev, "%s: unable to find %s err %d\n",
- __func__, prop_name, ret);
- goto out;
+ if (of_property_read_u32(np, prop_name, &vreg->max_uA)) {
+ dev_info(dev, "%s: unable to find %s\n", __func__, prop_name);
+ vreg->max_uA = 0;
}
- vreg->min_uA = 0;
if (!strcmp(name, "vcc")) {
if (of_property_read_bool(np, "vcc-supply-1p8")) {
vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
@@ -290,6 +283,103 @@ static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
}
/**
+ * ufshcd_get_pwr_dev_param - get finally agreed attributes for
+ * power mode change
+ * @pltfrm_param: pointer to platform parameters
+ * @dev_max: pointer to device attributes
+ * @agreed_pwr: returned agreed attributes
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_get_pwr_dev_param(struct ufs_dev_params *pltfrm_param,
+ struct ufs_pa_layer_attr *dev_max,
+ struct ufs_pa_layer_attr *agreed_pwr)
+{
+ int min_pltfrm_gear;
+ int min_dev_gear;
+ bool is_dev_sup_hs = false;
+ bool is_pltfrm_max_hs = false;
+
+ if (dev_max->pwr_rx == FAST_MODE)
+ is_dev_sup_hs = true;
+
+ if (pltfrm_param->desired_working_mode == UFS_HS_MODE) {
+ is_pltfrm_max_hs = true;
+ min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear,
+ pltfrm_param->hs_tx_gear);
+ } else {
+ min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear,
+ pltfrm_param->pwm_tx_gear);
+ }
+
+ /*
+ * device doesn't support HS but
+ * pltfrm_param->desired_working_mode is HS,
+ * thus device and pltfrm_param don't agree
+ */
+ if (!is_dev_sup_hs && is_pltfrm_max_hs) {
+ pr_info("%s: device doesn't support HS\n",
+ __func__);
+ return -ENOTSUPP;
+ } else if (is_dev_sup_hs && is_pltfrm_max_hs) {
+ /*
+ * since device supports HS, it supports FAST_MODE.
+ * since pltfrm_param->desired_working_mode is also HS
+ * then final decision (FAST/FASTAUTO) is done according
+ * to pltfrm_params as it is the restricting factor
+ */
+ agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs;
+ agreed_pwr->pwr_tx = agreed_pwr->pwr_rx;
+ } else {
+ /*
+ * here pltfrm_param->desired_working_mode is PWM.
+ * it doesn't matter whether device supports HS or PWM,
+ * in both cases pltfrm_param->desired_working_mode will
+ * determine the mode
+ */
+ agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm;
+ agreed_pwr->pwr_tx = agreed_pwr->pwr_rx;
+ }
+
+ /*
+ * we would like tx to work in the minimum number of lanes
+ * between device capability and vendor preferences.
+ * the same decision will be made for rx
+ */
+ agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx,
+ pltfrm_param->tx_lanes);
+ agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx,
+ pltfrm_param->rx_lanes);
+
+ /* device maximum gear is the minimum between device rx and tx gears */
+ min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx);
+
+ /*
+ * if both device capabilities and vendor pre-defined preferences are
+ * both HS or both PWM then set the minimum gear to be the chosen
+ * working gear.
+ * if one is PWM and one is HS then the one that is PWM get to decide
+ * what is the gear, as it is the one that also decided previously what
+ * pwr the device will be configured to.
+ */
+ if ((is_dev_sup_hs && is_pltfrm_max_hs) ||
+ (!is_dev_sup_hs && !is_pltfrm_max_hs)) {
+ agreed_pwr->gear_rx =
+ min_t(u32, min_dev_gear, min_pltfrm_gear);
+ } else if (!is_dev_sup_hs) {
+ agreed_pwr->gear_rx = min_dev_gear;
+ } else {
+ agreed_pwr->gear_rx = min_pltfrm_gear;
+ }
+ agreed_pwr->gear_tx = agreed_pwr->gear_rx;
+
+ agreed_pwr->hs_rate = pltfrm_param->hs_rate;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param);
+
+/**
* ufshcd_pltfrm_init - probe routine of the driver
* @pdev: pointer to Platform device handle
* @vops: pointer to variant ops
@@ -340,24 +430,21 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
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, "Initialization failed\n");
- goto out_disable_rpm;
+ goto dealloc_host;
}
platform_set_drvdata(pdev, hba);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
return 0;
-out_disable_rpm:
- pm_runtime_disable(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
dealloc_host:
ufshcd_dealloc_host(hba);
out:
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h
index 1f29e1fd6d52..b79cdf9129a0 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.h
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.h
@@ -1,14 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/* 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_
@@ -16,6 +7,27 @@
#include "ufshcd.h"
+#define UFS_PWM_MODE 1
+#define UFS_HS_MODE 2
+
+struct ufs_dev_params {
+ u32 pwm_rx_gear; /* pwm rx gear to work in */
+ u32 pwm_tx_gear; /* pwm tx gear to work in */
+ u32 hs_rx_gear; /* hs rx gear to work in */
+ u32 hs_tx_gear; /* hs tx gear to work in */
+ u32 rx_lanes; /* number of rx lanes */
+ u32 tx_lanes; /* number of tx lanes */
+ u32 rx_pwr_pwm; /* rx pwm working pwr */
+ u32 tx_pwr_pwm; /* tx pwm working pwr */
+ u32 rx_pwr_hs; /* rx hs working pwr */
+ u32 tx_pwr_hs; /* tx hs working pwr */
+ u32 hs_rate; /* rate A/B to work in HS */
+ u32 desired_working_mode;
+};
+
+int ufshcd_get_pwr_dev_param(struct ufs_dev_params *dev_param,
+ struct ufs_pa_layer_attr *dev_max,
+ struct ufs_pa_layer_attr *agreed_pwr);
int ufshcd_pltfrm_init(struct platform_device *pdev,
const struct ufs_hba_variant_ops *vops);
void ufshcd_pltfrm_shutdown(struct platform_device *pdev);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e040f9dd9ff3..04d3686511c8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1917,7 +1917,8 @@ int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, QUERY_OSF_SIZE);
/* Get the descriptor */
- if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
+ if (hba->dev_cmd.query.descriptor &&
+ lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
u8 *descp = (u8 *)lrbp->ucd_rsp_ptr +
GENERAL_UPIU_REQUEST_SIZE;
u16 resp_len;
@@ -3907,7 +3908,7 @@ static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
{
unsigned long flags;
- if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) || !hba->ahit)
+ if (!ufshcd_is_auto_hibern8_supported(hba) || !hba->ahit)
return;
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -4704,10 +4705,10 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
"Reject UPIU not fully implemented\n");
break;
default:
- result = DID_ERROR << 16;
dev_err(hba->dev,
"Unexpected request response code = %x\n",
result);
+ result = DID_ERROR << 16;
break;
}
break;
@@ -5254,6 +5255,7 @@ static void ufshcd_err_handler(struct work_struct *work)
goto skip_err_handling;
}
if ((hba->saved_err & INT_FATAL_ERRORS) ||
+ (hba->saved_err & UFSHCD_UIC_HIBERN8_MASK) ||
((hba->saved_err & UIC_ERROR) &&
(hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
@@ -5413,6 +5415,23 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
__func__, hba->uic_error);
}
+static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba,
+ u32 intr_mask)
+{
+ if (!ufshcd_is_auto_hibern8_supported(hba))
+ return false;
+
+ if (!(intr_mask & UFSHCD_UIC_HIBERN8_MASK))
+ return false;
+
+ if (hba->active_uic_cmd &&
+ (hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_ENTER ||
+ hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_EXIT))
+ return false;
+
+ return true;
+}
+
/**
* ufshcd_check_errors - Check for errors that need s/w attention
* @hba: per-adapter instance
@@ -5431,6 +5450,15 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
queue_eh_work = true;
}
+ if (hba->errors & UFSHCD_UIC_HIBERN8_MASK) {
+ dev_err(hba->dev,
+ "%s: Auto Hibern8 %s failed - status: 0x%08x, upmcrs: 0x%08x\n",
+ __func__, (hba->errors & UIC_HIBERNATE_ENTER) ?
+ "Enter" : "Exit",
+ hba->errors, ufshcd_get_upmcrs(hba));
+ queue_eh_work = true;
+ }
+
if (queue_eh_work) {
/*
* update the transfer error masks to sticky bits, let's do this
@@ -5493,6 +5521,10 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
{
hba->errors = UFSHCD_ERROR_MASK & intr_status;
+
+ if (ufshcd_is_auto_hibern8_error(hba, intr_status))
+ hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status);
+
if (hba->errors)
ufshcd_check_errors(hba);
@@ -6294,19 +6326,19 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
goto out;
}
- if (hba->vreg_info.vcc)
+ if (hba->vreg_info.vcc && hba->vreg_info.vcc->max_uA)
icc_level = ufshcd_get_max_icc_level(
hba->vreg_info.vcc->max_uA,
POWER_DESC_MAX_ACTV_ICC_LVLS - 1,
&desc_buf[PWR_DESC_ACTIVE_LVLS_VCC_0]);
- if (hba->vreg_info.vccq)
+ if (hba->vreg_info.vccq && hba->vreg_info.vccq->max_uA)
icc_level = ufshcd_get_max_icc_level(
hba->vreg_info.vccq->max_uA,
icc_level,
&desc_buf[PWR_DESC_ACTIVE_LVLS_VCCQ_0]);
- if (hba->vreg_info.vccq2)
+ if (hba->vreg_info.vccq2 && hba->vreg_info.vccq2->max_uA)
icc_level = ufshcd_get_max_icc_level(
hba->vreg_info.vccq2->max_uA,
icc_level,
@@ -7004,6 +7036,15 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
if (!vreg)
return 0;
+ /*
+ * "set_load" operation shall be required on those regulators
+ * which specifically configured current limitation. Otherwise
+ * zero max_uA may cause unexpected behavior when regulator is
+ * enabled or set as high power mode.
+ */
+ if (!vreg->max_uA)
+ return 0;
+
ret = regulator_set_load(vreg->reg, ua);
if (ret < 0) {
dev_err(dev, "%s: %s set load (ua=%d) failed, err=%d\n",
@@ -7039,12 +7080,15 @@ static int ufshcd_config_vreg(struct device *dev,
name = vreg->name;
if (regulator_count_voltages(reg) > 0) {
- min_uV = on ? vreg->min_uV : 0;
- ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
- if (ret) {
- dev_err(dev, "%s: %s set voltage failed, err=%d\n",
+ if (vreg->min_uV && vreg->max_uV) {
+ min_uV = on ? vreg->min_uV : 0;
+ ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
+ if (ret) {
+ dev_err(dev,
+ "%s: %s set voltage failed, err=%d\n",
__func__, name, ret);
- goto out;
+ goto out;
+ }
}
uA_load = on ? vreg->max_uA : 0;
@@ -7103,9 +7147,6 @@ static int ufshcd_setup_vreg(struct ufs_hba *hba, bool on)
struct device *dev = hba->dev;
struct ufs_vreg_info *info = &hba->vreg_info;
- if (!info)
- goto out;
-
ret = ufshcd_toggle_vreg(dev, info->vcc, on);
if (ret)
goto out;
@@ -7131,10 +7172,7 @@ static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on)
{
struct ufs_vreg_info *info = &hba->vreg_info;
- if (info)
- return ufshcd_toggle_vreg(hba->dev, info->vdd_hba, on);
-
- return 0;
+ return ufshcd_toggle_vreg(hba->dev, info->vdd_hba, on);
}
static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg)
@@ -7160,9 +7198,6 @@ static int ufshcd_init_vreg(struct ufs_hba *hba)
struct device *dev = hba->dev;
struct ufs_vreg_info *info = &hba->vreg_info;
- if (!info)
- goto out;
-
ret = ufshcd_get_vreg(dev, info->vcc);
if (ret)
goto out;
@@ -8309,7 +8344,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
UIC_LINK_HIBERN8_STATE);
/* Set the default auto-hiberate idle timer value to 150 ms */
- if (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) {
+ if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) {
hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) |
FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
}
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index ecfa898b9ccc..994d73d03207 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -740,6 +740,11 @@ return true;
#endif
}
+static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
+{
+ return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT);
+}
+
#define ufshcd_writel(hba, val, reg) \
writel((val), (hba)->mmio_base + (reg))
#define ufshcd_readl(hba, reg) \
diff --git a/drivers/scsi/ufs/ufshci-dwc.h b/drivers/scsi/ufs/ufshci-dwc.h
index ca341fece310..6c290e272106 100644
--- a/drivers/scsi/ufs/ufshci-dwc.h
+++ b/drivers/scsi/ufs/ufshci-dwc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* UFS Host driver for Synopsys Designware Core
*
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
*
* Authors: Joao Pinto <jpinto@synopsys.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#ifndef _UFSHCI_DWC_H
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 6fa889de5ee5..dbb75cd28dc8 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -144,8 +144,10 @@ enum {
#define CONTROLLER_FATAL_ERROR 0x10000
#define SYSTEM_BUS_FATAL_ERROR 0x20000
-#define UFSHCD_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\
- UIC_HIBERNATE_EXIT |\
+#define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\
+ UIC_HIBERNATE_EXIT)
+
+#define UFSHCD_UIC_PWR_MASK (UFSHCD_UIC_HIBERN8_MASK |\
UIC_POWER_MODE)
#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 23129d7b2678..f539f873f94d 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* drivers/scsi/ufs/unipro.h
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
- *
- * 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 _UNIPRO_H_
@@ -52,7 +48,7 @@
#define RX_HS_UNTERMINATED_ENABLE 0x00A6
#define RX_ENTER_HIBERN8 0x00A7
#define RX_BYPASS_8B10B_ENABLE 0x00A8
-#define RX_TERMINATION_FORCE_ENABLE 0x0089
+#define RX_TERMINATION_FORCE_ENABLE 0x00A9
#define RX_MIN_ACTIVATETIME_CAPABILITY 0x008F
#define RX_HIBERN8TIME_CAPABILITY 0x0092
#define RX_REFCLKFREQ 0x00EB
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index f8cb7c23305b..1705398b026a 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Virtio SCSI HBA driver
*
@@ -7,10 +8,6 @@
* Authors:
* Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
* Paolo Bonzini <pbonzini@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -77,9 +74,6 @@ struct virtio_scsi {
u32 num_queues;
- /* If the affinity hint is set for virtqueues */
- bool affinity_hint_set;
-
struct hlist_node node;
/* Protected by event_vq lock */
@@ -659,7 +653,7 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
static int virtscsi_map_queues(struct Scsi_Host *shost)
{
struct virtio_scsi *vscsi = shost_priv(shost);
- struct blk_mq_queue_map *qmap = &shost->tag_set.map[0];
+ struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
return blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2);
}
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index ecee4b3ff073..70008816c91f 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -335,7 +335,7 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT);
sge = &ctx->sgl->sge[0];
- for (i = 0; i < count; i++, sg++) {
+ for (i = 0; i < count; i++, sg = sg_next(sg)) {
sge[i].addr = sg_dma_address(sg);
sge[i].length = sg_dma_len(sg);
sge[i].flags = 0;
@@ -763,6 +763,7 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
struct pvscsi_adapter *adapter = shost_priv(host);
struct pvscsi_ctx *ctx;
unsigned long flags;
+ unsigned char op;
spin_lock_irqsave(&adapter->hw_lock, flags);
@@ -775,13 +776,14 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
}
cmd->scsi_done = done;
+ op = cmd->cmnd[0];
dev_dbg(&cmd->device->sdev_gendev,
- "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]);
+ "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op);
spin_unlock_irqrestore(&adapter->hw_lock, flags);
- pvscsi_kick_io(adapter, cmd->cmnd[0]);
+ pvscsi_kick_io(adapter, op);
return 0;
}
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 74be04f2357c..fb7b289fa09f 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1996 John Shifflett, GeoLog Consulting
* john@geolog.com
* jshiffle@netcom.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, 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.
*/
/*
@@ -744,7 +735,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
* source or destination for THIS transfer.
*/
if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
+ cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 08abe508e9ad..2edec34c5a42 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* wd33c93.h - Linux device driver definitions for the
* Commodore Amiga A2091/590 SCSI controller card
@@ -7,17 +8,6 @@
* Copyright (c) 1996 John Shifflett, GeoLog Consulting
* john@geolog.com
* jshiffle@netcom.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, 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.
- *
*/
#ifndef WD33C93_H
#define WD33C93_H
diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c
index e3310e9488d2..edc8a139a60d 100644
--- a/drivers/scsi/wd719x.c
+++ b/drivers/scsi/wd719x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Western Digital WD7193, WD7197 and WD7296 SCSI cards
* Copyright 2013 Ondrej Zary
@@ -107,8 +108,15 @@ static inline int wd719x_wait_done(struct wd719x *wd, int timeout)
}
if (status != WD719X_INT_NOERRORS) {
+ u8 sue = wd719x_readb(wd, WD719X_AMR_SCB_ERROR);
+ /* we get this after wd719x_dev_reset, it's not an error */
+ if (sue == WD719X_SUE_TERM)
+ return 0;
+ /* we get this after wd719x_bus_reset, it's not an error */
+ if (sue == WD719X_SUE_RESET)
+ return 0;
dev_err(&wd->pdev->dev, "direct command failed, status 0x%02x, SUE 0x%02x\n",
- status, wd719x_readb(wd, WD719X_AMR_SCB_ERROR));
+ status, sue);
return -EIO;
}
@@ -127,8 +135,10 @@ static int wd719x_direct_cmd(struct wd719x *wd, u8 opcode, u8 dev, u8 lun,
if (wd719x_wait_ready(wd))
return -ETIMEDOUT;
- /* make sure we get NO interrupts */
- dev |= WD719X_DISABLE_INT;
+ /* disable interrupts except for RESET/ABORT (it breaks them) */
+ if (opcode != WD719X_CMD_BUSRESET && opcode != WD719X_CMD_ABORT &&
+ opcode != WD719X_CMD_ABORT_TAG && opcode != WD719X_CMD_RESET)
+ dev |= WD719X_DISABLE_INT;
wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, dev);
wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_2, lun);
wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_3, tag);
@@ -464,6 +474,7 @@ static int wd719x_abort(struct scsi_cmnd *cmd)
spin_lock_irqsave(wd->sh->host_lock, flags);
result = wd719x_direct_cmd(wd, action, cmd->device->id,
cmd->device->lun, cmd->tag, scb->phys, 0);
+ wd719x_finish_cmd(scb, DID_ABORT);
spin_unlock_irqrestore(wd->sh->host_lock, flags);
if (result)
return FAILED;
@@ -476,6 +487,7 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device)
int result;
unsigned long flags;
struct wd719x *wd = shost_priv(cmd->device->host);
+ struct wd719x_scb *scb, *tmp;
dev_info(&wd->pdev->dev, "%s reset requested\n",
(opcode == WD719X_CMD_BUSRESET) ? "bus" : "device");
@@ -483,6 +495,12 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device)
spin_lock_irqsave(wd->sh->host_lock, flags);
result = wd719x_direct_cmd(wd, opcode, device, 0, 0, 0,
WD719X_WAIT_FOR_SCSI_RESET);
+ /* flush all SCBs (or all for a device if dev_reset) */
+ list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) {
+ if (opcode == WD719X_CMD_BUSRESET ||
+ scb->cmd->device->id == device)
+ wd719x_finish_cmd(scb, DID_RESET);
+ }
spin_unlock_irqrestore(wd->sh->host_lock, flags);
if (result)
return FAILED;
@@ -505,22 +523,23 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd)
struct wd719x *wd = shost_priv(cmd->device->host);
struct wd719x_scb *scb, *tmp;
unsigned long flags;
- int result;
dev_info(&wd->pdev->dev, "host reset requested\n");
spin_lock_irqsave(wd->sh->host_lock, flags);
- /* Try to reinit the RISC */
- if (wd719x_chip_init(wd) == 0)
- result = SUCCESS;
- else
- result = FAILED;
+ /* stop the RISC */
+ if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0,
+ WD719X_WAIT_FOR_RISC))
+ dev_warn(&wd->pdev->dev, "RISC sleep command failed\n");
+ /* disable RISC */
+ wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0);
/* flush all SCBs */
list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list)
- wd719x_finish_cmd(scb, result);
+ wd719x_finish_cmd(scb, DID_RESET);
spin_unlock_irqrestore(wd->sh->host_lock, flags);
- return result;
+ /* Try to reinit the RISC */
+ return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED;
}
static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
@@ -672,7 +691,7 @@ static irqreturn_t wd719x_interrupt(int irq, void *dev_id)
else
dev_err(&wd->pdev->dev, "card returned invalid SCB pointer\n");
} else
- dev_warn(&wd->pdev->dev, "direct command 0x%x completed\n",
+ dev_dbg(&wd->pdev->dev, "direct command 0x%x completed\n",
regs.bytes.OPC);
break;
case WD719X_INT_PIOREADY:
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
index 4722660958f8..77bce208210e 100644
--- a/drivers/scsi/zalon.c
+++ b/drivers/scsi/zalon.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Zalon 53c7xx device driver.
* By Richard Hirst (rhirst@linuxcare.com)
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
index aff31991aea9..27b9e2baab1a 100644
--- a/drivers/scsi/zorro7xx.c
+++ b/drivers/scsi/zorro7xx.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
* Amiga MacroSystemUS WarpEngine SCSI controller.