Explorar o código

Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi

Pull SCSI updates from James Bottomley:
 "This is mostly updates of the usual drivers: arcmsr, qla2xx, lpfc,
  ufs, mpt3sas, hisi_sas.

  In addition we have removed several really old drivers: sym53c416,
  NCR53c406a, fdomain, fdomain_cs and removed the old scsi_module.c
  initialization from all remaining drivers.

  Plus an assortment of bug fixes, initialization errors and other minor
  fixes"

* tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (168 commits)
  scsi: ufs: Add support for Auto-Hibernate Idle Timer
  scsi: ufs: sysfs: reworking of the rpm_lvl and spm_lvl entries
  scsi: qla2xxx: fx00 copypaste typo
  scsi: qla2xxx: fix error message on <qla2400
  scsi: smartpqi: update driver version
  scsi: smartpqi: workaround fw bug for oq deletion
  scsi: arcmsr: Change driver version to v1.40.00.05-20180309
  scsi: arcmsr: Sleep to avoid CPU stuck too long for waiting adapter ready
  scsi: arcmsr: Handle adapter removed due to thunderbolt cable disconnection.
  scsi: arcmsr: Rename ACB_F_BUS_HANG_ON to ACB_F_ADAPTER_REMOVED for adapter hot-plug
  scsi: qla2xxx: Update driver version to 10.00.00.06-k
  scsi: qla2xxx: Fix Async GPN_FT for FCP and FC-NVMe scan
  scsi: qla2xxx: Cleanup code to improve FC-NVMe error handling
  scsi: qla2xxx: Fix FC-NVMe IO abort during driver reset
  scsi: qla2xxx: Fix retry for PRLI RJT with reason of BUSY
  scsi: qla2xxx: Remove nvme_done_list
  scsi: qla2xxx: Return busy if rport going away
  scsi: qla2xxx: Fix n2n_ae flag to prevent dev_loss on PDB change
  scsi: qla2xxx: Add FC-NVMe abort processing
  scsi: qla2xxx: Add changes for devloss timeout in driver
  ...
Linus Torvalds %!s(int64=7) %!d(string=hai) anos
pai
achega
052c220da3
Modificáronse 100 ficheiros con 4251 adicións e 10960 borrados
  1. 885 0
      Documentation/ABI/testing/sysfs-driver-ufs
  2. 7 0
      Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
  3. 0 6
      Documentation/driver-api/scsi.rst
  4. 0 2023
      Documentation/scsi/ChangeLog.1992-1997
  5. 0 5
      Documentation/scsi/Mylex.txt
  6. 0 14
      Documentation/scsi/scsi-parameters.txt
  7. 1 121
      Documentation/scsi/scsi_mid_low_api.txt
  8. 22 0
      Documentation/scsi/sd-parameters.txt
  9. 0 443
      Documentation/scsi/tmscsim.txt
  10. 0 12
      MAINTAINERS
  11. 0 1
      arch/powerpc/configs/c2k_defconfig
  12. 2 112
      drivers/scsi/Kconfig
  13. 0 5
      drivers/scsi/Makefile
  14. 0 1090
      drivers/scsi/NCR53c406a.c
  15. 5 0
      drivers/scsi/aacraid/aacraid.h
  16. 193 12
      drivers/scsi/aacraid/src.c
  17. 1 1
      drivers/scsi/aha1740.c
  18. 4 4
      drivers/scsi/aic7xxx/aic79xx_core.c
  19. 1 2
      drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
  20. 4 4
      drivers/scsi/aic7xxx/aic7xxx_core.c
  21. 1 2
      drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
  22. 1 2
      drivers/scsi/aic7xxx/aicasm/aicasm.c
  23. 2 2
      drivers/scsi/arcmsr/arcmsr.h
  24. 90 0
      drivers/scsi/arcmsr/arcmsr_hba.c
  25. 2 2
      drivers/scsi/atp870u.c
  26. 1 1
      drivers/scsi/bfa/bfad_bsg.c
  27. 14 2
      drivers/scsi/csiostor/csio_attr.c
  28. 270 5
      drivers/scsi/csiostor/csio_hw.c
  29. 59 0
      drivers/scsi/csiostor/csio_hw.h
  30. 8 0
      drivers/scsi/csiostor/csio_lnode.c
  31. 42 28
      drivers/scsi/csiostor/csio_mb.c
  32. 2 7
      drivers/scsi/csiostor/csio_mb.h
  33. 5 5
      drivers/scsi/device_handler/scsi_dh_alua.c
  34. 1 1
      drivers/scsi/device_handler/scsi_dh_emc.c
  35. 1 1
      drivers/scsi/device_handler/scsi_dh_rdac.c
  36. 12 15
      drivers/scsi/dpt_i2o.c
  37. 0 1
      drivers/scsi/dpti.h
  38. 0 2571
      drivers/scsi/eata.c
  39. 0 401
      drivers/scsi/eata_generic.h
  40. 0 966
      drivers/scsi/eata_pio.c
  41. 0 54
      drivers/scsi/eata_pio.h
  42. 0 2
      drivers/scsi/esas2r/esas2r.h
  43. 0 21
      drivers/scsi/esas2r/esas2r_init.c
  44. 4 68
      drivers/scsi/esas2r/esas2r_main.c
  45. 0 1783
      drivers/scsi/fdomain.c
  46. 0 24
      drivers/scsi/fdomain.h
  47. 1 1
      drivers/scsi/hisi_sas/Kconfig
  48. 0 1
      drivers/scsi/hisi_sas/hisi_sas.h
  49. 14 20
      drivers/scsi/hisi_sas/hisi_sas_main.c
  50. 6 7
      drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
  51. 48 14
      drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
  52. 34 38
      drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
  53. 6 30
      drivers/scsi/hosts.c
  54. 10 43
      drivers/scsi/ipr.c
  55. 1 1
      drivers/scsi/ipr.h
  56. 0 4
      drivers/scsi/ips.c
  57. 1 1
      drivers/scsi/isci/host.c
  58. 1 1
      drivers/scsi/jazz_esp.c
  59. 1 1
      drivers/scsi/libfc/fc_disc.c
  60. 1 1
      drivers/scsi/libsas/sas_ata.c
  61. 7 6
      drivers/scsi/libsas/sas_discover.c
  62. 15 14
      drivers/scsi/libsas/sas_expander.c
  63. 1 1
      drivers/scsi/libsas/sas_init.c
  64. 3 2
      drivers/scsi/libsas/sas_port.c
  65. 11 12
      drivers/scsi/lpfc/lpfc.h
  66. 86 21
      drivers/scsi/lpfc/lpfc_attr.c
  67. 3 3
      drivers/scsi/lpfc/lpfc_bsg.c
  68. 4 1
      drivers/scsi/lpfc/lpfc_crtn.h
  69. 6 2
      drivers/scsi/lpfc/lpfc_ct.c
  70. 15 7
      drivers/scsi/lpfc/lpfc_debugfs.c
  71. 7 6
      drivers/scsi/lpfc/lpfc_debugfs.h
  72. 9 2
      drivers/scsi/lpfc/lpfc_els.c
  73. 10 3
      drivers/scsi/lpfc/lpfc_hbadisc.c
  74. 14 1
      drivers/scsi/lpfc/lpfc_hw.h
  75. 126 15
      drivers/scsi/lpfc/lpfc_hw4.h
  76. 3 1
      drivers/scsi/lpfc/lpfc_ids.h
  77. 263 57
      drivers/scsi/lpfc/lpfc_init.c
  78. 6 4
      drivers/scsi/lpfc/lpfc_mbox.c
  79. 8 4
      drivers/scsi/lpfc/lpfc_mem.c
  80. 16 6
      drivers/scsi/lpfc/lpfc_nportdisc.c
  81. 270 157
      drivers/scsi/lpfc/lpfc_nvme.c
  82. 3 1
      drivers/scsi/lpfc/lpfc_nvme.h
  83. 354 116
      drivers/scsi/lpfc/lpfc_nvmet.c
  84. 7 3
      drivers/scsi/lpfc/lpfc_nvmet.h
  85. 44 20
      drivers/scsi/lpfc/lpfc_scsi.c
  86. 1 1
      drivers/scsi/lpfc/lpfc_scsi.h
  87. 484 208
      drivers/scsi/lpfc/lpfc_sli.c
  88. 3 3
      drivers/scsi/lpfc/lpfc_sli.h
  89. 36 6
      drivers/scsi/lpfc/lpfc_sli4.h
  90. 4 4
      drivers/scsi/lpfc/lpfc_version.h
  91. 1 2
      drivers/scsi/megaraid/megaraid_sas_base.c
  92. 1 0
      drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h
  93. 521 178
      drivers/scsi/mpt3sas/mpt3sas_base.c
  94. 13 6
      drivers/scsi/mpt3sas/mpt3sas_base.h
  95. 2 1
      drivers/scsi/mpt3sas/mpt3sas_config.c
  96. 11 11
      drivers/scsi/mpt3sas/mpt3sas_ctl.c
  97. 46 28
      drivers/scsi/mpt3sas/mpt3sas_scsih.c
  98. 4 4
      drivers/scsi/mpt3sas/mpt3sas_transport.c
  99. 57 50
      drivers/scsi/mvme147.c
  100. 12 11
      drivers/scsi/mvsas/mv_94xx.c

+ 885 - 0
Documentation/ABI/testing/sysfs-driver-ufs

@@ -0,0 +1,885 @@
+What:		/sys/bus/*/drivers/ufshcd/*/auto_hibern8
+Date:		March 2018
+Contact:	linux-scsi@vger.kernel.org
+Description:
+		This file contains the auto-hibernate idle timer setting of a
+		UFS host controller. A value of '0' means auto-hibernate is not
+		enabled. Otherwise the value is the number of microseconds of
+		idle time before the UFS host controller will autonomously put
+		the link into hibernate state. That will save power at the
+		expense of increased latency. Note that the hardware supports
+		10-bit values with a power-of-ten multiplier which allows a
+		maximum value of 102300000. Refer to the UFS Host Controller
+		Interface specification for more details.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/device_type
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device type. This is one of the UFS
+		device descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/device_class
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device class. This is one of the UFS
+		device descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/device_sub_class
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the UFS storage subclass. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/protocol
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the protocol supported by an UFS device.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/number_of_luns
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows number of logical units. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/number_of_wluns
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows number of well known logical units.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/boot_enable
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows value that indicates whether the device is
+		enabled for boot. This is one of the UFS device descriptor
+		parameters. The full information about the descriptor could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/descriptor_access_enable
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows value that indicates whether the device
+		descriptor could be read after partial initialization phase
+		of the boot sequence. This is one of the UFS device descriptor
+		parameters. The full information about the descriptor could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/initial_power_mode
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows value that defines the power mode after
+		device initialization or hardware reset. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/high_priority_lun
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the high priority lun. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/secure_removal_type
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the secure removal type. This is one of
+		the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/support_security_lun
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the security lun is supported.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/bkops_termination_latency
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the background operations termination
+		latency. This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/initial_active_icc_level
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the initial active ICC level. This is one
+		of the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/specification_version
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the specification version. This is one
+		of the UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/manufacturing_date
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the manufacturing date in BCD format.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/manufacturer_id
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the manufacturee ID. This is one of the
+		UFS device descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/rtt_capability
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of outstanding RTTs
+		supported by the device. This is one of the UFS device
+		descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/rtc_update
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the frequency and method of the realtime
+		clock update. This is one of the UFS device descriptor
+		parameters. The full information about the descriptor
+		could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/ufs_features
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows which features are supported by the device.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be
+		found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/ffu_timeout
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the FFU timeout. This is one of the
+		UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/queue_depth
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device queue depth. This is one of the
+		UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/device_version
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device version. This is one of the
+		UFS device descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/number_of_secure_wpa
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows number of secure write protect areas
+		supported by the device. This is one of the UFS device
+		descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/psa_max_data_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum amount of data that may be
+		written during the pre-soldering phase of the PSA flow.
+		This is one of the UFS device descriptor parameters.
+		The full information about the descriptor could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/device_descriptor/psa_state_timeout
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the command maximum timeout for a change
+		in PSA state. This is one of the UFS device descriptor
+		parameters. The full information about the descriptor could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/interconnect_descriptor/unipro_version
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the MIPI UniPro version number in BCD format.
+		This is one of the UFS interconnect descriptor parameters.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/interconnect_descriptor/mphy_version
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the MIPI M-PHY version number in BCD format.
+		This is one of the UFS interconnect descriptor parameters.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/raw_device_capacity
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the total memory quantity available to
+		the user to configure the device logical units. This is one
+		of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/max_number_of_luns
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of logical units
+		supported by the UFS device. This is one of the UFS
+		geometry descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/segment_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the segment size. This is one of the UFS
+		geometry descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/allocation_unit_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the allocation unit size. This is one of
+		the UFS geometry descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/min_addressable_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the minimum addressable block size. This
+		is one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/optimal_read_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the optimal read block size. This is one
+		of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/optimal_write_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the optimal write block size. This is one
+		of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/max_in_buffer_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum data-in buffer size. This
+		is one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/max_out_buffer_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum data-out buffer size. This
+		is one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at UFS
+		specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/rpmb_rw_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of RPMB frames allowed
+		in Security Protocol In/Out. This is one of the UFS geometry
+		descriptor parameters. The full information about the
+		descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/dyn_capacity_resource_policy
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the dynamic capacity resource policy. This
+		is one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/data_ordering
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows support for out-of-order data transfer.
+		This is one of the UFS geometry descriptor parameters.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/max_number_of_contexts
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows maximum available number of contexts which
+		are supported by the device. This is one of the UFS geometry
+		descriptor parameters. The full information about the
+		descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/sys_data_tag_unit_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows system data tag unit size. This is one of
+		the UFS geometry descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/sys_data_tag_resource_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows maximum storage area size allocated by
+		the device to handle system data by the tagging mechanism.
+		This is one of the UFS geometry descriptor parameters.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/secure_removal_types
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows supported secure removal types. This is
+		one of the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/memory_types
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows supported memory types. This is one of
+		the UFS geometry descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/*_memory_max_alloc_units
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of allocation units for
+		different memory types (system code, non persistent,
+		enhanced type 1-4). This is one of the UFS geometry
+		descriptor parameters. The full information about the
+		descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/geometry_descriptor/*_memory_capacity_adjustment_factor
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the memory capacity adjustment factor for
+		different memory types (system code, non persistent,
+		enhanced type 1-4). This is one of the UFS geometry
+		descriptor parameters. The full information about the
+		descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/health_descriptor/eol_info
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows preend of life information. This is one
+		of the UFS health descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/health_descriptor/life_time_estimation_a
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows indication of the device life time
+		(method a). This is one of the UFS health descriptor
+		parameters. The full information about the descriptor
+		could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/health_descriptor/life_time_estimation_b
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows indication of the device life time
+		(method b). This is one of the UFS health descriptor
+		parameters. The full information about the descriptor
+		could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/power_descriptor/active_icc_levels_vcc*
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows maximum VCC, VCCQ and VCCQ2 value for
+		active ICC levels from 0 to 15. This is one of the UFS
+		power descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/manufacturer_name
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a device manufactureer name string.
+		The full information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/product_name
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a product name string. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/oem_id
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a OEM ID string. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/serial_number
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a device serial number string. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/string_descriptors/product_revision
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file contains a product revision string. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/boot_lun_id
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows boot LUN information. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/lun_write_protect
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows LUN write protection status. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/lun_queue_depth
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows LUN queue depth. This is one of the UFS
+		unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/psa_sensitive
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows PSA sensitivity. This is one of the UFS
+		unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/lun_memory_type
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows LUN memory type. This is one of the UFS
+		unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/data_reliability
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file defines the device behavior when a power failure
+		occurs during a write operation. This is one of the UFS
+		unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/logical_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the size of addressable logical blocks
+		(calculated as an exponent with base 2). This is one of
+		the UFS unit descriptor parameters. The full information about
+		the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/logical_block_count
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows total number of addressable logical blocks.
+		This is one of the UFS unit descriptor parameters. The full
+		information about the descriptor could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/erase_block_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the erase block size. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/provisioning_type
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the thin provisioning type. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/physical_memory_resourse_count
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the total physical memory resources. This is
+		one of the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/context_capabilities
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the context capabilities. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/unit_descriptor/large_unit_granularity
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the granularity of the LUN. This is one of
+		the UFS unit descriptor parameters. The full information
+		about the descriptor could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/device_init
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the device init status. The full information
+		about the flag could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/permanent_wpe
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether permanent write protection is enabled.
+		The full information about the flag could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/power_on_wpe
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether write protection is enabled on all
+		logical units configured as power on write protected. The
+		full information about the flag could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/bkops_enable
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the device background operations are
+		enabled. The full information about the flag could be
+		found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/life_span_mode_enable
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the device life span mode is enabled.
+		The full information about the flag could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/phy_resource_removal
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether physical resource removal is enable.
+		The full information about the flag could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/busy_rtc
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the device is executing internal
+		operation related to real time clock. The full information
+		about the flag could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/flags/disable_fw_update
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the device FW update is permanently
+		disabled. The full information about the flag could be found
+		at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/boot_lun_enabled
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the boot lun enabled UFS device attribute.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/current_power_mode
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the current power mode UFS device attribute.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/active_icc_level
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the active icc level UFS device attribute.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/ooo_data_enabled
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the out of order data transfer enabled UFS
+		device attribute. The full information about the attribute
+		could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/bkops_status
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the background operations status UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/purge_status
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the purge operation status UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/max_data_in_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum data size in a DATA IN
+		UPIU. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/max_data_out_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the maximum number of bytes that can be
+		requested with a READY TO TRANSFER UPIU. The full information
+		about the attribute could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/reference_clock_frequency
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the reference clock frequency UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/configuration_descriptor_lock
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows whether the configuration descriptor is locked.
+		The full information about the attribute could be found at
+		UFS specifications 2.1. The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/max_number_of_rtt
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the maximum current number of
+		outstanding RTTs in device that is allowed. The full
+		information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/exception_event_control
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the exception event control UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/exception_event_status
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the exception event status UFS device
+		attribute. The full information about the attribute could
+		be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/ffu_status
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file provides the ffu status UFS device attribute.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/psa_state
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file show the PSA feature status. The full information
+		about the attribute could be found at UFS specifications 2.1.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/attributes/psa_data_size
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the amount of data that the host plans to
+		load to all logical units in pre-soldering state.
+		The full information about the attribute could be found at
+		UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/class/scsi_device/*/device/dyn_cap_needed
+Date:		February 2018
+Contact:	Stanislav Nijnikov <stanislav.nijnikov@wdc.com>
+Description:	This file shows the The amount of physical memory needed
+		to be removed from the physical memory resources pool of
+		the particular logical unit. The full information about
+		the attribute could be found at UFS specifications 2.1.
+		The file is read only.
+
+
+What:		/sys/bus/platform/drivers/ufshcd/*/rpm_lvl
+Date:		September 2014
+Contact:	Subhash Jadavani <subhashj@codeaurora.org>
+Description:	This entry could be used to set or show the UFS device
+		runtime power management level. The current driver
+		implementation supports 6 levels with next target states:
+		0 - an UFS device will stay active, an UIC link will
+		stay active
+		1 - an UFS device will stay active, an UIC link will
+		hibernate
+		2 - an UFS device will moved to sleep, an UIC link will
+		stay active
+		3 - an UFS device will moved to sleep, an UIC link will
+		hibernate
+		4 - an UFS device will be powered off, an UIC link will
+		hibernate
+		5 - an UFS device will be powered off, an UIC link will
+		be powered off
+
+What:		/sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_state
+Date:		February 2018
+Contact:	Subhash Jadavani <subhashj@codeaurora.org>
+Description:	This entry shows the target power mode of an UFS device
+		for the chosen runtime power management level.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/rpm_target_link_state
+Date:		February 2018
+Contact:	Subhash Jadavani <subhashj@codeaurora.org>
+Description:	This entry shows the target state of an UFS UIC link
+		for the chosen runtime power management level.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/spm_lvl
+Date:		September 2014
+Contact:	Subhash Jadavani <subhashj@codeaurora.org>
+Description:	This entry could be used to set or show the UFS device
+		system power management level. The current driver
+		implementation supports 6 levels with next target states:
+		0 - an UFS device will stay active, an UIC link will
+		stay active
+		1 - an UFS device will stay active, an UIC link will
+		hibernate
+		2 - an UFS device will moved to sleep, an UIC link will
+		stay active
+		3 - an UFS device will moved to sleep, an UIC link will
+		hibernate
+		4 - an UFS device will be powered off, an UIC link will
+		hibernate
+		5 - an UFS device will be powered off, an UIC link will
+		be powered off
+
+What:		/sys/bus/platform/drivers/ufshcd/*/spm_target_dev_state
+Date:		February 2018
+Contact:	Subhash Jadavani <subhashj@codeaurora.org>
+Description:	This entry shows the target power mode of an UFS device
+		for the chosen system power management level.
+		The file is read only.
+
+What:		/sys/bus/platform/drivers/ufshcd/*/spm_target_link_state
+Date:		February 2018
+Contact:	Subhash Jadavani <subhashj@codeaurora.org>
+Description:	This entry shows the target state of an UFS UIC link
+		for the chosen system power management level.
+		The file is read only.

+ 7 - 0
Documentation/devicetree/bindings/scsi/hisilicon-sas.txt

@@ -53,6 +53,13 @@ Main node required properties:
 Optional main node properties:
 Optional main node properties:
  - hip06-sas-v2-quirk-amt : when set, indicates that the v2 controller has the
  - hip06-sas-v2-quirk-amt : when set, indicates that the v2 controller has the
 			    "am-max-transmissions" limitation.
 			    "am-max-transmissions" limitation.
+ - hisilicon,signal-attenuation : array of 3 32-bit values, containing de-emphasis,
+		preshoot, and boost attenuation readings for the board. They
+		are used to describe the signal attenuation of the board. These
+		values' range is 7600 to 12400, and used to represent -24dB to
+		24dB.
+		The formula is "y = (x-10000)/10000". For example, 10478
+		means 4.78dB.
 
 
 Example:
 Example:
 	sas0: sas@c1000000 {
 	sas0: sas@c1000000 {

+ 0 - 6
Documentation/driver-api/scsi.rst

@@ -154,12 +154,6 @@ lists).
 .. kernel-doc:: drivers/scsi/scsi_lib_dma.c
 .. kernel-doc:: drivers/scsi/scsi_lib_dma.c
    :export:
    :export:
 
 
-drivers/scsi/scsi_module.c
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The file drivers/scsi/scsi_module.c contains legacy support for
-old-style host templates. It should never be used by any new driver.
-
 drivers/scsi/scsi_proc.c
 drivers/scsi/scsi_proc.c
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 

+ 0 - 2023
Documentation/scsi/ChangeLog.1992-1997

@@ -1,2023 +0,0 @@
-Sat Jan 18 15:51:45 1997  Richard Henderson  <rth@tamu.edu>
-
-	* Don't play with usage_count directly, instead hand around
-	the module header and use the module macros.
-
-Fri May 17 00:00:00 1996  Leonard N. Zubkoff <lnz@dandelion.com>
-
-	* BusLogic Driver Version 2.0.3 Released.
-
-Tue Apr 16 21:00:00 1996  Leonard N. Zubkoff <lnz@dandelion.com>
-
-	* BusLogic Driver Version 1.3.2 Released.
-
-Sun Dec 31 23:26:00 1995  Leonard N. Zubkoff <lnz@dandelion.com>
-
-	* BusLogic Driver Version 1.3.1 Released.
-
-Fri Nov 10 15:29:49 1995  Leonard N. Zubkoff <lnz@dandelion.com>
-
-	* Released new BusLogic driver.
-
-Wed Aug  9 22:37:04 1995  Andries Brouwer  <aeb@cwi.nl>
-
-	As a preparation for new device code, separated the various
-	functions the request->dev field had into the device proper,
-	request->rq_dev and a status field request->rq_status.
-
-	The 2nd argument of bios_param is now a kdev_t.
-
-Wed Jul 19 10:43:15 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-        * scsi.c (scsi_proc_info): /proc/scsi/scsi now also lists all
-	attached devices.
-
-	* scsi_proc.c (proc_print_scsidevice): Added. Used by scsi.c and
-	eata_dma_proc.c to produce some device info for /proc/scsi.
-
-	* eata_dma.c (eata_queue)(eata_int_handler)(eata_scsi_done):
-	Changed handling of internal SCSI commands send to the HBA.
-
-
-Wed Jul 19 10:09:17 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-	* Linux 1.3.11 released.
-
-	* eata_dma.c (eata_queue)(eata_int_handler): Added code to do
-	command latency measurements if requested by root through
-	/proc/scsi interface.
-	Throughout Use HZ constant for time references.
-
-	* eata_pio.c: Use HZ constant for time references.
-
-	* aic7xxx.c, aic7xxx.h, aic7xxx_asm.c: Changed copyright from BSD
-	to GNU style.
-
-	* scsi.h: Added READ_12 command opcode constant
-
-Wed Jul 19 09:25:30 1995  Michael Neuffer <neuffer@goofy.zdv.uni-mainz.de>
-
-	* Linux 1.3.10 released.
-
-	* scsi_proc.c (dispatch_scsi_info): Removed unused variable.
-
-Wed Jul 19 09:25:30 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-	* Linux 1.3.9 released.
-
-	* scsi.c Blacklist concept expanded to 'support' more device
-	deficiencies. blacklist[] renamed to device_list[]
-	(scan_scsis): Code cleanup.
-
-	* scsi_debug.c (scsi_debug_proc_info): Added support to control
-	device lockup simulation via /proc/scsi interface.
-
-
-Wed Jul 19 09:22:34 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-	* Linux 1.3.7 released.
-
-	* scsi_proc.c: Fixed a number of bugs in directory handling
-
-Wed Jul 19 09:18:28 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-	* Linux 1.3.5 released.
-
-	* Native wide, multichannel and /proc/scsi support now in official
-	kernel distribution.
-
-        * scsi.c/h, hosts.c/h et al reindented to increase readability
-	(especially on 80 column wide terminals).
-
-	* scsi.c, scsi_proc.c, ../../fs/proc/inode.c: Added
-	/proc/scsi/scsi which allows root to scan for hotplugged devices.
-
-	* scsi.c (scsi_proc_info): Added, to support /proc/scsi/scsi.
-	(scan_scsis): Added some 'spaghetti' code to allow scanning for
-	single devices.
-	
-
-Thu Jun 20 15:20:27 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-        * proc.c: Renamed to scsi_proc.c
-
-Mon Jun 12 20:32:45 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-	* Linux 1.3.0 released.
-
-Mon May 15 19:33:14 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-	* scsi.c: Added native multichannel and wide scsi support.
-
-	* proc.c (dispatch_scsi_info) (build_proc_dir_hba_entries):
-	Updated /proc/scsi interface.
-
-Thu May  4 17:58:48 1995  Michael Neuffer  <neuffer@goofy.zdv.uni-mainz.de>
-
-	* sd.c (requeue_sd_request): Zero out the scatterlist only if
-	scsi_malloc returned memory for it.
-
-	* eata_dma.c (register_HBA) (eata_queue): Add support for
-	large scatter/gather tables and set use_clustering accordingly
-
-	* hosts.c: Make use_clustering changeable in the Scsi_Host structure.
-
-Wed Apr 12 15:25:52 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.2.5 released.
-
-	* buslogic.c: Update to version 1.15 (From Leonard N. Zubkoff).
-	Fixed interrupt routine to avoid races when handling multiple
-	complete commands per interrupt.  Seems to come up with faster
-	cards.
-
-	* eata_dma.c: Update to 2.3.5r. Modularize. Improved error handling
-        throughout and fixed bug interrupt routine which resulted in shifted
-        status bytes. Added blink LED state checks for ISA and EISA HBAs.
-        Memory management bug seems to have disappeared ==> increasing
-        C_P_L_CURRENT_MAX to 16 for now. Decreasing C_P_L_DIV to 3 for
-        performance reasons.
-
-	* scsi.c: If we get a FMK, EOM, or ILI when attempting to scan
-	the bus, assume that it was just noise on the bus, and ignore
-	the device.
-
-	* scsi.h: Update and add a bunch of missing commands which we
-	were never using.
-
-	* sd.c: Use restore_flags in do_sd_request - this may result in
-	latency conditions, but it gets rid of races and crashes.
-	Do not save flags again when searching for a second command to
-	queue.
-
-	* st.c: Use bytes, not STP->buffer->buffer_size when reading
-	from tape.
-
-
-Tue Apr  4 09:42:08 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.2.4 released.
-
-	* st.c: Fix typo - restoring wrong flags.
-
-Wed Mar 29 06:55:12 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.2.3 released.
-
-	* st.c: Perform some waiting operations with interrupts off.
-	Is this correct???
-
-Wed Mar 22 10:34:26 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.2.2 released.
-
-	* aha152x.c: Modularize.  Add support for PCMCIA.
-
-	* eata.c: Update to version 2.0.  Fixed bug preventing media
-	detection.  If scsi_register_host returns NULL, fail gracefully.
-
-	* scsi.c: Detect as NEC (for photo-cd purposes) for the 84
-	and 25 models as "NEC_OLDCDR".
-
-	* scsi.h: Add define for NEC_OLDCDR
-
-	* sr.c: Add handling for NEC_OLDCDR.  Treat as unknown.
-
-	* u14-34f.c: Update to version 2.0.  Fixed same bug as in
-	eata.c.
-
-
-Mon Mar  6 11:11:20 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.2.0 released.  Yeah!!!
-
-	* Minor spelling/punctuation changes throughout.  Nothing
-	substantive.
-
-Mon Feb 20 21:33:03 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.95 released.
-
-	* qlogic.c: Update to version 0.41.
-
-	* seagate.c: Change some message to be more descriptive about what
-	we detected.
-
-	* sr.c: spelling/whitespace changes.
-
-Mon Feb 20 21:33:03 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.94 released.
-
-Mon Feb 20 08:57:17 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.93 released.
-
-	* hosts.h: Change io_port to long int from short.
-
- 	* 53c7,8xx.c: crash on AEN fixed, SCSI reset is no longer a NOP,
- 	  NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output
- 	  fixed, should initialize correctly if left running, now loadable,
-  	  new memory allocation, extraneous diagnostic output suppressed,
- 	  splx() replaced with save/restore flags. [ Drew ]
-
-	* hosts.c, hosts.h, scsi_ioctl.c, sd.c, sd_ioctl.c, sg.c, sr.c,
-	sr_ioctl.c: Add special junk at end that Emacs will use for
-	formatting the file.
-
-	* qlogic.c: Update to v0.40a.  Improve parity handling.
-
-	* scsi.c: Add Hitachi DK312C to blacklist.  Change "};" to "}" in
-	many places.  Use scsi_init_malloc to get command block - may
-	need this to be dma compatible for some host adapters.
-	Restore interrupts after unregistering a host.
-
-	* sd.c: Use sti instead of restore flags - causes latency problems.
-
-	* seagate.c: Use controller_type to determine string used when
-	registering irq.
-
-	* sr.c: More photo-cd hacks to make sure we get the xa stuff right.
-	* sr.h, sr.c: Change is_xa to xa_flags field.
-
-	* st.c: Disable retries for write operations.
-
-Wed Feb 15 10:52:56 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.92 released.
-
-	* eata.c: Update to 1.17.
-
-	* eata_dma.c: Update to 2.31a. Add more support for /proc/scsi.
-        Continuing modularization. Less crashes because of the bug in the
-        memory management ==> increase C_P_L_CURRENT_MAX to 10
-        and decrease C_P_L_DIV to 4.
-
-	* hosts.c: If we remove last host registered, reuse host number.
-	When freeing memory from host being deregistered, free extra_bytes
-	too.
-
-	* scsi.c (scan_scsis): memset(SDpnt, 0) and set SCmd.device to SDpnt.
-	Change memory allocation to work around bugs in __get_dma_pages.
-	Do not free host if usage count is not zero (for modules).
-
-	* sr_ioctl.c: Increase IOCTL_TIMEOUT to 3000.
-
-	* st.c: Allow for ST_EXTRA_DEVS in st data structures.
-
-	* u14-34f.c: Update to 1.17.
-
-Thu Feb  9 10:11:16 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.91 released.
-
-	* eata.c: Update to 1.16.  Use wish_block instead of host->block.
-
-	* hosts.c: Initialize wish_block to 0.
-
-	* hosts.h: Add wish_block.
-
-	* scsi.c: Use wish_block as indicator that the host should be added
-	to block list.
-
-	* sg.c: Add SG_EXTRA_DEVS to number of slots.
-
-	* u14-34f.c: Use wish_block.
-
-Tue Feb  7 11:46:04 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.90 released.
-
-	* eata.c: Change naming from eata_* to eata2x_*.  Now at vers 1.15.
-	Update interrupt handler to take pt_regs as arg.  Allow blocking
-	even if loaded as module.  Initialize target_time_out array.
-	Do not put sti(); in timing loop.
-
-	* hosts.c: Do not reuse host numbers.
-	Use scsi_make_blocked_list to generate blocking list.
-
-	* script_asm.pl:  Beats me.  Don't know perl.  Something to do with
-	phase index.
-
-	* scsi.c (scsi_make_blocked_list): New function - code copied from
-	hosts.c.
-
-	* scsi.c: Update code to disable photo CD for Toshiba cdroms.
-	Use just manufacturer name, not model number.
-
-	* sr.c: Fix setting density for Toshiba drives.
-
-	* u14-34f.c: Clear target_time_out array during reset.
-
-Wed Feb  1 09:20:45 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.89 released.
-
-	* Makefile, u14-34f.c: Modularize.
-
-	* Makefile, eata.c: Modularize.  Now version 1.14
-
-	* NCR5380.c: Update interrupt handler with new arglist.  Minor
-	cleanups.
-
-	* eata_dma.c: Begin to modularize.  Add hooks for /proc/scsi.
-	New version 2.3.0a. Add code in interrupt handler to allow
-        certain CDROM drivers to be detected which return a
-        CHECK_CONDITION during SCSI bus scan. Add opcode check to get
-        all DATA IN and DATA OUT phases right. Utilize HBA_interpret flag.
-	Improvements in HBA identification. Various other minor stuff.
-
-	* hosts.c: Initialize ->dma_channel and ->io_port when registering
-	a new host.
-
-	* qlogic.c: Modularize and add PCMCIA support.
-
-	* scsi.c: Add Hitachi to blacklist.
-
-	* scsi.c: Change default to no lun scan (too many problem devices).
-
-	* scsi.h: Define QUEUE_FULL condition.
-
-	* sd.c: Do not check for non-existent partition until after
-	new media check.
-
-	* sg.c: Undo previous change which was wrong.
-
-	* sr_ioctl.c: Increase IOCTL_TIMEOUT to 2000.
-
-	* st.c: Patches from Kai - improve filemark handling.
-
-Tue Jan 31 17:32:12 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.88 released.
-
-	* Throughout - spelling/grammar fixups.
-
-	* scsi.c: Make sure that all buffers are 16 byte aligned - some
-	drivers (buslogic) need this.
-
-	* scsi.c (scan_scsis): Remove message printed.
-
-	* scsi.c (scsi_init): Move message here.
-
-Mon Jan 30 06:40:25 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.87 released.
-
-	* sr.c: Photo-cd related changes. (Gerd Knorr??).
-
-	* st.c: Changes from Kai related to EOM detection.
-
-Mon Jan 23 23:53:10 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.86 released.
-
-	* 53c7,8xx.h: Change SG size to 127.
-
-	* eata_dma: Update to version 2.10i. Remove bug in the registration
-        of multiple HBAs and channels. Minor other improvements and stylistic
-        changes.
-
-	* scsi.c: Test for Toshiba XM-3401TA and exclude from detection
-	as toshiba drive - photo cd does not work with this drive.
-
-	* sr.c:  Update photocd code.
-
-Mon Jan 23 23:53:10 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.85 released.
-
-	* st.c, st_ioctl.c, sg.c, sd_ioctl.c, scsi_ioctl.c, hosts.c:
-	include linux/mm.h
-
-	* qlogic.c, buslogic.c, aha1542.c: Include linux/module.h.
-
-Sun Jan 22 22:08:46 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.84 released.
-
-	* Makefile: Support for loadable QLOGIC boards.
-
-	* aha152x.c: Update to version 1.8 from Juergen.
-
-	* eata_dma.c: Update from Michael Neuffer.
-        Remove hard limit of 2 commands per lun and make it better
-        configurable. Improvements in HBA identification.
-
-	* in2000.c: Fix biosparam to support large disks.
-
-	* qlogic.c: Minor changes (change sti -> restore_flags).
-
-Wed Jan 18 23:33:09 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.83 released.
-
-	* aha1542.c(aha1542_intr_handle): Use arguments handed down to find
-	which irq.
-
-	* buslogic.c: Likewise.
-
-	* eata_dma.c: Use min of 2 cmd_per_lun for OCS_enabled boards.
-
-	* scsi.c: Make RECOVERED_ERROR a SUGGEST_IS_OK.
-
-	* sd.c: Fail if we are opening a non-existent partition.
-
-	* sr.c: Bump SR_TIMEOUT to 15000.
-	Do not probe for media size at boot time(hard on changers).
-	Flag device as needing sector size instead.
-
-	* sr_ioctl.c: Remove CDROMMULTISESSION_SYS ioctl.
-
-	* ultrastor.c: Fix bug in call to ultrastor_interrupt (wrong #args).
-
-Mon Jan 16 07:18:23 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.82 released.
-
-	Throughout.
-	- Change all interrupt handlers to accept new calling convention.
-	In particular, we now receive the irq number as one of the arguments.
-
-	* More minor spelling corrections in some of the new files.
-
-	* aha1542.c, buslogic.c: Clean up interrupt handler a little now
-	that we receive the irq as an arg.
-
-	* aha274x.c: s/snarf_region/request_region/
-
-	* eata.c: Update to version 1.12.   Fix some comments and display a
-	message if we cannot reserve the port addresses.
-
-	* u14-34f.c: Update to version 1.13.   Fix some comments and display a
-	message if we cannot reserve the port addresses.
-
-	* eata_dma.c: Define get_board_data function (send INQUIRY command).
-	Use to improve detection of variants of different DPT boards.  Change
-	version subnumber to "0g".
-
-	* fdomain.c:  Update to version 5.26.  Improve detection of some boards
-	repackaged by IBM.
-
-	* scsi.c (scsi_register_host): Change "name" to const char *.
-
-	* sr.c: Fix problem in set mode command for Toshiba drives.
-
-	* sr.c: Fix typo from patch 81.
-
-Fri Jan 13 12:54:46 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.81 released.  Codefreeze for 1.2 release announced.
-
-	Big changes here.
-
-	* eata_dma.*: New files from Michael Neuffer.
-	(neuffer@goofy.zdv.uni-mainz.de).  Should support
-	all eata/dpt cards.
-
-	* hosts.c, Makefile: Add eata_dma.
-
-	* README.st: Document MTEOM.
-
-	Patches from me (ERY) to finish support for low-level loadable scsi.
-	It now works, and is actually useful.
-
-	* Throughout - add new argument to scsi_init_malloc that takes an
-	additional parameter.  This is used as a priority to kmalloc,
-	and you can specify the GFP_DMA flag if you need DMA-able memory.
-
-	* Makefile: For source files that are loadable, always add name
-	to SCSI_SRCS.  Fill in modules: target.
-
-	* hosts.c:  Change next_host to next_scsi_host, and make global.
-	Print hosts after we have identified all of them.  Use info()
-	function if present, otherwise use name field.
-
-	* hosts.h: Change attach function to return int, not void.
-	Define number of device slots to allow for loadable devices.
-	Define tags to tell scsi module code what type of module we
-	are loading.
-
-	* scsi.c: Fix scan_scsis so that it can be run by a user process.
-	Do not use waiting loops - use up and down mechanism as long
-	as current != task[0].
-
-	* scsi.c(scan_scsis): Do not use stack variables for I/O - this
-	could be > 16Mb if we are loading a module at runtime (i.e. use
-	scsi_init_malloc to get some memory we know will be safe).
-
-	* scsi.c: Change dma freelist to be a set of pages.  This allows
-	us to dynamically adjust the size of the list by adding more pages
-	to the pagelist.  Fix scsi_malloc and scsi_free accordingly.
-
-	* scsi_module.c: Fix include.
-
-	* sd.c: Declare detach function.  Increment/decrement module usage
-	count as required.  Fix init functions to allow loaded devices.
-	Revalidate all new disks so we get the partition tables.  Define
-	detach function.
-
-	* sr.c: Likewise.
-
-	* sg.c: Declare detach function.  Allow attachment of devices on
-	loaded drivers.
-
-	* st.c: Declare detach function.  Increment/decrement module usage
-	count as required.
-
-Tue Jan 10 10:09:58 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.79 released.
-
-	Patch from some undetermined individual who needs to get a life :-).
-
-	* sr.c: Attacked by spelling bee...
-
-	Patches from Gerd Knorr:
-
-	* sr.c: make printk messages for photoCD a little more informative.
-
-	* sr_ioctl.c: Fix CDROMMULTISESSION_SYS ioctl.
-
-Mon Jan  9 10:01:37 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.78 released.
-
-	* Makefile: Add empty modules: target.
-
-	* Wheee.  Now change register_iomem to request_region.
-
-	* in2000.c: Bugfix - apparently this is the fix that we have
-	all been waiting for.  It fixes a problem whereby the driver
-	is not stable under heavy load.  Race condition and all that.
-	Patch from Peter Lu.
-
-Wed Jan  4 21:17:40 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.77 released.
-
-	* 53c7,8xx.c: Fix from Linus - emulate splx.
-
-	Throughout:
-
-		Change "snarf_region" with "register_iomem".
-
-	* scsi_module.c: New file.  Contains support for low-level loadable
-	  scsi drivers. [ERY].
-
-	* sd.c: More s/int/long/ changes.
-
-	* seagate.c: Explicitly include linux/config.h
-
-	* sg.c: Increment/decrement module usage count on open/close.
-
-	* sg.c: Be a bit more careful about the user not supplying enough
-	  information for a valid command.  Pass correct size down to
-	  scsi_do_cmd.
-
-	* sr.c:  More changes for Photo-CD.  This apparently breaks NEC drives.
-
-	* sr_ioctl.c:  Support CDROMMULTISESSION ioctl.
-
-
-Sun Jan  1 19:55:21 1995  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.76 released.
-
-	* constants.c: Add type cast in switch statement.
-
-	* scsi.c (scsi_free): Change datatype of "offset" to long.
-	  (scsi_malloc): Change a few more variables to long.  Who
-	  did this and why was it important?  64 bit machines?
-
-
-	Lots of changes to use save_state/restore_state instead of cli/sti.
-	Files changed include:
-
-	* aha1542.c:
-	* aha1740.c:
-	* buslogic.c:
-	* in2000.c:
-	* scsi.c:
-	* scsi_debug.c:
-	* sd.c:
-	* sr.c:
-	* st.c:
-
-Wed Dec 28 16:38:29 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.75 released.
-
-	* buslogic.c: Spelling fix.
-
-	* scsi.c: Add HP C1790A and C2500A scanjet to blacklist.
-
-	* scsi.c: Spelling fixup.
-
-	* sd.c: Add support for sd_hardsizes (hard sector sizes).
-
-	* ultrastor.c: Use save_flags/restore_flags instead of cli/sti.
-
-Fri Dec 23 13:36:25 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.74 released.
-
-	* README.st: Update from Kai Makisara.
-
-	* eata.c: New version from Dario - version 1.11.
-	  use scsicam bios_param routine.  Add support for 2011
-	  and 2021 boards.
-
-	* hosts.c: Add support for blocking.  Linked list automatically
-	  generated when shpnt->block is set.
-
-	* scsi.c: Add sankyo & HP scanjet to blacklist.  Add support for
-	  kicking things loose when we deadlock.
-
-	* scsi.c: Recognize scanners and processors in scan_scsis.
-
-	* scsi_ioctl.h: Increase timeout to 9 seconds.
-
-	* st.c: New version from Kai - add better support for backspace.
-
-	* u14-34f.c: New version from Dario.  Supports blocking.
-
-Wed Dec 14 14:46:30 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.73 released.
-
-	* buslogic.c: Update from Dave Gentzel.  Version 1.14.
-	  Add module related stuff.   More fault tolerant if out of
-	  DMA memory.
-
-	* fdomain.c: New version from Rik Faith - version 5.22.  Add support
-	  for ISA-200S SCSI adapter.
-
-	* hosts.c: Spelling.
-
-	* qlogic.c: Update to version 0.38a.  Add more support for PCMCIA.
-
-	* scsi.c: Mask device type with 0x1f during scan_scsis.
-	  Add support for deadlocking, err, make that getting out of
-	  deadlock situations that are created when we allow the user
-	  to limit requests to one host adapter at a time.
-
-	* scsi.c: Bugfix - pass pid, not SCpnt as second arg to
-	  scsi_times_out.
-
-	* scsi.c: Restore interrupt state to previous value instead of using
-	  cli/sti pairs.
-
-	* scsi.c: Add a bunch of module stuff (all commented out for now).
-
-	* scsi.c: Clean up scsi_dump_status.
-
-Tue Dec  6 12:34:20 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.72 released.
-
-	* sg.c: Bugfix - always use sg_free, since we might have big buff.
-
-Fri Dec  2 11:24:53 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.71 released.
-
-	* sg.c: Clear buff field when not in use.  Only call scsi_free if
-	non-null.
-
-	* scsi.h: Call wake_up(&wait_for_request) when done with a
-	command.
-
-	* scsi.c (scsi_times_out): Pass pid down so that we can protect
-	against race conditions.
-
-	* scsi.c (scsi_abort): Zero timeout field if we get the
-	NOT_RUNNING message back from low-level driver.
-
-
-	* scsi.c (scsi_done): Restore cmd_len, use_sg here.
-
-	* scsi.c (request_sense): Not here.
-
-	* hosts.h: Add new forbidden_addr, forbidden_size fields.  Who
-	added these and why????
-
-	* hosts.c (scsi_mem_init): Mark pages as reserved if they fall in
-	the forbidden regions.  I am not sure - I think this is so that
-	we can deal with boards that do incomplete decoding of their
-	address lines for the bios chips, but I am not entirely sure.
-
-	* buslogic.c: Set forbidden_addr stuff if using a buggy board.
-
-	* aha1740.c: Test for NULL pointer in SCtmp.  This should not
-	occur, but a nice message is better than a kernel segfault.
-
-	* 53c7,8xx.c: Add new PCI chip ID for 815.
-
-Fri Dec  2 11:24:53 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.70 released.
-
-	* ChangeLog, st.c: Spelling.
-
-Tue Nov 29 18:48:42 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.69 released.
-
-	* u14-34f.h: Non-functional change.  [Dario].
-
-	* u14-34f.c: Use block field in Scsi_Host to prevent commands from
-	being queued to more than one host at the same time (used when
-	motherboard does not deal with multiple bus-masters very well).
-	Only when SINGLE_HOST_OPERATIONS is defined.
-	Use new cmd_per_lun field.  [Dario]
-
-	* eata.c: Likewise.
-
-	* st.c: More changes from Kai.  Add ready flag to indicate drive
-	status.
-
-	* README.st: Document this.
-
-	* sr.c: Bugfix (do not subtract CD_BLOCK_OFFSET) for photo-cd
-	code.
-
-	* sg.c: Bugfix - fix problem where opcode is not correctly set up.
-
-	* seagate.[c,h]: Use #defines to set driver name.
-
-	* scsi_ioctl.c: Zero buffer before executing command.
-
-	* scsi.c: Use new cmd_per_lun field in Scsi_Hosts as appropriate.
-	Add Sony CDU55S to blacklist.
-
-	* hosts.h: Add new cmd_per_lun field to Scsi_Hosts.
-
-	* hosts.c: Initialize cmd_per_lun in Scsi_Hosts from template.
-
-	* buslogic.c: Use cmd_per_lun field - initialize to different
-	values depending upon bus type (i.e. use 1 if ISA, so we do not
-	hog memory).  Use other patches which got lost from 1.1.68.
-
-	* aha1542.c: Spelling.
-
-Tue Nov 29 15:43:50 1994  Eric Youngdale  (eric@andante.aib.com)
-
-	* Linux 1.1.68 released.
-
-	Add support for 12 byte vendor specific commands in scsi-generics,
-	more (i.e. the last mandatory) low-level changes to support
-	loadable modules, plus a few other changes people have requested
-	lately.  Changes by me (ERY) unless otherwise noted.  Spelling
-	changes appear from some unknown corner of the universe.
-
-	* Throughout: Change COMMAND_SIZE() to use SCpnt->cmd_len.
-
-	* Throughout: Change info() low level function to take a Scsi_Host
-	pointer.  This way the info function can return specific
-	information about the host in question, if desired.
-
-	* All low-level drivers: Add NULL in initializer for the
-	usage_count field added to Scsi_Host_Template.
-
-	* aha152x.[c,h]: Remove redundant info() function.
-
-	* aha1542.[c,h]: Likewise.
-
-	* aha1740.[c,h]: Likewise.
-
-	* aha274x.[c,h]: Likewise.
-
-	* eata.[c,h]: Likewise.
-
-	* pas16.[c,h]: Likewise.
-
-	* scsi_debug.[c,h]: Likewise.
-
-	* t128.[c,h]: Likewise.
-
-	* u14-34f.[c,h]: Likewise.
-
-	* ultrastor.[c,h]: Likewise.
-
-	* wd7000.[c,h]: Likewise.
-
-	* aha1542.c: Add support for command line options with lilo to set
-	DMA parameters, I/O port.  From Matt Aarnio.
-
-	* buslogic.[c,h]: New version (1.13) from Dave Gentzel.
-
-	* hosts.h: Add new field to Scsi_Hosts "block" to allow blocking
-	all I/O to certain other cards.  Helps prevent problems with some
-	ISA motherboards.
-
-	* hosts.h: Add usage_count to Scsi_Host_Template.
-
-	* hosts.h: Add n_io_port to Scsi_Host (used when releasing module).
-
-	* hosts.c: Initialize block field.
-
-	* in2000.c: Remove "static" declarations from exported functions.
-
-	* in2000.h: Likewise.
-
-	* scsi.c: Correctly set cmd_len field as required.  Save and
-	change setting when doing a request_sense, restore when done.
-	Move abort timeout message.  Fix panic in request_queueable to
-	print correct function name.
-
-	* scsi.c: When incrementing usage count, walk block linked list
-	for host, and or in SCSI_HOST_BLOCK bit.  When decrementing usage
-	count to 0, clear this bit to allow usage to continue, wake up
-	processes waiting.
-
-
-	* scsi_ioctl.c: If we have an info() function, call it, otherwise
-	if we have a "name" field, use it, else do nothing.
-
-	* sd.c, sr.c: Clear cmd_len field prior to each command we
-	generate.
-
-	* sd.h: Add "has_part_table" bit to rscsi_disks.
-
-	* sg.[c,h]: Add support for vendor specific 12 byte commands (i.e.
-	override command length in COMMAND_SIZE).
-
-	* sr.c: Bugfix from Gerd in photocd code.
-
-	* sr.c: Bugfix in get_sectorsize - always use scsi_malloc buffer -
-	we cannot guarantee that the stack is < 16Mb.
-
-Tue Nov 22 15:40:46 1994  Eric Youngdale  (eric@andante.aib.com)
-
-	* Linux 1.1.67 released.
-
-	* sr.c: Change spelling of manufactor to manufacturer.
-
-	* scsi.h: Likewise.
-
-	* scsi.c: Likewise.
-
-	* qlogic.c: Spelling corrections.
-
-	* in2000.h: Spelling corrections.
-
-	* in2000.c: Update from Bill Earnest, change from
-	jshiffle@netcom.com.  Support new bios versions.
-
-	* README.qlogic: Spelling correction.
-
-Tue Nov 22 15:40:46 1994  Eric Youngdale  (eric@andante.aib.com)
-
-	* Linux 1.1.66 released.
-
-	* u14-34f.c: Spelling corrections.
-
-	* sr.[h,c]: Add support for multi-session CDs from Gerd Knorr.
-
-	* scsi.h: Add manufactor field for keeping track of device
-	manufacturer.
-
-	* scsi.c: More spelling corrections.
-
-	* qlogic.h, qlogic.c, README.qlogic: New driver from Tom Zerucha.
-
-	* in2000.c, in2000.h: New driver from Brad McLean/Bill Earnest.
-
-	* fdomain.c: Spelling correction.
-
-	* eata.c: Spelling correction.
-
-Fri Nov 18 15:22:44 1994  Eric Youngdale  (eric@andante.aib.com)
-
-	* Linux 1.1.65 released.
-
-	* eata.h: Update version string to 1.08.00.
-
-	* eata.c: Set sg_tablesize correctly for DPT PM2012 boards.
-
-	* aha274x.seq: Spell checking.
-
-	* README.st: Likewise.
-
-	* README.aha274x: Likewise.
-
-	* ChangeLog: Likewise.
-
-Tue Nov 15 15:35:08 1994  Eric Youngdale  (eric@andante.aib.com)
-
-	* Linux 1.1.64 released.
-
-	* u14-34f.h: Update version number to 1.10.01.
-
-	* u14-34f.c: Use Scsi_Host can_queue variable instead of one from template.
-
-	* eata.[c,h]: New driver for DPT boards from Dario Ballabio.
-
-	* buslogic.c: Use can_queue field.
-
-Wed Nov 30 12:09:09 1994  Eric Youngdale  (eric@andante.aib.com)
-
-	* Linux 1.1.63 released.
-
-	* sd.c: Give I/O error if we attempt 512 byte I/O to a disk with
-	1024 byte sectors.
-
-	* scsicam.c: Make sure we do read from whole disk (mask off
-	partition).
-
-	* scsi.c: Use can_queue in Scsi_Host structure.
-	Fix panic message about invalid host.
-
-	* hosts.c: Initialize can_queue from template.
-
-	* hosts.h: Add can_queue to Scsi_Host structure.
-
-	* aha1740.c: Print out warning about NULL ecbptr.
-
-Fri Nov  4 12:40:30 1994  Eric Youngdale  (eric@andante.aib.com)
-
-	* Linux 1.1.62 released.
-
-	* fdomain.c: Update to version 5.20. (From Rik Faith).  Support
-	BIOS version 3.5.
-
-	* st.h: Add ST_EOD symbol.
-
-	* st.c: Patches from Kai Makisara - support additional densities,
-	add support for MTFSS, MTBSS, MTWSM commands.
-
-	* README.st: Update to document new commands.
-
-	* scsi.c: Add Mediavision CDR-H93MV to blacklist.
-
-Sat Oct 29 20:57:36 1994  Eric Youngdale  (eric@andante.aib.com)
-
-	* Linux 1.1.60 released.
-
-	* u14-34f.[c,h]: New driver from Dario Ballabio.
-
-	* aic7770.c, aha274x_seq.h, aha274x.seq, aha274x.h, aha274x.c,
-	README.aha274x: New files, new driver from John Aycock.
-
-
-Tue Oct 11 08:47:39 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.54 released.
-
-	* Add third PCI chip id.  [Drew]
-
-	* buslogic.c: Set BUSLOGIC_CMDLUN back to 1 [Eric].
-
-	* ultrastor.c: Fix asm directives for new GCC.
-
-	* sr.c, sd.c: Use new end_scsi_request function.
-
-	* scsi.h(end_scsi_request): Return pointer to block if still
-	active, else return NULL if inactive.  Fixes race condition.
-
-Sun Oct  9 20:23:14 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.53 released.
-
-	* scsi.c: Do not allocate dma bounce buffers if we have exactly
-	16Mb.
-
-Fri Sep  9 05:35:30 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.51 released.
-
-	* aha152x.c: Add support for disabling the parity check.  Update
-	to version 1.4. [Juergen].
-
-	* seagate.c: Tweak debugging message.
-
-Wed Aug 31 10:15:55 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.50 released.
-
-	* aha152x.c: Add eb800 for Vtech Platinum SMP boards. [Juergen].
-
-	* scsi.c: Add Quantum PD1225S to blacklist.
-
-Fri Aug 26 09:38:45 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.49 released.
-
-	* sd.c: Fix bug when we were deleting the wrong entry if we
-	get an unsupported sector size device.
-
-	* sr.c: Another spelling patch.
-
-Thu Aug 25 09:15:27 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.48 released.
-
-	* Throughout: Use new semantics for request_dma, as appropriate.
-
-	* sr.c: Print correct device number.
-
-Sun Aug 21 17:49:23 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.47 released.
-
-	* NCR5380.c: Add support for LIMIT_TRANSFERSIZE.
-
-	* constants.h: Add prototype for print_Scsi_Cmnd.
-
-	* pas16.c: Some more minor tweaks.  Test for Mediavision board.
-	Allow for disks > 1Gb.  [Drew??]
-
-	* sr.c: Set SCpnt->transfersize.
-
-Tue Aug 16 17:29:35 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.46 released.
-
-	* Throughout: More spelling fixups.
-
-	* buslogic.c: Add a few more fixups from Dave.  Disk translation
-	mainly.
-
-	* pas16.c: Add a few patches (Drew?).
-
-
-Thu Aug 11 20:45:15 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.44 released.
-
-	* hosts.c: Add type casts for scsi_init_malloc.
-
-	* scsicam.c: Add type cast.
-
-Wed Aug 10 19:23:01 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.43 released.
-
-	* Throughout: Spelling cleanups. [??]
-
-	* aha152x.c, NCR53*.c, fdomain.c, g_NCR5380.c, pas16.c, seagate.c,
-	 t128.c: Use request_irq, not irqaction. [??]
-
-	* aha1542.c: Move test for shost before we start to use shost.
-
-	* aha1542.c, aha1740.c, ultrastor.c, wd7000.c: Use new
-	calling sequence for request_irq.
-
-	* buslogic.c: Update from Dave Gentzel.
-
-Tue Aug  9 09:32:59 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.42 released.
-
-	* NCR5380.c: Change NCR5380_print_status to static.
-
-	* seagate.c: A few more bugfixes.  Only Drew knows what they are
-	for.
-
-	* ultrastor.c: Tweak some __asm__ directives so that it works
-	with newer compilers. [??]
-
-Sat Aug  6 21:29:36 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.40 released.
-
-	* NCR5380.c: Return SCSI_RESET_WAKEUP from reset function.
-
-	* aha1542.c: Reset mailbox status after a bus device reset.
-
-	* constants.c: Fix typo (;;).
-
-	* g_NCR5380.c:
-	* pas16.c:  Correct usage of NCR5380_init.
-
-	* scsi.c: Remove redundant (and unused variables).
-
-	* sd.c: Use memset to clear all of rscsi_disks before we use it.
-
-	* sg.c: Ditto, except for scsi_generics.
-
-	* sr.c: Ditto, except for scsi_CDs.
-
-	* st.c: Initialize STp->device.
-
-	* seagate.c: Fix bug. [Drew]
-
-Thu Aug  4 08:47:27 1994  Eric Youngdale  (eric@andante)
-
-	* Linux 1.1.39 released.
-
-	* Makefile: Fix typo in NCR53C7xx.
-
-	* st.c: Print correct number for device.
-
-Tue Aug  2 11:29:14 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.38 released.
-
-	Lots of changes in 1.1.38.  All from Drew unless otherwise noted.
-
-	* 53c7,8xx.c: New file from Drew.  PCI driver.
-
-	* 53c7,8xx.h: Likewise.
-
-	* 53c7,8xx.scr: Likewise.
-
-	* 53c8xx_d.h, 53c8xx_u.h, script_asm.pl: Likewise.
-
-	* scsicam.c: New file from Drew.  Read block 0 on the disk and
-	read the partition table.  Attempt to deduce the geometry from
-	the partition table if possible.  Only used by 53c[7,8]xx right
-	now, but could be used by any device for which we have no way
-	of identifying the geometry.
-
-	* sd.c: Use device letters instead of sd%d in a lot of messages.
-
-	* seagate.c: Fix bug that resulted in lockups with some devices.
-
-	* sr.c (sr_open): Return -EROFS, not -EACCES if we attempt to open
-	device for write.
-
-	* hosts.c, Makefile: Update for new driver.
-
-	* NCR5380.c, NCR5380.h, g_NCR5380.h: Update from Drew to support
-	53C400 chip.
-
-	* constants.c: Define CONST_CMND and CONST_MSG.  Other minor
-	cleanups along the way.  Improve handling of CONST_MSG.
-
-	* fdomain.c, fdomain.h: New version from Rik Faith.  Update to
-	5.18.  Should now support TMC-3260 PCI card with 18C30 chip.
-
-	* pas16.c: Update with new irq initialization.
-
-	* t128.c: Update with minor cleanups.
-
-	* scsi.c (scsi_pid): New variable - gives each command a unique
-	id. Add Quantum LPS5235S to blacklist.  Change in_scan to
-	in_scan_scsis and make global.
-
-	* scsi.h: Add some defines for extended message handling,
-	INITIATE/RELEASE_RECOVERY.  Add a few new fields to support sync
-	transfers.
-
-	* scsi_ioctl.h: Add ioctl to request synchronous transfers.
-
-
-Tue Jul 26 21:36:58 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.37 released.
-
-	* aha1542.c: Always call aha1542_mbenable, use new udelay
-	mechanism so we do not wait a long time if the board does not
-	implement this command.
-
-	* g_NCR5380.c: Remove #include <linux/config.h> and #if
-	defined(CONFIG_SCSI_*).
-
-	* seagate.c: Likewise.
-
-	Next round of changes to support loadable modules.  Getting closer
-	now, still not possible to do anything remotely usable.
-
-	hosts.c: Create a linked list of detected high level devices.
-	(scsi_register_device): New function to insert into this list.
-	(scsi_init): Call scsi_register_device for each of the known high
-	level drivers.
-
-	hosts.h: Add prototype for linked list header.  Add structure
-	definition for device template structure which defines the linked
-	list.
-
-	scsi.c: (scan_scsis): Use linked list instead of knowledge about
-	existing high level device drivers.
-	(scsi_dev_init): Use init functions for drivers on linked list
-	instead of explicit list to initialize and attach devices to high
-	level drivers.
-
-	scsi.h: Add new field "attached" to scsi_device - count of number
-	of high level devices attached.
-
-	sd.c, sr.c, sg.c, st.c: Adjust init/attach functions to use new
-	scheme.
-
-Sat Jul 23 13:03:17 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.35 released.
-
-	* ultrastor.c: Change constraint on asm() operand so that it works
-	with gcc 2.6.0.
-
-Thu Jul 21 10:37:39 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.33 released.
-
-	* sr.c(sr_open): Do not allow opens with write access.
-
-Mon Jul 18 09:51:22 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.31 released.
-
-	* sd.c: Increase SD_TIMEOUT from 300 to 600.
-
-	* sr.c: Remove stray task_struct* variable that was no longer
-	used.
-
-	* sr_ioctl.c: Fix typo in up() call.
-
-Sun Jul 17 16:25:29 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.30 released.
-
-	* scsi.c (scan_scsis): Fix detection of some Toshiba CDROM drives
-	that report themselves as disk drives.
-
-	* (Throughout): Use request.sem instead of request.waiting.
-	Should fix swap problem with fdomain.
-
-Thu Jul 14 10:51:42 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.29 released.
-
-	* scsi.c (scan_scsis): Add new devices to end of linked list, not
-	to the beginning.
-
-	* scsi.h (SCSI_SLEEP): Remove brain dead hack to try to save
-	the task state before sleeping.
-
-Sat Jul  9 15:01:03 1994  Eric Youngdale  (eric@esp22)
-
-	More changes to eventually support loadable modules.  Mainly
-	we want to use linked lists instead of arrays because it is easier
-	to dynamically add and remove things this way.
-
-	Quite a bit more work is needed before loadable modules are
-	possible (and usable) with scsi, but this is most of the grunge
-	work.
-
-	* Linux 1.1.28 released.
-
-	* scsi.c, scsi.h (allocate_device, request_queueable): Change
-	argument from index into scsi_devices to a pointer to the
-	Scsi_Device struct.
-
-	* Throughout: Change all calls to allocate_device,
-	request_queueable to use new calling sequence.
-
-	* Throughout: Use SCpnt->device instead of
-	scsi_devices[SCpnt->index].  Ugh - the pointer was there all along
-	- much cleaner this way.
-
-	* scsi.c (scsi_init_malloc, scsi_free_malloc): New functions -
-	allow us to pretend that we have a working malloc when we
-	initialize.  Use this instead of passing memory_start, memory_end
-	around all over the place.
-
-	* scsi.h, st.c, sr.c, sd.c, sg.c: Change *_init1 functions to use
-	scsi_init_malloc, remove all arguments, no return value.
-
-	* scsi.h: Remove index field from Scsi_Device and Scsi_Cmnd
-	structs.
-
-	* scsi.c (scsi_dev_init): Set up for scsi_init_malloc.
-	(scan_scsis): Get SDpnt from scsi_init_malloc, and refresh
-	when we discover a device.  Free pointer before returning.
-	Change scsi_devices into a linked list.
-
-	* scsi.c (scan_scsis): Change to only scan one host.
-	(scsi_dev_init): Loop over all detected hosts, and scan them.
-
-	* hosts.c  (scsi_init_free): Change so that  number of extra bytes
-	is stored in struct, and we do not have to pass it each time.
-
-	* hosts.h: Change Scsi_Host_Template struct to include "next" and
-	"release" functions.  Initialize to NULL in all low level
-	adapters.
-
-	* hosts.c: Rename scsi_hosts to builtin_scsi_hosts, create linked
-	list scsi_hosts, linked together with the new "next" field.
-
-Wed Jul  6 05:45:02 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.25 released.
-
-	* aha152x.c: Changes from Juergen - cleanups and updates.
-
-	* sd.c, sr.c: Use new check_media_change and revalidate
-	file_operations fields.
-
-	* st.c, st.h: Add changes from Kai Makisara, dated Jun 22.
-
-	* hosts.h: Change SG_ALL back to 0xff.  Apparently soft error
-	in /dev/brain resulted in having this bumped up.
-	Change first parameter in bios_param function to be Disk * instead
-	of index into rscsi_disks.
-
-	* sd_ioctl.c: Pass pointer to rscsi_disks element instead of index
-	to array.
-
-	* sd.h: Add struct name "scsi_disk" to typedef for Scsi_Disk.
-
-	* scsi.c: Remove redundant Maxtor XT8760S from blacklist.
-	In scsi_reset, add printk when DEBUG defined.
-
-	* All low level drivers: Modify definitions of bios_param in
-	appropriate way.
-
-Thu Jun 16 10:31:59 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.20 released.
-
-	* scsi_ioctl.c: Only pass down the actual number of characters
-	required to scsi_do_cmd, not the one rounded up to a even number
-	of sectors.
-
-	* ultrastor.c: Changes from Caleb Epstein for 24f cards.  Support
-	larger SG lists.
-
-	* ultrastor.c: Changes from me - use scsi_register to register
-	host.  Add some consistency checking,
-
-Wed Jun  1 21:12:13 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.19 released.
-
-	* scsi.h: Add new return code for reset() function:
-	SCSI_RESET_PUNT.
-
-	* scsi.c: Make SCSI_RESET_PUNT the same as SCSI_RESET_WAKEUP for
-	now.
-
-	* aha1542.c: If the command responsible for the reset is not
-	pending, return SCSI_RESET_PUNT.
-
-	* aha1740.c, buslogic.c, wd7000.c, ultrastor.c: Return
-	SCSI_RESET_PUNT instead of SCSI_RESET_SNOOZE.
-
-Tue May 31 19:36:01 1994  Eric Youngdale  (eric@esp22)
-
-	* buslogic.c: Do not print out message about "must be Adaptec"
-	if we have detected a buslogic card.  Print out a warning message
-	if we are configuring for >16Mb, since the 445S at board level
-	D or earlier does not work right.  The "D" level board can be made
-	to work by flipping an undocumented switch, but this is too subtle.
-
-    Changes based upon patches in Yggdrasil distribution.
-
-	* sg.c, sg.h: Return sense data to user.
-
-	* aha1542.c, aha1740.c, buslogic.c: Do not panic if
-	sense buffer is wrong size.
-
-	* hosts.c: Test for ultrastor card before any of the others.
-
-	* scsi.c: Allow boot-time option for max_scsi_luns=? so that
-	buggy firmware has an easy work-around.
-
-Sun May 15 20:24:34 1994  Eric Youngdale  (eric@esp22)
-
-	* Linux 1.1.15 released.
-
-	Post-codefreeze thaw...
-
-	* buslogic.[c,h]: New driver from David Gentzel.
-
-	* hosts.h: Add use_clustering field to explicitly say whether
-	clustering should be used for devices attached to this host
-	adapter.  The buslogic board apparently supports large SG lists,
-	but it is apparently faster if sd.c condenses this into a smaller
-	list.
-
-	* sd.c: Use this field instead of heuristic.
-
-	* All host adapter include files: Add appropriate initializer for
-	use_clustering field.
-
-	* scsi.h: Add #defines for return codes for the abort and reset
-	functions.  There are now a specific set of return codes to fully
-	specify all of the possible things that the low-level adapter
-	could do.
-
-	* scsi.c: Act based upon return codes from abort/reset functions.
-
-	* All host adapter abort/reset functions: Return new return code.
-
-	* Add code in scsi.c to help debug timeouts.  Use #define
-	DEBUG_TIMEOUT to enable this.
-
-	* scsi.c: If the host->irq field is set, use
-	disable_irq/enable_irq before calling queuecommand if we
-	are not already in an interrupt.  Reduce races, and we
-	can be sloppier about cli/sti in the interrupt routines now
-	(reduce interrupt latency).
-
-	* constants.c: Fix some things to eliminate warnings.  Add some
-	sense descriptions that were omitted before.
-
-	* aha1542.c: Watch for SCRD from host adapter - if we see it, set
-	a flag.  Currently we only print out the number of pending
-	commands that might need to be restarted.
-
-	* aha1542.c (aha1542_abort): Look for lost interrupts, OGMB still
-	full, and attempt to recover.  Otherwise give up.
-
-	* aha1542.c (aha1542_reset): Try BUS DEVICE RESET, and then pass
-	DID_RESET back up to the upper level code for all commands running
-	on this target (even on different LUNs).
-
-Sat May  7 14:54:01 1994
-
-	* Linux 1.1.12 released.
-
-	* st.c, st.h: New version from Kai.  Supports boot time
-	specification of number of buffers.
-
-	* wd7000.[c,h]: Updated driver from John Boyd.  Now supports
-	more than one wd7000 board in machine at one time, among other things.
-
-Wed Apr 20 22:20:35 1994
-
-	* Linux 1.1.8 released.
-
-	* sd.c: Add a few type casts where scsi_malloc is called.
-
-Wed Apr 13 12:53:29 1994
-
-	* Linux 1.1.4 released.
-
-	* scsi.c: Clean up a few printks (use %p to print pointers).
-
-Wed Apr 13 11:33:02 1994
-
-	* Linux 1.1.3 released.
-
-	* fdomain.c: Update to version 5.16 (Handle different FIFO sizes
-	better).
-
-Fri Apr  8 08:57:19 1994
-
-	* Linux 1.1.2 released.
-
-	* Throughout: SCSI portion of cluster diffs added.
-
-Tue Apr  5 07:41:50 1994
-
-	* Linux 1.1 development tree initiated.
-
-	* The linux 1.0 development tree is now effectively frozen except
-	for obvious bugfixes.
-
-******************************************************************
-******************************************************************
-******************************************************************
-******************************************************************
-
-Sun Apr 17 00:17:39 1994
-
-	* Linux 1.0, patchlevel 9 released.
-
-	* fdomain.c: Update to version 5.16 (Handle different FIFO sizes
-	better).
-
-Thu Apr  7 08:36:20 1994
-
-	* Linux 1.0, patchlevel8 released.
-
-	* fdomain.c: Update to version 5.15 from 5.9.  Handles 3.4 bios.
-
-Sun Apr  3 14:43:03 1994
-
-	* Linux 1.0, patchlevel6 released.
-
-	* wd7000.c: Make stab at fixing race condition.
-
-Sat Mar 26 14:14:50 1994
-
-	* Linux 1.0, patchlevel5 released.
-
-	* aha152x.c, Makefile: Fix a few bugs (too much data message).
-	Add a few more bios signatures. (Patches from Juergen).
-
-	* aha1542.c: Fix race condition in aha1542_out.
-
-Mon Mar 21 16:36:20 1994
-
-	* Linux 1.0, patchlevel3 released.
-
-	* sd.c, st.c, sr.c, sg.c: Return -ENXIO, not -ENODEV if we attempt
-	to open a non-existent device.
-
-	* scsi.c: Add Chinon cdrom to blacklist.
-
-	* sr_ioctl.c: Check return status of verify_area.
-
-Sat Mar  6 16:06:19 1994
-
-	* Linux 1.0 released (technically a pre-release).
-
-	* scsi.c: Add IMS CDD521, Maxtor XT-8760S to blacklist.
-
-Tue Feb 15 10:58:20 1994
-
-        * pl15e released.
-
-        * aha1542.c: For 1542C, allow dynamic device scan with >1Gb turned
-	off.
-
-	* constants.c: Fix typo in definition of CONSTANTS.
-
-        * pl15d released.
-
-Fri Feb 11 10:10:16 1994
-
-        * pl15c released.
-
-	* scsi.c: Add Maxtor XT-3280 and Rodime RO3000S to blacklist.
-
-	* scsi.c: Allow tagged queueing for scsi 3 devices as well.
-	Some really old devices report a version number of 0.  Disallow
-	LUN != 0 for these.
-
-Thu Feb 10 09:48:57 1994
-
-        * pl15b released.
-
-Sun Feb  6 12:19:46 1994
-
-        * pl15a released.
-
-Fri Feb  4 09:02:17 1994
-
-        * scsi.c: Add Teac cdrom to blacklist.
-
-Thu Feb  3 14:16:43 1994
-
-	* pl15 released.
-
-Tue Feb  1 15:47:43 1994
-
-	* pl14w released.
-
-	* wd7000.c (wd_bases): Fix typo in last change.
-
-Mon Jan 24 17:37:23 1994
-
-	* pl14u released.
-
-	* aha1542.c: Support 1542CF/extended bios.  Different from 1542C
-
-	* wd7000.c: Allow bios at 0xd8000 as well.
-
-	* ultrastor.c: Do not truncate cylinders to 1024.
-
-	* fdomain.c: Update to version 5.9 (add new bios signature).
-
-	* NCR5380.c: Update from Drew - should work a lot better now.
-
-Sat Jan  8 15:13:10 1994
-
-	* pl14o released.
-
-	* sr_ioctl.c: Zero reserved field before trying to set audio volume.
-
-Wed Jan  5 13:21:10 1994
-
-	* pl14m released.
-
-	* fdomain.c: Update to version 5.8.  No functional difference???
-
-Tue Jan  4 14:26:13 1994
-
-	* pl14l released.
-
-	* ultrastor.c: Remove outl, inl functions (now provided elsewhere).
-
-Mon Jan  3 12:27:25 1994
-
-	* pl14k released.
-
-	* aha152x.c: Remove insw and outsw functions.
-
-	* fdomain.c: Ditto.
-
-Wed Dec 29 09:47:20 1993
-
-	* pl14i released.
-
-	* scsi.c: Support RECOVERED_ERROR for tape drives.
-
-	* st.c: Update of tape driver from Kai.
-
-Tue Dec 21 09:18:30 1993
-
-	* pl14g released.
-
-	* aha1542.[c,h]: Support extended BIOS stuff.
-
-	* scsi.c: Clean up messages about disks, so they are displayed as
-	sda, sdb, etc instead of sd0, sd1, etc.
-
-	* sr.c:  Force reread of capacity if disk was changed.
-	Clear buffer before asking for capacity/sectorsize (some drives
-	do not report this properly).  Set needs_sector_size flag if
-	drive did not return sensible sector size.
-
-Mon Dec 13 12:13:47 1993
-
-	* aha152x.c: Update to version .101 from Juergen.
-
-Mon Nov 29 03:03:00 1993
-
-        * linux 0.99.14 released.
-
-	* All scsi stuff moved from kernel/blk_drv/scsi to drivers/scsi.
-
-	* Throughout: Grammatical corrections to various comments.
-
-	* Makefile: fix so that we do not need to compile things we are
-	not going to use.
-
-	* NCR5380.c, NCR5380.h, g_NCR5380.c, g_NCR5380.h, pas16.c,
-	pas16.h, t128.c, t128.h:  New files from Drew.
-
-	* aha152x.c, aha152x.h: New files from Juergen Fischer.
-
-	* aha1542.c: Support for more than one 1542 in the machine
-	at the same time.  Make functions static that do not need
-	visibility.
-
-	* aha1740.c: Set NEEDS_JUMPSTART flag in reset function, so we
-	know to restart the command.  Change prototype of aha1740_reset
-	to take a command pointer.
-
-	* constants.c: Clean up a few things.
-
-	* fdomain.c: Update to version 5.6.  Move snarf_region.  Allow
-	board to be set at different SCSI ids.  Remove support for
-	reselection (did not work well).  Set JUMPSTART flag in reset
-	code.
-
-	* hosts.c: Support new low-level adapters.  Allow for more than
-	one adapter of a given type.
-
-	* hosts.h: Allow for more than one adapter of a given type.
-
-	* scsi.c:  Add scsi_device_types array, if NEEDS_JUMPSTART is set
-	after a low-level reset, start the command again.  Sort blacklist,
-	and add Maxtor MXT-1240S, XT-4170S, NEC CDROM 84, Seagate ST157N.
-
-	* scsi.h: Add constants for tagged queueing.
-
-	* Throughout: Use constants from major.h instead of hardcoded
-	numbers for major numbers.
-
-	* scsi_ioctl.c: Fix bug in buffer length in ioctl_command.  Use
-	verify_area in GET_IDLUN ioctl.  Add new ioctls for
-	TAGGED_QUEUE_ENABLE, DISABLE.  Only allow IOCTL_SEND_COMMAND by
-	superuser.
-
-	* sd.c: Only pay attention to UNIT_ATTENTION for removable disks.
-	Fix bug where sometimes portions of blocks would get lost
-	resulting in processes hanging.  Add messages when we spin up a
-	disk, and fix a bug in the timing.  Increase read-ahead for disks
-	that are on a scatter-gather capable host adapter.
-
-	* seagate.c: Fix so that some parameters can be set from the lilo
-	prompt.  Supply jumpstart flag if we are resetting and need the
-	command restarted.   Fix so that we return 1 if we detect a card
-	so that multiple card detection works correctly.  Add yet another
-	signature for FD cards (950).  Add another signature for ST0x.
-
-	* sg.c, sg.h: New files from Lawrence Foard for generic scsi
-	access.
-
-	* sr.c:  Add type casts for (void*) so that we can do pointer
-	arithmetic.  Works with GCC without this, but it is not strictly
-	correct.  Same bugfix as was in sd.c.  Increase read-ahead a la
-	disk driver.
-
-	* sr_ioctl.c: Use scsi_malloc buffer instead of buffer from stack
-	since we cannot guarantee that the stack is < 16Mb.
-
-	ultrastor.c: Update to support 24f properly (JFC's driver).
-
-	wd7000.c: Supply jumpstart flag for reset.  Do not round up
-	number of cylinders in biosparam function.
-
-Sat Sep  4 20:49:56 1993
-
-    * 0.99pl13 released.
-
-    * Throughout:  Use check_region/snarf_region for all low-level
-    drivers.
-
-    * aha1542.c: Do hard reset instead of soft (some ethercard probes
-    screw us up).
-
-    * scsi.c: Add new flag ASKED_FOR_SENSE so that we can tell if we are
-    in a loop whereby the device returns null sense data.
-
-    * sd.c: Add code to spin up a drive if it is not already spinning.
-    Do this one at a time to make it easier on power supplies.
-
-    * sd_ioctl.c: Use sync_dev instead of fsync_dev in BLKFLSBUF ioctl.
-
-    * seagate.c: Switch around DATA/CONTROL lines.
-
-    * st.c: Change sense to unsigned.
-
-Thu Aug  5 11:59:18 1993
-
-    * 0.99pl12 released.
-
-    * constants.c, constants.h: New files with ascii descriptions of
-    various conditions.
-
-    * Makefile: Do not try to count the number of low-level drivers,
-    just generate the list of .o files.
-
-    * aha1542.c: Replace 16 with sizeof(SCpnt->sense_buffer).  Add tests
-    for addresses > 16Mb, panic if we find one.
-
-    * aha1740.c: Ditto with sizeof().
-
-    * fdomain.c: Update to version 3.18.  Add new signature, register IRQ
-    with irqaction.  Use ID 7 for new board.  Be more intelligent about
-    obtaining the h/s/c numbers for biosparam.
-
-    * hosts.c: Do not depend upon Makefile generated count of the number
-    of low-level host adapters.
-
-    * scsi.c: Use array for scsi_command_size instead of a function.  Add
-    Texel cdrom and Maxtor XT-4380S to blacklist.  Allow compile time
-    option for no-multi lun scan.  Add semaphore for possible problems
-    with handshaking, assume device is faulty until we know it not to be
-    the case.  Add DEBUG_INIT symbol to dump info as we scan for devices.
-    Zero sense buffer so we can tell if we need to request it.  When
-    examining sense information, request sense if buffer is all zero.
-    If RESET, request sense information to see what to do next.
-
-    * scsi_debug.c: Change some constants to use symbols like INT_MAX.
-
-    * scsi_ioctl.c (kernel_scsi_ioctl): New function -for making ioctl
-    calls from kernel space.
-
-    * sd.c: Increase timeout to 300.  Use functions in constants.h to
-    display info.  Use scsi_malloc buffer for READ_CAPACITY, since
-    we cannot guarantee that a stack based buffer is < 16Mb.
-
-    * sd_ioctl.c: Add BLKFLSBUF ioctl.
-
-    * seagate.c: Add new compile time options for ARBITRATE,
-    SLOW_HANDSHAKE, and SLOW_RATE.  Update assembly loops for transferring
-    data.  Use kernel_scsi_ioctl to request mode page with geometry.
-
-    * sr.c: Use functions in constants.c to display messages.
-
-    * st.c: Support for variable block size.
-
-    * ultrastor.c: Do not use cache for tape drives.  Set
-    unchecked_isa_dma flag, even though this may not be needed (gets set
-    later).
-
-Sat Jul 17 18:32:44 1993
-
-    * 0.99pl11 released.  C++ compilable.
-
-    * Throughout: Add type casts all over the place, and use "ip" instead
-    of "info" in the various biosparam functions.
-
-    * Makefile: Compile seagate.c with C++ compiler.
-
-    * aha1542.c: Always set ccb pointer as this gets trashed somehow on
-    some systems.  Add a few type casts.  Update biosparam function a little.
-
-    * aha1740.c: Add a few type casts.
-
-    * fdomain.c: Update to version 3.17 from 3.6.  Now works with
-    TMC-18C50.
-
-    * scsi.c: Minor changes here and there with datatypes.  Save use_sg
-    when requesting sense information so that this can properly be
-    restored if we retry the command.  Set aside dma buffers assuming each
-    block is 1 page, not 1Kb minix block.
-
-    * scsi_ioctl.c: Add a few type casts.  Other minor changes.
-
-    * sd.c:  Correctly  free all scsi_malloc'd memory if we run out of
-    dma_pool. Store blocksize information for each partition.
-
-    * seagate.c: Minor cleanups here and there.
-
-    * sr.c: Set up blocksize array for all discs.  Fix bug in freeing
-    buffers if we run out of dma pool.
-
-Thu Jun  2 17:58:11 1993
-
-    * 0.99pl10 released.
-
-    * aha1542.c: Support for BT 445S (VL-bus board with no dma channel).
-
-    * fdomain.c: Upgrade to version 3.6. Preliminary support for TNC-18C50.
-
-    * scsi.c: First attempt to fix problem with old_use_sg.  Change
-    NOT_READY to a SUGGEST_ABORT.  Fix timeout race where time might
-    get decremented past zero.
-
-    * sd.c: Add block_fsync function to dispatch table.
-
-    * sr.c: Increase timeout to 500 from 250.  Add entry for sync in
-    dispatch table (supply NULL).  If we do not have a sectorsize,
-    try to get it in the sd_open function.  Add new function just to
-    obtain sectorsize.
-
-    * sr.h: Add needs_sector_size semaphore.
-
-    * st.c: Add NULL for fsync in dispatch table.
-
-    * wd7000.c: Allow another condition for power on that are normal
-    and do not require a panic.
-
-Thu Apr 22 23:10:11 1993
-
-    * 0.99pl9 released.
-
-    * aha1542.c: Use (void) instead of () in setup_mailboxes.
-
-    * scsi.c: Initialize transfersize and underflow fields in SCmd to 0.
-    Do not panic for unsupported message bytes.
-
-    * scsi.h: Allocate 12 bytes instead of 10 for commands.  Add
-    transfersize and underflow fields.
-
-    * scsi_ioctl.c: Further bugfix to ioctl_probe.
-
-    * sd.c: Use long instead of int for last parameter in sd_ioctl.
-    Initialize transfersize and underflow fields.
-
-    * sd_ioctl.c: Ditto for sd_ioctl(,,,,);
-
-    * seagate.c: New version from Drew.  Includes new signatures for FD
-    cards.  Support for 0ws jumper. Correctly initialize
-    scsi_hosts[hostnum].this_id.  Improved handing of
-    disconnect/reconnect, and support command linking.  Use
-    transfersize and underflow fields.  Support scatter-gather.
-
-    * sr.c, sr_ioctl.c: Use long instead of int for last parameter in sr_ioctl.
-    Use buffer and buflength in do_ioctl.  Patches from Chris Newbold for
-    scsi-2 audio commands.
-
-    * ultrastor.c: Comment out in_byte (compiler warning).
-
-    * wd7000.c: Change () to (void) in wd7000_enable_dma.
-
-Wed Mar 31 16:36:25 1993
-
-    * 0.99pl8 released.
-
-    * aha1542.c: Handle mailboxes better for 1542C.
-        Do not truncate number of cylinders at 1024 for biosparam call.
-
-    * aha1740.c: Fix a few minor bugs for multiple devices.
-        Same as above for biosparam.
-
-    * scsi.c: Add lockable semaphore for removable devices that can have
-    media removal prevented.  Add another signature for flopticals.
-    (allocate_device): Fix race condition.  Allow more space in dma pool
-    for blocksizes of up to 4Kb.
-
-    * scsi.h: Define COMMAND_SIZE.  Define a SCSI specific version of
-    INIT_REQUEST that can run with interrupts off.
-
-    * scsi_ioctl.c: Make ioctl_probe function more idiot-proof.  If
-    a removable device says ILLEGAL REQUEST to a door-locking command,
-    clear lockable flag.  Add SCSI_IOCTL_GET_IDLUN ioctl.  Do not attempt
-    to lock door for devices that do not have lockable semaphore set.
-
-    * sd.c: Fix race condition for multiple disks.  Use INIT_SCSI_REQUEST
-    instead of INIT_REQUEST.  Allow sector sizes of 1024 and 256.  For
-    removable disks that are not ready, mark them as having a media change
-    (some drives do not report this later).
-
-    * seagate.c: Use volatile keyword for memory-mapped register pointers.
-
-    * sr.c: Fix race condition, a la sd.c.  Increase the number of retries
-    to 1.  Use INIT_SCSI_REQUEST.  Allow 512 byte sector sizes.  Do a
-    read_capacity when we init the device so we know the size and
-    sectorsize.
-
-    * st.c: If ioctl not found in st.c, try scsi_ioctl for others.
-
-    * ultrastor.c: Do not truncate number of cylinders at 1024 for
-    biosparam call.
-
-    * wd7000.c: Ditto.
-    Throughout: Use COMMAND_SIZE macro to determine length of scsi
-    command.
-
-
-
-Sat Mar 13 17:31:29 1993
-
-    * 0.99pl7 released.
-
-    Throughout: Improve punctuation in some messages, and use new
-    verify_area syntax.
-
-    * aha1542.c: Handle unexpected interrupts better.
-
-    * scsi.c: Ditto.  Handle reset conditions a bit better, asking for
-    sense information and retrying if required.
-
-    * scsi_ioctl.c: Allow for 12 byte scsi commands.
-
-    * ultrastor.c: Update to use scatter-gather.
-
-Sat Feb 20 17:57:15 1993
-
-    * 0.99pl6 released.
-
-    * fdomain.c: Update to version 3.5.  Handle spurious interrupts
-    better.
-
-    * sd.c: Use register_blkdev function.
-
-    * sr.c: Ditto.
-
-    * st.c: Use register_chrdev function.
-
-    * wd7000.c: Undo previous change.
-
-Sat Feb  6 11:20:43 1993
-
-    * 0.99pl5 released.
-
-    * scsi.c: Fix bug in testing for UNIT_ATTENTION.
-
-    * wd7000.c: Check at more addresses for bios.  Fix bug in biosparam
-    (heads & sectors turned around).
-
-Wed Jan 20 18:13:59 1993
-
-    * 0.99pl4 released.
-
-    * scsi.c: Ignore leading spaces when looking for blacklisted devices.
-
-    * seagate.c: Add a few new signatures for FD cards.  Another patch
-    with SCint to fix race condition.  Use recursion_depth to keep track
-    of how many times we have been recursively called, and do not start
-    another command unless we are on the outer level.  Fixes bug
-    with Syquest cartridge drives (used to crash kernel), because
-    they do not disconnect with large data transfers.
-
-Tue Jan 12 14:33:36 1993
-
-    * 0.99pl3 released.
-
-    * fdomain.c: Update to version 3.3 (a few new signatures).
-
-    * scsi.c: Add CDU-541, Denon DRD-25X to blacklist.
-    (allocate_request, request_queueable): Init request.waiting to NULL if
-    non-buffer type of request.
-
-    * seagate.c:  Allow controller to be overridden with CONTROLLER symbol.
-    Set SCint=NULL when we are done, to remove race condition.
-
-    * st.c: Changes from Kai.
-
-Wed Dec 30 20:03:47 1992
-
-    * 0.99pl2 released.
-
-    * scsi.c: Blacklist back in.  Remove Newbury drive as other bugfix
-    eliminates need for it here.
-
-    * sd.c: Return ENODEV instead of EACCES if no such device available.
-    (sd_init) Init blkdev_fops earlier so that sd_open is available sooner.
-
-    * sr.c: Same as above for sd.c.
-
-    * st.c: Return ENODEV instead of ENXIO if no device.  Init chrdev_fops
-    sooner, so that it is always there even if no tapes.
-
-    * seagate.c (controller_type): New variable to keep track of ST0x or
-    FD.  Modify signatures list to indicate controller type, and init
-    controller_type once we find a match.
-
-    * wd7000.c (wd7000_set_sync): Remove redundant function.
-
-Sun Dec 20 16:26:24 1992
-
-    * 0.99pl1 released.
-
-    * scsi_ioctl.c: Bugfix - check dev->index, not dev->id against
-    NR_SCSI_DEVICES.
-
-    * sr_ioctl.c: Verify that device exists before allowing an ioctl.
-
-    * st.c: Patches from Kai - change timeout values, improve end of tape
-    handling.
-
-Sun Dec 13 18:15:23 1992
-
-    * 0.99 kernel released.  Baseline for this ChangeLog.

+ 0 - 5
Documentation/scsi/Mylex.txt

@@ -1,5 +0,0 @@
-Please see the file README.BusLogic for information about Linux support for
-Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters.
-
-The Mylex DAC960 PCI RAID Controllers are now supported.  Please consult
-http://sourceforge.net/projects/dandelion for further information on the DAC960 driver.

+ 0 - 14
Documentation/scsi/scsi-parameters.txt

@@ -34,11 +34,6 @@ parameters may be changed at runtime by the command
 			See drivers/scsi/BusLogic.c, comment before function
 			See drivers/scsi/BusLogic.c, comment before function
 			BusLogic_ParseDriverOptions().
 			BusLogic_ParseDriverOptions().
 
 
-	eata=		[HW,SCSI]
-
-	fdomain=	[HW,SCSI]
-			See header of drivers/scsi/fdomain.c.
-
 	gdth=		[HW,SCSI]
 	gdth=		[HW,SCSI]
 			See header of drivers/scsi/gdth.c.
 			See header of drivers/scsi/gdth.c.
 
 
@@ -70,8 +65,6 @@ parameters may be changed at runtime by the command
 	ncr53c400a=	[HW,SCSI]
 	ncr53c400a=	[HW,SCSI]
 			See Documentation/scsi/g_NCR5380.txt.
 			See Documentation/scsi/g_NCR5380.txt.
 
 
-	ncr53c406a=	[HW,SCSI]
-
 	ncr53c8xx=	[HW,SCSI]
 	ncr53c8xx=	[HW,SCSI]
 
 
 	osst=		[HW,SCSI] SCSI Tape Driver
 	osst=		[HW,SCSI] SCSI Tape Driver
@@ -110,12 +103,5 @@ parameters may be changed at runtime by the command
 	st=		[HW,SCSI] SCSI tape parameters (buffers, etc.)
 	st=		[HW,SCSI] SCSI tape parameters (buffers, etc.)
 			See Documentation/scsi/st.txt.
 			See Documentation/scsi/st.txt.
 
 
-	sym53c416=	[HW,SCSI]
-			See header of drivers/scsi/sym53c416.c.
-
-	tmscsim=	[HW,SCSI]
-			See comment before function dc390_setup() in
-			drivers/scsi/tmscsim.c.
-
 	wd33c93=	[HW,SCSI]
 	wd33c93=	[HW,SCSI]
 			See header of drivers/scsi/wd33c93.c.
 			See header of drivers/scsi/wd33c93.c.

+ 1 - 121
Documentation/scsi/scsi_mid_low_api.txt

@@ -114,9 +114,7 @@ called "xxx" could be defined as
 "static int xxx_slave_alloc(struct scsi_device * sdev) { /* code */ }"
 "static int xxx_slave_alloc(struct scsi_device * sdev) { /* code */ }"
 
 
 ** the scsi_host_alloc() function is a replacement for the rather vaguely
 ** the scsi_host_alloc() function is a replacement for the rather vaguely
-named scsi_register() function in most situations. The scsi_register()
-and scsi_unregister() functions remain to support legacy LLDs that use
-the passive initialization model.
+named scsi_register() function in most situations.
 
 
 
 
 Hotplug initialization model
 Hotplug initialization model
@@ -228,79 +226,6 @@ slave_configure() callbacks). Such instances are "owned" by the mid-level.
 struct scsi_device instances are freed after slave_destroy().
 struct scsi_device instances are freed after slave_destroy().
 
 
 
 
-Passive initialization model
-============================
-These older LLDs include a file called "scsi_module.c" [yes the ".c" is a
-little surprising] in their source code. For that file to work an
-instance of struct scsi_host_template with the name "driver_template"
-needs to be defined. Here is a typical code sequence used in this model:
-    static struct scsi_host_template driver_template = {
-        ...
-    };
-    #include "scsi_module.c"
-
-The scsi_module.c file contains two functions:
-  - init_this_scsi_driver() which is executed when the LLD is
-    initialized (i.e. boot time or module load time)
-  - exit_this_scsi_driver() which is executed when the LLD is shut
-    down (i.e. module unload time)
-Note: since these functions are tagged with __init and __exit qualifiers
-an LLD should not call them explicitly (since the kernel does that).
-
-Here is an example of an initialization sequence when two hosts are
-detected (so detect() returns 2) and the SCSI bus scan on each host
-finds 1 SCSI device (and a second device does not respond).
-
-LLD                      mid level                 LLD
-===----------------------=========-----------------===------
-init_this_scsi_driver() ----+
-                            |
-                         detect()  -----------------+
-                            |                       |
-                            |                scsi_register()
-                            |                scsi_register()
-                            |
-                      slave_alloc()
-                      slave_configure()  -->  scsi_change_queue_depth()
-                      slave_alloc()   ***
-                      slave_destroy() ***
-                            |
-                      slave_alloc()
-                      slave_configure()
-                      slave_alloc()   ***
-                      slave_destroy() ***
-------------------------------------------------------------
-
-The mid level invokes scsi_change_queue_depth() with "cmd_per_lun" for that
-host as the queue length. These settings can be overridden by a
-slave_configure() supplied by the LLD.
-
-*** For scsi devices that the mid level tries to scan but do not
-    respond, a slave_alloc(), slave_destroy() pair is called.
-
-Here is an LLD shutdown sequence:
-
-LLD                      mid level                 LLD
-===----------------------=========-----------------===------
-exit_this_scsi_driver() ----+
-                            |
-                     slave_destroy()
-                        release()   -->   scsi_unregister()
-                            |
-                     slave_destroy()
-                        release()   -->   scsi_unregister()
-------------------------------------------------------------
-
-An LLD need not define slave_destroy() (i.e. it is optional). 
-
-The shortcoming of the "passive initialization model" is that host
-registration and de-registration are (typically) tied to LLD initialization
-and shutdown. Once the LLD is initialized then a new host that appears
-(e.g. via hotplugging) cannot easily be added without a redundant
-driver shutdown and re-initialization. It may be possible to write an LLD
-that uses both initialization models.
-
-
 Reference Counting
 Reference Counting
 ==================
 ==================
 The Scsi_Host structure has had reference counting infrastructure added.
 The Scsi_Host structure has had reference counting infrastructure added.
@@ -738,7 +663,6 @@ The interface functions are listed below in alphabetical order.
 
 
 Summary:
 Summary:
    bios_param - fetch head, sector, cylinder info for a disk
    bios_param - fetch head, sector, cylinder info for a disk
-   detect - detects HBAs this driver wants to control
    eh_timed_out - notify the host that a command timer expired
    eh_timed_out - notify the host that a command timer expired
    eh_abort_handler - abort given command
    eh_abort_handler - abort given command
    eh_bus_reset_handler - issue SCSI bus reset
    eh_bus_reset_handler - issue SCSI bus reset
@@ -748,7 +672,6 @@ Summary:
    ioctl - driver can respond to ioctls
    ioctl - driver can respond to ioctls
    proc_info - supports /proc/scsi/{driver_name}/{host_no}
    proc_info - supports /proc/scsi/{driver_name}/{host_no}
    queuecommand - queue scsi command, invoke 'done' on completion
    queuecommand - queue scsi command, invoke 'done' on completion
-   release - release all resources associated with given host
    slave_alloc - prior to any commands being sent to a new device 
    slave_alloc - prior to any commands being sent to a new device 
    slave_configure - driver fine tuning for given device after attach
    slave_configure - driver fine tuning for given device after attach
    slave_destroy - given device is about to be shut down
    slave_destroy - given device is about to be shut down
@@ -784,28 +707,6 @@ Details:
                    sector_t capacity, int params[3])
                    sector_t capacity, int params[3])
 
 
 
 
-/**
- *      detect - detects HBAs this driver wants to control
- *      @shtp: host template for this driver.
- *
- *      Returns number of hosts this driver wants to control. 0 means no
- *      suitable hosts found.
- *
- *      Locks: none held
- *
- *      Calling context: process [invoked from init_this_scsi_driver()]
- *
- *      Notes: First function called from the SCSI mid level on this
- *      driver. Upper level drivers (e.g. sd) may not (yet) be present.
- *      For each host found, this method should call scsi_register() 
- *      [see hosts.c].
- *
- *      Defined in: LLD (required if "passive initialization mode" is used,
- *                       not invoked in "hotplug initialization mode")
- **/
-    int detect(struct scsi_host_template * shtp)
-
-
 /**
 /**
  *      eh_timed_out - The timer for the command has just fired
  *      eh_timed_out - The timer for the command has just fired
  *      @scp: identifies command timing out
  *      @scp: identifies command timing out
@@ -1073,27 +974,6 @@ Details:
     int queuecommand(struct Scsi_Host *shost, struct scsi_cmnd * scp)
     int queuecommand(struct Scsi_Host *shost, struct scsi_cmnd * scp)
 
 
 
 
-/**
- *      release - release all resources associated with given host
- *      @shp: host to be released.
- *
- *      Return value ignored (could soon be a function returning void).
- *
- *      Locks: none held
- *
- *      Calling context: process
- *
- *      Notes: Invoked from scsi_module.c's exit_this_scsi_driver().
- *      LLD's implementation of this function should call 
- *      scsi_unregister(shp) prior to returning.
- *      Only needed for old-style host templates.
- *
- *      Defined in: LLD (required in "passive initialization model",
- *                       should not be defined in hotplug model)
- **/
-    int release(struct Scsi_Host * shp)
-
-
 /**
 /**
  *      slave_alloc -   prior to any commands being sent to a new device 
  *      slave_alloc -   prior to any commands being sent to a new device 
  *                      (i.e. just prior to scan) this call is made
  *                      (i.e. just prior to scan) this call is made

+ 22 - 0
Documentation/scsi/sd-parameters.txt

@@ -0,0 +1,22 @@
+Linux SCSI Disk Driver (sd) Parameters
+======================================
+
+cache_type (RW)
+---------------
+Enable/disable drive write & read cache.
+
+ cache_type string          | WCE RCD | Write cache | Read cache
+----------------------------+---------+-------------+------------
+ write through              | 0   0   | off         | on
+ none                       | 0   1   | off         | off
+ write back                 | 1   0   | on          | on
+ write back, no read (daft) | 1   1   | on          | off
+
+To set cache type to "write back" and save this setting to the drive:
+
+  # echo "write back" > cache_type
+
+To modify the caching mode without making the change persistent, prepend
+"temporary " to the cache type string. E.g.:
+
+  # echo "temporary write back" > cache_type

+ 0 - 443
Documentation/scsi/tmscsim.txt

@@ -1,443 +0,0 @@
-The tmscsim driver
-==================
-
-1. Purpose and history
-2. Installation
-3. Features
-4. Configuration via /proc/scsi/tmscsim/?
-5. Configuration via boot/module params
-6. Potential improvements
-7. Bug reports, debugging and updates
-8. Acknowledgements
-9. Copyright
-
-
-1. Purpose and history
-----------------------
-The tmscsim driver supports PCI SCSI Host Adapters based on the AM53C974
-chip. AM53C974 based SCSI adapters include: 
- Tekram DC390, DC390T
- Dawicontrol 2974
- QLogic Fast! PCI Basic
- some on-board adapters
-(This is most probably not a complete list)
-
-It has originally written by C.L. Huang from the Tekram corp. to support the
-Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram
-scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F
-(NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter,
-tmscsiw, which supported DC390W/U/F adapters. It's not maintained any more,
-as the ncr53c8xx is perfectly supporting these adapters since some time.
-
-The driver first appeared in April 1996, exclusively supported the DC390 
-and has been enhanced since then in various steps. In May 1998 support for 
-general AM53C974 based adapters and some possibilities to configure it were
-added. The non-DC390 support works by assuming some values for the data
-normally taken from the DC390 EEPROM. See below (chapter 5) for details.
-
-When using the DC390, the configuration is still be done using the DC390
-BIOS setup. The DC390 EEPROM is read and used by the driver, any boot or
-module parameters (chapter 5) are ignored! However, you can change settings
-dynamically, as described in chapter 4. 
-
-For a more detailed description of the driver's history, see the first lines
-of tmscsim.c.
-The numbering scheme isn't consistent. The first versions went from 1.00 to
-1.12, then 1.20a to 1.20t. Finally I decided to use the ncr53c8xx scheme. So
-the next revisions will be 2.0a to 2.0X (stable), 2.1a to 2.1X (experimental),
-2.2a to 2.2X (stable, again) etc. (X = anything between a and z.) If I send
-fixes to people for testing, I create intermediate versions with a digit 
-appended, e.g. 2.0c3.
-
-
-2. Installation
----------------
-If you got any recent kernel with this driver and document included in
-linux/drivers/scsi, you basically have to do nothing special to use this
-driver. Of course you have to choose to compile SCSI support and DC390(T)
-support into your kernel or as module when configuring your kernel for
-compiling.
-NEW: You may as well compile this module outside your kernel, using the
-supplied Makefile.
-
- If you got an old kernel (pre 2.1.127, pre 2.0.37p1) with an old version of
- this driver: Get dc390-21125-20b.diff.gz or dc390-2036p21-20b1.diff.gz from
- my web page and apply the patch. Apply further patches to upgrade to the 
- latest version of the driver.
-
- If you want to do it manually, you should copy the files (dc390.h,
- tmscsim.h, tmscsim.c, scsiiom.c and README.tmscsim) from this directory to
- linux/drivers/scsi. You have to recompile your kernel/module of course.
-
- You should apply the three patches included in dc390-120-kernel.diff
- (Applying them: cd /usr/src; patch -p0 <~/dc390-120-kernel.diff)
- The patches are against 2.1.125, so you might have to manually resolve
- rejections when applying to another kernel version.
-
- The patches will update the kernel startup code to allow boot parameters to
- be passed to the driver, update the Documentation and finally offer you the
- possibility to omit the non-DC390 parts of the driver.
- (By selecting "Omit support for non DC390" you basically disable the
- emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes
- of memory.)
-
-If you got a very old kernel without the tmscsim driver (pre 2.0.31)
-I recommend upgrading your kernel. However, if you don't want to, please
-contact me to get the appropriate patches.
-
-
-Upgrading a SCSI driver is always a delicate thing to do. The 2.0 driver has
-proven stable on many systems, but it's still a good idea to take some
-precautions. In an ideal world you would have a full backup of your disks.
-The world isn't ideal and most people don't have full backups (me neither).
-So take at least the following measures:
-* make your kernel remount the FS read-only on detecting an error:
-  tune2fs -e remount-ro /dev/sd??
-* have copies of your SCSI disk's partition tables on some safe location:
-  dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1
-  or just print it with:
-  fdisk -l | lpr
-* make sure you are able to boot Linux (e.g. from floppy disk using InitRD)
-  if your SCSI disk gets corrupted. You can use 
-  ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz
-
-One more warning: I used to overclock my PCI bus to 41.67 MHz. My Tekram
-DC390F (Sym53c875) accepted this as well as my Millennium. But the Am53C974
-produced errors and started to corrupt my disks. So don't do that! A 37.50
-MHz PCI bus works for me, though, but I don't recommend using higher clocks
-than the 33.33 MHz being in the PCI spec.
-
-
-3.Features
-----------
-- SCSI
- * Tagged command queueing
- * Sync speed up to 10 MHz
- * Disconnection
- * Multiple LUNs
-
-- General / Linux interface
- * Support for up to 4 AM53C974 adapters.
- * DC390 EEPROM usage or boot/module params
- * Information via cat /proc/scsi/tmscsim/?
- * Dynamically configurable by writing to /proc/scsi/tmscsim/?
- * Dynamic allocation of resources
- * SMP support: Locking on io_request lock (Linux 2.1/2.2) or adapter 
-    specific locks (Linux 2.5?)
- * Uniform source code for Linux-2.x.y
- * Support for dyn. addition/removal of devices via add/remove-single-device
-   (Try: echo "scsi add-single-device C B T U" >/proc/scsi/scsi 
-    C = Controller, B = Bus, T = Target SCSI ID, U = Unit SCSI LUN.) 
-    Use with care!
- * Try to use the partition table for the determination of the mapping
-
-
-4. Configuration via /proc/scsi/tmscsim/?
------------------------------------------
-First of all look at the output of /proc/scsi/tmscsim/? by typing
- cat /proc/scsi/tmscsim/?
-The "?" should be replaced by the SCSI host number. (The shell might do this
-for you.)
-You will see some info regarding the adapter and, at the end, a listing of
-the attached devices and their settings.
-
-Here's an example:
-garloff@kurt:/home/garloff > cat /proc/scsi/tmscsim/0
-Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 2.0e7 2000-11-28
-SCSI Host Nr 1, AM53C974 Adapter Nr 0
-IOPortBase 0xb000, IRQ 10
-MaxID 8, MaxLUN 8, AdapterID 6, SelTimeout 250 ms, DelayReset 1 s
-TagMaxNum 16, Status 0x00, ACBFlag 0x00, GlitchEater 24 ns
-Statistics: Cmnds 1470165, Cmnds not sent directly 0, Out of SRB conds 0
-            Lost arbitrations 587,  Sel. connected 0, Connected: No
-Nr of attached devices: 4, Nr of DCBs: 4
-Map of attached LUNs: 01 00 00 03 01 00 00 00
-Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd
-00  00  00  Yes  Yes  Yes  Yes  Yes   100 ns    10.0 M      15      16
-01  03  00  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15      01
-02  03  01  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15      01
-03  04  00  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15      01
-
-Note that the settings MaxID and MaxLUN are not zero- but one-based, which
-means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This
-is somehow inconvenient, but the way the mid-level SCSI code expects it to be.
-
-ACB and DCB are acronyms for Adapter Control Block and Device Control Block.
-These are data structures of the driver containing information about the
-adapter and the connected SCSI devices respectively.
-
-Idx is the device index (just a consecutive number for the driver), ID and
-LUN are the SCSI ID and LUN, Prty means Parity checking, Sync synchronous
-negotiation, DsCn Disconnection, SndS Send Start command on startup (not
-used by the driver) and TagQ Tagged Command Queueing. NegoPeriod and
-SyncSpeed are somehow redundant, because they are reciprocal values 
-(1 / 112 ns = 8.9 MHz). At least in theory. The driver is able to adjust the
-NegoPeriod more accurate (4ns) than the SyncSpeed (1 / 25ns). I don't know
-if certain devices will have problems with this discrepancy. Max. speed is
-10 MHz corresp. to a min. NegoPeriod of 100 ns. 
-(The driver allows slightly higher speeds if the devices (Ultra SCSI) accept
-it, but that's out of adapter spec, on your own risk and unlikely to improve
-performance. You're likely to crash your disks.) 
-SyncOffs is the offset used for synchronous negotiations; max. is 15. 
-The last values are only shown, if Sync is enabled. (NegoPeriod is still
-displayed in brackets to show the values which will be used after enabling
-Sync.)
-MaxCmd ist the number of commands (=tags) which can be processed at the same
-time by the device.
-
-If you want to change a setting, you can do that by writing to
-/proc/scsi/tmscsim/?. Basically you have to imitate the output of driver.
-(Don't use the brackets for NegoPeriod on Sync disabled devices.)
-You don't have to care about capitalisation. The driver will accept space,
-tab, comma, = and : as separators.
-
-There are three kinds of changes: 
-
-(1) Change driver settings: 
-    You type the names of the parameters and the params following it.
-    Example:
-     echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0
-
-    Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut,
-    TagMaxNum, ACBFlag, GlitchEater and DelayReset. Don't change ACBFlag
-    unless you want to see what happens, if the driver hangs.
-
-(2) Change device settings: You write a config line to the driver. The Nr
-    must match the ID and LUN given. If you give "-" as parameter, it is
-    ignored and the corresponding setting won't be changed. 
-    You can use "y" or "n" instead of "Yes" and "No" if you want to.
-    You don't need to specify a full line. The driver automatically performs
-    an INQUIRY on the device if necessary to check if it is capable to operate
-    with the given settings (Sync, TagQ).
-    Examples:
-     echo "0 0 0 y y y - y - 10 " >/proc/scsi/tmscsim/0
-     echo "3 5 0 y n y " >/proc/scsi/tmscsim/0
-
-    To give a short explanation of the first example: 
-    The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0),
-    select the device to which the following parameters apply. Note that it
-    would be sufficient to use the index or both SCSI ID and LUN, but I chose
-    to require all three to have a syntax similar to the output.
-    The following "y y y - y" enables Parity checking, enables Synchronous
-    transfers, Disconnection, leaves Send Start (not used) untouched and
-    enables Tagged Command Queueing for the selected device. The "-" skips
-    the Negotiation Period setting but the "10" sets the max sync. speed to
-    10 MHz. It's useless to specify both NegoPeriod and SyncSpeed as
-    discussed above. The values used in this example will result in maximum
-    performance.
-
-(3) Special commands: You can force a SCSI bus reset, an INQUIRY command, the
-    removal or the addition of a device's DCB and a SCSI register dump.
-    This is only used for debugging when you meet problems. The parameter of
-    the INQUIRY and REMOVE commands is the device index as shown by the
-    output of /proc/scsi/tmscsim/? in the device listing in the first column
-    (Idx). ADD takes the SCSI ID and LUN.
-    Examples:
-     echo "reset" >/proc/scsi/tmscsim/0
-     echo "inquiry 1" >/proc/scsi/tmscsim/0
-     echo "remove 2" >/proc/scsi/tmscsim/1
-     echo "add 2 3" >/proc/scsi/tmscsim/?
-     echo "dump" >/proc/scsi/tmscsim/0
-
-    Note that you will meet problems when you REMOVE a device's DCB with the
-    remove command if it contains partitions which are mounted. Only use it
-    after unmounting its partitions, telling the SCSI mid-level code to
-    remove it (scsi remove-single-device) and you really need a few bytes of
-    memory.
-    The ADD command allows you to configure a device before you tell the
-    mid-level code to try detection.
-
-
-I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing
-settings to see if everything changed as requested.
-
-
-5. Configuration via boot/module parameters
--------------------------------------------
-With the DC390, the driver reads its EEPROM settings and tries to use them.
-But you may want to override the settings prior to being able to change the
-driver configuration via /proc/scsi/tmscsim/?.
-If you do have another AM53C974 based adapter, that's even the only
-possibility to adjust settings before you are able to write to the
-/proc/scsi/tmscsim/? pseudo-file, e.g. if you want to use another 
-adapter ID than 7.  
-(BTW, the log message "DC390: No EEPROM found!" is normal without a DC390.)
-For this purpose, you can pass options to the driver before it is initialised
-by using kernel or module parameters. See lilo(8) or modprobe(1) manual
-pages on how to pass params to the kernel or a module.
-[NOTE: Formerly, it was not possible to override the EEPROM supplied
- settings of the DC390 with cmd line parameters. This has changed since
- 2.0e7]
-
-The syntax of the params is much shorter than the syntax of the /proc/...
-interface. This makes it a little bit more difficult to use. However, long
-parameter lines have the risk to be misinterpreted and the length of kernel
-parameters is limited.
-
-As the support for non-DC390 adapters works by simulating the values of the
-DC390 EEPROM, the settings are given in a DC390 BIOS' way.
-
-Here's the syntax:
-tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds,DelayReset
-
-Each of the parameters is a number, containing the described information:
-
-* AdaptID: The SCSI ID of the host adapter. Must be in the range 0..7
-  Default is 7.
-
-* SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values
-  0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is
-  0 (10.0 MHz).
-
-* DevMode is a bit mapped value describing the per-device features. It
-  applies to all devices. (Sync, Disc and TagQ will only apply, if the
-  device supports it.) The meaning of the bits (* = default):
-
-   Bit Val(hex) Val(dec)  Meaning
-   *0	 0x01	    1	  Parity check
-   *1	 0x02	    2	  Synchronous Negotiation
-   *2	 0x04	    4	  Disconnection
-   *3	 0x08	    8	  Send Start command on startup. (Not used)
-   *4	 0x10	   16	  Tagged Command Queueing
-
-  As usual, the desired value is obtained by adding the wanted values. If
-  you want to enable all values, e.g., you would use 31(0x1f). Default is 31.
-
-* AdaptMode is a bit mapped value describing the enabled adapter features.
-
-   Bit Val(hex) Val(dec)  Meaning
-   *0	 0x01	    1	  Support more than two drives. (Not used)
-   *1	 0x02	    2	  Use DOS compatible mapping for HDs greater than 1GB.
-   *2	 0x04	    4	  Reset SCSI Bus on startup.
-   *3	 0x08	    8	  Active Negation: Improves SCSI Bus noise immunity.
-    4	 0x10	   16	  Immediate return on BIOS seek command. (Not used)
- (*)5	 0x20	   32	  Check for LUNs >= 1.
-  
-* TaggedCmnds is a number indicating the maximum number of Tagged Commands.
-  It is the binary logarithm - 1 of the actual number. Max is 4 (32).
-   Value  Number of Tagged Commands
-     0		 2
-     1		 4
-     2		 8
-    *3		16
-     4		32
-
-* DelayReset is the time in seconds (minus 0.5s), the adapter waits, after a
-  bus reset. Default is 1 (corresp. to 1.5s).
-
-Example:
- modprobe tmscsim tmscsim=6,2,31
-would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device
-features and leave the adapter features, the number of Tagged Commands
-and the Delay after a reset to the defaults.
-
-As you can see, you don't need to specify all of the six params.
-If you want values to be ignored (i.e. the EEprom settings or the defaults
-will be used), you may pass -2 (not 0!) at the corresponding position.
-
-The defaults (7,0,31,15,3,1) are aggressive to allow good performance. You
-can use tmscsim=7,0,31,63,4,0 for maximum performance, if your SCSI chain
-allows it. If you meet problems, you can use tmscsim=-1 which is a shortcut
-for tmscsim=7,4,9,15,2,10.
-
-
-6. Potential improvements
--------------------------
-Most of the intended work on the driver has been done. Here are a few ideas
-to further improve its usability:
-
-* Cleanly separate per-Target and per-LUN properties (DCB)
-* More intelligent abort() routine
-* Use new_eh code (Linux-2.1+)
-* Have the mid-level (ML) code (and not the driver) handle more of the
-  various conditions.
-* Command queueing in the driver: Eliminate Query list and use ML instead.
-* More user friendly boot/module param syntax
-
-Further investigation on these problems:
-
-* Driver hangs with sync readcdda (xcdroast) (most probably VIA PCI error)
-
-Known problems: 
-Please see http://www.garloff.de/kurt/linux/dc390/problems.html
-
-* Changing the parameters of multi-lun by the tmscsim/? interface will
-  cause problems, cause these settings are mostly per Target and not per LUN
-  and should be updated accordingly. To be fixed for 2.0d24.
-* CDRs (eg Yam CRW4416) not recognized, because some buggy devices don't 
-  recover from a SCSI reset in time. Use a higher delay or don't issue
-  a SCSI bus reset on driver initialization. See problems page.
-  For the CRW4416S, this seems to be solved with firmware 1.0g (reported by 
-  Jean-Yves Barbier).
-* TEAC CD-532S not being recognized. (Works with 1.11).
-* Scanners (eg. Astra UMAX 1220S) don't work: Disable Sync Negotiation.
-  If this does not help, try echo "INQUIRY t" >/proc/scsi/tmscsim/? (t
-  replaced by the dev index of your scanner). You may try to reset your SCSI
-  bus afterwards (echo "RESET" >/proc/scsi/tmscsim/?).
-  The problem seems to be solved as of 2.0d18, thanks to Andreas Rick.
-* If there is a valid partition table, the driver will use it for determining
-  the mapping. If there's none, a reasonable mapping (Symbios-like) will be
-  assumed. Other operating systems may not like this mapping, though
-  it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the
-  partition table and used a H/S = 64/32 or 255/63 translation. So if you
-  want to be compatible to those, use this old mapping when creating
-  partition tables. Even worse, on bootup the DC390 might complain if other
-  mappings are found, so auto rebooting may fail.
-* In some situations, the driver will get stuck in an abort loop. This is a
-  bad interaction between the Mid-Layer of Linux' SCSI code and the driver.
-  Try to disable DsCn, if you meet this problem. Please contact me for
-  further debugging.
-
-
-7. Bug reports, debugging and updates
--------------------------------------
-Whenever you have problems with the driver, you are invited to ask the
-author for help. However, I'd suggest reading the docs and trying to solve
-the problem yourself, first. 
-If you find something, which you believe to be a bug, please report it to me. 
-Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and
-maybe the DC390 log messages to the report. 
-
-Bug reports should be send to me (Kurt Garloff <dc390@garloff.de>) as well
-as to the linux-scsi list (<linux-scsi@vger.kernel.org>), as sometimes bugs
-are caused by the SCSI mid-level code.
-
-I will ask you for some more details and probably I will also ask you to
-enable some of the DEBUG options in the driver (tmscsim.c:DC390_DEBUGXXX
-defines). The driver will produce some data for the syslog facility then.
-Beware: If your syslog gets written to a SCSI disk connected to your
-AM53C974, the logging might produce log output again, and you might end
-having your box spending most of its time doing the logging.
-
-The latest version of the driver can be found at:
- http://www.garloff.de/kurt/linux/dc390/
- ftp://ftp.suse.com/pub/people/garloff/linux/dc390/
-
-
-8. Acknowledgements
--------------------
-Thanks to Linus Torvalds, Alan Cox, the FSF people, the XFree86 team and 
-all the others for the wonderful OS and software.
-Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver
-release and support.
-Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding.
-Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert 
-Tonneau) for intensively testing the driver (and even risking data loss
-doing this during early revisions).
-Recently, SuSE GmbH, Nuernberg, FRG, has been paying me for the driver
-development and maintenance. Special thanks!
-
-
-9. Copyright
-------------
- This 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.
- If you want to use any later version of the GNU GPL, you will probably
- be allowed to, but you have to ask me and Tekram <erich@tekram.com.tw>
- before.
-
--------------------------------------------------------------------------
-Written by Kurt Garloff <kurt@garloff.de> 1998/06/11
-Last updated 2000/11/28, driver revision 2.0e7
-$Id: README.tmscsim,v 2.25.2.7 2000/12/20 01:07:12 garloff Exp $

+ 0 - 12
MAINTAINERS

@@ -4971,12 +4971,6 @@ T:	git git://linuxtv.org/anttip/media_tree.git
 S:	Maintained
 S:	Maintained
 F:	drivers/media/tuners/e4000*
 F:	drivers/media/tuners/e4000*
 
 
-EATA ISA/EISA/PCI SCSI DRIVER
-M:	Dario Ballabio <ballabio_dario@emc.com>
-L:	linux-scsi@vger.kernel.org
-S:	Maintained
-F:	drivers/scsi/eata.c
-
 EC100 MEDIA DRIVER
 EC100 MEDIA DRIVER
 M:	Antti Palosaari <crope@iki.fi>
 M:	Antti Palosaari <crope@iki.fi>
 L:	linux-media@vger.kernel.org
 L:	linux-media@vger.kernel.org
@@ -5812,12 +5806,6 @@ F:	tools/testing/selftests/futex/
 F:	tools/perf/bench/futex*
 F:	tools/perf/bench/futex*
 F:	Documentation/*futex*
 F:	Documentation/*futex*
 
 
-FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
-M:	Rik Faith <faith@cs.unc.edu>
-L:	linux-scsi@vger.kernel.org
-S:	Odd Fixes (e.g., new signatures)
-F:	drivers/scsi/fdomain.*
-
 GCC PLUGINS
 GCC PLUGINS
 M:	Kees Cook <keescook@chromium.org>
 M:	Kees Cook <keescook@chromium.org>
 R:	Emese Revfy <re.emese@gmail.com>
 R:	Emese Revfy <re.emese@gmail.com>

+ 0 - 1
arch/powerpc/configs/c2k_defconfig

@@ -184,7 +184,6 @@ CONFIG_MEGARAID_NEWGEN=y
 CONFIG_MEGARAID_MM=m
 CONFIG_MEGARAID_MM=m
 CONFIG_MEGARAID_MAILBOX=m
 CONFIG_MEGARAID_MAILBOX=m
 CONFIG_MEGARAID_SAS=m
 CONFIG_MEGARAID_SAS=m
-CONFIG_SCSI_FUTURE_DOMAIN=m
 CONFIG_SCSI_GDTH=m
 CONFIG_SCSI_GDTH=m
 CONFIG_SCSI_IPS=m
 CONFIG_SCSI_IPS=m
 CONFIG_SCSI_INITIO=m
 CONFIG_SCSI_INITIO=m

+ 2 - 112
drivers/scsi/Kconfig

@@ -640,88 +640,6 @@ config SCSI_DMX3191D
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called dmx3191d.
 	  module will be called dmx3191d.
 
 
-config SCSI_EATA
-	tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support"
-	depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
-	---help---
-	  This driver supports all EATA/DMA-compliant SCSI host adapters.  DPT
-	  ISA and all EISA I/O addresses are probed looking for the "EATA"
-	  signature. The addresses of all the PCI SCSI controllers reported
-          by the PCI subsystem are probed as well.
-
-	  You want to read the start of <file:drivers/scsi/eata.c> and the
-	  SCSI-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called eata.
-
-config SCSI_EATA_TAGGED_QUEUE
-	bool "enable tagged command queueing"
-	depends on SCSI_EATA
-	help
-	  This is a feature of SCSI-2 which improves performance: the host
-	  adapter can send several SCSI commands to a device's queue even if
-	  previous commands haven't finished yet.
-	  This is equivalent to the "eata=tc:y" boot option.
-
-config SCSI_EATA_LINKED_COMMANDS
-	bool "enable elevator sorting"
-	depends on SCSI_EATA
-	help
-	  This option enables elevator sorting for all probed SCSI disks and
-	  CD-ROMs. It definitely reduces the average seek distance when doing
-	  random seeks, but this does not necessarily result in a noticeable
-	  performance improvement: your mileage may vary...
-	  This is equivalent to the "eata=lc:y" boot option.
-
-config SCSI_EATA_MAX_TAGS
-	int "maximum number of queued commands"
-	depends on SCSI_EATA
-	default "16"
-	help
-	  This specifies how many SCSI commands can be maximally queued for
-	  each probed SCSI device. You should reduce the default value of 16
-	  only if you have disks with buggy or limited tagged command support.
-	  Minimum is 2 and maximum is 62. This value is also the window size
-	  used by the elevator sorting option above. The effective value used
-	  by the driver for each probed SCSI device is reported at boot time.
-	  This is equivalent to the "eata=mq:8" boot option.
-
-config SCSI_EATA_PIO
-	tristate "EATA-PIO (old DPT PM2001, PM2012A) support"
-	depends on (ISA || EISA || PCI) && SCSI && BROKEN
-	---help---
-	  This driver supports all EATA-PIO protocol compliant SCSI Host
-	  Adapters like the DPT PM2001 and the PM2012A.  EATA-DMA compliant
-	  host adapters could also use this driver but are discouraged from
-	  doing so, since this driver only supports hard disks and lacks
-	  numerous features.  You might want to have a look at the SCSI-HOWTO,
-	  available from <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called eata_pio.
-
-config SCSI_FUTURE_DOMAIN
-	tristate "Future Domain 16xx SCSI/AHA-2920A support"
-	depends on (ISA || PCI) && SCSI
-	select CHECK_SIGNATURE
-	---help---
-	  This is support for Future Domain's 16-bit SCSI host adapters
-	  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
-	  other adapters based on the Future Domain chipsets (Quantum
-	  ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board).
-	  It is explained in section 3.7 of the SCSI-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  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.
-
 config SCSI_GDTH
 config SCSI_GDTH
 	tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
 	tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
 	depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
 	depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
@@ -923,18 +841,6 @@ config SCSI_IZIP_SLOW_CTR
 
 
 	  Generally, saying N is fine.
 	  Generally, saying N is fine.
 
 
-config SCSI_NCR53C406A
-	tristate "NCR53c406a SCSI support"
-	depends on ISA && SCSI
-	help
-	  This is support for the NCR53c406a SCSI host adapter.  For user
-	  configurable parameters, check out <file:drivers/scsi/NCR53c406a.c>
-	  in the kernel source.  Also read the SCSI-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called NCR53c406.
-
 config SCSI_NCR_D700
 config SCSI_NCR_D700
 	tristate "NCR Dual 700 MCA SCSI support"
 	tristate "NCR Dual 700 MCA SCSI support"
 	depends on MCA && SCSI
 	depends on MCA && SCSI
@@ -1059,6 +965,7 @@ config SCSI_IPR
 	depends on PCI && SCSI && ATA
 	depends on PCI && SCSI && ATA
 	select FW_LOADER
 	select FW_LOADER
 	select IRQ_POLL
 	select IRQ_POLL
+	select SGL_ALLOC
 	---help---
 	---help---
 	  This driver supports the IBM Power Linux family RAID adapters.
 	  This driver supports the IBM Power Linux family RAID adapters.
 	  This includes IBM pSeries 5712, 5703, 5709, and 570A, as well
 	  This includes IBM pSeries 5712, 5703, 5709, and 570A, as well
@@ -1265,24 +1172,6 @@ config SCSI_SIM710
 
 
 	  It currently supports Compaq EISA cards and NCR MCA cards
 	  It currently supports Compaq EISA cards and NCR MCA cards
 
 
-config SCSI_SYM53C416
-	tristate "Symbios 53c416 SCSI support"
-	depends on ISA && SCSI
-	---help---
-	  This is support for the sym53c416 SCSI host adapter, the SCSI
-	  adapter that comes with some HP scanners. This driver requires that
-	  the sym53c416 is configured first using some sort of PnP
-	  configuration program (e.g. isapnp) or by a PnP aware BIOS. If you
-	  are using isapnp then you need to compile this driver as a module
-	  and then load it using insmod after isapnp has run. The parameters
-	  of the configured card(s) should be passed to the driver. The format
-	  is:
-
-	  insmod sym53c416 sym53c416=<base>,<irq> [sym53c416_1=<base>,<irq>]
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called sym53c416.
-
 config SCSI_DC395x
 config SCSI_DC395x
 	tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support"
 	tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support"
 	depends on PCI && SCSI
 	depends on PCI && SCSI
@@ -1576,6 +1465,7 @@ config ZFCP
 config SCSI_PMCRAID
 config SCSI_PMCRAID
 	tristate "PMC SIERRA Linux MaxRAID adapter support"
 	tristate "PMC SIERRA Linux MaxRAID adapter support"
 	depends on PCI && SCSI && NET
 	depends on PCI && SCSI && NET
+	select SGL_ALLOC
 	---help---
 	---help---
 	  This driver supports the PMC SIERRA MaxRAID adapters.
 	  This driver supports the PMC SIERRA MaxRAID adapters.
 
 

+ 0 - 5
drivers/scsi/Makefile

@@ -74,12 +74,9 @@ obj-$(CONFIG_SCSI_AIC94XX)	+= aic94xx/
 obj-$(CONFIG_SCSI_PM8001)	+= pm8001/
 obj-$(CONFIG_SCSI_PM8001)	+= pm8001/
 obj-$(CONFIG_SCSI_ISCI)		+= isci/
 obj-$(CONFIG_SCSI_ISCI)		+= isci/
 obj-$(CONFIG_SCSI_IPS)		+= ips.o
 obj-$(CONFIG_SCSI_IPS)		+= ips.o
-obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
 obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
 obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
-obj-$(CONFIG_SCSI_NCR53C406A)	+= NCR53c406a.o
 obj-$(CONFIG_SCSI_NCR_D700)	+= 53c700.o NCR_D700.o
 obj-$(CONFIG_SCSI_NCR_D700)	+= 53c700.o NCR_D700.o
 obj-$(CONFIG_SCSI_NCR_Q720)	+= NCR_Q720_mod.o
 obj-$(CONFIG_SCSI_NCR_Q720)	+= NCR_Q720_mod.o
-obj-$(CONFIG_SCSI_SYM53C416)	+= sym53c416.o
 obj-$(CONFIG_SCSI_QLOGIC_FAS)	+= qlogicfas408.o	qlogicfas.o
 obj-$(CONFIG_SCSI_QLOGIC_FAS)	+= qlogicfas408.o	qlogicfas.o
 obj-$(CONFIG_PCMCIA_QLOGIC)	+= qlogicfas408.o
 obj-$(CONFIG_PCMCIA_QLOGIC)	+= qlogicfas408.o
 obj-$(CONFIG_SCSI_QLOGIC_1280)	+= qla1280.o 
 obj-$(CONFIG_SCSI_QLOGIC_1280)	+= qla1280.o 
@@ -93,8 +90,6 @@ obj-$(CONFIG_SCSI_HPSA)		+= hpsa.o
 obj-$(CONFIG_SCSI_SMARTPQI)	+= smartpqi/
 obj-$(CONFIG_SCSI_SMARTPQI)	+= smartpqi/
 obj-$(CONFIG_SCSI_SYM53C8XX_2)	+= sym53c8xx_2/
 obj-$(CONFIG_SCSI_SYM53C8XX_2)	+= sym53c8xx_2/
 obj-$(CONFIG_SCSI_ZALON)	+= zalon7xx.o
 obj-$(CONFIG_SCSI_ZALON)	+= zalon7xx.o
-obj-$(CONFIG_SCSI_EATA_PIO)	+= eata_pio.o
-obj-$(CONFIG_SCSI_EATA)		+= eata.o
 obj-$(CONFIG_SCSI_DC395x)	+= dc395x.o
 obj-$(CONFIG_SCSI_DC395x)	+= dc395x.o
 obj-$(CONFIG_SCSI_AM53C974)	+= esp_scsi.o	am53c974.o
 obj-$(CONFIG_SCSI_AM53C974)	+= esp_scsi.o	am53c974.o
 obj-$(CONFIG_CXLFLASH)		+= cxlflash/
 obj-$(CONFIG_CXLFLASH)		+= cxlflash/

+ 0 - 1090
drivers/scsi/NCR53c406a.c

@@ -1,1090 +0,0 @@
-/* 
- *  NCR53c406.c
- *  Low-level SCSI driver for NCR53c406a chip.
- *  Copyright (C) 1994, 1995, 1996 Normunds Saumanis (normunds@fi.ibm.com)
- * 
- *  LILO command line usage: ncr53c406a=<PORTBASE>[,<IRQ>[,<FASTPIO>]]
- *  Specify IRQ = 0 for non-interrupt driven mode.
- *  FASTPIO = 1 for fast pio mode, 0 for slow mode.
- *
- *  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 NCR53C406A_DEBUG 0
-#define VERBOSE_NCR53C406A_DEBUG 0
-
-/* Set this to 1 for PIO mode (recommended) or to 0 for DMA mode */
-#define USE_PIO 1
-
-#define USE_BIOS 0
-				/* #define BIOS_ADDR 0xD8000 *//* define this if autoprobe fails */
-				/* #define PORT_BASE 0x330 *//* define this if autoprobe fails */
-				/* #define IRQ_LEV   0	*//* define this if autoprobe fails */
-#define DMA_CHAN  5		/* this is ignored if DMA is disabled */
-
-/* Set this to 0 if you encounter kernel lockups while transferring 
- * data in PIO mode */
-#define USE_FAST_PIO 1
-
-/* ============= End of user configurable parameters ============= */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
-#include <linux/blkdev.h>
-#include <linux/spinlock.h>
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-/* ============================================================= */
-
-#define WATCHDOG 5000000
-
-#define SYNC_MODE 0		/* Synchronous transfer mode */
-
-#ifdef DEBUG
-#undef NCR53C406A_DEBUG
-#define NCR53C406A_DEBUG 1
-#endif
-
-#if USE_PIO
-#define USE_DMA 0
-#else
-#define USE_DMA 1
-#endif
-
-/* Default configuration */
-#define C1_IMG   0x07		/* ID=7 */
-#define C2_IMG   0x48		/* FE SCSI2 */
-#if USE_DMA
-#define C3_IMG   0x21		/* CDB TE */
-#else
-#define C3_IMG   0x20		/* CDB */
-#endif
-#define C4_IMG   0x04		/* ANE */
-#define C5_IMG   0xb6		/* AA PI SIE POL */
-
-#define REG0 (outb(C4_IMG, CONFIG4))
-#define REG1 (outb(C5_IMG, CONFIG5))
-
-#if NCR53C406A_DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
-
-#if VERBOSE_NCR53C406A_DEBUG
-#define VDEB(x) x
-#else
-#define VDEB(x)
-#endif
-
-#define LOAD_DMA_COUNT(count) \
-  outb(count & 0xff, TC_LSB); \
-  outb((count >> 8) & 0xff, TC_MSB); \
-  outb((count >> 16) & 0xff, TC_HIGH);
-
-/* Chip commands */
-#define DMA_OP               0x80
-
-#define SCSI_NOP             0x00
-#define FLUSH_FIFO           0x01
-#define CHIP_RESET           0x02
-#define SCSI_RESET           0x03
-#define RESELECT             0x40
-#define SELECT_NO_ATN        0x41
-#define SELECT_ATN           0x42
-#define SELECT_ATN_STOP      0x43
-#define ENABLE_SEL           0x44
-#define DISABLE_SEL          0x45
-#define SELECT_ATN3          0x46
-#define RESELECT3            0x47
-#define TRANSFER_INFO        0x10
-#define INIT_CMD_COMPLETE    0x11
-#define MSG_ACCEPT           0x12
-#define TRANSFER_PAD         0x18
-#define SET_ATN              0x1a
-#define RESET_ATN            0x1b
-#define SEND_MSG             0x20
-#define SEND_STATUS          0x21
-#define SEND_DATA            0x22
-#define DISCONN_SEQ          0x23
-#define TERMINATE_SEQ        0x24
-#define TARG_CMD_COMPLETE    0x25
-#define DISCONN              0x27
-#define RECV_MSG             0x28
-#define RECV_CMD             0x29
-#define RECV_DATA            0x2a
-#define RECV_CMD_SEQ         0x2b
-#define TARGET_ABORT_DMA     0x04
-
-/*----------------------------------------------------------------*/
-/* the following will set the monitor border color (useful to find
-   where something crashed or gets stuck at */
-/* 1 = blue
-   2 = green
-   3 = cyan
-   4 = red
-   5 = magenta
-   6 = yellow
-   7 = white
-*/
-
-#if NCR53C406A_DEBUG
-#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
-#else
-#define rtrc(i) {}
-#endif
-/*----------------------------------------------------------------*/
-
-enum Phase {
-	idle,
-	data_out,
-	data_in,
-	command_ph,
-	status_ph,
-	message_out,
-	message_in
-};
-
-/* Static function prototypes */
-static void NCR53c406a_intr(void *);
-static irqreturn_t do_NCR53c406a_intr(int, void *);
-static void chip_init(void);
-static void calc_port_addr(void);
-#ifndef IRQ_LEV
-static int irq_probe(void);
-#endif
-
-/* ================================================================= */
-
-#if USE_BIOS
-static void *bios_base;
-#endif
-
-#ifdef PORT_BASE
-static int port_base = PORT_BASE;
-#else
-static int port_base;
-#endif
-
-#ifdef IRQ_LEV
-static int irq_level = IRQ_LEV;
-#else
-static int irq_level = -1;	/* 0 is 'no irq', so use -1 for 'uninitialized' */
-#endif
-
-#if USE_DMA
-static int dma_chan;
-#endif
-
-#if USE_PIO
-static int fast_pio = USE_FAST_PIO;
-#endif
-
-static Scsi_Cmnd *current_SC;
-static char info_msg[256];
-
-/* ================================================================= */
-
-/* possible BIOS locations */
-#if USE_BIOS
-static void *addresses[] = {
-	(void *) 0xd8000,
-	(void *) 0xc8000
-};
-#define ADDRESS_COUNT ARRAY_SIZE(addresses)
-#endif				/* USE_BIOS */
-
-/* possible i/o port addresses */
-static unsigned short ports[] = { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 };
-#define PORT_COUNT ARRAY_SIZE(ports)
-
-#ifndef MODULE
-/* possible interrupt channels */
-static unsigned short intrs[] = { 10, 11, 12, 15 };
-#define INTR_COUNT ARRAY_SIZE(intrs)
-#endif /* !MODULE */
-
-/* signatures for NCR 53c406a based controllers */
-#if USE_BIOS
-struct signature {
-	char *signature;
-	int sig_offset;
-	int sig_length;
-} signatures[] __initdata = {
-	/*          1         2         3         4         5         6 */
-	/* 123456789012345678901234567890123456789012345678901234567890 */
-	{
-"Copyright (C) Acculogic, Inc.\r\n2.8M Diskette Extension Bios ver 4.04.03 03/01/1993", 61, 82},};
-
-#define SIGNATURE_COUNT ARRAY_SIZE(signatures)
-#endif				/* USE_BIOS */
-
-/* ============================================================ */
-
-/* Control Register Set 0 */
-static int TC_LSB;		/* transfer counter lsb         */
-static int TC_MSB;		/* transfer counter msb */
-static int SCSI_FIFO;		/* scsi fifo register   */
-static int CMD_REG;		/* command register             */
-static int STAT_REG;		/* status register              */
-static int DEST_ID;		/* selection/reselection bus id */
-static int INT_REG;		/* interrupt status register    */
-static int SRTIMOUT;		/* select/reselect timeout reg  */
-static int SEQ_REG;		/* sequence step register       */
-static int SYNCPRD;		/* synchronous transfer period  */
-static int FIFO_FLAGS;		/* indicates # of bytes in fifo */
-static int SYNCOFF;		/* synchronous offset register  */
-static int CONFIG1;		/* configuration register       */
-static int CLKCONV;		/* clock conversion reg */
-				/*static int TESTREG;*//* test mode register           */
-static int CONFIG2;		/* Configuration 2 Register     */
-static int CONFIG3;		/* Configuration 3 Register     */
-static int CONFIG4;		/* Configuration 4 Register     */
-static int TC_HIGH;		/* Transfer Counter High */
-				/*static int FIFO_BOTTOM;*//* Reserve FIFO byte register   */
-
-/* Control Register Set 1 */
-				/*static int JUMPER_SENSE;*//* Jumper sense port reg (r/w) */
-				/*static int SRAM_PTR;*//* SRAM address pointer reg (r/w) */
-				/*static int SRAM_DATA;*//* SRAM data register (r/w) */
-static int PIO_FIFO;		/* PIO FIFO registers (r/w) */
-				/*static int PIO_FIFO1;*//*  */
-				/*static int PIO_FIFO2;*//*  */
-				/*static int PIO_FIFO3;*//*  */
-static int PIO_STATUS;		/* PIO status (r/w) */
-				/*static int ATA_CMD;*//* ATA command/status reg (r/w) */
-				/*static int ATA_ERR;*//* ATA features/error register (r/w) */
-static int PIO_FLAG;		/* PIO flag interrupt enable (r/w) */
-static int CONFIG5;		/* Configuration 5 register (r/w) */
-				/*static int SIGNATURE;*//* Signature Register (r) */
-				/*static int CONFIG6;*//* Configuration 6 register (r) */
-
-/* ============================================================== */
-
-#if USE_DMA
-static __inline__ int NCR53c406a_dma_setup(unsigned char *ptr, unsigned int count, unsigned char mode)
-{
-	unsigned limit;
-	unsigned long flags = 0;
-
-	VDEB(printk("dma: before count=%d   ", count));
-	if (dma_chan <= 3) {
-		if (count > 65536)
-			count = 65536;
-		limit = 65536 - (((unsigned) ptr) & 0xFFFF);
-	} else {
-		if (count > (65536 << 1))
-			count = (65536 << 1);
-		limit = (65536 << 1) - (((unsigned) ptr) & 0x1FFFF);
-	}
-
-	if (count > limit)
-		count = limit;
-
-	VDEB(printk("after count=%d\n", count));
-	if ((count & 1) || (((unsigned) ptr) & 1))
-		panic("NCR53c406a: attempted unaligned DMA transfer\n");
-
-	flags = claim_dma_lock();
-	disable_dma(dma_chan);
-	clear_dma_ff(dma_chan);
-	set_dma_addr(dma_chan, (long) ptr);
-	set_dma_count(dma_chan, count);
-	set_dma_mode(dma_chan, mode);
-	enable_dma(dma_chan);
-	release_dma_lock(flags);
-
-	return count;
-}
-
-static __inline__ int NCR53c406a_dma_write(unsigned char *src, unsigned int count)
-{
-	return NCR53c406a_dma_setup(src, count, DMA_MODE_WRITE);
-}
-
-static __inline__ int NCR53c406a_dma_read(unsigned char *src, unsigned int count)
-{
-	return NCR53c406a_dma_setup(src, count, DMA_MODE_READ);
-}
-
-static __inline__ int NCR53c406a_dma_residual(void)
-{
-	register int tmp;
-	unsigned long flags;
-
-	flags = claim_dma_lock();
-	clear_dma_ff(dma_chan);
-	tmp = get_dma_residue(dma_chan);
-	release_dma_lock(flags);
-
-	return tmp;
-}
-#endif				/* USE_DMA */
-
-#if USE_PIO
-static __inline__ int NCR53c406a_pio_read(unsigned char *request, unsigned int reqlen)
-{
-	int i;
-	int len;		/* current scsi fifo size */
-
-	REG1;
-	while (reqlen) {
-		i = inb(PIO_STATUS);
-		/*    VDEB(printk("pio_status=%x\n", i)); */
-		if (i & 0x80)
-			return 0;
-
-		switch (i & 0x1e) {
-		default:
-		case 0x10:
-			len = 0;
-			break;
-		case 0x0:
-			len = 1;
-			break;
-		case 0x8:
-			len = 42;
-			break;
-		case 0xc:
-			len = 84;
-			break;
-		case 0xe:
-			len = 128;
-			break;
-		}
-
-		if ((i & 0x40) && len == 0) {	/* fifo empty and interrupt occurred */
-			return 0;
-		}
-
-		if (len) {
-			if (len > reqlen)
-				len = reqlen;
-
-			if (fast_pio && len > 3) {
-				insl(PIO_FIFO, request, len >> 2);
-				request += len & 0xfc;
-				reqlen -= len & 0xfc;
-			} else {
-				while (len--) {
-					*request++ = inb(PIO_FIFO);
-					reqlen--;
-				}
-			}
-		}
-	}
-	return 0;
-}
-
-static __inline__ int NCR53c406a_pio_write(unsigned char *request, unsigned int reqlen)
-{
-	int i = 0;
-	int len;		/* current scsi fifo size */
-
-	REG1;
-	while (reqlen && !(i & 0x40)) {
-		i = inb(PIO_STATUS);
-		/*    VDEB(printk("pio_status=%x\n", i)); */
-		if (i & 0x80)	/* error */
-			return 0;
-
-		switch (i & 0x1e) {
-		case 0x10:
-			len = 128;
-			break;
-		case 0x0:
-			len = 84;
-			break;
-		case 0x8:
-			len = 42;
-			break;
-		case 0xc:
-			len = 1;
-			break;
-		default:
-		case 0xe:
-			len = 0;
-			break;
-		}
-
-		if (len) {
-			if (len > reqlen)
-				len = reqlen;
-
-			if (fast_pio && len > 3) {
-				outsl(PIO_FIFO, request, len >> 2);
-				request += len & 0xfc;
-				reqlen -= len & 0xfc;
-			} else {
-				while (len--) {
-					outb(*request++, PIO_FIFO);
-					reqlen--;
-				}
-			}
-		}
-	}
-	return 0;
-}
-#endif				/* USE_PIO */
-
-static int __init NCR53c406a_detect(struct scsi_host_template * tpnt)
-{
-	int present = 0;
-	struct Scsi_Host *shpnt = NULL;
-#ifndef PORT_BASE
-	int i;
-#endif
-
-#if USE_BIOS
-	int ii, jj;
-	bios_base = 0;
-	/* look for a valid signature */
-	for (ii = 0; ii < ADDRESS_COUNT && !bios_base; ii++)
-		for (jj = 0; (jj < SIGNATURE_COUNT) && !bios_base; jj++)
-			if (!memcmp((void *) addresses[ii] + signatures[jj].sig_offset, (void *) signatures[jj].signature, (int) signatures[jj].sig_length))
-				bios_base = addresses[ii];
-
-	if (!bios_base) {
-		printk("NCR53c406a: BIOS signature not found\n");
-		return 0;
-	}
-
-	DEB(printk("NCR53c406a BIOS found at 0x%x\n", (unsigned int) bios_base);
-	    );
-#endif				/* USE_BIOS */
-
-#ifdef PORT_BASE
-	if (!request_region(port_base, 0x10, "NCR53c406a"))	/* ports already snatched */
-		port_base = 0;
-
-#else				/* autodetect */
-	if (port_base) {	/* LILO override */
-		if (!request_region(port_base, 0x10, "NCR53c406a"))
-			port_base = 0;
-	} else {
-		for (i = 0; i < PORT_COUNT && !port_base; i++) {
-			if (!request_region(ports[i], 0x10, "NCR53c406a")) {
-				DEB(printk("NCR53c406a: port 0x%x in use\n", ports[i]));
-			} else {
-				VDEB(printk("NCR53c406a: port 0x%x available\n", ports[i]));
-				outb(C5_IMG, ports[i] + 0x0d);	/* reg set 1 */
-				if ((inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) & 0xf8) == 0x58) {
-					port_base = ports[i];
-					VDEB(printk("NCR53c406a: Sig register valid\n"));
-					VDEB(printk("port_base=0x%x\n", port_base));
-					break;
-				}
-				release_region(ports[i], 0x10);
-			}
-		}
-	}
-#endif				/* PORT_BASE */
-
-	if (!port_base) {	/* no ports found */
-		printk("NCR53c406a: no available ports found\n");
-		return 0;
-	}
-
-	DEB(printk("NCR53c406a detected\n"));
-
-	calc_port_addr();
-	chip_init();
-
-#ifndef IRQ_LEV
-	if (irq_level < 0) {	/* LILO override if >= 0 */
-		irq_level = irq_probe();
-		if (irq_level < 0) {	/* Trouble */
-			printk("NCR53c406a: IRQ problem, irq_level=%d, giving up\n", irq_level);
-			goto err_release;
-		}
-	}
-#endif
-
-	DEB(printk("NCR53c406a: using port_base 0x%x\n", port_base));
-
-	present = 1;
-	tpnt->proc_name = "NCR53c406a";
-
-	shpnt = scsi_register(tpnt, 0);
-	if (!shpnt) {
-		printk("NCR53c406a: Unable to register host, giving up.\n");
-		goto err_release;
-	}
-
-	if (irq_level > 0) {
-		if (request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", shpnt)) {
-			printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level);
-			goto err_free_scsi;
-		}
-		tpnt->can_queue = 1;
-		DEB(printk("NCR53c406a: allocated IRQ %d\n", irq_level));
-	} else if (irq_level == 0) {
-		tpnt->can_queue = 0;
-		DEB(printk("NCR53c406a: No interrupts detected\n"));
-		printk("NCR53c406a driver no longer supports polling interface\n");
-		printk("Please email linux-scsi@vger.kernel.org\n");
-                        
-#if USE_DMA
-		printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n");
-#endif				/* USE_DMA */
-		goto err_free_scsi;
-	} else {
-		DEB(printk("NCR53c406a: Shouldn't get here!\n"));
-		goto err_free_scsi;
-	}
-
-#if USE_DMA
-	dma_chan = DMA_CHAN;
-	if (request_dma(dma_chan, "NCR53c406a") != 0) {
-		printk("NCR53c406a: unable to allocate DMA channel %d\n", dma_chan);
-		goto err_free_irq;
-	}
-
-	DEB(printk("Allocated DMA channel %d\n", dma_chan));
-#endif				/* USE_DMA */
-
-	shpnt->irq = irq_level;
-	shpnt->io_port = port_base;
-	shpnt->n_io_port = 0x10;
-#if USE_DMA
-	shpnt->dma = dma_chan;
-#endif
-
-#if USE_DMA
-	sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, DMA channel %d.", port_base, irq_level, dma_chan);
-#else
-	sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, %s PIO mode.", port_base, irq_level, fast_pio ? "fast" : "slow");
-#endif
-
-	return (present);
-
-#if USE_DMA
-      err_free_irq:
-	if (irq_level)
-		free_irq(irq_level, shpnt);
-#endif
-      err_free_scsi:
-	scsi_unregister(shpnt);
-      err_release:
-	release_region(port_base, 0x10);
-	return 0;
-}
-
-static int NCR53c406a_release(struct Scsi_Host *shost)
-{
-	if (shost->irq)
-		free_irq(shost->irq, NULL);
-#if USE_DMA
-	if (shost->dma_channel != 0xff)
-		free_dma(shost->dma_channel);
-#endif
-	if (shost->io_port && shost->n_io_port)
-		release_region(shost->io_port, shost->n_io_port);
-
-	scsi_unregister(shost);
-	return 0;
-}
-
-#ifndef MODULE
-/* called from init/main.c */
-static int __init NCR53c406a_setup(char *str)
-{
-	static size_t setup_idx = 0;
-	size_t i;
-	int ints[4];
-
-	DEB(printk("NCR53c406a: Setup called\n");
-	    );
-
-	if (setup_idx >= PORT_COUNT - 1) {
-		printk("NCR53c406a: Setup called too many times.  Bad LILO params?\n");
-		return 0;
-	}
-	get_options(str, 4, ints);
-	if (ints[0] < 1 || ints[0] > 3) {
-		printk("NCR53c406a: Malformed command line\n");
-		printk("NCR53c406a: Usage: ncr53c406a=<PORTBASE>[,<IRQ>[,<FASTPIO>]]\n");
-		return 0;
-	}
-	for (i = 0; i < PORT_COUNT && !port_base; i++)
-		if (ports[i] == ints[1]) {
-			port_base = ints[1];
-			DEB(printk("NCR53c406a: Specified port_base 0x%x\n", port_base);
-			    )
-		}
-	if (!port_base) {
-		printk("NCR53c406a: Invalid PORTBASE 0x%x specified\n", ints[1]);
-		return 0;
-	}
-
-	if (ints[0] > 1) {
-		if (ints[2] == 0) {
-			irq_level = 0;
-			DEB(printk("NCR53c406a: Specified irq %d\n", irq_level);
-			    )
-		} else
-			for (i = 0; i < INTR_COUNT && irq_level < 0; i++)
-				if (intrs[i] == ints[2]) {
-					irq_level = ints[2];
-					DEB(printk("NCR53c406a: Specified irq %d\n", port_base);
-					    )
-				}
-		if (irq_level < 0)
-			printk("NCR53c406a: Invalid IRQ %d specified\n", ints[2]);
-	}
-
-	if (ints[0] > 2)
-		fast_pio = ints[3];
-
-	DEB(printk("NCR53c406a: port_base=0x%x, irq=%d, fast_pio=%d\n", port_base, irq_level, fast_pio);)
-	return 1;
-}
-
-__setup("ncr53c406a=", NCR53c406a_setup);
-
-#endif /* !MODULE */
-
-static const char *NCR53c406a_info(struct Scsi_Host *SChost)
-{
-	DEB(printk("NCR53c406a_info called\n"));
-	return (info_msg);
-}
-
-#if 0
-static void wait_intr(void)
-{
-	unsigned long i = jiffies + WATCHDOG;
-
-	while (time_after(i, jiffies) && !(inb(STAT_REG) & 0xe0)) {	/* wait for a pseudo-interrupt */
-		cpu_relax();
-		barrier();
-	}
-
-	if (time_before_eq(i, jiffies)) {	/* Timed out */
-		rtrc(0);
-		current_SC->result = DID_TIME_OUT << 16;
-		current_SC->SCp.phase = idle;
-		current_SC->scsi_done(current_SC);
-		return;
-	}
-
-	NCR53c406a_intr(NULL);
-}
-#endif
-
-static int NCR53c406a_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
-{
-	int i;
-
-	VDEB(printk("NCR53c406a_queue called\n"));
-        DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->target, (u8)SCpnt->device->lun, scsi_bufflen(SCpnt)));
-
-#if 0
-	VDEB(for (i = 0; i < SCpnt->cmd_len; i++)
-	     printk("cmd[%d]=%02x  ", i, SCpnt->cmnd[i]));
-	VDEB(printk("\n"));
-#endif
-
-	current_SC = SCpnt;
-	current_SC->scsi_done = done;
-	current_SC->SCp.phase = command_ph;
-	current_SC->SCp.Status = 0;
-	current_SC->SCp.Message = 0;
-
-	/* We are locked here already by the mid layer */
-	REG0;
-	outb(scmd_id(SCpnt), DEST_ID);	/* set destination */
-	outb(FLUSH_FIFO, CMD_REG);	/* reset the fifos */
-
-	for (i = 0; i < SCpnt->cmd_len; i++) {
-		outb(SCpnt->cmnd[i], SCSI_FIFO);
-	}
-	outb(SELECT_NO_ATN, CMD_REG);
-
-	rtrc(1);
-	return 0;
-}
-
-static DEF_SCSI_QCMD(NCR53c406a_queue)
-
-static int NCR53c406a_host_reset(Scsi_Cmnd * SCpnt)
-{
-	DEB(printk("NCR53c406a_reset called\n"));
-
-	spin_lock_irq(SCpnt->device->host->host_lock);
-
-	outb(C4_IMG, CONFIG4);	/* Select reg set 0 */
-	outb(CHIP_RESET, CMD_REG);
-	outb(SCSI_NOP, CMD_REG);	/* required after reset */
-	outb(SCSI_RESET, CMD_REG);
-	chip_init();
-
-	rtrc(2);
-
-	spin_unlock_irq(SCpnt->device->host->host_lock);
-
-	return SUCCESS;
-}
-
-static int NCR53c406a_biosparm(struct scsi_device *disk,
-                               struct block_device *dev,
-			       sector_t capacity, int *info_array)
-{
-	int size;
-
-	DEB(printk("NCR53c406a_biosparm called\n"));
-
-	size = capacity;
-	info_array[0] = 64;	/* heads */
-	info_array[1] = 32;	/* sectors */
-	info_array[2] = size >> 11;	/* cylinders */
-	if (info_array[2] > 1024) {	/* big disk */
-		info_array[0] = 255;
-		info_array[1] = 63;
-		info_array[2] = size / (255 * 63);
-	}
-	return 0;
-}
-
-static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id)
-{
-	unsigned long flags;
-	struct Scsi_Host *dev = dev_id;
-
-	spin_lock_irqsave(dev->host_lock, flags);
-	NCR53c406a_intr(dev_id);
-	spin_unlock_irqrestore(dev->host_lock, flags);
-	return IRQ_HANDLED;
-}
-
-static void NCR53c406a_intr(void *dev_id)
-{
-	DEB(unsigned char fifo_size;
-	    )
-	    DEB(unsigned char seq_reg;
-	    )
-	unsigned char status, int_reg;
-#if USE_PIO
-	unsigned char pio_status;
-	struct scatterlist *sg;
-        int i;
-#endif
-
-	VDEB(printk("NCR53c406a_intr called\n"));
-
-#if USE_PIO
-	REG1;
-	pio_status = inb(PIO_STATUS);
-#endif
-	REG0;
-	status = inb(STAT_REG);
-	DEB(seq_reg = inb(SEQ_REG));
-	int_reg = inb(INT_REG);
-	DEB(fifo_size = inb(FIFO_FLAGS) & 0x1f);
-
-#if NCR53C406A_DEBUG
-	printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", status, seq_reg, int_reg, fifo_size);
-#if (USE_DMA)
-	printk("\n");
-#else
-	printk(", pio=%02x\n", pio_status);
-#endif				/* USE_DMA */
-#endif				/* NCR53C406A_DEBUG */
-
-	if (int_reg & 0x80) {	/* SCSI reset intr */
-		rtrc(3);
-		DEB(printk("NCR53c406a: reset intr received\n"));
-		current_SC->SCp.phase = idle;
-		current_SC->result = DID_RESET << 16;
-		current_SC->scsi_done(current_SC);
-		return;
-	}
-#if USE_PIO
-	if (pio_status & 0x80) {
-		printk("NCR53C406A: Warning: PIO error!\n");
-		current_SC->SCp.phase = idle;
-		current_SC->result = DID_ERROR << 16;
-		current_SC->scsi_done(current_SC);
-		return;
-	}
-#endif				/* USE_PIO */
-
-	if (status & 0x20) {	/* Parity error */
-		printk("NCR53c406a: Warning: parity error!\n");
-		current_SC->SCp.phase = idle;
-		current_SC->result = DID_PARITY << 16;
-		current_SC->scsi_done(current_SC);
-		return;
-	}
-
-	if (status & 0x40) {	/* Gross error */
-		printk("NCR53c406a: Warning: gross error!\n");
-		current_SC->SCp.phase = idle;
-		current_SC->result = DID_ERROR << 16;
-		current_SC->scsi_done(current_SC);
-		return;
-	}
-
-	if (int_reg & 0x20) {	/* Disconnect */
-		DEB(printk("NCR53c406a: disconnect intr received\n"));
-		if (current_SC->SCp.phase != message_in) {	/* Unexpected disconnect */
-			current_SC->result = DID_NO_CONNECT << 16;
-		} else {	/* Command complete, return status and message */
-			current_SC->result = (current_SC->SCp.Status & 0xff)
-			    | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16);
-		}
-
-		rtrc(0);
-		current_SC->SCp.phase = idle;
-		current_SC->scsi_done(current_SC);
-		return;
-	}
-
-	switch (status & 0x07) {	/* scsi phase */
-	case 0x00:		/* DATA-OUT */
-		if (int_reg & 0x10) {	/* Target requesting info transfer */
-			rtrc(5);
-			current_SC->SCp.phase = data_out;
-			VDEB(printk("NCR53c406a: Data-Out phase\n"));
-			outb(FLUSH_FIFO, CMD_REG);
-			LOAD_DMA_COUNT(scsi_bufflen(current_SC));	/* Max transfer size */
-#if USE_DMA			/* No s/g support for DMA */
-			NCR53c406a_dma_write(scsi_sglist(current_SC),
-                                             scsdi_bufflen(current_SC));
-
-#endif				/* USE_DMA */
-			outb(TRANSFER_INFO | DMA_OP, CMD_REG);
-#if USE_PIO
-                        scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
-                                NCR53c406a_pio_write(sg_virt(sg), sg->length);
-                        }
-			REG0;
-#endif				/* USE_PIO */
-		}
-		break;
-
-	case 0x01:		/* DATA-IN */
-		if (int_reg & 0x10) {	/* Target requesting info transfer */
-			rtrc(6);
-			current_SC->SCp.phase = data_in;
-			VDEB(printk("NCR53c406a: Data-In phase\n"));
-			outb(FLUSH_FIFO, CMD_REG);
-			LOAD_DMA_COUNT(scsi_bufflen(current_SC));	/* Max transfer size */
-#if USE_DMA			/* No s/g support for DMA */
-			NCR53c406a_dma_read(scsi_sglist(current_SC),
-                                            scsdi_bufflen(current_SC));
-#endif				/* USE_DMA */
-			outb(TRANSFER_INFO | DMA_OP, CMD_REG);
-#if USE_PIO
-                        scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
-                                NCR53c406a_pio_read(sg_virt(sg), sg->length);
-                        }
-			REG0;
-#endif				/* USE_PIO */
-		}
-		break;
-
-	case 0x02:		/* COMMAND */
-		current_SC->SCp.phase = command_ph;
-		printk("NCR53c406a: Warning: Unknown interrupt occurred in command phase!\n");
-		break;
-
-	case 0x03:		/* STATUS */
-		rtrc(7);
-		current_SC->SCp.phase = status_ph;
-		VDEB(printk("NCR53c406a: Status phase\n"));
-		outb(FLUSH_FIFO, CMD_REG);
-		outb(INIT_CMD_COMPLETE, CMD_REG);
-		break;
-
-	case 0x04:		/* Reserved */
-	case 0x05:		/* Reserved */
-		printk("NCR53c406a: WARNING: Reserved phase!!!\n");
-		break;
-
-	case 0x06:		/* MESSAGE-OUT */
-		DEB(printk("NCR53c406a: Message-Out phase\n"));
-		current_SC->SCp.phase = message_out;
-		outb(SET_ATN, CMD_REG);	/* Reject the message */
-		outb(MSG_ACCEPT, CMD_REG);
-		break;
-
-	case 0x07:		/* MESSAGE-IN */
-		rtrc(4);
-		VDEB(printk("NCR53c406a: Message-In phase\n"));
-		current_SC->SCp.phase = message_in;
-
-		current_SC->SCp.Status = inb(SCSI_FIFO);
-		current_SC->SCp.Message = inb(SCSI_FIFO);
-
-		VDEB(printk("SCSI FIFO size=%d\n", inb(FIFO_FLAGS) & 0x1f));
-		DEB(printk("Status = %02x  Message = %02x\n", current_SC->SCp.Status, current_SC->SCp.Message));
-
-		if (current_SC->SCp.Message == SAVE_POINTERS || current_SC->SCp.Message == DISCONNECT) {
-			outb(SET_ATN, CMD_REG);	/* Reject message */
-			DEB(printk("Discarding SAVE_POINTERS message\n"));
-		}
-		outb(MSG_ACCEPT, CMD_REG);
-		break;
-	}
-}
-
-#ifndef IRQ_LEV
-static int irq_probe(void)
-{
-	int irqs, irq;
-	unsigned long i;
-
-	inb(INT_REG);		/* clear the interrupt register */
-	irqs = probe_irq_on();
-
-	/* Invalid command will cause an interrupt */
-	REG0;
-	outb(0xff, CMD_REG);
-
-	/* Wait for the interrupt to occur */
-	i = jiffies + WATCHDOG;
-	while (time_after(i, jiffies) && !(inb(STAT_REG) & 0x80))
-		barrier();
-	if (time_before_eq(i, jiffies)) {	/* Timed out, must be hardware trouble */
-		probe_irq_off(irqs);
-		return -1;
-	}
-
-	irq = probe_irq_off(irqs);
-
-	/* Kick the chip */
-	outb(CHIP_RESET, CMD_REG);
-	outb(SCSI_NOP, CMD_REG);
-	chip_init();
-
-	return irq;
-}
-#endif				/* IRQ_LEV */
-
-static void chip_init(void)
-{
-	REG1;
-#if USE_DMA
-	outb(0x00, PIO_STATUS);
-#else				/* USE_PIO */
-	outb(0x01, PIO_STATUS);
-#endif
-	outb(0x00, PIO_FLAG);
-
-	outb(C4_IMG, CONFIG4);	/* REG0; */
-	outb(C3_IMG, CONFIG3);
-	outb(C2_IMG, CONFIG2);
-	outb(C1_IMG, CONFIG1);
-
-	outb(0x05, CLKCONV);	/* clock conversion factor */
-	outb(0x9C, SRTIMOUT);	/* Selection timeout */
-	outb(0x05, SYNCPRD);	/* Synchronous transfer period */
-	outb(SYNC_MODE, SYNCOFF);	/* synchronous mode */
-}
-
-static void __init calc_port_addr(void)
-{
-	/* Control Register Set 0 */
-	TC_LSB = (port_base + 0x00);
-	TC_MSB = (port_base + 0x01);
-	SCSI_FIFO = (port_base + 0x02);
-	CMD_REG = (port_base + 0x03);
-	STAT_REG = (port_base + 0x04);
-	DEST_ID = (port_base + 0x04);
-	INT_REG = (port_base + 0x05);
-	SRTIMOUT = (port_base + 0x05);
-	SEQ_REG = (port_base + 0x06);
-	SYNCPRD = (port_base + 0x06);
-	FIFO_FLAGS = (port_base + 0x07);
-	SYNCOFF = (port_base + 0x07);
-	CONFIG1 = (port_base + 0x08);
-	CLKCONV = (port_base + 0x09);
-	/* TESTREG          = (port_base+0x0A); */
-	CONFIG2 = (port_base + 0x0B);
-	CONFIG3 = (port_base + 0x0C);
-	CONFIG4 = (port_base + 0x0D);
-	TC_HIGH = (port_base + 0x0E);
-	/* FIFO_BOTTOM      = (port_base+0x0F); */
-
-	/* Control Register Set 1 */
-	/* JUMPER_SENSE     = (port_base+0x00); */
-	/* SRAM_PTR         = (port_base+0x01); */
-	/* SRAM_DATA        = (port_base+0x02); */
-	PIO_FIFO = (port_base + 0x04);
-	/* PIO_FIFO1        = (port_base+0x05); */
-	/* PIO_FIFO2        = (port_base+0x06); */
-	/* PIO_FIFO3        = (port_base+0x07); */
-	PIO_STATUS = (port_base + 0x08);
-	/* ATA_CMD          = (port_base+0x09); */
-	/* ATA_ERR          = (port_base+0x0A); */
-	PIO_FLAG = (port_base + 0x0B);
-	CONFIG5 = (port_base + 0x0D);
-	/* SIGNATURE        = (port_base+0x0E); */
-	/* CONFIG6          = (port_base+0x0F); */
-}
-
-MODULE_LICENSE("GPL");
-
-/* NOTE:  scatter-gather support only works in PIO mode.
- * Use SG_NONE if DMA mode is enabled!
- */
-
-static struct scsi_host_template driver_template =
-{
-     .proc_name         	= "NCR53c406a"		/* proc_name */,        
-     .name              	= "NCR53c406a"		/* name */,             
-     .detect            	= NCR53c406a_detect	/* detect */,           
-     .release            	= NCR53c406a_release,
-     .info              	= NCR53c406a_info		/* info */,             
-     .queuecommand      	= NCR53c406a_queue	/* queuecommand */,     
-     .eh_host_reset_handler     = NCR53c406a_host_reset	/* reset */,            
-     .bios_param        	= NCR53c406a_biosparm	/* biosparm */,         
-     .can_queue         	= 1			/* can_queue */,        
-     .this_id           	= 7			/* SCSI ID of the chip */,
-     .sg_tablesize      	= 32			/*SG_ALL*/ /*SG_NONE*/, 
-     .unchecked_isa_dma 	= 1			/* unchecked_isa_dma */,
-     .use_clustering    	= ENABLE_CLUSTERING,
-};
-
-#include "scsi_module.c"
-
-/*
- * Overrides for Emacs so that we get a uniform tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */

+ 5 - 0
drivers/scsi/aacraid/aacraid.h

@@ -1231,6 +1231,7 @@ struct src_registers {
 
 
 #define SRC_ODR_SHIFT		12
 #define SRC_ODR_SHIFT		12
 #define SRC_IDR_SHIFT		9
 #define SRC_IDR_SHIFT		9
+#define SRC_MSI_READ_MASK	0x1000
 
 
 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
 
 
@@ -1528,6 +1529,7 @@ struct aac_bus_info_response {
 #define AAC_COMM_MESSAGE_TYPE3		5
 #define AAC_COMM_MESSAGE_TYPE3		5
 
 
 #define AAC_EXTOPT_SA_FIRMWARE		cpu_to_le32(1<<1)
 #define AAC_EXTOPT_SA_FIRMWARE		cpu_to_le32(1<<1)
+#define AAC_EXTOPT_SOFT_RESET		cpu_to_le32(1<<16)
 
 
 /* MSIX context */
 /* MSIX context */
 struct aac_msix_ctx {
 struct aac_msix_ctx {
@@ -1662,6 +1664,7 @@ struct aac_dev
 	u8			raw_io_64;
 	u8			raw_io_64;
 	u8			printf_enabled;
 	u8			printf_enabled;
 	u8			in_reset;
 	u8			in_reset;
+	u8			in_soft_reset;
 	u8			msi;
 	u8			msi;
 	u8			sa_firmware;
 	u8			sa_firmware;
 	int			management_fib_count;
 	int			management_fib_count;
@@ -2504,6 +2507,7 @@ struct aac_hba_info {
 #define RCV_TEMP_READINGS		0x00000025
 #define RCV_TEMP_READINGS		0x00000025
 #define GET_COMM_PREFERRED_SETTINGS	0x00000026
 #define GET_COMM_PREFERRED_SETTINGS	0x00000026
 #define IOP_RESET_FW_FIB_DUMP		0x00000034
 #define IOP_RESET_FW_FIB_DUMP		0x00000034
+#define DROP_IO			0x00000035
 #define IOP_RESET			0x00001000
 #define IOP_RESET			0x00001000
 #define IOP_RESET_ALWAYS		0x00001001
 #define IOP_RESET_ALWAYS		0x00001001
 #define RE_INIT_ADAPTER		0x000000ee
 #define RE_INIT_ADAPTER		0x000000ee
@@ -2539,6 +2543,7 @@ struct aac_hba_info {
 #define	FLASH_UPD_PENDING		0x00002000
 #define	FLASH_UPD_PENDING		0x00002000
 #define	FLASH_UPD_SUCCESS		0x00004000
 #define	FLASH_UPD_SUCCESS		0x00004000
 #define	FLASH_UPD_FAILED		0x00008000
 #define	FLASH_UPD_FAILED		0x00008000
+#define	INVALID_OMR			0xffffffff
 #define	FWUPD_TIMEOUT			(5 * 60)
 #define	FWUPD_TIMEOUT			(5 * 60)
 
 
 /*
 /*

+ 193 - 12
drivers/scsi/aacraid/src.c

@@ -255,7 +255,8 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command,
 	 */
 	 */
 	src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT);
 	src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT);
 
 
-	if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) {
+	if ((!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) &&
+		!dev->in_soft_reset) {
 		ok = 0;
 		ok = 0;
 		start = jiffies;
 		start = jiffies;
 
 
@@ -679,6 +680,25 @@ void aac_set_intx_mode(struct aac_dev *dev)
 	}
 	}
 }
 }
 
 
+static void aac_clear_omr(struct aac_dev *dev)
+{
+	u32 omr_value = 0;
+
+	omr_value = src_readl(dev, MUnit.OMR);
+
+	/*
+	 * Check for PCI Errors or Kernel Panic
+	 */
+	if ((omr_value == INVALID_OMR) || (omr_value & KERNEL_PANIC))
+		omr_value = 0;
+
+	/*
+	 * Preserve MSIX Value if any
+	 */
+	src_writel(dev, MUnit.OMR, omr_value & AAC_INT_MODE_MSIX);
+	src_readl(dev, MUnit.OMR);
+}
+
 static void aac_dump_fw_fib_iop_reset(struct aac_dev *dev)
 static void aac_dump_fw_fib_iop_reset(struct aac_dev *dev)
 {
 {
 	__le32 supported_options3;
 	__le32 supported_options3;
@@ -739,6 +759,8 @@ static void aac_send_iop_reset(struct aac_dev *dev)
 
 
 	aac_set_intx_mode(dev);
 	aac_set_intx_mode(dev);
 
 
+	aac_clear_omr(dev);
+
 	src_writel(dev, MUnit.IDR, IOP_SRC_RESET_MASK);
 	src_writel(dev, MUnit.IDR, IOP_SRC_RESET_MASK);
 
 
 	msleep(5000);
 	msleep(5000);
@@ -748,6 +770,7 @@ static void aac_send_hardware_soft_reset(struct aac_dev *dev)
 {
 {
 	u_int32_t val;
 	u_int32_t val;
 
 
+	aac_clear_omr(dev);
 	val = readl(((char *)(dev->base) + IBW_SWR_OFFSET));
 	val = readl(((char *)(dev->base) + IBW_SWR_OFFSET));
 	val |= 0x01;
 	val |= 0x01;
 	writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET));
 	writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET));
@@ -992,6 +1015,148 @@ error_iounmap:
 	return -1;
 	return -1;
 }
 }
 
 
+static int aac_src_wait_sync(struct aac_dev *dev, int *status)
+{
+	unsigned long start = jiffies;
+	unsigned long usecs = 0;
+	int delay = 5 * HZ;
+	int rc = 1;
+
+	while (time_before(jiffies, start+delay)) {
+		/*
+		 * Delay 5 microseconds to let Mon960 get info.
+		 */
+		udelay(5);
+
+		/*
+		 * Mon960 will set doorbell0 bit when it has completed the
+		 * command.
+		 */
+		if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) {
+			/*
+			 * Clear: the doorbell.
+			 */
+			if (dev->msi_enabled)
+				aac_src_access_devreg(dev, AAC_CLEAR_SYNC_BIT);
+			else
+				src_writel(dev, MUnit.ODR_C,
+					OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
+			rc = 0;
+
+			break;
+		}
+
+		/*
+		 * Yield the processor in case we are slow
+		 */
+		usecs = 1 * USEC_PER_MSEC;
+		usleep_range(usecs, usecs + 50);
+	}
+	/*
+	 * Pull the synch status from Mailbox 0.
+	 */
+	if (status && !rc) {
+		status[0] = readl(&dev->IndexRegs->Mailbox[0]);
+		status[1] = readl(&dev->IndexRegs->Mailbox[1]);
+		status[2] = readl(&dev->IndexRegs->Mailbox[2]);
+		status[3] = readl(&dev->IndexRegs->Mailbox[3]);
+		status[4] = readl(&dev->IndexRegs->Mailbox[4]);
+	}
+
+	return rc;
+}
+
+/**
+ *  aac_src_soft_reset	-	perform soft reset to speed up
+ *  access
+ *
+ *  Assumptions: That the controller is in a state where we can
+ *  bring it back to life with an init struct. We can only use
+ *  fast sync commands, as the timeout is 5 seconds.
+ *
+ *  @dev: device to configure
+ *
+ */
+
+static int aac_src_soft_reset(struct aac_dev *dev)
+{
+	u32 status_omr = src_readl(dev, MUnit.OMR);
+	u32 status[5];
+	int rc = 1;
+	int state = 0;
+	char *state_str[7] = {
+		"GET_ADAPTER_PROPERTIES Failed",
+		"GET_ADAPTER_PROPERTIES timeout",
+		"SOFT_RESET not supported",
+		"DROP_IO Failed",
+		"DROP_IO timeout",
+		"Check Health failed"
+	};
+
+	if (status_omr == INVALID_OMR)
+		return 1;       // pcie hosed
+
+	if (!(status_omr & KERNEL_UP_AND_RUNNING))
+		return 1;       // not up and running
+
+	/*
+	 * We go into soft reset mode to allow us to handle response
+	 */
+	dev->in_soft_reset = 1;
+	dev->msi_enabled = status_omr & AAC_INT_MODE_MSIX;
+
+	/* Get adapter properties */
+	rc = aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0,
+		0, 0, 0, status+0, status+1, status+2, status+3, status+4);
+	if (rc)
+		goto out;
+
+	state++;
+	if (aac_src_wait_sync(dev, status)) {
+		rc = 1;
+		goto out;
+	}
+
+	state++;
+	if (!(status[1] & le32_to_cpu(AAC_OPT_EXTENDED) &&
+		(status[4] & le32_to_cpu(AAC_EXTOPT_SOFT_RESET)))) {
+		rc = 2;
+		goto out;
+	}
+
+	if ((status[1] & le32_to_cpu(AAC_OPT_EXTENDED)) &&
+		(status[4] & le32_to_cpu(AAC_EXTOPT_SA_FIRMWARE)))
+		dev->sa_firmware = 1;
+
+	state++;
+	rc = aac_adapter_sync_cmd(dev, DROP_IO, 0, 0, 0, 0, 0, 0,
+		 status+0, status+1, status+2, status+3, status+4);
+
+	if (rc)
+		goto out;
+
+	state++;
+	if (aac_src_wait_sync(dev, status)) {
+		rc = 3;
+		goto out;
+	}
+
+	if (status[1])
+		dev_err(&dev->pdev->dev, "%s: %d outstanding I/O pending\n",
+			__func__, status[1]);
+
+	state++;
+	rc = aac_src_check_health(dev);
+
+out:
+	dev->in_soft_reset = 0;
+	dev->msi_enabled = 0;
+	if (rc)
+		dev_err(&dev->pdev->dev, "%s: %s status = %d", __func__,
+			state_str[state], rc);
+
+return rc;
+}
 /**
 /**
  *  aac_srcv_init	-	initialize an SRCv card
  *  aac_srcv_init	-	initialize an SRCv card
  *  @dev: device to configure
  *  @dev: device to configure
@@ -1021,8 +1186,10 @@ int aac_srcv_init(struct aac_dev *dev)
 
 
 	if (dev->init_reset) {
 	if (dev->init_reset) {
 		dev->init_reset = false;
 		dev->init_reset = false;
-		if (!aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET))
+		if (aac_src_soft_reset(dev)) {
+			aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET);
 			++restart;
 			++restart;
+		}
 	}
 	}
 
 
 	/*
 	/*
@@ -1072,13 +1239,16 @@ int aac_srcv_init(struct aac_dev *dev)
 		printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
 		printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
 		goto error_iounmap;
 		goto error_iounmap;
 	}
 	}
+
 	start = jiffies;
 	start = jiffies;
 	/*
 	/*
 	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
 	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
 	 */
 	 */
-	while (!((status = src_readl(dev, MUnit.OMR)) &
-		KERNEL_UP_AND_RUNNING) ||
-		status == 0xffffffff) {
+	do {
+		status = src_readl(dev, MUnit.OMR);
+		if (status == INVALID_OMR)
+			status = 0;
+
 		if ((restart &&
 		if ((restart &&
 		  (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
 		  (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
 		  time_after(jiffies, start+HZ*startup_timeout)) {
 		  time_after(jiffies, start+HZ*startup_timeout)) {
@@ -1098,7 +1268,8 @@ int aac_srcv_init(struct aac_dev *dev)
 			++restart;
 			++restart;
 		}
 		}
 		msleep(1);
 		msleep(1);
-	}
+	} while (!(status & KERNEL_UP_AND_RUNNING));
+
 	if (restart && aac_commit)
 	if (restart && aac_commit)
 		aac_commit = 1;
 		aac_commit = 1;
 	/*
 	/*
@@ -1234,13 +1405,23 @@ void aac_src_access_devreg(struct aac_dev *dev, int mode)
 
 
 static int aac_src_get_sync_status(struct aac_dev *dev)
 static int aac_src_get_sync_status(struct aac_dev *dev)
 {
 {
+	int msix_val = 0;
+	int legacy_val = 0;
 
 
-	int val;
+	msix_val = src_readl(dev, MUnit.ODR_MSI) & SRC_MSI_READ_MASK ? 1 : 0;
 
 
-	if (dev->msi_enabled)
-		val = src_readl(dev, MUnit.ODR_MSI) & 0x1000 ? 1 : 0;
-	else
-		val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT;
+	if (!dev->msi_enabled) {
+		/*
+		 * if Legacy int status indicates cmd is not complete
+		 * sample MSIx register to see if it indiactes cmd complete,
+		 * if yes set the controller in MSIx mode and consider cmd
+		 * completed
+		 */
+		legacy_val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT;
+		if (!(legacy_val & 1) && msix_val)
+			dev->msi_enabled = 1;
+		return legacy_val;
+	}
 
 
-	return val;
+	return msix_val;
 }
 }

+ 1 - 1
drivers/scsi/aha1740.c

@@ -592,7 +592,7 @@ static int aha1740_probe (struct device *dev)
 					     DMA_BIDIRECTIONAL);
 					     DMA_BIDIRECTIONAL);
 	if (!host->ecb_dma_addr) {
 	if (!host->ecb_dma_addr) {
 		printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
 		printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
-		scsi_unregister (shpnt);
+		scsi_host_put (shpnt);
 		goto err_host_put;
 		goto err_host_put;
 	}
 	}
 	
 	

+ 4 - 4
drivers/scsi/aic7xxx/aic79xx_core.c

@@ -9338,9 +9338,9 @@ ahd_dumpseq(struct ahd_softc* ahd)
 static void
 static void
 ahd_loadseq(struct ahd_softc *ahd)
 ahd_loadseq(struct ahd_softc *ahd)
 {
 {
-	struct	cs cs_table[num_critical_sections];
-	u_int	begin_set[num_critical_sections];
-	u_int	end_set[num_critical_sections];
+	struct	cs cs_table[NUM_CRITICAL_SECTIONS];
+	u_int	begin_set[NUM_CRITICAL_SECTIONS];
+	u_int	end_set[NUM_CRITICAL_SECTIONS];
 	const struct patch *cur_patch;
 	const struct patch *cur_patch;
 	u_int	cs_count;
 	u_int	cs_count;
 	u_int	cur_cs;
 	u_int	cur_cs;
@@ -9456,7 +9456,7 @@ ahd_loadseq(struct ahd_softc *ahd)
 		 * Move through the CS table until we find a CS
 		 * Move through the CS table until we find a CS
 		 * that might apply to this instruction.
 		 * that might apply to this instruction.
 		 */
 		 */
-		for (; cur_cs < num_critical_sections; cur_cs++) {
+		for (; cur_cs < NUM_CRITICAL_SECTIONS; cur_cs++) {
 			if (critical_sections[cur_cs].end <= i) {
 			if (critical_sections[cur_cs].end <= i) {
 				if (begin_set[cs_count] == TRUE
 				if (begin_set[cs_count] == TRUE
 				 && end_set[cs_count] == FALSE) {
 				 && end_set[cs_count] == FALSE) {

+ 1 - 2
drivers/scsi/aic7xxx/aic79xx_seq.h_shipped

@@ -1186,5 +1186,4 @@ static const struct cs {
 	{ 759, 763 }
 	{ 759, 763 }
 };
 };
 
 
-static const int num_critical_sections = sizeof(critical_sections)
-				       / sizeof(*critical_sections);
+#define NUM_CRITICAL_SECTIONS ARRAY_SIZE(critical_sections)

+ 4 - 4
drivers/scsi/aic7xxx/aic7xxx_core.c

@@ -6848,9 +6848,9 @@ ahc_dumpseq(struct ahc_softc* ahc)
 static int
 static int
 ahc_loadseq(struct ahc_softc *ahc)
 ahc_loadseq(struct ahc_softc *ahc)
 {
 {
-	struct	cs cs_table[num_critical_sections];
-	u_int	begin_set[num_critical_sections];
-	u_int	end_set[num_critical_sections];
+	struct	cs cs_table[NUM_CRITICAL_SECTIONS];
+	u_int	begin_set[NUM_CRITICAL_SECTIONS];
+	u_int	end_set[NUM_CRITICAL_SECTIONS];
 	const struct patch *cur_patch;
 	const struct patch *cur_patch;
 	u_int	cs_count;
 	u_int	cs_count;
 	u_int	cur_cs;
 	u_int	cur_cs;
@@ -6915,7 +6915,7 @@ ahc_loadseq(struct ahc_softc *ahc)
 		 * Move through the CS table until we find a CS
 		 * Move through the CS table until we find a CS
 		 * that might apply to this instruction.
 		 * that might apply to this instruction.
 		 */
 		 */
-		for (; cur_cs < num_critical_sections; cur_cs++) {
+		for (; cur_cs < NUM_CRITICAL_SECTIONS; cur_cs++) {
 			if (critical_sections[cur_cs].end <= i) {
 			if (critical_sections[cur_cs].end <= i) {
 				if (begin_set[cs_count] == TRUE
 				if (begin_set[cs_count] == TRUE
 				 && end_set[cs_count] == FALSE) {
 				 && end_set[cs_count] == FALSE) {

+ 1 - 2
drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped

@@ -1304,5 +1304,4 @@ static const struct cs {
 	{ 875, 877 }
 	{ 875, 877 }
 };
 };
 
 
-static const int num_critical_sections = sizeof(critical_sections)
-				       / sizeof(*critical_sections);
+#define NUM_CRITICAL_SECTIONS ARRAY_SIZE(critical_sections)

+ 1 - 2
drivers/scsi/aic7xxx/aicasm/aicasm.c

@@ -451,8 +451,7 @@ output_code()
 	fprintf(ofile, "\n};\n\n");
 	fprintf(ofile, "\n};\n\n");
 
 
 	fprintf(ofile,
 	fprintf(ofile,
-"static const int num_critical_sections = sizeof(critical_sections)\n"
-"				       / sizeof(*critical_sections);\n");
+	"#define NUM_CRITICAL_SECTIONS ARRAY_SIZE(critical_sections)\n");
 
 
 	fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
 	fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
 }
 }

+ 2 - 2
drivers/scsi/arcmsr/arcmsr.h

@@ -49,7 +49,7 @@ struct device_attribute;
 #define ARCMSR_MAX_OUTSTANDING_CMD	1024
 #define ARCMSR_MAX_OUTSTANDING_CMD	1024
 #define ARCMSR_DEFAULT_OUTSTANDING_CMD	128
 #define ARCMSR_DEFAULT_OUTSTANDING_CMD	128
 #define ARCMSR_MIN_OUTSTANDING_CMD	32
 #define ARCMSR_MIN_OUTSTANDING_CMD	32
-#define ARCMSR_DRIVER_VERSION		"v1.40.00.04-20171130"
+#define ARCMSR_DRIVER_VERSION		"v1.40.00.05-20180309"
 #define ARCMSR_SCSI_INITIATOR_ID	255
 #define ARCMSR_SCSI_INITIATOR_ID	255
 #define ARCMSR_MAX_XFER_SECTORS		512
 #define ARCMSR_MAX_XFER_SECTORS		512
 #define ARCMSR_MAX_XFER_SECTORS_B	4096
 #define ARCMSR_MAX_XFER_SECTORS_B	4096
@@ -779,12 +779,12 @@ struct AdapterControlBlock
 /* message clear rqbuffer */
 /* message clear rqbuffer */
 #define ACB_F_MESSAGE_WQBUFFER_READED   0x0040
 #define ACB_F_MESSAGE_WQBUFFER_READED   0x0040
 #define ACB_F_BUS_RESET               	0x0080
 #define ACB_F_BUS_RESET               	0x0080
-#define ACB_F_BUS_HANG_ON		0x0800/* need hardware reset bus */
 
 
 #define ACB_F_IOP_INITED              	0x0100
 #define ACB_F_IOP_INITED              	0x0100
 /* iop init */
 /* iop init */
 #define ACB_F_ABORT			0x0200
 #define ACB_F_ABORT			0x0200
 #define ACB_F_FIRMWARE_TRAP           	0x0400
 #define ACB_F_FIRMWARE_TRAP           	0x0400
+#define ACB_F_ADAPTER_REMOVED		0x0800
 #define ACB_F_MSG_GET_CONFIG		0x1000
 #define ACB_F_MSG_GET_CONFIG		0x1000
 	struct CommandControlBlock *	pccb_pool[ARCMSR_MAX_FREECCB_NUM];
 	struct CommandControlBlock *	pccb_pool[ARCMSR_MAX_FREECCB_NUM];
 	/* used for memory free */
 	/* used for memory free */

+ 90 - 0
drivers/scsi/arcmsr/arcmsr_hba.c

@@ -1446,12 +1446,80 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
 	}
 	}
 }
 }
 
 
+static void arcmsr_remove_scsi_devices(struct AdapterControlBlock *acb)
+{
+	char *acb_dev_map = (char *)acb->device_map;
+	int target, lun, i;
+	struct scsi_device *psdev;
+	struct CommandControlBlock *ccb;
+	char temp;
+
+	for (i = 0; i < acb->maxFreeCCB; i++) {
+		ccb = acb->pccb_pool[i];
+		if (ccb->startdone == ARCMSR_CCB_START) {
+			ccb->pcmd->result = DID_NO_CONNECT << 16;
+			arcmsr_pci_unmap_dma(ccb);
+			ccb->pcmd->scsi_done(ccb->pcmd);
+		}
+	}
+	for (target = 0; target < ARCMSR_MAX_TARGETID; target++) {
+		temp = *acb_dev_map;
+		if (temp) {
+			for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+				if (temp & 1) {
+					psdev = scsi_device_lookup(acb->host,
+						0, target, lun);
+					if (psdev != NULL) {
+						scsi_remove_device(psdev);
+						scsi_device_put(psdev);
+					}
+				}
+				temp >>= 1;
+			}
+			*acb_dev_map = 0;
+		}
+		acb_dev_map++;
+	}
+}
+
+static void arcmsr_free_pcidev(struct AdapterControlBlock *acb)
+{
+	struct pci_dev *pdev;
+	struct Scsi_Host *host;
+
+	host = acb->host;
+	arcmsr_free_sysfs_attr(acb);
+	scsi_remove_host(host);
+	flush_work(&acb->arcmsr_do_message_isr_bh);
+	del_timer_sync(&acb->eternal_timer);
+	if (set_date_time)
+		del_timer_sync(&acb->refresh_timer);
+	pdev = acb->pdev;
+	arcmsr_free_irq(pdev, acb);
+	arcmsr_free_ccb_pool(acb);
+	arcmsr_free_mu(acb);
+	arcmsr_unmap_pciregion(acb);
+	pci_release_regions(pdev);
+	scsi_host_put(host);
+	pci_disable_device(pdev);
+}
+
 static void arcmsr_remove(struct pci_dev *pdev)
 static void arcmsr_remove(struct pci_dev *pdev)
 {
 {
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	struct AdapterControlBlock *acb =
 	struct AdapterControlBlock *acb =
 		(struct AdapterControlBlock *) host->hostdata;
 		(struct AdapterControlBlock *) host->hostdata;
 	int poll_count = 0;
 	int poll_count = 0;
+	uint16_t dev_id;
+
+	pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+	if (dev_id == 0xffff) {
+		acb->acb_flags &= ~ACB_F_IOP_INITED;
+		acb->acb_flags |= ACB_F_ADAPTER_REMOVED;
+		arcmsr_remove_scsi_devices(acb);
+		arcmsr_free_pcidev(acb);
+		return;
+	}
 	arcmsr_free_sysfs_attr(acb);
 	arcmsr_free_sysfs_attr(acb);
 	scsi_remove_host(host);
 	scsi_remove_host(host);
 	flush_work(&acb->arcmsr_do_message_isr_bh);
 	flush_work(&acb->arcmsr_do_message_isr_bh);
@@ -1499,6 +1567,8 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	struct AdapterControlBlock *acb =
 	struct AdapterControlBlock *acb =
 		(struct AdapterControlBlock *)host->hostdata;
 		(struct AdapterControlBlock *)host->hostdata;
+	if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
+		return;
 	del_timer_sync(&acb->eternal_timer);
 	del_timer_sync(&acb->eternal_timer);
 	if (set_date_time)
 	if (set_date_time)
 		del_timer_sync(&acb->refresh_timer);
 		del_timer_sync(&acb->refresh_timer);
@@ -2931,6 +3001,12 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
 	struct CommandControlBlock *ccb;
 	struct CommandControlBlock *ccb;
 	int target = cmd->device->id;
 	int target = cmd->device->id;
+
+	if (acb->acb_flags & ACB_F_ADAPTER_REMOVED) {
+		cmd->result = (DID_NO_CONNECT << 16);
+		cmd->scsi_done(cmd);
+		return 0;
+	}
 	cmd->scsi_done = done;
 	cmd->scsi_done = done;
 	cmd->host_scribble = NULL;
 	cmd->host_scribble = NULL;
 	cmd->result = 0;
 	cmd->result = 0;
@@ -3731,6 +3807,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 	case ACB_ADAPTER_TYPE_A: {
 	case ACB_ADAPTER_TYPE_A: {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 		do {
 		do {
+			if (!(acb->acb_flags & ACB_F_IOP_INITED))
+				msleep(20);
 			firmware_state = readl(&reg->outbound_msgaddr1);
 			firmware_state = readl(&reg->outbound_msgaddr1);
 		} while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
 		} while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
 		}
 		}
@@ -3739,6 +3817,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 	case ACB_ADAPTER_TYPE_B: {
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
 		struct MessageUnit_B *reg = acb->pmuB;
 		do {
 		do {
+			if (!(acb->acb_flags & ACB_F_IOP_INITED))
+				msleep(20);
 			firmware_state = readl(reg->iop2drv_doorbell);
 			firmware_state = readl(reg->iop2drv_doorbell);
 		} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
 		} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
 		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
 		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
@@ -3747,6 +3827,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 	case ACB_ADAPTER_TYPE_C: {
 	case ACB_ADAPTER_TYPE_C: {
 		struct MessageUnit_C __iomem *reg = acb->pmuC;
 		struct MessageUnit_C __iomem *reg = acb->pmuC;
 		do {
 		do {
+			if (!(acb->acb_flags & ACB_F_IOP_INITED))
+				msleep(20);
 			firmware_state = readl(&reg->outbound_msgaddr1);
 			firmware_state = readl(&reg->outbound_msgaddr1);
 		} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
 		} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
 		}
 		}
@@ -3754,6 +3836,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 	case ACB_ADAPTER_TYPE_D: {
 	case ACB_ADAPTER_TYPE_D: {
 		struct MessageUnit_D *reg = acb->pmuD;
 		struct MessageUnit_D *reg = acb->pmuD;
 		do {
 		do {
+			if (!(acb->acb_flags & ACB_F_IOP_INITED))
+				msleep(20);
 			firmware_state = readl(reg->outbound_msgaddr1);
 			firmware_state = readl(reg->outbound_msgaddr1);
 		} while ((firmware_state &
 		} while ((firmware_state &
 			ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK) == 0);
 			ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK) == 0);
@@ -3762,6 +3846,8 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 	case ACB_ADAPTER_TYPE_E: {
 	case ACB_ADAPTER_TYPE_E: {
 		struct MessageUnit_E __iomem *reg = acb->pmuE;
 		struct MessageUnit_E __iomem *reg = acb->pmuE;
 		do {
 		do {
+			if (!(acb->acb_flags & ACB_F_IOP_INITED))
+				msleep(20);
 			firmware_state = readl(&reg->outbound_msgaddr1);
 			firmware_state = readl(&reg->outbound_msgaddr1);
 		} while ((firmware_state & ARCMSR_HBEMU_MESSAGE_FIRMWARE_OK) == 0);
 		} while ((firmware_state & ARCMSR_HBEMU_MESSAGE_FIRMWARE_OK) == 0);
 		}
 		}
@@ -4177,6 +4263,8 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
 	int retry_count = 0;
 	int retry_count = 0;
 	int rtn = FAILED;
 	int rtn = FAILED;
 	acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
 	acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
+	if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
+		return SUCCESS;
 	pr_notice("arcmsr: executing bus reset eh.....num_resets = %d,"
 	pr_notice("arcmsr: executing bus reset eh.....num_resets = %d,"
 		" num_aborts = %d \n", acb->num_resets, acb->num_aborts);
 		" num_aborts = %d \n", acb->num_resets, acb->num_aborts);
 	acb->num_resets++;
 	acb->num_resets++;
@@ -4243,6 +4331,8 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
 	int rtn = FAILED;
 	int rtn = FAILED;
 	uint32_t intmask_org;
 	uint32_t intmask_org;
 
 
+	if (acb->acb_flags & ACB_F_ADAPTER_REMOVED)
+		return SUCCESS;
 	printk(KERN_NOTICE
 	printk(KERN_NOTICE
 		"arcmsr%d: abort device command of scsi id = %d lun = %d\n",
 		"arcmsr%d: abort device command of scsi id = %d lun = %d\n",
 		acb->host->host_no, cmd->device->id, (u32)cmd->device->lun);
 		acb->host->host_no, cmd->device->id, (u32)cmd->device->lun);

+ 2 - 2
drivers/scsi/atp870u.c

@@ -1413,11 +1413,11 @@ static void atp885_init(struct Scsi_Host *shpnt)
 			atpdev->global_map[m] = 0;
 			atpdev->global_map[m] = 0;
 			for (k = 0; k < 4; k++) {
 			for (k = 0; k < 4; k++) {
 				atp_writew_base(atpdev, 0x3c, n++);
 				atp_writew_base(atpdev, 0x3c, n++);
-				((unsigned long *)&setupdata[m][0])[k] = atp_readl_base(atpdev, 0x38);
+				((u32 *)&setupdata[m][0])[k] = atp_readl_base(atpdev, 0x38);
 			}
 			}
 			for (k = 0; k < 4; k++) {
 			for (k = 0; k < 4; k++) {
 				atp_writew_base(atpdev, 0x3c, n++);
 				atp_writew_base(atpdev, 0x3c, n++);
-				((unsigned long *)&atpdev->sp[m][0])[k] = atp_readl_base(atpdev, 0x38);
+				((u32 *)&atpdev->sp[m][0])[k] = atp_readl_base(atpdev, 0x38);
 			}
 			}
 			n += 8;
 			n += 8;
 		}
 		}

+ 1 - 1
drivers/scsi/bfa/bfad_bsg.c

@@ -891,7 +891,7 @@ bfad_iocmd_fabric_get_lports(struct bfad_s *bfad, void *cmd,
 
 
 	if (bfad_chk_iocmd_sz(payload_len,
 	if (bfad_chk_iocmd_sz(payload_len,
 		sizeof(struct bfa_bsg_fabric_get_lports_s),
 		sizeof(struct bfa_bsg_fabric_get_lports_s),
-		sizeof(wwn_t[iocmd->nports])) != BFA_STATUS_OK) {
+		sizeof(wwn_t) * iocmd->nports) != BFA_STATUS_OK) {
 		iocmd->status = BFA_STATUS_VERSION_FAIL;
 		iocmd->status = BFA_STATUS_VERSION_FAIL;
 		goto out;
 		goto out;
 	}
 	}

+ 14 - 2
drivers/scsi/csiostor/csio_attr.c

@@ -274,12 +274,24 @@ csio_get_host_speed(struct Scsi_Host *shost)
 
 
 	spin_lock_irq(&hw->lock);
 	spin_lock_irq(&hw->lock);
 	switch (hw->pport[ln->portid].link_speed) {
 	switch (hw->pport[ln->portid].link_speed) {
-	case FW_PORT_CAP_SPEED_1G:
+	case FW_PORT_CAP32_SPEED_1G:
 		fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
 		fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
 		break;
 		break;
-	case FW_PORT_CAP_SPEED_10G:
+	case FW_PORT_CAP32_SPEED_10G:
 		fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
 		fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
 		break;
 		break;
+	case FW_PORT_CAP32_SPEED_25G:
+		fc_host_speed(shost) = FC_PORTSPEED_25GBIT;
+		break;
+	case FW_PORT_CAP32_SPEED_40G:
+		fc_host_speed(shost) = FC_PORTSPEED_40GBIT;
+		break;
+	case FW_PORT_CAP32_SPEED_50G:
+		fc_host_speed(shost) = FC_PORTSPEED_50GBIT;
+		break;
+	case FW_PORT_CAP32_SPEED_100G:
+		fc_host_speed(shost) = FC_PORTSPEED_100GBIT;
+		break;
 	default:
 	default:
 		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 		break;
 		break;

+ 270 - 5
drivers/scsi/csiostor/csio_hw.c

@@ -1409,6 +1409,235 @@ out:
 	return rv;
 	return rv;
 }
 }
 
 
+static inline enum cc_fec fwcap_to_cc_fec(fw_port_cap32_t fw_fec)
+{
+	enum cc_fec cc_fec = 0;
+
+	if (fw_fec & FW_PORT_CAP32_FEC_RS)
+		cc_fec |= FEC_RS;
+	if (fw_fec & FW_PORT_CAP32_FEC_BASER_RS)
+		cc_fec |= FEC_BASER_RS;
+
+	return cc_fec;
+}
+
+static inline fw_port_cap32_t cc_to_fwcap_pause(enum cc_pause cc_pause)
+{
+	fw_port_cap32_t fw_pause = 0;
+
+	if (cc_pause & PAUSE_RX)
+		fw_pause |= FW_PORT_CAP32_FC_RX;
+	if (cc_pause & PAUSE_TX)
+		fw_pause |= FW_PORT_CAP32_FC_TX;
+
+	return fw_pause;
+}
+
+static inline fw_port_cap32_t cc_to_fwcap_fec(enum cc_fec cc_fec)
+{
+	fw_port_cap32_t fw_fec = 0;
+
+	if (cc_fec & FEC_RS)
+		fw_fec |= FW_PORT_CAP32_FEC_RS;
+	if (cc_fec & FEC_BASER_RS)
+		fw_fec |= FW_PORT_CAP32_FEC_BASER_RS;
+
+	return fw_fec;
+}
+
+/**
+ * fwcap_to_fwspeed - return highest speed in Port Capabilities
+ * @acaps: advertised Port Capabilities
+ *
+ * Get the highest speed for the port from the advertised Port
+ * Capabilities.
+ */
+fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps)
+{
+	#define TEST_SPEED_RETURN(__caps_speed) \
+		do { \
+			if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \
+				return FW_PORT_CAP32_SPEED_##__caps_speed; \
+		} while (0)
+
+	TEST_SPEED_RETURN(400G);
+	TEST_SPEED_RETURN(200G);
+	TEST_SPEED_RETURN(100G);
+	TEST_SPEED_RETURN(50G);
+	TEST_SPEED_RETURN(40G);
+	TEST_SPEED_RETURN(25G);
+	TEST_SPEED_RETURN(10G);
+	TEST_SPEED_RETURN(1G);
+	TEST_SPEED_RETURN(100M);
+
+	#undef TEST_SPEED_RETURN
+
+	return 0;
+}
+
+/**
+ *      fwcaps16_to_caps32 - convert 16-bit Port Capabilities to 32-bits
+ *      @caps16: a 16-bit Port Capabilities value
+ *
+ *      Returns the equivalent 32-bit Port Capabilities value.
+ */
+fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16)
+{
+	fw_port_cap32_t caps32 = 0;
+
+	#define CAP16_TO_CAP32(__cap) \
+		do { \
+			if (caps16 & FW_PORT_CAP_##__cap) \
+				caps32 |= FW_PORT_CAP32_##__cap; \
+		} while (0)
+
+	CAP16_TO_CAP32(SPEED_100M);
+	CAP16_TO_CAP32(SPEED_1G);
+	CAP16_TO_CAP32(SPEED_25G);
+	CAP16_TO_CAP32(SPEED_10G);
+	CAP16_TO_CAP32(SPEED_40G);
+	CAP16_TO_CAP32(SPEED_100G);
+	CAP16_TO_CAP32(FC_RX);
+	CAP16_TO_CAP32(FC_TX);
+	CAP16_TO_CAP32(ANEG);
+	CAP16_TO_CAP32(MDIX);
+	CAP16_TO_CAP32(MDIAUTO);
+	CAP16_TO_CAP32(FEC_RS);
+	CAP16_TO_CAP32(FEC_BASER_RS);
+	CAP16_TO_CAP32(802_3_PAUSE);
+	CAP16_TO_CAP32(802_3_ASM_DIR);
+
+	#undef CAP16_TO_CAP32
+
+	return caps32;
+}
+
+/**
+ *      lstatus_to_fwcap - translate old lstatus to 32-bit Port Capabilities
+ *      @lstatus: old FW_PORT_ACTION_GET_PORT_INFO lstatus value
+ *
+ *      Translates old FW_PORT_ACTION_GET_PORT_INFO lstatus field into new
+ *      32-bit Port Capabilities value.
+ */
+fw_port_cap32_t lstatus_to_fwcap(u32 lstatus)
+{
+	fw_port_cap32_t linkattr = 0;
+
+	/* The format of the Link Status in the old
+	 * 16-bit Port Information message isn't the same as the
+	 * 16-bit Port Capabilities bitfield used everywhere else.
+	 */
+	if (lstatus & FW_PORT_CMD_RXPAUSE_F)
+		linkattr |= FW_PORT_CAP32_FC_RX;
+	if (lstatus & FW_PORT_CMD_TXPAUSE_F)
+		linkattr |= FW_PORT_CAP32_FC_TX;
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
+		linkattr |= FW_PORT_CAP32_SPEED_100M;
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
+		linkattr |= FW_PORT_CAP32_SPEED_1G;
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
+		linkattr |= FW_PORT_CAP32_SPEED_10G;
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_25G))
+		linkattr |= FW_PORT_CAP32_SPEED_25G;
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
+		linkattr |= FW_PORT_CAP32_SPEED_40G;
+	if (lstatus & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100G))
+		linkattr |= FW_PORT_CAP32_SPEED_100G;
+
+	return linkattr;
+}
+
+/**
+ *      csio_init_link_config - initialize a link's SW state
+ *      @lc: pointer to structure holding the link state
+ *      @pcaps: link Port Capabilities
+ *      @acaps: link current Advertised Port Capabilities
+ *
+ *      Initializes the SW state maintained for each link, including the link's
+ *      capabilities and default speed/flow-control/autonegotiation settings.
+ */
+static void csio_init_link_config(struct link_config *lc, fw_port_cap32_t pcaps,
+				  fw_port_cap32_t acaps)
+{
+	lc->pcaps = pcaps;
+	lc->def_acaps = acaps;
+	lc->lpacaps = 0;
+	lc->speed_caps = 0;
+	lc->speed = 0;
+	lc->requested_fc = PAUSE_RX | PAUSE_TX;
+	lc->fc = lc->requested_fc;
+
+	/*
+	 * For Forward Error Control, we default to whatever the Firmware
+	 * tells us the Link is currently advertising.
+	 */
+	lc->requested_fec = FEC_AUTO;
+	lc->fec = fwcap_to_cc_fec(lc->def_acaps);
+
+	/* If the Port is capable of Auto-Negtotiation, initialize it as
+	 * "enabled" and copy over all of the Physical Port Capabilities
+	 * to the Advertised Port Capabilities.  Otherwise mark it as
+	 * Auto-Negotiate disabled and select the highest supported speed
+	 * for the link.  Note parallel structure in t4_link_l1cfg_core()
+	 * and t4_handle_get_port_info().
+	 */
+	if (lc->pcaps & FW_PORT_CAP32_ANEG) {
+		lc->acaps = lc->pcaps & ADVERT_MASK;
+		lc->autoneg = AUTONEG_ENABLE;
+		lc->requested_fc |= PAUSE_AUTONEG;
+	} else {
+		lc->acaps = 0;
+		lc->autoneg = AUTONEG_DISABLE;
+	}
+}
+
+static void csio_link_l1cfg(struct link_config *lc, uint16_t fw_caps,
+			    uint32_t *rcaps)
+{
+	unsigned int fw_mdi = FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO);
+	fw_port_cap32_t fw_fc, cc_fec, fw_fec, lrcap;
+
+	lc->link_ok = 0;
+
+	/*
+	 * Convert driver coding of Pause Frame Flow Control settings into the
+	 * Firmware's API.
+	 */
+	fw_fc = cc_to_fwcap_pause(lc->requested_fc);
+
+	/*
+	 * Convert Common Code Forward Error Control settings into the
+	 * Firmware's API.  If the current Requested FEC has "Automatic"
+	 * (IEEE 802.3) specified, then we use whatever the Firmware
+	 * sent us as part of it's IEEE 802.3-based interpratation of
+	 * the Transceiver Module EPROM FEC parameters.  Otherwise we
+	 * use whatever is in the current Requested FEC settings.
+	 */
+	if (lc->requested_fec & FEC_AUTO)
+		cc_fec = fwcap_to_cc_fec(lc->def_acaps);
+	else
+		cc_fec = lc->requested_fec;
+	fw_fec = cc_to_fwcap_fec(cc_fec);
+
+	/* Figure out what our Requested Port Capabilities are going to be.
+	 * Note parallel structure in t4_handle_get_port_info() and
+	 * init_link_config().
+	 */
+	if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
+		lrcap = (lc->pcaps & ADVERT_MASK) | fw_fc | fw_fec;
+		lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
+		lc->fec = cc_fec;
+	} else if (lc->autoneg == AUTONEG_DISABLE) {
+		lrcap = lc->speed_caps | fw_fc | fw_fec | fw_mdi;
+		lc->fc = lc->requested_fc & ~PAUSE_AUTONEG;
+		lc->fec = cc_fec;
+	} else {
+		lrcap = lc->acaps | fw_fc | fw_fec | fw_mdi;
+	}
+
+	*rcaps = lrcap;
+}
+
 /*
 /*
  * csio_enable_ports - Bring up all available ports.
  * csio_enable_ports - Bring up all available ports.
  * @hw: HW module.
  * @hw: HW module.
@@ -1418,8 +1647,10 @@ static int
 csio_enable_ports(struct csio_hw *hw)
 csio_enable_ports(struct csio_hw *hw)
 {
 {
 	struct csio_mb  *mbp;
 	struct csio_mb  *mbp;
+	u16 fw_caps = FW_CAPS_UNKNOWN;
 	enum fw_retval retval;
 	enum fw_retval retval;
 	uint8_t portid;
 	uint8_t portid;
+	fw_port_cap32_t pcaps, acaps, rcaps;
 	int i;
 	int i;
 
 
 	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
 	mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
@@ -1431,9 +1662,39 @@ csio_enable_ports(struct csio_hw *hw)
 	for (i = 0; i < hw->num_pports; i++) {
 	for (i = 0; i < hw->num_pports; i++) {
 		portid = hw->pport[i].portid;
 		portid = hw->pport[i].portid;
 
 
+		if (fw_caps == FW_CAPS_UNKNOWN) {
+			u32 param, val;
+
+			param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) |
+			 FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_PORT_CAPS32));
+			val = 1;
+
+			csio_mb_params(hw, mbp, CSIO_MB_DEFAULT_TMO,
+				       hw->pfn, 0, 1, &param, &val, false,
+				       NULL);
+
+			if (csio_mb_issue(hw, mbp)) {
+				csio_err(hw, "failed to issue FW_PARAMS_CMD(r) port:%d\n",
+					 portid);
+				mempool_free(mbp, hw->mb_mempool);
+				return -EINVAL;
+			}
+
+			csio_mb_process_read_params_rsp(hw, mbp, &retval, 1,
+							&val);
+			if (retval != FW_SUCCESS) {
+				csio_err(hw, "FW_PARAMS_CMD(r) port:%d failed: 0x%x\n",
+					 portid, retval);
+				mempool_free(mbp, hw->mb_mempool);
+				return -EINVAL;
+			}
+
+			fw_caps = val;
+		}
+
 		/* Read PORT information */
 		/* Read PORT information */
 		csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid,
 		csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid,
-			     false, 0, 0, NULL);
+			     false, 0, fw_caps, NULL);
 
 
 		if (csio_mb_issue(hw, mbp)) {
 		if (csio_mb_issue(hw, mbp)) {
 			csio_err(hw, "failed to issue FW_PORT_CMD(r) port:%d\n",
 			csio_err(hw, "failed to issue FW_PORT_CMD(r) port:%d\n",
@@ -1442,8 +1703,8 @@ csio_enable_ports(struct csio_hw *hw)
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 
 
-		csio_mb_process_read_port_rsp(hw, mbp, &retval,
-					      &hw->pport[i].pcap);
+		csio_mb_process_read_port_rsp(hw, mbp, &retval, fw_caps,
+					      &pcaps, &acaps);
 		if (retval != FW_SUCCESS) {
 		if (retval != FW_SUCCESS) {
 			csio_err(hw, "FW_PORT_CMD(r) port:%d failed: 0x%x\n",
 			csio_err(hw, "FW_PORT_CMD(r) port:%d failed: 0x%x\n",
 				 portid, retval);
 				 portid, retval);
@@ -1451,9 +1712,13 @@ csio_enable_ports(struct csio_hw *hw)
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 
 
+		csio_init_link_config(&hw->pport[i].link_cfg, pcaps, acaps);
+
+		csio_link_l1cfg(&hw->pport[i].link_cfg, fw_caps, &rcaps);
+
 		/* Write back PORT information */
 		/* Write back PORT information */
-		csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid, true,
-			     (PAUSE_RX | PAUSE_TX), hw->pport[i].pcap, NULL);
+		csio_mb_port(hw, mbp, CSIO_MB_DEFAULT_TMO, portid,
+			     true, rcaps, fw_caps, NULL);
 
 
 		if (csio_mb_issue(hw, mbp)) {
 		if (csio_mb_issue(hw, mbp)) {
 			csio_err(hw, "failed to issue FW_PORT_CMD(w) port:%d\n",
 			csio_err(hw, "failed to issue FW_PORT_CMD(w) port:%d\n",

+ 59 - 0
drivers/scsi/csiostor/csio_hw.h

@@ -268,8 +268,62 @@ struct csio_vpd {
 	uint8_t id[ID_LEN + 1];
 	uint8_t id[ID_LEN + 1];
 };
 };
 
 
+/* Firmware Port Capabilities types. */
+
+typedef u16 fw_port_cap16_t;    /* 16-bit Port Capabilities integral value */
+typedef u32 fw_port_cap32_t;    /* 32-bit Port Capabilities integral value */
+
+enum fw_caps {
+	FW_CAPS_UNKNOWN = 0,    /* 0'ed out initial state */
+	FW_CAPS16       = 1,    /* old Firmware: 16-bit Port Capabilities */
+	FW_CAPS32       = 2,    /* new Firmware: 32-bit Port Capabilities */
+};
+
+enum cc_pause {
+	PAUSE_RX      = 1 << 0,
+	PAUSE_TX      = 1 << 1,
+	PAUSE_AUTONEG = 1 << 2
+};
+
+enum cc_fec {
+	FEC_AUTO	= 1 << 0,  /* IEEE 802.3 "automatic" */
+	FEC_RS		= 1 << 1,  /* Reed-Solomon */
+	FEC_BASER_RS	= 1 << 2   /* BaseR/Reed-Solomon */
+};
+
+struct link_config {
+	fw_port_cap32_t pcaps;		/* link capabilities */
+	fw_port_cap32_t def_acaps;	/* default advertised capabilities */
+	fw_port_cap32_t acaps;		/* advertised capabilities */
+	fw_port_cap32_t lpacaps;	/* peer advertised capabilities */
+
+	fw_port_cap32_t speed_caps;	/* speed(s) user has requested */
+	unsigned int   speed;		/* actual link speed (Mb/s) */
+
+	enum cc_pause  requested_fc;	/* flow control user has requested */
+	enum cc_pause  fc;		/* actual link flow control */
+
+	enum cc_fec    requested_fec;	/* Forward Error Correction: */
+	enum cc_fec    fec;		/* requested and actual in use */
+
+	unsigned char  autoneg;		/* autonegotiating? */
+
+	unsigned char  link_ok;		/* link up? */
+	unsigned char  link_down_rc;	/* link down reason */
+};
+
+#define FW_LEN16(fw_struct) FW_CMD_LEN16_V(sizeof(fw_struct) / 16)
+
+#define ADVERT_MASK (FW_PORT_CAP32_SPEED_V(FW_PORT_CAP32_SPEED_M) | \
+		     FW_PORT_CAP32_ANEG)
+
+/* Enable or disable autonegotiation. */
+#define AUTONEG_DISABLE	0x00
+#define AUTONEG_ENABLE	0x01
+
 struct csio_pport {
 struct csio_pport {
 	uint16_t	pcap;
 	uint16_t	pcap;
+	uint16_t	acap;
 	uint8_t		portid;
 	uint8_t		portid;
 	uint8_t		link_status;
 	uint8_t		link_status;
 	uint16_t	link_speed;
 	uint16_t	link_speed;
@@ -278,6 +332,7 @@ struct csio_pport {
 	uint8_t		rsvd1;
 	uint8_t		rsvd1;
 	uint8_t		rsvd2;
 	uint8_t		rsvd2;
 	uint8_t		rsvd3;
 	uint8_t		rsvd3;
+	struct link_config link_cfg;
 };
 };
 
 
 /* fcoe resource information */
 /* fcoe resource information */
@@ -582,6 +637,10 @@ int csio_hw_slow_intr_handler(struct csio_hw *);
 int csio_handle_intr_status(struct csio_hw *, unsigned int,
 int csio_handle_intr_status(struct csio_hw *, unsigned int,
 			    const struct intr_info *);
 			    const struct intr_info *);
 
 
+fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps);
+fw_port_cap32_t fwcaps16_to_caps32(fw_port_cap16_t caps16);
+fw_port_cap32_t lstatus_to_fwcap(u32 lstatus);
+
 int csio_hw_start(struct csio_hw *);
 int csio_hw_start(struct csio_hw *);
 int csio_hw_stop(struct csio_hw *);
 int csio_hw_stop(struct csio_hw *);
 int csio_hw_reset(struct csio_hw *);
 int csio_hw_reset(struct csio_hw *);

+ 8 - 0
drivers/scsi/csiostor/csio_lnode.c

@@ -352,6 +352,14 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req)
 		val = htonl(FC_PORTSPEED_1GBIT);
 		val = htonl(FC_PORTSPEED_1GBIT);
 	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_10G)
 	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP_SPEED_10G)
 		val = htonl(FC_PORTSPEED_10GBIT);
 		val = htonl(FC_PORTSPEED_10GBIT);
+	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_25G)
+		val = htonl(FC_PORTSPEED_25GBIT);
+	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_40G)
+		val = htonl(FC_PORTSPEED_40GBIT);
+	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_50G)
+		val = htonl(FC_PORTSPEED_50GBIT);
+	else if (hw->pport[ln->portid].link_speed == FW_PORT_CAP32_SPEED_100G)
+		val = htonl(FC_PORTSPEED_100GBIT);
 	else
 	else
 		val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN);
 		val = htonl(CSIO_HBA_PORTSPEED_UNKNOWN);
 	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,
 	csio_append_attrib(&pld, FC_FDMI_PORT_ATTR_CURRENTPORTSPEED,

+ 42 - 28
drivers/scsi/csiostor/csio_mb.c

@@ -326,10 +326,6 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 		cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_TARGET);
 		cmdp->fcoecaps |= htons(FW_CAPS_CONFIG_FCOE_TARGET);
 }
 }
 
 
-#define CSIO_ADVERT_MASK     (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
-			      FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G |\
-			      FW_PORT_CAP_ANEG)
-
 /*
 /*
  * csio_mb_port- FW PORT command helper
  * csio_mb_port- FW PORT command helper
  * @hw: The HW structure
  * @hw: The HW structure
@@ -344,11 +340,10 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
  */
  */
 void
 void
 csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
-	     uint8_t portid, bool wr, uint32_t fc, uint16_t caps,
+	     u8 portid, bool wr, uint32_t fc, uint16_t fw_caps,
 	     void (*cbfn) (struct csio_hw *, struct csio_mb *))
 	     void (*cbfn) (struct csio_hw *, struct csio_mb *))
 {
 {
 	struct fw_port_cmd *cmdp = (struct fw_port_cmd *)(mbp->mb);
 	struct fw_port_cmd *cmdp = (struct fw_port_cmd *)(mbp->mb);
-	unsigned int lfc = 0, mdi = FW_PORT_CAP_MDI_V(FW_PORT_CAP_MDI_AUTO);
 
 
 	CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn,  1);
 	CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn,  1);
 
 
@@ -358,26 +353,24 @@ csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 				   FW_PORT_CMD_PORTID_V(portid));
 				   FW_PORT_CMD_PORTID_V(portid));
 	if (!wr) {
 	if (!wr) {
 		cmdp->action_to_len16 = htonl(
 		cmdp->action_to_len16 = htonl(
-			FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) |
+			FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
+			? FW_PORT_ACTION_GET_PORT_INFO
+			: FW_PORT_ACTION_GET_PORT_INFO32) |
 			FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 			FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 		return;
 		return;
 	}
 	}
 
 
 	/* Set port */
 	/* Set port */
 	cmdp->action_to_len16 = htonl(
 	cmdp->action_to_len16 = htonl(
-			FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_L1_CFG) |
+			FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
+			? FW_PORT_ACTION_L1_CFG
+			: FW_PORT_ACTION_L1_CFG32) |
 			FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 			FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
 
-	if (fc & PAUSE_RX)
-		lfc |= FW_PORT_CAP_FC_RX;
-	if (fc & PAUSE_TX)
-		lfc |= FW_PORT_CAP_FC_TX;
-
-	if (!(caps & FW_PORT_CAP_ANEG))
-		cmdp->u.l1cfg.rcap = htonl((caps & CSIO_ADVERT_MASK) | lfc);
+	if (fw_caps == FW_CAPS16)
+		cmdp->u.l1cfg.rcap = cpu_to_be32(fc);
 	else
 	else
-		cmdp->u.l1cfg.rcap = htonl((caps & CSIO_ADVERT_MASK) |
-								lfc | mdi);
+		cmdp->u.l1cfg32.rcap32 = cpu_to_be32(fc);
 }
 }
 
 
 /*
 /*
@@ -390,14 +383,22 @@ csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
  */
  */
 void
 void
 csio_mb_process_read_port_rsp(struct csio_hw *hw, struct csio_mb *mbp,
 csio_mb_process_read_port_rsp(struct csio_hw *hw, struct csio_mb *mbp,
-			 enum fw_retval *retval, uint16_t *caps)
+			 enum fw_retval *retval, uint16_t fw_caps,
+			 u32 *pcaps, u32 *acaps)
 {
 {
 	struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb);
 	struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb);
 
 
 	*retval = FW_CMD_RETVAL_G(ntohl(rsp->action_to_len16));
 	*retval = FW_CMD_RETVAL_G(ntohl(rsp->action_to_len16));
 
 
-	if (*retval == FW_SUCCESS)
-		*caps = ntohs(rsp->u.info.pcap);
+	if (*retval == FW_SUCCESS) {
+		if (fw_caps == FW_CAPS16) {
+			*pcaps = fwcaps16_to_caps32(ntohs(rsp->u.info.pcap));
+			*acaps = fwcaps16_to_caps32(ntohs(rsp->u.info.acap));
+		} else {
+			*pcaps = ntohs(rsp->u.info32.pcaps32);
+			*acaps = ntohs(rsp->u.info32.acaps32);
+		}
+	}
 }
 }
 
 
 /*
 /*
@@ -1409,6 +1410,7 @@ csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd)
 	uint32_t link_status;
 	uint32_t link_status;
 	uint16_t action;
 	uint16_t action;
 	uint8_t mod_type;
 	uint8_t mod_type;
+	fw_port_cap32_t linkattr;
 
 
 	if (opcode == FW_PORT_CMD) {
 	if (opcode == FW_PORT_CMD) {
 		pcmd = (struct fw_port_cmd *)cmd;
 		pcmd = (struct fw_port_cmd *)cmd;
@@ -1416,22 +1418,34 @@ csio_mb_fwevt_handler(struct csio_hw *hw, __be64 *cmd)
 				ntohl(pcmd->op_to_portid));
 				ntohl(pcmd->op_to_portid));
 		action = FW_PORT_CMD_ACTION_G(
 		action = FW_PORT_CMD_ACTION_G(
 				ntohl(pcmd->action_to_len16));
 				ntohl(pcmd->action_to_len16));
-		if (action != FW_PORT_ACTION_GET_PORT_INFO) {
+		if (action != FW_PORT_ACTION_GET_PORT_INFO &&
+		    action != FW_PORT_ACTION_GET_PORT_INFO32) {
 			csio_err(hw, "Unhandled FW_PORT_CMD action: %u\n",
 			csio_err(hw, "Unhandled FW_PORT_CMD action: %u\n",
 				action);
 				action);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 
 
-		link_status = ntohl(pcmd->u.info.lstatus_to_modtype);
-		mod_type = FW_PORT_CMD_MODTYPE_G(link_status);
+		if (action == FW_PORT_ACTION_GET_PORT_INFO) {
+			link_status = ntohl(pcmd->u.info.lstatus_to_modtype);
+			mod_type = FW_PORT_CMD_MODTYPE_G(link_status);
+			linkattr = lstatus_to_fwcap(link_status);
+
+			hw->pport[port_id].link_status =
+				FW_PORT_CMD_LSTATUS_G(link_status);
+		} else {
+			link_status =
+				ntohl(pcmd->u.info32.lstatus32_to_cbllen32);
+			mod_type = FW_PORT_CMD_MODTYPE32_G(link_status);
+			linkattr = ntohl(pcmd->u.info32.linkattr32);
+
+			hw->pport[port_id].link_status =
+				FW_PORT_CMD_LSTATUS32_G(link_status);
+		}
 
 
-		hw->pport[port_id].link_status =
-			FW_PORT_CMD_LSTATUS_G(link_status);
-		hw->pport[port_id].link_speed =
-			FW_PORT_CMD_LSPEED_G(link_status);
+		hw->pport[port_id].link_speed = fwcap_to_fwspeed(linkattr);
 
 
 		csio_info(hw, "Port:%x - LINK %s\n", port_id,
 		csio_info(hw, "Port:%x - LINK %s\n", port_id,
-			FW_PORT_CMD_LSTATUS_G(link_status) ? "UP" : "DOWN");
+			hw->pport[port_id].link_status ? "UP" : "DOWN");
 
 
 		if (mod_type != hw->pport[port_id].mod_type) {
 		if (mod_type != hw->pport[port_id].mod_type) {
 			hw->pport[port_id].mod_type = mod_type;
 			hw->pport[port_id].mod_type = mod_type;

+ 2 - 7
drivers/scsi/csiostor/csio_mb.h

@@ -88,12 +88,6 @@ enum csio_dev_state {
 	 FW_PARAMS_PARAM_Y_V(0) | \
 	 FW_PARAMS_PARAM_Y_V(0) | \
 	 FW_PARAMS_PARAM_Z_V(0))
 	 FW_PARAMS_PARAM_Z_V(0))
 
 
-enum {
-	PAUSE_RX      = 1 << 0,
-	PAUSE_TX      = 1 << 1,
-	PAUSE_AUTONEG = 1 << 2
-};
-
 #define CSIO_INIT_MBP(__mbp, __cp,  __tmo, __priv, __fn, __clear)	\
 #define CSIO_INIT_MBP(__mbp, __cp,  __tmo, __priv, __fn, __clear)	\
 do {									\
 do {									\
 	if (__clear)							\
 	if (__clear)							\
@@ -189,7 +183,8 @@ void csio_mb_port(struct csio_hw *, struct csio_mb *, uint32_t,
 		  void (*) (struct csio_hw *, struct csio_mb *));
 		  void (*) (struct csio_hw *, struct csio_mb *));
 
 
 void csio_mb_process_read_port_rsp(struct csio_hw *, struct csio_mb *,
 void csio_mb_process_read_port_rsp(struct csio_hw *, struct csio_mb *,
-				   enum fw_retval *, uint16_t *);
+				   enum fw_retval *, uint16_t,
+				   uint32_t *, uint32_t *);
 
 
 void csio_mb_initialize(struct csio_hw *, struct csio_mb *, uint32_t,
 void csio_mb_initialize(struct csio_hw *, struct csio_mb *, uint32_t,
 			void (*)(struct csio_hw *, struct csio_mb *));
 			void (*)(struct csio_hw *, struct csio_mb *));

+ 5 - 5
drivers/scsi/device_handler/scsi_dh_alua.c

@@ -138,12 +138,12 @@ static void release_port_group(struct kref *kref)
 static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
 static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
 		       int bufflen, struct scsi_sense_hdr *sshdr, int flags)
 		       int bufflen, struct scsi_sense_hdr *sshdr, int flags)
 {
 {
-	u8 cdb[COMMAND_SIZE(MAINTENANCE_IN)];
+	u8 cdb[MAX_COMMAND_SIZE];
 	int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
 	int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
 		REQ_FAILFAST_DRIVER;
 		REQ_FAILFAST_DRIVER;
 
 
 	/* Prepare the command. */
 	/* Prepare the command. */
-	memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_IN));
+	memset(cdb, 0x0, MAX_COMMAND_SIZE);
 	cdb[0] = MAINTENANCE_IN;
 	cdb[0] = MAINTENANCE_IN;
 	if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
 	if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
 		cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
 		cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
@@ -166,7 +166,7 @@ static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
 static int submit_stpg(struct scsi_device *sdev, int group_id,
 static int submit_stpg(struct scsi_device *sdev, int group_id,
 		       struct scsi_sense_hdr *sshdr)
 		       struct scsi_sense_hdr *sshdr)
 {
 {
-	u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)];
+	u8 cdb[MAX_COMMAND_SIZE];
 	unsigned char stpg_data[8];
 	unsigned char stpg_data[8];
 	int stpg_len = 8;
 	int stpg_len = 8;
 	int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
 	int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
@@ -178,7 +178,7 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
 	put_unaligned_be16(group_id, &stpg_data[6]);
 	put_unaligned_be16(group_id, &stpg_data[6]);
 
 
 	/* Prepare the command. */
 	/* Prepare the command. */
-	memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_OUT));
+	memset(cdb, 0x0, MAX_COMMAND_SIZE);
 	cdb[0] = MAINTENANCE_OUT;
 	cdb[0] = MAINTENANCE_OUT;
 	cdb[1] = MO_SET_TARGET_PGS;
 	cdb[1] = MO_SET_TARGET_PGS;
 	put_unaligned_be32(stpg_len, &cdb[6]);
 	put_unaligned_be32(stpg_len, &cdb[6]);
@@ -214,8 +214,8 @@ static struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size,
 /*
 /*
  * alua_alloc_pg - Allocate a new port_group structure
  * alua_alloc_pg - Allocate a new port_group structure
  * @sdev: scsi device
  * @sdev: scsi device
- * @h: alua device_handler data
  * @group_id: port group id
  * @group_id: port group id
+ * @tpgs: target port group settings
  *
  *
  * Allocate a new port_group structure for a given
  * Allocate a new port_group structure for a given
  * device.
  * device.

+ 1 - 1
drivers/scsi/device_handler/scsi_dh_emc.c

@@ -249,7 +249,7 @@ static int send_trespass_cmd(struct scsi_device *sdev,
 			    struct clariion_dh_data *csdev)
 			    struct clariion_dh_data *csdev)
 {
 {
 	unsigned char *page22;
 	unsigned char *page22;
-	unsigned char cdb[COMMAND_SIZE(MODE_SELECT)];
+	unsigned char cdb[MAX_COMMAND_SIZE];
 	int err, res = SCSI_DH_OK, len;
 	int err, res = SCSI_DH_OK, len;
 	struct scsi_sense_hdr sshdr;
 	struct scsi_sense_hdr sshdr;
 	u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
 	u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |

+ 1 - 1
drivers/scsi/device_handler/scsi_dh_rdac.c

@@ -533,7 +533,7 @@ static void send_mode_select(struct work_struct *work)
 	int err = SCSI_DH_OK, retry_cnt = RDAC_RETRY_COUNT;
 	int err = SCSI_DH_OK, retry_cnt = RDAC_RETRY_COUNT;
 	struct rdac_queue_data *tmp, *qdata;
 	struct rdac_queue_data *tmp, *qdata;
 	LIST_HEAD(list);
 	LIST_HEAD(list);
-	unsigned char cdb[COMMAND_SIZE(MODE_SELECT_10)];
+	unsigned char cdb[MAX_COMMAND_SIZE];
 	struct scsi_sense_hdr sshdr;
 	struct scsi_sense_hdr sshdr;
 	unsigned int data_size;
 	unsigned int data_size;
 	u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
 	u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |

+ 12 - 15
drivers/scsi/dpt_i2o.c

@@ -302,16 +302,14 @@ rebuild_sys_tab:
 }
 }
 
 
 
 
-/*
- * scsi_unregister will be called AFTER we return.
- */
-static int adpt_release(struct Scsi_Host *host)
+static void adpt_release(adpt_hba *pHba)
 {
 {
-	adpt_hba* pHba = (adpt_hba*) host->hostdata[0];
+	struct Scsi_Host *shost = pHba->host;
+
+	scsi_remove_host(shost);
 //	adpt_i2o_quiesce_hba(pHba);
 //	adpt_i2o_quiesce_hba(pHba);
 	adpt_i2o_delete_hba(pHba);
 	adpt_i2o_delete_hba(pHba);
-	scsi_unregister(host);
-	return 0;
+	scsi_host_put(shost);
 }
 }
 
 
 
 
@@ -801,14 +799,17 @@ static int __adpt_reset(struct scsi_cmnd* cmd)
 {
 {
 	adpt_hba* pHba;
 	adpt_hba* pHba;
 	int rcode;
 	int rcode;
+	char name[32];
+
 	pHba = (adpt_hba*)cmd->device->host->hostdata[0];
 	pHba = (adpt_hba*)cmd->device->host->hostdata[0];
-	printk(KERN_WARNING"%s: Hba Reset: scsi id %d: tid: %d\n",pHba->name,cmd->device->channel,pHba->channel[cmd->device->channel].tid );
+	strncpy(name, pHba->name, sizeof(name));
+	printk(KERN_WARNING"%s: Hba Reset: scsi id %d: tid: %d\n", name, cmd->device->channel, pHba->channel[cmd->device->channel].tid);
 	rcode =  adpt_hba_reset(pHba);
 	rcode =  adpt_hba_reset(pHba);
 	if(rcode == 0){
 	if(rcode == 0){
-		printk(KERN_WARNING"%s: HBA reset complete\n",pHba->name);
+		printk(KERN_WARNING"%s: HBA reset complete\n", name);
 		return SUCCESS;
 		return SUCCESS;
 	} else {
 	} else {
-		printk(KERN_WARNING"%s: HBA reset failed (%x)\n",pHba->name, rcode);
+		printk(KERN_WARNING"%s: HBA reset failed (%x)\n", name, rcode);
 		return FAILED;
 		return FAILED;
 	}
 	}
 }
 }
@@ -1087,8 +1088,6 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
 
 
 
 
 	mutex_lock(&adpt_configuration_lock);
 	mutex_lock(&adpt_configuration_lock);
-	// scsi_unregister calls our adpt_release which
-	// does a quiese
 	if(pHba->host){
 	if(pHba->host){
 		free_irq(pHba->host->irq, pHba);
 		free_irq(pHba->host->irq, pHba);
 	}
 	}
@@ -3595,11 +3594,9 @@ static void __exit adpt_exit(void)
 {
 {
 	adpt_hba	*pHba, *next;
 	adpt_hba	*pHba, *next;
 
 
-	for (pHba = hba_chain; pHba; pHba = pHba->next)
-		scsi_remove_host(pHba->host);
 	for (pHba = hba_chain; pHba; pHba = next) {
 	for (pHba = hba_chain; pHba; pHba = next) {
 		next = pHba->next;
 		next = pHba->next;
-		adpt_release(pHba->host);
+		adpt_release(pHba);
 	}
 	}
 }
 }
 
 

+ 0 - 1
drivers/scsi/dpti.h

@@ -32,7 +32,6 @@ static int adpt_detect(struct scsi_host_template * sht);
 static int adpt_queue(struct Scsi_Host *h, struct scsi_cmnd * cmd);
 static int adpt_queue(struct Scsi_Host *h, struct scsi_cmnd * cmd);
 static int adpt_abort(struct scsi_cmnd * cmd);
 static int adpt_abort(struct scsi_cmnd * cmd);
 static int adpt_reset(struct scsi_cmnd* cmd);
 static int adpt_reset(struct scsi_cmnd* cmd);
-static int adpt_release(struct Scsi_Host *host);
 static int adpt_slave_configure(struct scsi_device *);
 static int adpt_slave_configure(struct scsi_device *);
 
 
 static const char *adpt_info(struct Scsi_Host *pSHost);
 static const char *adpt_info(struct Scsi_Host *pSHost);

+ 0 - 2571
drivers/scsi/eata.c

@@ -1,2571 +0,0 @@
-/*
- *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
- *
- *      03 Jun 2003 Rev. 8.10 for linux-2.5.70
- *        + Update for new IRQ API.
- *        + Use "goto" when appropriate.
- *        + Drop eata.h.
- *        + Update for new module_param API.
- *        + Module parameters  can now be specified only in the
- *          same format as the kernel boot options.
- *
- *             boot option    old module param 
- *             -----------    ------------------
- *             addr,...       io_port=addr,...
- *             lc:[y|n]       linked_comm=[1|0]
- *             mq:xx          max_queue_depth=xx
- *             tm:[0|1|2]     tag_mode=[0|1|2]
- *             et:[y|n]       ext_tran=[1|0]
- *             rs:[y|n]       rev_scan=[1|0]
- *             ip:[y|n]       isa_probe=[1|0]
- *             ep:[y|n]       eisa_probe=[1|0]
- *             pp:[y|n]       pci_probe=[1|0]
- *
- *          A valid example using the new parameter format is:
- *          modprobe eata "eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n"
- *
- *          which is equivalent to the old format:
- *          modprobe eata io_port=0x7410,0x230 linked_comm=1 tag_mode=0 \
- *                        max_queue_depth=4 eisa_probe=0
- *
- *      12 Feb 2003 Rev. 8.04 for linux 2.5.60
- *        + Release irq before calling scsi_register.
- *
- *      12 Nov 2002 Rev. 8.02 for linux 2.5.47
- *        + Release driver_lock before calling scsi_register.
- *
- *      11 Nov 2002 Rev. 8.01 for linux 2.5.47
- *        + Fixed bios_param and scsicam_bios_param calling parameters.
- *
- *      28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4
- *        + Use new tcq and adjust_queue_depth api.
- *        + New command line option (tm:[0-2]) to choose the type of tags:
- *          0 -> disable tagging ; 1 -> simple tags  ; 2 -> ordered tags.
- *          Default is tm:0 (tagged commands disabled).
- *          For compatibility the "tc:" option is an alias of the "tm:"
- *          option; tc:n is equivalent to tm:0 and tc:y is equivalent to
- *          tm:1.
- *        + The tagged_comm module parameter has been removed, use tag_mode
- *          instead, equivalent to the "tm:" boot option.
- *
- *      10 Oct 2002 Rev. 7.70 for linux 2.5.42
- *        + Foreport from revision 6.70.
- *
- *      25 Jun 2002 Rev. 6.70 for linux 2.4.19
- *        + This release is the first one tested on a Big Endian platform:
- *          fixed endian-ness problem due to bitfields;
- *          fixed endian-ness problem in read_pio.
- *        + Added new options for selectively probing ISA, EISA and PCI bus:
- *
- *          Boot option   Parameter name    Default according to
- *
- *          ip:[y|n]      isa_probe=[1|0]   CONFIG_ISA  defined
- *          ep:[y|n]      eisa_probe=[1|0]  CONFIG_EISA defined
- *          pp:[y|n]      pci_probe=[1|0]   CONFIG_PCI  defined
- *
- *          The default action is to perform probing if the corresponding
- *          bus is configured and to skip probing otherwise.
- *
- *        + If pci_probe is in effect and a list of I/O  ports is specified
- *          as parameter or boot option, pci_enable_device() is performed
- *          on all pci devices matching PCI_CLASS_STORAGE_SCSI.
- *
- *      21 Feb 2002 Rev. 6.52 for linux 2.4.18
- *        + Backport from rev. 7.22 (use io_request_lock).
- *
- *      20 Feb 2002 Rev. 7.22 for linux 2.5.5
- *        + Remove any reference to virt_to_bus().
- *        + Fix pio hang while detecting multiple HBAs.
- *        + Fixed a board detection bug: in a system with
- *          multiple ISA/EISA boards, all but the first one
- *          were erroneously detected as PCI.
- *
- *      01 Jan 2002 Rev. 7.20 for linux 2.5.1
- *        + Use the dynamic DMA mapping API.
- *
- *      19 Dec 2001 Rev. 7.02 for linux 2.5.1
- *        + Use SCpnt->sc_data_direction if set.
- *        + Use sglist.page instead of sglist.address.
- *
- *      11 Dec 2001 Rev. 7.00 for linux 2.5.1
- *        + Use host->host_lock instead of io_request_lock.
- *
- *       1 May 2001 Rev. 6.05 for linux 2.4.4
- *        + Clean up all pci related routines.
- *        + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
- *
- *      30 Jan 2001 Rev. 6.04 for linux 2.4.1
- *        + Call pci_resource_start after pci_enable_device.
- *
- *      25 Jan 2001 Rev. 6.03 for linux 2.4.0
- *        + "check_region" call replaced by "request_region".
- *
- *      22 Nov 2000 Rev. 6.02 for linux 2.4.0-test11
- *        + Return code checked when calling pci_enable_device.
- *        + Removed old scsi error handling support.
- *        + The obsolete boot option flag eh:n is silently ignored.
- *        + Removed error messages while a disk drive is powered up at
- *          boot time.
- *        + Improved boot messages: all tagged capable device are
- *          indicated as "tagged" or "soft-tagged" :
- *          - "soft-tagged"  means that the driver is trying to do its
- *            own tagging (i.e. the tc:y option is in effect);
- *          - "tagged" means that the device supports tagged commands,
- *            but the driver lets the HBA be responsible for tagging
- *            support.
- *
- *      16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18
- *        + Updated to the new __setup interface for boot command line options.
- *        + When loaded as a module, accepts the new parameter boot_options
- *          which value is a string with the same format of the kernel boot
- *          command line options. A valid example is:
- *          modprobe eata 'boot_options="0x7410,0x230,lc:y,tc:n,mq:4"'
- *
- *       9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17
- *        + 64bit cleanup for Linux/Alpha platform support
- *          (contribution from H.J. Lu).
- *
- *      22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11
- *        + Removed pre-2.2 source code compatibility.
- *        + Added call to pci_set_master.
- *
- *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
- *        + Added command line option (rs:[y|n]) to reverse the scan order
- *          of PCI boards. The default is rs:y, which reverses the BIOS order
- *          while registering PCI boards. The default value rs:y generates
- *          the same order of all previous revisions of this driver.
- *          Pls. note that "BIOS order" might have been reversed itself
- *          after the 2.1.9x PCI modifications in the linux kernel.
- *          The rs value is ignored when the explicit list of addresses
- *          is used by the "eata=port0,port1,..." command line option.
- *        + Added command line option (et:[y|n]) to force use of extended
- *          translation (255 heads, 63 sectors) as disk geometry.
- *          The default is et:n, which uses the disk geometry returned
- *          by scsicam_bios_param. The default value et:n is compatible with
- *          all previous revisions of this driver.
- *
- *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
- *          Increased busy timeout from 10 msec. to 200 msec. while
- *          processing interrupts.
- *
- *      16 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
- *          Improved abort handling during the eh recovery process.
- *
- *      13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101
- *          The driver is now fully SMP safe, including the
- *          abort and reset routines.
- *          Added command line options (eh:[y|n]) to choose between
- *          new_eh_code and the old scsi code.
- *          If linux version >= 2.1.101 the default is eh:y, while the eh
- *          option is ignored for previous releases and the old scsi code
- *          is used.
- *
- *      18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
- *          Reworked interrupt handler.
- *
- *      11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
- *          Major reliability improvement: when a batch with overlapping
- *          requests is detected, requests are queued one at a time
- *          eliminating any possible board or drive reordering.
- *
- *      10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
- *          Improved SMP support (if linux version >= 2.1.95).
- *
- *       9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
- *          Added support for new PCI code and IO-APIC remapping of irqs.
- *          Performance improvement: when sequential i/o is detected,
- *          always use direct sort instead of reverse sort.
- *
- *       4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
- *          io_port is now unsigned long.
- *
- *      17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88
- *          Use new scsi error handling code (if linux version >= 2.1.88).
- *          Use new interrupt code.
- *
- *      12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
- *          Use of udelay inside the wait loops to avoid timeout
- *          problems with fast cpus.
- *          Removed check about useless calls to the interrupt service
- *          routine (reported on SMP systems only).
- *          At initialization time "sorted/unsorted" is displayed instead
- *          of "linked/unlinked" to reinforce the fact that "linking" is
- *          nothing but "elevator sorting" in the actual implementation.
- *
- *      17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
- *          Use of serial_number_at_timeout in abort and reset processing.
- *          Use of the __initfunc and __initdata macro in setup code.
- *          Minor cleanups in the list_statistics code.
- *          Increased controller busy timeout in order to better support
- *          slow SCSI devices.
- *
- *      24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
- *          When loading as a module, parameter passing is now supported
- *          both in 2.0 and in 2.1 style.
- *          Fixed data transfer direction for some SCSI opcodes.
- *          Immediate acknowledge to request sense commands.
- *          Linked commands to each disk device are now reordered by elevator
- *          sorting. Rare cases in which reordering of write requests could
- *          cause wrong results are managed.
- *          Fixed spurious timeouts caused by long simple queue tag sequences.
- *          New command line option (tm:[0-3]) to choose the type of tags:
- *          0 -> mixed (default); 1 -> simple; 2 -> head; 3 -> ordered.
- *
- *      18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28
- *          Added command line options to enable/disable linked commands
- *          (lc:[y|n]), tagged commands (tc:[y|n]) and to set the max queue
- *          depth (mq:xx). Default is "eata=lc:n,tc:n,mq:16".
- *          Improved command linking.
- *          Documented how to setup RAID-0 with DPT SmartRAID boards.
- *
- *       8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27
- *          Added linked command support.
- *          Improved detection of PCI boards using ISA base addresses.
- *
- *       3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27
- *          Added support for tagged commands and queue depth adjustment.
- *
- *      22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26
- *          When CONFIG_PCI is defined, BIOS32 is used to include in the
- *          list of i/o ports to be probed all the PCI SCSI controllers.
- *          The list of i/o ports to be probed can be overwritten by the
- *          "eata=port0,port1,...." boot command line option.
- *          Scatter/gather lists are now allocated by a number of kmalloc
- *          calls, in order to avoid the previous size limit of 64Kb.
- *
- *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
- *          Added support for EATA 2.0C, PCI, multichannel and wide SCSI.
- *
- *      27 Sep 1996 rev. 2.12 for linux 2.1.0
- *          Portability cleanups (virtual/bus addressing, little/big endian
- *          support).
- *
- *      09 Jul 1996 rev. 2.11 for linux 2.0.4
- *          Number of internal retries is now limited.
- *
- *      16 Apr 1996 rev. 2.10 for linux 1.3.90
- *          New argument "reset_flags" to the reset routine.
- *
- *       6 Jul 1995 rev. 2.01 for linux 1.3.7
- *          Update required by the new /proc/scsi support.
- *
- *      11 Mar 1995 rev. 2.00 for linux 1.2.0
- *          Fixed a bug which prevented media change detection for removable
- *          disk drives.
- *
- *      23 Feb 1995 rev. 1.18 for linux 1.1.94
- *          Added a check for scsi_register returning NULL.
- *
- *      11 Feb 1995 rev. 1.17 for linux 1.1.91
- *          Now DEBUG_RESET is disabled by default.
- *          Register a board even if it does not assert DMA protocol support
- *          (DPT SK2011B does not report correctly the dmasup bit).
- *
- *       9 Feb 1995 rev. 1.16 for linux 1.1.90
- *          Use host->wish_block instead of host->block.
- *          New list of Data Out SCSI commands.
- *
- *       8 Feb 1995 rev. 1.15 for linux 1.1.89
- *          Cleared target_time_out counter while performing a reset.
- *          All external symbols renamed to avoid possible name conflicts.
- *
- *      28 Jan 1995 rev. 1.14 for linux 1.1.86
- *          Added module support.
- *          Log and do a retry when a disk drive returns a target status
- *          different from zero on a recovered error.
- *
- *      24 Jan 1995 rev. 1.13 for linux 1.1.85
- *          Use optimized board configuration, with a measured performance
- *          increase in the range 10%-20% on i/o throughput.
- *
- *      16 Jan 1995 rev. 1.12 for linux 1.1.81
- *          Fix mscp structure comments (no functional change).
- *          Display a message if check_region detects a port address
- *          already in use.
- *
- *      17 Dec 1994 rev. 1.11 for linux 1.1.74
- *          Use the scsicam_bios_param routine. This allows an easy
- *          migration path from disk partition tables created using
- *          different SCSI drivers and non optimal disk geometry.
- *
- *      15 Dec 1994 rev. 1.10 for linux 1.1.74
- *          Added support for ISA EATA boards (DPT PM2011, DPT PM2021).
- *          The host->block flag is set for all the detected ISA boards.
- *          The detect routine no longer enforces LEVEL triggering
- *          for EISA boards, it just prints a warning message.
- *
- *      30 Nov 1994 rev. 1.09 for linux 1.1.68
- *          Redo i/o on target status CHECK_CONDITION for TYPE_DISK only.
- *          Added optional support for using a single board at a time.
- *
- *      18 Nov 1994 rev. 1.08 for linux 1.1.64
- *          Forces sg_tablesize = 64 and can_queue = 64 if these
- *          values are not correctly detected (DPT PM2012).
- *
- *      14 Nov 1994 rev. 1.07 for linux 1.1.63  Final BETA release.
- *      04 Aug 1994 rev. 1.00 for linux 1.1.39  First BETA release.
- *
- *
- *          This driver is based on the CAM (Common Access Method Committee)
- *          EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
- *
- *  Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com)
- *
- *  Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that redistributions of source
- *  code retain the above copyright notice and this comment without
- *  modification.
- *
- */
-
-/*
- *
- *  Here is a brief description of the DPT SCSI host adapters.
- *  All these boards provide an EATA/DMA compatible programming interface
- *  and are fully supported by this driver in any configuration, including
- *  multiple SCSI channels:
- *
- *  PM2011B/9X -  Entry Level ISA
- *  PM2021A/9X -  High Performance ISA
- *  PM2012A       Old EISA
- *  PM2012B       Old EISA
- *  PM2022A/9X -  Entry Level EISA
- *  PM2122A/9X -  High Performance EISA
- *  PM2322A/9X -  Extra High Performance EISA
- *  PM3021     -  SmartRAID Adapter for ISA
- *  PM3222     -  SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI)
- *  PM3224     -  SmartRAID Adapter for PCI  (PM3224W is 16-bit wide SCSI)
- *  PM33340UW  -  SmartRAID Adapter for PCI  ultra wide multichannel
- *
- *  The above list is just an indication: as a matter of fact all DPT
- *  boards using the EATA/DMA protocol are supported by this driver,
- *  since they use exactely the same programming interface.
- *
- *  The DPT PM2001 provides only the EATA/PIO interface and hence is not
- *  supported by this driver.
- *
- *  This code has been tested with up to 3 Distributed Processing Technology
- *  PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers,
- *  in any combination of private and shared IRQ.
- *  PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS
- *  v003.D0, firmware v07G.0).
- *
- *  DPT SmartRAID boards support "Hardware Array" - a group of disk drives
- *  which are all members of the same RAID-0, RAID-1 or RAID-5 array implemented
- *  in host adapter hardware. Hardware Arrays are fully compatible with this
- *  driver, since they look to it as a single disk drive.
- *
- *  WARNING: to create a RAID-0 "Hardware Array" you must select "Other Unix"
- *  as the current OS in the DPTMGR "Initial System Installation" menu.
- *  Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0),
- *  which is not supported by the actual SCSI subsystem.
- *  To get the "Array Group" functionality, the Linux MD driver must be used
- *  instead of the DPT "Array Group" feature.
- *
- *  Multiple ISA, EISA and PCI boards can be configured in the same system.
- *  It is suggested to put all the EISA boards on the same IRQ level, all
- *  the PCI  boards on another IRQ level, while ISA boards cannot share
- *  interrupts.
- *
- *  If you configure multiple boards on the same IRQ, the interrupt must
- *  be _level_ triggered (not _edge_ triggered).
- *
- *  This driver detects EATA boards by probes at fixed port addresses,
- *  so no BIOS32 or PCI BIOS support is required.
- *  The suggested way to detect a generic EATA PCI board is to force on it
- *  any unused EISA address, even if there are other controllers on the EISA
- *  bus, or even if you system has no EISA bus at all.
- *  Do not force any ISA address on EATA PCI boards.
- *
- *  If PCI bios support is configured into the kernel, BIOS32 is used to
- *  include in the list of i/o ports to be probed all the PCI SCSI controllers.
- *
- *  Due to a DPT BIOS "feature", it might not be possible to force an EISA
- *  address on more than a single DPT PCI board, so in this case you have to
- *  let the PCI BIOS assign the addresses.
- *
- *  The sequence of detection probes is:
- *
- *  - ISA 0x1F0;
- *  - PCI SCSI controllers (only if BIOS32 is available);
- *  - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15);
- *  - ISA  0x170, 0x230, 0x330.
- *
- *  The above list of detection probes can be totally replaced by the
- *  boot command line option: "eata=port0,port1,port2,...", where the
- *  port0, port1... arguments are ISA/EISA/PCI addresses to be probed.
- *  For example using "eata=0x7410,0x7450,0x230", the driver probes
- *  only the two PCI addresses 0x7410 and 0x7450 and the ISA address 0x230,
- *  in this order; "eata=0" totally disables this driver.
- *
- *  After the optional list of detection probes, other possible command line
- *  options are:
- *
- *  et:y  force use of extended translation (255 heads, 63 sectors);
- *  et:n  use disk geometry detected by scsicam_bios_param;
- *  rs:y  reverse scan order while detecting PCI boards;
- *  rs:n  use BIOS order while detecting PCI boards;
- *  lc:y  enables linked commands;
- *  lc:n  disables linked commands;
- *  tm:0  disables tagged commands (same as tc:n);
- *  tm:1  use simple queue tags (same as tc:y);
- *  tm:2  use ordered queue tags (same as tc:2);
- *  mq:xx set the max queue depth to the value xx (2 <= xx <= 32).
- *
- *  The default value is: "eata=lc:n,mq:16,tm:0,et:n,rs:n".
- *  An example using the list of detection probes could be:
- *  "eata=0x7410,0x230,lc:y,tm:2,mq:4,et:n".
- *
- *  When loading as a module, parameters can be specified as well.
- *  The above example would be (use 1 in place of y and 0 in place of n):
- *
- *  modprobe eata io_port=0x7410,0x230 linked_comm=1 \
- *                max_queue_depth=4 ext_tran=0 tag_mode=2 \
- *                rev_scan=1
- *
- *  ----------------------------------------------------------------------------
- *  In this implementation, linked commands are designed to work with any DISK
- *  or CD-ROM, since this linking has only the intent of clustering (time-wise)
- *  and reordering by elevator sorting commands directed to each device,
- *  without any relation with the actual SCSI protocol between the controller
- *  and the device.
- *  If Q is the queue depth reported at boot time for each device (also named
- *  cmds/lun) and Q > 2, whenever there is already an active command to the
- *  device all other commands to the same device  (up to Q-1) are kept waiting
- *  in the elevator sorting queue. When the active command completes, the
- *  commands in this queue are sorted by sector address. The sort is chosen
- *  between increasing or decreasing by minimizing the seek distance between
- *  the sector of the commands just completed and the sector of the first
- *  command in the list to be sorted.
- *  Trivial math assures that the unsorted average seek distance when doing
- *  random seeks over S sectors is S/3.
- *  When (Q-1) requests are uniformly distributed over S sectors, the average
- *  distance between two adjacent requests is S/((Q-1) + 1), so the sorted
- *  average seek distance for (Q-1) random requests over S sectors is S/Q.
- *  The elevator sorting hence divides the seek distance by a factor Q/3.
- *  The above pure geometric remarks are valid in all cases and the
- *  driver effectively reduces the seek distance by the predicted factor
- *  when there are Q concurrent read i/o operations on the device, but this
- *  does not necessarily results in a noticeable performance improvement:
- *  your mileage may vary....
- *
- *  Note: command reordering inside a batch of queued commands could cause
- *        wrong results only if there is at least one write request and the
- *        intersection (sector-wise) of all requests is not empty.
- *        When the driver detects a batch including overlapping requests
- *        (a really rare event) strict serial (pid) order is enforced.
- *  ----------------------------------------------------------------------------
- *  The extended translation option (et:y) is useful when using large physical
- *  disks/arrays. It could also be useful when switching between Adaptec boards
- *  and DPT boards without reformatting the disk.
- *  When a boot disk is partitioned with extended translation, in order to
- *  be able to boot it with a DPT board is could be necessary to add to
- *  lilo.conf additional commands as in the following example:
- *
- *  fix-table
- *  disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546
- *
- *  where the above geometry should be replaced with the one reported at
- *  power up by the DPT controller.
- *  ----------------------------------------------------------------------------
- *
- *  The boards are named EATA0, EATA1,... according to the detection order.
- *
- *  In order to support multiple ISA boards in a reliable way,
- *  the driver sets host->wish_block = 1 for all ISA boards.
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/stat.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ctype.h>
-#include <linux/spinlock.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.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/scsicam.h>
-
-static int eata2x_detect(struct scsi_host_template *);
-static int eata2x_release(struct Scsi_Host *);
-static int eata2x_queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
-static int eata2x_eh_abort(struct scsi_cmnd *);
-static int eata2x_eh_host_reset(struct scsi_cmnd *);
-static int eata2x_bios_param(struct scsi_device *, struct block_device *,
-			     sector_t, int *);
-static int eata2x_slave_configure(struct scsi_device *);
-
-static struct scsi_host_template driver_template = {
-	.name = "EATA/DMA 2.0x rev. 8.10.00 ",
-	.detect = eata2x_detect,
-	.release = eata2x_release,
-	.queuecommand = eata2x_queuecommand,
-	.eh_abort_handler = eata2x_eh_abort,
-	.eh_host_reset_handler = eata2x_eh_host_reset,
-	.bios_param = eata2x_bios_param,
-	.slave_configure = eata2x_slave_configure,
-	.this_id = 7,
-	.unchecked_isa_dma = 1,
-	.use_clustering = ENABLE_CLUSTERING,
-};
-
-#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
-#error "Adjust your <asm/byteorder.h> defines"
-#endif
-
-/* Subversion values */
-#define ISA  0
-#define ESA 1
-
-#undef  FORCE_CONFIG
-
-#undef  DEBUG_LINKED_COMMANDS
-#undef  DEBUG_DETECT
-#undef  DEBUG_PCI_DETECT
-#undef  DEBUG_INTERRUPT
-#undef  DEBUG_RESET
-#undef  DEBUG_GENERATE_ERRORS
-#undef  DEBUG_GENERATE_ABORTS
-#undef  DEBUG_GEOMETRY
-
-#define MAX_ISA 4
-#define MAX_VESA 0
-#define MAX_EISA 15
-#define MAX_PCI 16
-#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
-#define MAX_CHANNEL 4
-#define MAX_LUN 32
-#define MAX_TARGET 32
-#define MAX_MAILBOXES 64
-#define MAX_SGLIST 64
-#define MAX_LARGE_SGLIST 122
-#define MAX_INTERNAL_RETRIES 64
-#define MAX_CMD_PER_LUN 2
-#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)
-
-#define SKIP ULONG_MAX
-#define FREE 0
-#define IN_USE   1
-#define LOCKED   2
-#define IN_RESET 3
-#define IGNORE   4
-#define READY    5
-#define ABORTING 6
-#define NO_DMA  0xff
-#define MAXLOOP  10000
-#define TAG_DISABLED 0
-#define TAG_SIMPLE   1
-#define TAG_ORDERED  2
-
-#define REG_CMD         7
-#define REG_STATUS      7
-#define REG_AUX_STATUS  8
-#define REG_DATA        0
-#define REG_DATA2       1
-#define REG_SEE         6
-#define REG_LOW         2
-#define REG_LM          3
-#define REG_MID         4
-#define REG_MSB         5
-#define REGION_SIZE     9UL
-#define MAX_ISA_ADDR    0x03ff
-#define MIN_EISA_ADDR   0x1c88
-#define MAX_EISA_ADDR   0xfc88
-#define BSY_ASSERTED      0x80
-#define DRQ_ASSERTED      0x08
-#define ABSY_ASSERTED     0x01
-#define IRQ_ASSERTED      0x02
-#define READ_CONFIG_PIO   0xf0
-#define SET_CONFIG_PIO    0xf1
-#define SEND_CP_PIO       0xf2
-#define RECEIVE_SP_PIO    0xf3
-#define TRUNCATE_XFR_PIO  0xf4
-#define RESET_PIO         0xf9
-#define READ_CONFIG_DMA   0xfd
-#define SET_CONFIG_DMA    0xfe
-#define SEND_CP_DMA       0xff
-#define ASOK              0x00
-#define ASST              0x01
-
-#define YESNO(a) ((a) ? 'y' : 'n')
-#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
-
-/* "EATA", in Big Endian format */
-#define EATA_SIG_BE 0x45415441
-
-/* Number of valid bytes in the board config structure for EATA 2.0x */
-#define EATA_2_0A_SIZE 28
-#define EATA_2_0B_SIZE 30
-#define EATA_2_0C_SIZE 34
-
-/* Board info structure */
-struct eata_info {
-	u_int32_t data_len;	/* Number of valid bytes after this field */
-	u_int32_t sign;		/* ASCII "EATA" signature */
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unchar version	: 4,
-	       		: 4;
-	unchar haaval	: 1,
-	       ata	: 1,
-	       drqvld	: 1,
-	       dmasup	: 1,
-	       morsup	: 1,
-	       trnxfr	: 1,
-	       tarsup	: 1,
-	       ocsena	: 1;
-#else
-	unchar		: 4,	/* unused low nibble */
-	 	version	: 4;	/* EATA version, should be 0x1 */
-	unchar ocsena	: 1,	/* Overlap Command Support Enabled */
-	       tarsup	: 1,	/* Target Mode Supported */
-	       trnxfr	: 1,	/* Truncate Transfer Cmd NOT Necessary */
-	       morsup	: 1,	/* More Supported */
-	       dmasup	: 1,	/* DMA Supported */
-	       drqvld	: 1,	/* DRQ Index (DRQX) is valid */
-	       ata	: 1,	/* This is an ATA device */
-	       haaval	: 1;	/* Host Adapter Address Valid */
-#endif
-
-	ushort cp_pad_len;	/* Number of pad bytes after cp_len */
-	unchar host_addr[4];	/* Host Adapter SCSI ID for channels 3, 2, 1, 0 */
-	u_int32_t cp_len;	/* Number of valid bytes in cp */
-	u_int32_t sp_len;	/* Number of valid bytes in sp */
-	ushort queue_size;	/* Max number of cp that can be queued */
-	ushort unused;
-	ushort scatt_size;	/* Max number of entries in scatter/gather table */
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unchar drqx	: 2,
-	       second	: 1,
-	       irq_tr	: 1,
-	       irq	: 4;
-	unchar sync;
-	unchar		: 4,
-	       res1	: 1,
-	       large_sg	: 1,
-	       forcaddr	: 1,
-	       isaena	: 1;
-	unchar max_chan	: 3,
-	       max_id	: 5;
-	unchar max_lun;
-	unchar eisa	: 1,
-	       pci	: 1,
-	       idquest	: 1,
-	       m1	: 1,
-	       		: 4;
-#else
-	unchar irq	: 4,	/* Interrupt Request assigned to this controller */
-	       irq_tr	: 1,	/* 0 for edge triggered, 1 for level triggered */
-	       second	: 1,	/* 1 if this is a secondary (not primary) controller */
-	       drqx	: 2;	/* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
-	unchar sync;		/* 1 if scsi target id 7...0 is running sync scsi */
-
-	/* Structure extension defined in EATA 2.0B */
-	unchar isaena	: 1,	/* ISA i/o addressing is disabled/enabled */
-	       forcaddr	: 1,	/* Port address has been forced */
-	       large_sg	: 1,	/* 1 if large SG lists are supported */
-	       res1	: 1,
-	       		: 4;
-	unchar max_id	: 5,	/* Max SCSI target ID number */
-	       max_chan	: 3;	/* Max SCSI channel number on this board */
-
-	/* Structure extension defined in EATA 2.0C */
-	unchar max_lun;		/* Max SCSI LUN number */
-	unchar
-			: 4,
-	       m1	: 1,	/* This is a PCI with an M1 chip installed */
-	       idquest	: 1,	/* RAIDNUM returned is questionable */
-	       pci	: 1,	/* This board is PCI */
-	       eisa	: 1;	/* This board is EISA */
-#endif
-
-	unchar raidnum;		/* Uniquely identifies this HBA in a system */
-	unchar notused;
-
-	ushort ipad[247];
-};
-
-/* Board config structure */
-struct eata_config {
-	ushort len;		/* Number of bytes following this field */
-
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unchar		: 4,
-	       tarena	: 1,
-	       mdpena	: 1,
-	       ocena	: 1,
-	       edis	: 1;
-#else
-	unchar edis	: 1,	/* Disable EATA interface after config command */
-	       ocena	: 1,	/* Overlapped Commands Enabled */
-	       mdpena	: 1,	/* Transfer all Modified Data Pointer Messages */
-	       tarena	: 1,	/* Target Mode Enabled for this controller */
-	       		: 4;
-#endif
-	unchar cpad[511];
-};
-
-/* Returned status packet structure */
-struct mssp {
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unchar eoc	: 1,
-	       adapter_status : 7;
-#else
-	unchar adapter_status : 7,	/* State related to current command */
-	       eoc	: 1;		/* End Of Command (1 = command completed) */
-#endif
-	unchar target_status;	/* SCSI status received after data transfer */
-	unchar unused[2];
-	u_int32_t inv_res_len;	/* Number of bytes not transferred */
-	u_int32_t cpp_index;	/* Index of address set in cp */
-	char mess[12];
-};
-
-struct sg_list {
-	unsigned int address;	/* Segment Address */
-	unsigned int num_bytes;	/* Segment Length */
-};
-
-/* MailBox SCSI Command Packet */
-struct mscp {
-#if defined(__BIG_ENDIAN_BITFIELD)
-	unchar din	: 1,
-	       dout	: 1,
-	       interp	: 1,
-	       		: 1,
-		sg	: 1,
-		reqsen	:1,
-		init	: 1,
-		sreset	: 1;
-	unchar sense_len;
-	unchar unused[3];
-	unchar		: 7,
-	       fwnest	: 1;
-	unchar		: 5,
-	       hbaci	: 1,
-	       iat	: 1,
-	       phsunit	: 1;
-	unchar channel	: 3,
-	       target	: 5;
-	unchar one	: 1,
-	       dispri	: 1,
-	       luntar	: 1,
-	       lun	: 5;
-#else
-	unchar sreset	:1,	/* SCSI Bus Reset Signal should be asserted */
-	       init	:1,	/* Re-initialize controller and self test */
-	       reqsen	:1,	/* Transfer Request Sense Data to addr using DMA */
-	       sg	:1,	/* Use Scatter/Gather */
-	       		:1,
-	       interp	:1,	/* The controller interprets cp, not the target */
-	       dout	:1,	/* Direction of Transfer is Out (Host to Target) */
-	       din	:1;	/* Direction of Transfer is In (Target to Host) */
-	unchar sense_len;	/* Request Sense Length */
-	unchar unused[3];
-	unchar fwnest	: 1,	/* Send command to a component of an Array Group */
-			: 7;
-	unchar phsunit	: 1,	/* Send to Target Physical Unit (bypass RAID) */
-	       iat	: 1,	/* Inhibit Address Translation */
-	       hbaci	: 1,	/* Inhibit HBA Caching for this command */
-	       		: 5;
-	unchar target	: 5,	/* SCSI target ID */
-	       channel	: 3;	/* SCSI channel number */
-	unchar lun	: 5,	/* SCSI logical unit number */
-	       luntar	: 1,	/* This cp is for Target (not LUN) */
-	       dispri	: 1,	/* Disconnect Privilege granted */
-	       one	: 1;	/* 1 */
-#endif
-
-	unchar mess[3];		/* Massage to/from Target */
-	unchar cdb[12];		/* Command Descriptor Block */
-	u_int32_t data_len;	/* If sg=0 Data Length, if sg=1 sglist length */
-	u_int32_t cpp_index;	/* Index of address to be returned in sp */
-	u_int32_t data_address;	/* If sg=0 Data Address, if sg=1 sglist address */
-	u_int32_t sp_dma_addr;	/* Address where sp is DMA'ed when cp completes */
-	u_int32_t sense_addr;	/* Address where Sense Data is DMA'ed on error */
-
-	/* Additional fields begin here. */
-	struct scsi_cmnd *SCpnt;
-
-	/* All the cp structure is zero filled by queuecommand except the
-	   following CP_TAIL_SIZE bytes, initialized by detect */
-	dma_addr_t cp_dma_addr;	/* dma handle for this cp structure */
-	struct sg_list *sglist;	/* pointer to the allocated SG list */
-};
-
-#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t))
-
-struct hostdata {
-	struct mscp cp[MAX_MAILBOXES];	/* Mailboxes for this board */
-	unsigned int cp_stat[MAX_MAILBOXES];	/* FREE, IN_USE, LOCKED, IN_RESET */
-	unsigned int last_cp_used;	/* Index of last mailbox used */
-	unsigned int iocount;	/* Total i/o done for this board */
-	int board_number;	/* Number of this board */
-	char board_name[16];	/* Name of this board */
-	int in_reset;		/* True if board is doing a reset */
-	int target_to[MAX_TARGET][MAX_CHANNEL];	/* N. of timeout errors on target */
-	int target_redo[MAX_TARGET][MAX_CHANNEL];	/* If 1 redo i/o on target */
-	unsigned int retries;	/* Number of internal retries */
-	unsigned long last_retried_pid;	/* Pid of last retried command */
-	unsigned char subversion;	/* Bus type, either ISA or EISA/PCI */
-	unsigned char protocol_rev;	/* EATA 2.0 rev., 'A' or 'B' or 'C' */
-	unsigned char is_pci;	/* 1 is bus type is PCI */
-	struct pci_dev *pdev;	/* pdev for PCI bus, NULL otherwise */
-	struct mssp *sp_cpu_addr;	/* cpu addr for DMA buffer sp */
-	dma_addr_t sp_dma_addr;	/* dma handle for DMA buffer sp */
-	struct mssp sp;		/* Local copy of sp buffer */
-};
-
-static struct Scsi_Host *sh[MAX_BOARDS];
-static const char *driver_name = "EATA";
-static char sha[MAX_BOARDS];
-
-/* Initialize num_boards so that ihdlr can work while detect is in progress */
-static unsigned int num_boards = MAX_BOARDS;
-
-static unsigned long io_port[] = {
-
-	/* Space for MAX_INT_PARAM ports usable while loading as a module */
-	SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
-	SKIP, SKIP,
-
-	/* First ISA */
-	0x1f0,
-
-	/* Space for MAX_PCI ports possibly reported by PCI_BIOS */
-	SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
-	SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
-
-	/* MAX_EISA ports */
-	0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
-	0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88,
-
-	/* Other (MAX_ISA - 1) ports */
-	0x170, 0x230, 0x330,
-
-	/* End of list */
-	0x0
-};
-
-/* Device is Big Endian */
-#define H2DEV(x)   cpu_to_be32(x)
-#define DEV2H(x)   be32_to_cpu(x)
-#define H2DEV16(x) cpu_to_be16(x)
-#define DEV2H16(x) be16_to_cpu(x)
-
-/* But transfer orientation from the 16 bit data register is Little Endian */
-#define REG2H(x)   le16_to_cpu(x)
-
-static irqreturn_t do_interrupt_handler(int, void *);
-static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *,
-		      unsigned int);
-static int do_trace = 0;
-static int setup_done = 0;
-static int link_statistics;
-static int ext_tran = 0;
-static int rev_scan = 1;
-
-#if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
-static int tag_mode = TAG_SIMPLE;
-#else
-static int tag_mode = TAG_DISABLED;
-#endif
-
-#if defined(CONFIG_SCSI_EATA_LINKED_COMMANDS)
-static int linked_comm = 1;
-#else
-static int linked_comm = 0;
-#endif
-
-#if defined(CONFIG_SCSI_EATA_MAX_TAGS)
-static int max_queue_depth = CONFIG_SCSI_EATA_MAX_TAGS;
-#else
-static int max_queue_depth = MAX_CMD_PER_LUN;
-#endif
-
-#if defined(CONFIG_ISA)
-static int isa_probe = 1;
-#else
-static int isa_probe = 0;
-#endif
-
-#if defined(CONFIG_EISA)
-static int eisa_probe = 1;
-#else
-static int eisa_probe = 0;
-#endif
-
-#if defined(CONFIG_PCI)
-static int pci_probe = 1;
-#else
-static int pci_probe = 0;
-#endif
-
-#define MAX_INT_PARAM 10
-#define MAX_BOOT_OPTIONS_SIZE 256
-static char boot_options[MAX_BOOT_OPTIONS_SIZE];
-
-#if defined(MODULE)
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-module_param_string(eata, boot_options, MAX_BOOT_OPTIONS_SIZE, 0);
-MODULE_PARM_DESC(eata, " equivalent to the \"eata=...\" kernel boot option."
-		 "            Example: modprobe eata \"eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n\"");
-MODULE_AUTHOR("Dario Ballabio");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("EATA/DMA SCSI Driver");
-
-#endif
-
-static int eata2x_slave_configure(struct scsi_device *dev)
-{
-	int tqd, utqd;
-	char *tag_suffix, *link_suffix;
-
-	utqd = MAX_CMD_PER_LUN;
-	tqd = max_queue_depth;
-
-	if (TLDEV(dev->type) && dev->tagged_supported) {
-		if (tag_mode == TAG_SIMPLE) {
-			tag_suffix = ", simple tags";
-		} else if (tag_mode == TAG_ORDERED) {
-			tag_suffix = ", ordered tags";
-		} else {
-			tag_suffix = ", no tags";
-		}
-		scsi_change_queue_depth(dev, tqd);
-	} else if (TLDEV(dev->type) && linked_comm) {
-		scsi_change_queue_depth(dev, tqd);
-		tag_suffix = ", untagged";
-	} else {
-		scsi_change_queue_depth(dev, utqd);
-		tag_suffix = "";
-	}
-
-	if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2)
-		link_suffix = ", sorted";
-	else if (TLDEV(dev->type))
-		link_suffix = ", unsorted";
-	else
-		link_suffix = "";
-
-	sdev_printk(KERN_INFO, dev,
-		"cmds/lun %d%s%s.\n",
-	       dev->queue_depth, link_suffix, tag_suffix);
-
-	return 0;
-}
-
-static int wait_on_busy(unsigned long iobase, unsigned int loop)
-{
-	while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) {
-		udelay(1L);
-		if (--loop == 0)
-			return 1;
-	}
-	return 0;
-}
-
-static int do_dma(unsigned long iobase, unsigned long addr, unchar cmd)
-{
-	unsigned char *byaddr;
-	unsigned long devaddr;
-
-	if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP)))
-		return 1;
-
-	if (addr) {
-		devaddr = H2DEV(addr);
-		byaddr = (unsigned char *)&devaddr;
-		outb(byaddr[3], iobase + REG_LOW);
-		outb(byaddr[2], iobase + REG_LM);
-		outb(byaddr[1], iobase + REG_MID);
-		outb(byaddr[0], iobase + REG_MSB);
-	}
-
-	outb(cmd, iobase + REG_CMD);
-	return 0;
-}
-
-static int read_pio(unsigned long iobase, ushort * start, ushort * end)
-{
-	unsigned int loop = MAXLOOP;
-	ushort *p;
-
-	for (p = start; p <= end; p++) {
-		while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) {
-			udelay(1L);
-			if (--loop == 0)
-				return 1;
-		}
-		loop = MAXLOOP;
-		*p = REG2H(inw(iobase));
-	}
-
-	return 0;
-}
-
-static struct pci_dev *get_pci_dev(unsigned long port_base)
-{
-#if defined(CONFIG_PCI)
-	unsigned int addr;
-	struct pci_dev *dev = NULL;
-
-	while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
-		addr = pci_resource_start(dev, 0);
-
-#if defined(DEBUG_PCI_DETECT)
-		printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n",
-		       driver_name, dev->bus->number, dev->devfn, addr);
-#endif
-
-		/* we are in so much trouble for a pci hotplug system with this driver
-		 * anyway, so doing this at least lets people unload the driver and not
-		 * cause memory problems, but in general this is a bad thing to do (this
-		 * driver needs to be converted to the proper PCI api someday... */
-		pci_dev_put(dev);
-		if (addr + PCI_BASE_ADDRESS_0 == port_base)
-			return dev;
-	}
-#endif				/* end CONFIG_PCI */
-	return NULL;
-}
-
-static void enable_pci_ports(void)
-{
-#if defined(CONFIG_PCI)
-	struct pci_dev *dev = NULL;
-
-	while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
-#if defined(DEBUG_PCI_DETECT)
-		printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n",
-		       driver_name, dev->bus->number, dev->devfn);
-#endif
-
-		if (pci_enable_device(dev))
-			printk
-			    ("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n",
-			     driver_name, dev->bus->number, dev->devfn);
-	}
-
-#endif				/* end CONFIG_PCI */
-}
-
-static int port_detect(unsigned long port_base, unsigned int j,
-		struct scsi_host_template *tpnt)
-{
-	unsigned char irq, dma_channel, subversion, i, is_pci = 0;
-	unsigned char protocol_rev;
-	struct eata_info info;
-	char *bus_type, dma_name[16];
-	struct pci_dev *pdev;
-	/* Allowed DMA channels for ISA (0 indicates reserved) */
-	unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
-	struct Scsi_Host *shost;
-	struct hostdata *ha;
-	char name[16];
-
-	sprintf(name, "%s%d", driver_name, j);
-
-	if (!request_region(port_base, REGION_SIZE, driver_name)) {
-#if defined(DEBUG_DETECT)
-		printk("%s: address 0x%03lx in use, skipping probe.\n", name,
-		       port_base);
-#endif
-		goto fail;
-	}
-
-	if (do_dma(port_base, 0, READ_CONFIG_PIO)) {
-#if defined(DEBUG_DETECT)
-		printk("%s: detect, do_dma failed at 0x%03lx.\n", name,
-		       port_base);
-#endif
-		goto freelock;
-	}
-
-	/* Read the info structure */
-	if (read_pio(port_base, (ushort *) & info, (ushort *) & info.ipad[0])) {
-#if defined(DEBUG_DETECT)
-		printk("%s: detect, read_pio failed at 0x%03lx.\n", name,
-		       port_base);
-#endif
-		goto freelock;
-	}
-
-	info.data_len = DEV2H(info.data_len);
-	info.sign = DEV2H(info.sign);
-	info.cp_pad_len = DEV2H16(info.cp_pad_len);
-	info.cp_len = DEV2H(info.cp_len);
-	info.sp_len = DEV2H(info.sp_len);
-	info.scatt_size = DEV2H16(info.scatt_size);
-	info.queue_size = DEV2H16(info.queue_size);
-
-	/* Check the controller "EATA" signature */
-	if (info.sign != EATA_SIG_BE) {
-#if defined(DEBUG_DETECT)
-		printk("%s: signature 0x%04x discarded.\n", name, info.sign);
-#endif
-		goto freelock;
-	}
-
-	if (info.data_len < EATA_2_0A_SIZE) {
-		printk
-		    ("%s: config structure size (%d bytes) too short, detaching.\n",
-		     name, info.data_len);
-		goto freelock;
-	} else if (info.data_len == EATA_2_0A_SIZE)
-		protocol_rev = 'A';
-	else if (info.data_len == EATA_2_0B_SIZE)
-		protocol_rev = 'B';
-	else
-		protocol_rev = 'C';
-
-	if (protocol_rev != 'A' && info.forcaddr) {
-		printk("%s: warning, port address has been forced.\n", name);
-		bus_type = "PCI";
-		is_pci = 1;
-		subversion = ESA;
-	} else if (port_base > MAX_EISA_ADDR
-		   || (protocol_rev == 'C' && info.pci)) {
-		bus_type = "PCI";
-		is_pci = 1;
-		subversion = ESA;
-	} else if (port_base >= MIN_EISA_ADDR
-		   || (protocol_rev == 'C' && info.eisa)) {
-		bus_type = "EISA";
-		subversion = ESA;
-	} else if (protocol_rev == 'C' && !info.eisa && !info.pci) {
-		bus_type = "ISA";
-		subversion = ISA;
-	} else if (port_base > MAX_ISA_ADDR) {
-		bus_type = "PCI";
-		is_pci = 1;
-		subversion = ESA;
-	} else {
-		bus_type = "ISA";
-		subversion = ISA;
-	}
-
-	if (!info.haaval || info.ata) {
-		printk
-		    ("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n",
-		     name, port_base, bus_type, info.haaval, info.ata);
-		goto freelock;
-	}
-
-	if (info.drqvld) {
-		if (subversion == ESA)
-			printk("%s: warning, weird %s board using DMA.\n", name,
-			       bus_type);
-
-		subversion = ISA;
-		dma_channel = dma_channel_table[3 - info.drqx];
-	} else {
-		if (subversion == ISA)
-			printk("%s: warning, weird %s board not using DMA.\n",
-			       name, bus_type);
-
-		subversion = ESA;
-		dma_channel = NO_DMA;
-	}
-
-	if (!info.dmasup)
-		printk("%s: warning, DMA protocol support not asserted.\n",
-		       name);
-
-	irq = info.irq;
-
-	if (subversion == ESA && !info.irq_tr)
-		printk
-		    ("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
-		     name, irq);
-
-	if (is_pci) {
-		pdev = get_pci_dev(port_base);
-		if (!pdev)
-			printk
-			    ("%s: warning, failed to get pci_dev structure.\n",
-			     name);
-	} else
-		pdev = NULL;
-
-	if (pdev && (irq != pdev->irq)) {
-		printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq,
-		       pdev->irq);
-		irq = pdev->irq;
-	}
-
-	/* Board detected, allocate its IRQ */
-	if (request_irq(irq, do_interrupt_handler,
-			(subversion == ESA) ? IRQF_SHARED : 0,
-			driver_name, (void *)&sha[j])) {
-		printk("%s: unable to allocate IRQ %u, detaching.\n", name,
-		       irq);
-		goto freelock;
-	}
-
-	if (subversion == ISA && request_dma(dma_channel, driver_name)) {
-		printk("%s: unable to allocate DMA channel %u, detaching.\n",
-		       name, dma_channel);
-		goto freeirq;
-	}
-#if defined(FORCE_CONFIG)
-	{
-		struct eata_config *cf;
-		dma_addr_t cf_dma_addr;
-
-		cf = pci_zalloc_consistent(pdev, sizeof(struct eata_config),
-					   &cf_dma_addr);
-
-		if (!cf) {
-			printk
-			    ("%s: config, pci_alloc_consistent failed, detaching.\n",
-			     name);
-			goto freedma;
-		}
-
-		/* Set board configuration */
-		cf->len = (ushort) H2DEV16((ushort) 510);
-		cf->ocena = 1;
-
-		if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) {
-			printk
-			    ("%s: busy timeout sending configuration, detaching.\n",
-			     name);
-			pci_free_consistent(pdev, sizeof(struct eata_config),
-					    cf, cf_dma_addr);
-			goto freedma;
-		}
-
-	}
-#endif
-
-	sh[j] = shost = scsi_register(tpnt, sizeof(struct hostdata));
-	if (shost == NULL) {
-		printk("%s: unable to register host, detaching.\n", name);
-		goto freedma;
-	}
-
-	shost->io_port = port_base;
-	shost->unique_id = port_base;
-	shost->n_io_port = REGION_SIZE;
-	shost->dma_channel = dma_channel;
-	shost->irq = irq;
-	shost->sg_tablesize = (ushort) info.scatt_size;
-	shost->this_id = (ushort) info.host_addr[3];
-	shost->can_queue = (ushort) info.queue_size;
-	shost->cmd_per_lun = MAX_CMD_PER_LUN;
-
-	ha = (struct hostdata *)shost->hostdata;
-	
-	memset(ha, 0, sizeof(struct hostdata));
-	ha->subversion = subversion;
-	ha->protocol_rev = protocol_rev;
-	ha->is_pci = is_pci;
-	ha->pdev = pdev;
-	ha->board_number = j;
-
-	if (ha->subversion == ESA)
-		shost->unchecked_isa_dma = 0;
-	else {
-		unsigned long flags;
-		shost->unchecked_isa_dma = 1;
-
-		flags = claim_dma_lock();
-		disable_dma(dma_channel);
-		clear_dma_ff(dma_channel);
-		set_dma_mode(dma_channel, DMA_MODE_CASCADE);
-		enable_dma(dma_channel);
-		release_dma_lock(flags);
-
-	}
-
-	strcpy(ha->board_name, name);
-
-	/* DPT PM2012 does not allow to detect sg_tablesize correctly */
-	if (shost->sg_tablesize > MAX_SGLIST || shost->sg_tablesize < 2) {
-		printk("%s: detect, wrong n. of SG lists %d, fixed.\n",
-		       ha->board_name, shost->sg_tablesize);
-		shost->sg_tablesize = MAX_SGLIST;
-	}
-
-	/* DPT PM2012 does not allow to detect can_queue correctly */
-	if (shost->can_queue > MAX_MAILBOXES || shost->can_queue < 2) {
-		printk("%s: detect, wrong n. of mbox %d, fixed.\n",
-		       ha->board_name, shost->can_queue);
-		shost->can_queue = MAX_MAILBOXES;
-	}
-
-	if (protocol_rev != 'A') {
-		if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL)
-			shost->max_channel = info.max_chan;
-
-		if (info.max_id > 7 && info.max_id < MAX_TARGET)
-			shost->max_id = info.max_id + 1;
-
-		if (info.large_sg && shost->sg_tablesize == MAX_SGLIST)
-			shost->sg_tablesize = MAX_LARGE_SGLIST;
-	}
-
-	if (protocol_rev == 'C') {
-		if (info.max_lun > 7 && info.max_lun < MAX_LUN)
-			shost->max_lun = info.max_lun + 1;
-	}
-
-	if (dma_channel == NO_DMA)
-		sprintf(dma_name, "%s", "BMST");
-	else
-		sprintf(dma_name, "DMA %u", dma_channel);
-
-	for (i = 0; i < shost->can_queue; i++)
-		ha->cp[i].cp_dma_addr = pci_map_single(ha->pdev,
-							  &ha->cp[i],
-							  sizeof(struct mscp),
-							  PCI_DMA_BIDIRECTIONAL);
-
-	for (i = 0; i < shost->can_queue; i++) {
-		size_t sz = shost->sg_tablesize *sizeof(struct sg_list);
-		gfp_t gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC;
-		ha->cp[i].sglist = kmalloc(sz, gfp_mask);
-		if (!ha->cp[i].sglist) {
-			printk
-			    ("%s: kmalloc SGlist failed, mbox %d, detaching.\n",
-			     ha->board_name, i);
-			goto release;
-		}
-	}
-
-	if (!(ha->sp_cpu_addr = pci_alloc_consistent(ha->pdev,
-							sizeof(struct mssp),
-							&ha->sp_dma_addr))) {
-		printk("%s: pci_alloc_consistent failed, detaching.\n", ha->board_name);
-		goto release;
-	}
-
-	if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
-		max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
-
-	if (max_queue_depth < MAX_CMD_PER_LUN)
-		max_queue_depth = MAX_CMD_PER_LUN;
-
-	if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE)
-		tag_mode = TAG_ORDERED;
-
-	if (j == 0) {
-		printk
-		    ("EATA/DMA 2.0x: Copyright (C) 1994-2003 Dario Ballabio.\n");
-		printk
-		    ("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, "
-		     "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode,
-		     YESNO(linked_comm), max_queue_depth, YESNO(rev_scan),
-		     YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe),
-		     YESNO(pci_probe));
-	}
-
-	printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
-	       ha->board_name, ha->protocol_rev, bus_type,
-	       (unsigned long)shost->io_port, shost->irq, dma_name,
-	       shost->sg_tablesize, shost->can_queue);
-
-	if (shost->max_id > 8 || shost->max_lun > 8)
-		printk
-		    ("%s: wide SCSI support enabled, max_id %u, max_lun %llu.\n",
-		     ha->board_name, shost->max_id, shost->max_lun);
-
-	for (i = 0; i <= shost->max_channel; i++)
-		printk("%s: SCSI channel %u enabled, host target ID %d.\n",
-		       ha->board_name, i, info.host_addr[3 - i]);
-
-#if defined(DEBUG_DETECT)
-	printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "
-	       "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version,
-	       info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync,
-	       info.second, info.data_len, info.cp_len, info.sp_len);
-
-	if (protocol_rev == 'B' || protocol_rev == 'C')
-		printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "
-		       "large_sg %u, res1 %u.\n", name, info.isaena,
-		       info.forcaddr, info.max_id, info.max_chan, info.large_sg,
-		       info.res1);
-
-	if (protocol_rev == 'C')
-		printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, "
-		       "raidnum %u.\n", name, info.max_lun, info.m1,
-		       info.idquest, info.pci, info.eisa, info.raidnum);
-#endif
-
-	if (ha->pdev) {
-		pci_set_master(ha->pdev);
-		if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32)))
-			printk("%s: warning, pci_set_dma_mask failed.\n",
-			       ha->board_name);
-	}
-
-	return 1;
-
-      freedma:
-	if (subversion == ISA)
-		free_dma(dma_channel);
-      freeirq:
-	free_irq(irq, &sha[j]);
-      freelock:
-	release_region(port_base, REGION_SIZE);
-      fail:
-	return 0;
-
-      release:
-	eata2x_release(shost);
-	return 0;
-}
-
-static void internal_setup(char *str, int *ints)
-{
-	int i, argc = ints[0];
-	char *cur = str, *pc;
-
-	if (argc > 0) {
-		if (argc > MAX_INT_PARAM)
-			argc = MAX_INT_PARAM;
-
-		for (i = 0; i < argc; i++)
-			io_port[i] = ints[i + 1];
-
-		io_port[i] = 0;
-		setup_done = 1;
-	}
-
-	while (cur && (pc = strchr(cur, ':'))) {
-		int val = 0, c = *++pc;
-
-		if (c == 'n' || c == 'N')
-			val = 0;
-		else if (c == 'y' || c == 'Y')
-			val = 1;
-		else
-			val = (int)simple_strtoul(pc, NULL, 0);
-
-		if (!strncmp(cur, "lc:", 3))
-			linked_comm = val;
-		else if (!strncmp(cur, "tm:", 3))
-			tag_mode = val;
-		else if (!strncmp(cur, "tc:", 3))
-			tag_mode = val;
-		else if (!strncmp(cur, "mq:", 3))
-			max_queue_depth = val;
-		else if (!strncmp(cur, "ls:", 3))
-			link_statistics = val;
-		else if (!strncmp(cur, "et:", 3))
-			ext_tran = val;
-		else if (!strncmp(cur, "rs:", 3))
-			rev_scan = val;
-		else if (!strncmp(cur, "ip:", 3))
-			isa_probe = val;
-		else if (!strncmp(cur, "ep:", 3))
-			eisa_probe = val;
-		else if (!strncmp(cur, "pp:", 3))
-			pci_probe = val;
-
-		if ((cur = strchr(cur, ',')))
-			++cur;
-	}
-
-	return;
-}
-
-static int option_setup(char *str)
-{
-	int ints[MAX_INT_PARAM];
-	char *cur = str;
-	int i = 1;
-
-	while (cur && isdigit(*cur) && i < MAX_INT_PARAM) {
-		ints[i++] = simple_strtoul(cur, NULL, 0);
-
-		if ((cur = strchr(cur, ',')) != NULL)
-			cur++;
-	}
-
-	ints[0] = i - 1;
-	internal_setup(cur, ints);
-	return 1;
-}
-
-static void add_pci_ports(void)
-{
-#if defined(CONFIG_PCI)
-	unsigned int addr, k;
-	struct pci_dev *dev = NULL;
-
-	for (k = 0; k < MAX_PCI; k++) {
-
-		if (!(dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev)))
-			break;
-
-		if (pci_enable_device(dev)) {
-#if defined(DEBUG_PCI_DETECT)
-			printk
-			    ("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n",
-			     driver_name, dev->bus->number, dev->devfn);
-#endif
-
-			continue;
-		}
-
-		addr = pci_resource_start(dev, 0);
-
-#if defined(DEBUG_PCI_DETECT)
-		printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
-		       driver_name, k, dev->bus->number, dev->devfn, addr);
-#endif
-
-		/* Order addresses according to rev_scan value */
-		io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
-		    addr + PCI_BASE_ADDRESS_0;
-	}
-
-	pci_dev_put(dev);
-#endif				/* end CONFIG_PCI */
-}
-
-static int eata2x_detect(struct scsi_host_template *tpnt)
-{
-	unsigned int j = 0, k;
-
-	tpnt->proc_name = "eata2x";
-
-	if (strlen(boot_options))
-		option_setup(boot_options);
-
-#if defined(MODULE)
-	/* io_port could have been modified when loading as a module */
-	if (io_port[0] != SKIP) {
-		setup_done = 1;
-		io_port[MAX_INT_PARAM] = 0;
-	}
-#endif
-
-	for (k = MAX_INT_PARAM; io_port[k]; k++)
-		if (io_port[k] == SKIP)
-			continue;
-		else if (io_port[k] <= MAX_ISA_ADDR) {
-			if (!isa_probe)
-				io_port[k] = SKIP;
-		} else if (io_port[k] >= MIN_EISA_ADDR
-			   && io_port[k] <= MAX_EISA_ADDR) {
-			if (!eisa_probe)
-				io_port[k] = SKIP;
-		}
-
-	if (pci_probe) {
-		if (!setup_done)
-			add_pci_ports();
-		else
-			enable_pci_ports();
-	}
-
-	for (k = 0; io_port[k]; k++) {
-
-		if (io_port[k] == SKIP)
-			continue;
-
-		if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt))
-			j++;
-	}
-
-	num_boards = j;
-	return j;
-}
-
-static void map_dma(unsigned int i, struct hostdata *ha)
-{
-	unsigned int k, pci_dir;
-	int count;
-	struct scatterlist *sg;
-	struct mscp *cpp;
-	struct scsi_cmnd *SCpnt;
-
-	cpp = &ha->cp[i];
-	SCpnt = cpp->SCpnt;
-	pci_dir = SCpnt->sc_data_direction;
-
-	if (SCpnt->sense_buffer)
-		cpp->sense_addr =
-		    H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer,
-			   SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
-
-	cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
-
-	if (!scsi_sg_count(SCpnt)) {
-		cpp->data_len = 0;
-		return;
-	}
-
-	count = pci_map_sg(ha->pdev, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
-			   pci_dir);
-	BUG_ON(!count);
-
-	scsi_for_each_sg(SCpnt, sg, count, k) {
-		cpp->sglist[k].address = H2DEV(sg_dma_address(sg));
-		cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg));
-	}
-
-	cpp->sg = 1;
-	cpp->data_address = H2DEV(pci_map_single(ha->pdev, cpp->sglist,
-						 scsi_sg_count(SCpnt) *
-						 sizeof(struct sg_list),
-						 pci_dir));
-	cpp->data_len = H2DEV((scsi_sg_count(SCpnt) * sizeof(struct sg_list)));
-}
-
-static void unmap_dma(unsigned int i, struct hostdata *ha)
-{
-	unsigned int pci_dir;
-	struct mscp *cpp;
-	struct scsi_cmnd *SCpnt;
-
-	cpp = &ha->cp[i];
-	SCpnt = cpp->SCpnt;
-	pci_dir = SCpnt->sc_data_direction;
-
-	if (DEV2H(cpp->sense_addr))
-		pci_unmap_single(ha->pdev, DEV2H(cpp->sense_addr),
-				 DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
-
-	if (scsi_sg_count(SCpnt))
-		pci_unmap_sg(ha->pdev, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
-			     pci_dir);
-
-	if (!DEV2H(cpp->data_len))
-		pci_dir = PCI_DMA_BIDIRECTIONAL;
-
-	if (DEV2H(cpp->data_address))
-		pci_unmap_single(ha->pdev, DEV2H(cpp->data_address),
-				 DEV2H(cpp->data_len), pci_dir);
-}
-
-static void sync_dma(unsigned int i, struct hostdata *ha)
-{
-	unsigned int pci_dir;
-	struct mscp *cpp;
-	struct scsi_cmnd *SCpnt;
-
-	cpp = &ha->cp[i];
-	SCpnt = cpp->SCpnt;
-	pci_dir = SCpnt->sc_data_direction;
-
-	if (DEV2H(cpp->sense_addr))
-		pci_dma_sync_single_for_cpu(ha->pdev, DEV2H(cpp->sense_addr),
-					    DEV2H(cpp->sense_len),
-					    PCI_DMA_FROMDEVICE);
-
-	if (scsi_sg_count(SCpnt))
-		pci_dma_sync_sg_for_cpu(ha->pdev, scsi_sglist(SCpnt),
-					scsi_sg_count(SCpnt), pci_dir);
-
-	if (!DEV2H(cpp->data_len))
-		pci_dir = PCI_DMA_BIDIRECTIONAL;
-
-	if (DEV2H(cpp->data_address))
-		pci_dma_sync_single_for_cpu(ha->pdev,
-					    DEV2H(cpp->data_address),
-					    DEV2H(cpp->data_len), pci_dir);
-}
-
-static void scsi_to_dev_dir(unsigned int i, struct hostdata *ha)
-{
-	unsigned int k;
-
-	static const unsigned char data_out_cmds[] = {
-		0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
-		0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
-		0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d
-	};
-
-	static const unsigned char data_none_cmds[] = {
-		0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
-		0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
-		0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
-	};
-
-	struct mscp *cpp;
-	struct scsi_cmnd *SCpnt;
-
-	cpp = &ha->cp[i];
-	SCpnt = cpp->SCpnt;
-
-	if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
-		cpp->din = 1;
-		cpp->dout = 0;
-		return;
-	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
-		cpp->din = 0;
-		cpp->dout = 1;
-		return;
-	} else if (SCpnt->sc_data_direction == DMA_NONE) {
-		cpp->din = 0;
-		cpp->dout = 0;
-		return;
-	}
-
-	if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL)
-		panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n",
-				ha->board_name);
-
-	for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
-		if (SCpnt->cmnd[0] == data_out_cmds[k]) {
-			cpp->dout = 1;
-			break;
-		}
-
-	if ((cpp->din = !cpp->dout))
-		for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
-			if (SCpnt->cmnd[0] == data_none_cmds[k]) {
-				cpp->din = 0;
-				break;
-			}
-
-}
-
-static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt,
-			       void (*done) (struct scsi_cmnd *))
-{
-	struct Scsi_Host *shost = SCpnt->device->host;
-	struct hostdata *ha = (struct hostdata *)shost->hostdata;
-	unsigned int i, k;
-	struct mscp *cpp;
-
-	if (SCpnt->host_scribble)
-		panic("%s: qcomm, SCpnt %p already active.\n",
-		      ha->board_name, SCpnt);
-
-	/* i is the mailbox number, look for the first free mailbox
-	   starting from last_cp_used */
-	i = ha->last_cp_used + 1;
-
-	for (k = 0; k < shost->can_queue; k++, i++) {
-		if (i >= shost->can_queue)
-			i = 0;
-		if (ha->cp_stat[i] == FREE) {
-			ha->last_cp_used = i;
-			break;
-		}
-	}
-
-	if (k == shost->can_queue) {
-		printk("%s: qcomm, no free mailbox.\n", ha->board_name);
-		return 1;
-	}
-
-	/* Set pointer to control packet structure */
-	cpp = &ha->cp[i];
-
-	memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
-
-	/* Set pointer to status packet structure, Big Endian format */
-	cpp->sp_dma_addr = H2DEV(ha->sp_dma_addr);
-
-	SCpnt->scsi_done = done;
-	cpp->cpp_index = i;
-	SCpnt->host_scribble = (unsigned char *)&cpp->cpp_index;
-
-	if (do_trace)
-		scmd_printk(KERN_INFO, SCpnt,
-			"qcomm, mbox %d.\n", i);
-
-	cpp->reqsen = 1;
-	cpp->dispri = 1;
-#if 0
-	if (SCpnt->device->type == TYPE_TAPE)
-		cpp->hbaci = 1;
-#endif
-	cpp->one = 1;
-	cpp->channel = SCpnt->device->channel;
-	cpp->target = SCpnt->device->id;
-	cpp->lun = SCpnt->device->lun;
-	cpp->SCpnt = SCpnt;
-	memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
-	/* Use data transfer direction SCpnt->sc_data_direction */
-	scsi_to_dev_dir(i, ha);
-
-	/* Map DMA buffers and SG list */
-	map_dma(i, ha);
-
-	if (linked_comm && SCpnt->device->queue_depth > 2
-	    && TLDEV(SCpnt->device->type)) {
-		ha->cp_stat[i] = READY;
-		flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 0);
-		return 0;
-	}
-
-	/* Send control packet to the board */
-	if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
-		unmap_dma(i, ha);
-		SCpnt->host_scribble = NULL;
-		scmd_printk(KERN_INFO, SCpnt, "qcomm, adapter busy.\n");
-		return 1;
-	}
-
-	ha->cp_stat[i] = IN_USE;
-	return 0;
-}
-
-static DEF_SCSI_QCMD(eata2x_queuecommand)
-
-static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
-{
-	struct Scsi_Host *shost = SCarg->device->host;
-	struct hostdata *ha = (struct hostdata *)shost->hostdata;
-	unsigned int i;
-
-	if (SCarg->host_scribble == NULL) {
-		scmd_printk(KERN_INFO, SCarg, "abort, cmd inactive.\n");
-		return SUCCESS;
-	}
-
-	i = *(unsigned int *)SCarg->host_scribble;
-	scmd_printk(KERN_WARNING, SCarg, "abort, mbox %d.\n", i);
-
-	if (i >= shost->can_queue)
-		panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name);
-
-	if (wait_on_busy(shost->io_port, MAXLOOP)) {
-		printk("%s: abort, timeout error.\n", ha->board_name);
-		return FAILED;
-	}
-
-	if (ha->cp_stat[i] == FREE) {
-		printk("%s: abort, mbox %d is free.\n", ha->board_name, i);
-		return SUCCESS;
-	}
-
-	if (ha->cp_stat[i] == IN_USE) {
-		printk("%s: abort, mbox %d is in use.\n", ha->board_name, i);
-
-		if (SCarg != ha->cp[i].SCpnt)
-			panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
-			      ha->board_name, i, SCarg, ha->cp[i].SCpnt);
-
-		if (inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)
-			printk("%s: abort, mbox %d, interrupt pending.\n",
-			       ha->board_name, i);
-
-		return FAILED;
-	}
-
-	if (ha->cp_stat[i] == IN_RESET) {
-		printk("%s: abort, mbox %d is in reset.\n", ha->board_name, i);
-		return FAILED;
-	}
-
-	if (ha->cp_stat[i] == LOCKED) {
-		printk("%s: abort, mbox %d is locked.\n", ha->board_name, i);
-		return SUCCESS;
-	}
-
-	if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) {
-		unmap_dma(i, ha);
-		SCarg->result = DID_ABORT << 16;
-		SCarg->host_scribble = NULL;
-		ha->cp_stat[i] = FREE;
-		printk("%s, abort, mbox %d ready, DID_ABORT, done.\n",
-		       ha->board_name, i);
-		SCarg->scsi_done(SCarg);
-		return SUCCESS;
-	}
-
-	panic("%s: abort, mbox %d, invalid cp_stat.\n", ha->board_name, i);
-}
-
-static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
-{
-	unsigned int i, time, k, c, limit = 0;
-	struct scsi_cmnd *SCpnt;
-	struct Scsi_Host *shost = SCarg->device->host;
-	struct hostdata *ha = (struct hostdata *)shost->hostdata;
-
-	scmd_printk(KERN_INFO, SCarg, "reset, enter.\n");
-
-	spin_lock_irq(shost->host_lock);
-
-	if (SCarg->host_scribble == NULL)
-		printk("%s: reset, inactive.\n", ha->board_name);
-
-	if (ha->in_reset) {
-		printk("%s: reset, exit, already in reset.\n", ha->board_name);
-		spin_unlock_irq(shost->host_lock);
-		return FAILED;
-	}
-
-	if (wait_on_busy(shost->io_port, MAXLOOP)) {
-		printk("%s: reset, exit, timeout error.\n", ha->board_name);
-		spin_unlock_irq(shost->host_lock);
-		return FAILED;
-	}
-
-	ha->retries = 0;
-
-	for (c = 0; c <= shost->max_channel; c++)
-		for (k = 0; k < shost->max_id; k++) {
-			ha->target_redo[k][c] = 1;
-			ha->target_to[k][c] = 0;
-		}
-
-	for (i = 0; i < shost->can_queue; i++) {
-
-		if (ha->cp_stat[i] == FREE)
-			continue;
-
-		if (ha->cp_stat[i] == LOCKED) {
-			ha->cp_stat[i] = FREE;
-			printk("%s: reset, locked mbox %d forced free.\n",
-			       ha->board_name, i);
-			continue;
-		}
-
-		if (!(SCpnt = ha->cp[i].SCpnt))
-			panic("%s: reset, mbox %d, SCpnt == NULL.\n", ha->board_name, i);
-
-		if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) {
-			ha->cp_stat[i] = ABORTING;
-			printk("%s: reset, mbox %d aborting.\n",
-			       ha->board_name, i);
-		}
-
-		else {
-			ha->cp_stat[i] = IN_RESET;
-			printk("%s: reset, mbox %d in reset.\n",
-			       ha->board_name, i);
-		}
-
-		if (SCpnt->host_scribble == NULL)
-			panic("%s: reset, mbox %d, garbled SCpnt.\n", ha->board_name, i);
-
-		if (*(unsigned int *)SCpnt->host_scribble != i)
-			panic("%s: reset, mbox %d, index mismatch.\n", ha->board_name, i);
-
-		if (SCpnt->scsi_done == NULL)
-			panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n",
-			      ha->board_name, i);
-	}
-
-	if (do_dma(shost->io_port, 0, RESET_PIO)) {
-		printk("%s: reset, cannot reset, timeout error.\n", ha->board_name);
-		spin_unlock_irq(shost->host_lock);
-		return FAILED;
-	}
-
-	printk("%s: reset, board reset done, enabling interrupts.\n", ha->board_name);
-
-#if defined(DEBUG_RESET)
-	do_trace = 1;
-#endif
-
-	ha->in_reset = 1;
-
-	spin_unlock_irq(shost->host_lock);
-
-	/* FIXME: use a sleep instead */
-	time = jiffies;
-	while ((jiffies - time) < (10 * HZ) && limit++ < 200000)
-		udelay(100L);
-
-	spin_lock_irq(shost->host_lock);
-
-	printk("%s: reset, interrupts disabled, loops %d.\n", ha->board_name, limit);
-
-	for (i = 0; i < shost->can_queue; i++) {
-
-		if (ha->cp_stat[i] == IN_RESET) {
-			SCpnt = ha->cp[i].SCpnt;
-			unmap_dma(i, ha);
-			SCpnt->result = DID_RESET << 16;
-			SCpnt->host_scribble = NULL;
-
-			/* This mailbox is still waiting for its interrupt */
-			ha->cp_stat[i] = LOCKED;
-
-			printk
-			    ("%s, reset, mbox %d locked, DID_RESET, done.\n",
-			     ha->board_name, i);
-		}
-
-		else if (ha->cp_stat[i] == ABORTING) {
-			SCpnt = ha->cp[i].SCpnt;
-			unmap_dma(i, ha);
-			SCpnt->result = DID_RESET << 16;
-			SCpnt->host_scribble = NULL;
-
-			/* This mailbox was never queued to the adapter */
-			ha->cp_stat[i] = FREE;
-
-			printk
-			    ("%s, reset, mbox %d aborting, DID_RESET, done.\n",
-			     ha->board_name, i);
-		}
-
-		else
-			/* Any other mailbox has already been set free by interrupt */
-			continue;
-
-		SCpnt->scsi_done(SCpnt);
-	}
-
-	ha->in_reset = 0;
-	do_trace = 0;
-
-	printk("%s: reset, exit.\n", ha->board_name);
-
-	spin_unlock_irq(shost->host_lock);
-	return SUCCESS;
-}
-
-int eata2x_bios_param(struct scsi_device *sdev, struct block_device *bdev,
-		      sector_t capacity, int *dkinfo)
-{
-	unsigned int size = capacity;
-
-	if (ext_tran || (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) {
-		dkinfo[0] = 255;
-		dkinfo[1] = 63;
-		dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
-	}
-#if defined (DEBUG_GEOMETRY)
-	printk("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name,
-	       dkinfo[0], dkinfo[1], dkinfo[2]);
-#endif
-
-	return 0;
-}
-
-static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
-		 unsigned int rev)
-{
-	unsigned int i, j, k, y;
-	unsigned long x;
-
-	for (i = 0; i < n - 1; i++) {
-		k = i;
-
-		for (j = k + 1; j < n; j++)
-			if (rev) {
-				if (sk[j] > sk[k])
-					k = j;
-			} else {
-				if (sk[j] < sk[k])
-					k = j;
-			}
-
-		if (k != i) {
-			x = sk[k];
-			sk[k] = sk[i];
-			sk[i] = x;
-			y = da[k];
-			da[k] = da[i];
-			da[i] = y;
-		}
-	}
-
-	return;
-}
-
-static int reorder(struct hostdata *ha, unsigned long cursec,
-		   unsigned int ihdlr, unsigned int il[], unsigned int n_ready)
-{
-	struct scsi_cmnd *SCpnt;
-	struct mscp *cpp;
-	unsigned int k, n;
-	unsigned int rev = 0, s = 1, r = 1;
-	unsigned int input_only = 1, overlap = 0;
-	unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
-	unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
-	unsigned long ioseek = 0;
-
-	static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
-	static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
-	static unsigned int readysorted = 0, revcount = 0;
-	static unsigned long seeksorted = 0, seeknosort = 0;
-
-	if (link_statistics && !(++flushcount % link_statistics))
-		printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"
-		       " av %ldK as %ldK.\n", flushcount, batchcount,
-		       inputcount, ovlcount, readycount, readysorted, sortcount,
-		       revcount, seeknosort / (readycount + 1),
-		       seeksorted / (readycount + 1));
-
-	if (n_ready <= 1)
-		return 0;
-
-	for (n = 0; n < n_ready; n++) {
-		k = il[n];
-		cpp = &ha->cp[k];
-		SCpnt = cpp->SCpnt;
-
-		if (!cpp->din)
-			input_only = 0;
-
-		if (blk_rq_pos(SCpnt->request) < minsec)
-			minsec = blk_rq_pos(SCpnt->request);
-		if (blk_rq_pos(SCpnt->request) > maxsec)
-			maxsec = blk_rq_pos(SCpnt->request);
-
-		sl[n] = blk_rq_pos(SCpnt->request);
-		ioseek += blk_rq_sectors(SCpnt->request);
-
-		if (!n)
-			continue;
-
-		if (sl[n] < sl[n - 1])
-			s = 0;
-		if (sl[n] > sl[n - 1])
-			r = 0;
-
-		if (link_statistics) {
-			if (sl[n] > sl[n - 1])
-				seek += sl[n] - sl[n - 1];
-			else
-				seek += sl[n - 1] - sl[n];
-		}
-
-	}
-
-	if (link_statistics) {
-		if (cursec > sl[0])
-			seek += cursec - sl[0];
-		else
-			seek += sl[0] - cursec;
-	}
-
-	if (cursec > ((maxsec + minsec) / 2))
-		rev = 1;
-
-	if (ioseek > ((maxsec - minsec) / 2))
-		rev = 0;
-
-	if (!((rev && r) || (!rev && s)))
-		sort(sl, il, n_ready, rev);
-
-	if (!input_only)
-		for (n = 0; n < n_ready; n++) {
-			k = il[n];
-			cpp = &ha->cp[k];
-			SCpnt = cpp->SCpnt;
-			ll[n] = blk_rq_sectors(SCpnt->request);
-			pl[n] = SCpnt->serial_number;
-
-			if (!n)
-				continue;
-
-			if ((sl[n] == sl[n - 1])
-			    || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
-			    || (rev && ((sl[n] + ll[n]) > sl[n - 1])))
-				overlap = 1;
-		}
-
-	if (overlap)
-		sort(pl, il, n_ready, 0);
-
-	if (link_statistics) {
-		if (cursec > sl[0])
-			iseek = cursec - sl[0];
-		else
-			iseek = sl[0] - cursec;
-		batchcount++;
-		readycount += n_ready;
-		seeknosort += seek / 1024;
-		if (input_only)
-			inputcount++;
-		if (overlap) {
-			ovlcount++;
-			seeksorted += iseek / 1024;
-		} else
-			seeksorted += (iseek + maxsec - minsec) / 1024;
-		if (rev && !r) {
-			revcount++;
-			readysorted += n_ready;
-		}
-		if (!rev && !s) {
-			sortcount++;
-			readysorted += n_ready;
-		}
-	}
-#if defined(DEBUG_LINKED_COMMANDS)
-	if (link_statistics && (overlap || !(flushcount % link_statistics)))
-		for (n = 0; n < n_ready; n++) {
-			k = il[n];
-			cpp = &ha->cp[k];
-			SCpnt = cpp->SCpnt;
-			scmd_printk(KERN_INFO, SCpnt,
-			    "%s mb %d fc %d nr %d sec %ld ns %u"
-			     " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
-			     (ihdlr ? "ihdlr" : "qcomm"),
-			     k, flushcount,
-			     n_ready, blk_rq_pos(SCpnt->request),
-			     blk_rq_sectors(SCpnt->request), cursec, YESNO(s),
-			     YESNO(r), YESNO(rev), YESNO(input_only),
-			     YESNO(overlap), cpp->din);
-		}
-#endif
-	return overlap;
-}
-
-static void flush_dev(struct scsi_device *dev, unsigned long cursec,
-		      struct hostdata *ha, unsigned int ihdlr)
-{
-	struct scsi_cmnd *SCpnt;
-	struct mscp *cpp;
-	unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES];
-
-	for (k = 0; k < dev->host->can_queue; k++) {
-
-		if (ha->cp_stat[k] != READY && ha->cp_stat[k] != IN_USE)
-			continue;
-
-		cpp = &ha->cp[k];
-		SCpnt = cpp->SCpnt;
-
-		if (SCpnt->device != dev)
-			continue;
-
-		if (ha->cp_stat[k] == IN_USE)
-			return;
-
-		il[n_ready++] = k;
-	}
-
-	if (reorder(ha, cursec, ihdlr, il, n_ready))
-		n_ready = 1;
-
-	for (n = 0; n < n_ready; n++) {
-		k = il[n];
-		cpp = &ha->cp[k];
-		SCpnt = cpp->SCpnt;
-
-		if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
-			scmd_printk(KERN_INFO, SCpnt,
-			    "%s, mbox %d, adapter"
-			     " busy, will abort.\n",
-			     (ihdlr ? "ihdlr" : "qcomm"),
-			     k);
-			ha->cp_stat[k] = ABORTING;
-			continue;
-		}
-
-		ha->cp_stat[k] = IN_USE;
-	}
-}
-
-static irqreturn_t ihdlr(struct Scsi_Host *shost)
-{
-	struct scsi_cmnd *SCpnt;
-	unsigned int i, k, c, status, tstatus, reg;
-	struct mssp *spp;
-	struct mscp *cpp;
-	struct hostdata *ha = (struct hostdata *)shost->hostdata;
-	int irq = shost->irq;
-
-	/* Check if this board need to be serviced */
-	if (!(inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED))
-		goto none;
-
-	ha->iocount++;
-
-	if (do_trace)
-		printk("%s: ihdlr, enter, irq %d, count %d.\n", ha->board_name, irq,
-		       ha->iocount);
-
-	/* Check if this board is still busy */
-	if (wait_on_busy(shost->io_port, 20 * MAXLOOP)) {
-		reg = inb(shost->io_port + REG_STATUS);
-		printk
-		    ("%s: ihdlr, busy timeout error,  irq %d, reg 0x%x, count %d.\n",
-		     ha->board_name, irq, reg, ha->iocount);
-		goto none;
-	}
-
-	spp = &ha->sp;
-
-	/* Make a local copy just before clearing the interrupt indication */
-	memcpy(spp, ha->sp_cpu_addr, sizeof(struct mssp));
-
-	/* Clear the completion flag and cp pointer on the dynamic copy of sp */
-	memset(ha->sp_cpu_addr, 0, sizeof(struct mssp));
-
-	/* Read the status register to clear the interrupt indication */
-	reg = inb(shost->io_port + REG_STATUS);
-
-#if defined (DEBUG_INTERRUPT)
-	{
-		unsigned char *bytesp;
-		int cnt;
-		bytesp = (unsigned char *)spp;
-		if (ha->iocount < 200) {
-			printk("sp[] =");
-			for (cnt = 0; cnt < 15; cnt++)
-				printk(" 0x%x", bytesp[cnt]);
-			printk("\n");
-		}
-	}
-#endif
-
-	/* Reject any sp with supspect data */
-	if (spp->eoc == 0 && ha->iocount > 1)
-		printk
-		    ("%s: ihdlr, spp->eoc == 0, irq %d, reg 0x%x, count %d.\n",
-		     ha->board_name, irq, reg, ha->iocount);
-	if (spp->cpp_index < 0 || spp->cpp_index >= shost->can_queue)
-		printk
-		    ("%s: ihdlr, bad spp->cpp_index %d, irq %d, reg 0x%x, count %d.\n",
-		     ha->board_name, spp->cpp_index, irq, reg, ha->iocount);
-	if (spp->eoc == 0 || spp->cpp_index < 0
-	    || spp->cpp_index >= shost->can_queue)
-		goto handled;
-
-	/* Find the mailbox to be serviced on this board */
-	i = spp->cpp_index;
-
-	cpp = &(ha->cp[i]);
-
-#if defined(DEBUG_GENERATE_ABORTS)
-	if ((ha->iocount > 500) && ((ha->iocount % 500) < 3))
-		goto handled;
-#endif
-
-	if (ha->cp_stat[i] == IGNORE) {
-		ha->cp_stat[i] = FREE;
-		goto handled;
-	} else if (ha->cp_stat[i] == LOCKED) {
-		ha->cp_stat[i] = FREE;
-		printk("%s: ihdlr, mbox %d unlocked, count %d.\n", ha->board_name, i,
-		       ha->iocount);
-		goto handled;
-	} else if (ha->cp_stat[i] == FREE) {
-		printk("%s: ihdlr, mbox %d is free, count %d.\n", ha->board_name, i,
-		       ha->iocount);
-		goto handled;
-	} else if (ha->cp_stat[i] == IN_RESET)
-		printk("%s: ihdlr, mbox %d is in reset.\n", ha->board_name, i);
-	else if (ha->cp_stat[i] != IN_USE)
-		panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
-		      ha->board_name, i, ha->cp_stat[i]);
-
-	ha->cp_stat[i] = FREE;
-	SCpnt = cpp->SCpnt;
-
-	if (SCpnt == NULL)
-		panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", ha->board_name, i);
-
-	if (SCpnt->host_scribble == NULL)
-		panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", ha->board_name,
-		      i, SCpnt);
-
-	if (*(unsigned int *)SCpnt->host_scribble != i)
-		panic("%s: ihdlr, mbox %d, index mismatch %d.\n",
-		      ha->board_name, i,
-		      *(unsigned int *)SCpnt->host_scribble);
-
-	sync_dma(i, ha);
-
-	if (linked_comm && SCpnt->device->queue_depth > 2
-	    && TLDEV(SCpnt->device->type))
-		flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 1);
-
-	tstatus = status_byte(spp->target_status);
-
-#if defined(DEBUG_GENERATE_ERRORS)
-	if ((ha->iocount > 500) && ((ha->iocount % 200) < 2))
-		spp->adapter_status = 0x01;
-#endif
-
-	switch (spp->adapter_status) {
-	case ASOK:		/* status OK */
-
-		/* Forces a reset if a disk drive keeps returning BUSY */
-		if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
-			status = DID_ERROR << 16;
-
-		/* If there was a bus reset, redo operation on each target */
-		else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
-			 && ha->target_redo[SCpnt->device->id][SCpnt->
-								  device->
-								  channel])
-			status = DID_BUS_BUSY << 16;
-
-		/* Works around a flaw in scsi.c */
-		else if (tstatus == CHECK_CONDITION
-			 && SCpnt->device->type == TYPE_DISK
-			 && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
-			status = DID_BUS_BUSY << 16;
-
-		else
-			status = DID_OK << 16;
-
-		if (tstatus == GOOD)
-			ha->target_redo[SCpnt->device->id][SCpnt->device->
-							      channel] = 0;
-
-		if (spp->target_status && SCpnt->device->type == TYPE_DISK &&
-		    (!(tstatus == CHECK_CONDITION && ha->iocount <= 1000 &&
-		       (SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
-			printk("%s: ihdlr, target %d.%d:%d, "
-			       "target_status 0x%x, sense key 0x%x.\n",
-			       ha->board_name,
-			       SCpnt->device->channel, SCpnt->device->id,
-			       (u8)SCpnt->device->lun,
-			       spp->target_status, SCpnt->sense_buffer[2]);
-
-		ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0;
-
-		if (ha->last_retried_pid == SCpnt->serial_number)
-			ha->retries = 0;
-
-		break;
-	case ASST:		/* Selection Time Out */
-	case 0x02:		/* Command Time Out   */
-
-		if (ha->target_to[SCpnt->device->id][SCpnt->device->channel] > 1)
-			status = DID_ERROR << 16;
-		else {
-			status = DID_TIME_OUT << 16;
-			ha->target_to[SCpnt->device->id][SCpnt->device->
-							    channel]++;
-		}
-
-		break;
-
-		/* Perform a limited number of internal retries */
-	case 0x03:		/* SCSI Bus Reset Received */
-	case 0x04:		/* Initial Controller Power-up */
-
-		for (c = 0; c <= shost->max_channel; c++)
-			for (k = 0; k < shost->max_id; k++)
-				ha->target_redo[k][c] = 1;
-
-		if (SCpnt->device->type != TYPE_TAPE
-		    && ha->retries < MAX_INTERNAL_RETRIES) {
-
-#if defined(DID_SOFT_ERROR)
-			status = DID_SOFT_ERROR << 16;
-#else
-			status = DID_BUS_BUSY << 16;
-#endif
-
-			ha->retries++;
-			ha->last_retried_pid = SCpnt->serial_number;
-		} else
-			status = DID_ERROR << 16;
-
-		break;
-	case 0x05:		/* Unexpected Bus Phase */
-	case 0x06:		/* Unexpected Bus Free */
-	case 0x07:		/* Bus Parity Error */
-	case 0x08:		/* SCSI Hung */
-	case 0x09:		/* Unexpected Message Reject */
-	case 0x0a:		/* SCSI Bus Reset Stuck */
-	case 0x0b:		/* Auto Request-Sense Failed */
-	case 0x0c:		/* Controller Ram Parity Error */
-	default:
-		status = DID_ERROR << 16;
-		break;
-	}
-
-	SCpnt->result = status | spp->target_status;
-
-#if defined(DEBUG_INTERRUPT)
-	if (SCpnt->result || do_trace)
-#else
-	if ((spp->adapter_status != ASOK && ha->iocount > 1000) ||
-	    (spp->adapter_status != ASOK &&
-	     spp->adapter_status != ASST && ha->iocount <= 1000) ||
-	    do_trace || msg_byte(spp->target_status))
-#endif
-		scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"
-		       " reg 0x%x, count %d.\n",
-		       i, spp->adapter_status, spp->target_status,
-		       reg, ha->iocount);
-
-	unmap_dma(i, ha);
-
-	/* Set the command state to inactive */
-	SCpnt->host_scribble = NULL;
-
-	SCpnt->scsi_done(SCpnt);
-
-	if (do_trace)
-		printk("%s: ihdlr, exit, irq %d, count %d.\n", ha->board_name,
-				irq, ha->iocount);
-
-      handled:
-	return IRQ_HANDLED;
-      none:
-	return IRQ_NONE;
-}
-
-static irqreturn_t do_interrupt_handler(int dummy, void *shap)
-{
-	struct Scsi_Host *shost;
-	unsigned int j;
-	unsigned long spin_flags;
-	irqreturn_t ret;
-
-	/* Check if the interrupt must be processed by this handler */
-	if ((j = (unsigned int)((char *)shap - sha)) >= num_boards)
-		return IRQ_NONE;
-	shost = sh[j];
-
-	spin_lock_irqsave(shost->host_lock, spin_flags);
-	ret = ihdlr(shost);
-	spin_unlock_irqrestore(shost->host_lock, spin_flags);
-	return ret;
-}
-
-static int eata2x_release(struct Scsi_Host *shost)
-{
-	struct hostdata *ha = (struct hostdata *)shost->hostdata;
-	unsigned int i;
-
-	for (i = 0; i < shost->can_queue; i++)
-		kfree((&ha->cp[i])->sglist);
-
-	for (i = 0; i < shost->can_queue; i++)
-		pci_unmap_single(ha->pdev, ha->cp[i].cp_dma_addr,
-				 sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
-
-	if (ha->sp_cpu_addr)
-		pci_free_consistent(ha->pdev, sizeof(struct mssp),
-				    ha->sp_cpu_addr, ha->sp_dma_addr);
-
-	free_irq(shost->irq, &sha[ha->board_number]);
-
-	if (shost->dma_channel != NO_DMA)
-		free_dma(shost->dma_channel);
-
-	release_region(shost->io_port, shost->n_io_port);
-	scsi_unregister(shost);
-	return 0;
-}
-
-#include "scsi_module.c"
-
-#ifndef MODULE
-__setup("eata=", option_setup);
-#endif				/* end MODULE */

+ 0 - 401
drivers/scsi/eata_generic.h

@@ -1,401 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/********************************************************
-* Header file for eata_dma.c and eata_pio.c		*
-* Linux EATA SCSI drivers				*
-* (c) 1993-96 Michael Neuffer                           *
-*             mike@i-Connect.Net                        *
-*             neuffer@mail.uni-mainz.de                 *
-*********************************************************
-* last change: 96/08/14                                 *
-********************************************************/
-
-
-#ifndef _EATA_GENERIC_H
-#define _EATA_GENERIC_H
-
-
-
-/*********************************************
- * Misc. definitions			     *
- *********************************************/
-
-#define R_LIMIT 0x20000
-
-#define MAXISA	   4
-#define MAXEISA	  16  
-#define MAXPCI	  16
-#define MAXIRQ	  16 
-#define MAXTARGET 16
-#define MAXCHANNEL 3
-
-#define IS_ISA	   'I'
-#define IS_EISA	   'E'
-#define IS_PCI	   'P'
-
-#define BROKEN_INQUIRY	1
-
-#define BUSMASTER       0xff
-#define PIO             0xfe
-
-#define EATA_SIGNATURE	0x45415441     /* BIG ENDIAN coded "EATA" sig.	 */
-
-#define DPT_ID1         0x12
-#define DPT_ID2         0x14
-
-#define ATT_ID1         0x06
-#define ATT_ID2         0x94
-#define ATT_ID3         0x0
-
-#define NEC_ID1         0x38
-#define NEC_ID2         0xa3
-#define NEC_ID3         0x82
-
- 
-#define EATA_CP_SIZE	 44
-
-#define MAX_PCI_DEVICES  32	       /* Maximum # Of Devices Per Bus	 */
-#define MAX_METHOD_2	 16	       /* Max Devices For Method 2	 */
-#define MAX_PCI_BUS	 16	       /* Maximum # Of Busses Allowed	 */
-
-#define SG_SIZE		 64 
-#define SG_SIZE_BIG	 252	       /* max. 8096 elements, 64k */
-
-#define UPPER_DEVICE_QUEUE_LIMIT 64    /* The limit we have to set for the 
-					* device queue to keep the broken 
-					* midlevel SCSI code from producing
-					* bogus timeouts
-					*/
-
-#define TYPE_DISK_QUEUE  16
-#define TYPE_TAPE_QUEUE  4
-#define TYPE_ROM_QUEUE   4
-#define TYPE_OTHER_QUEUE 2
-
-#define FREE	         0
-#define OK	         0
-#define NO_TIMEOUT       0
-#define USED	         1
-#define TIMEOUT	         2
-#define RESET	         4
-#define LOCKED	         8
-#define ABORTED          16
-
-#define READ             0
-#define WRITE            1
-#define OTHER            2
-
-#define HD(cmd)	 ((hostdata *)&(cmd->device->host->hostdata))
-#define CD(cmd)	 ((struct eata_ccb *)(cmd->host_scribble))
-#define SD(host) ((hostdata *)&(host->hostdata))
-
-/***********************************************
- *    EATA Command & Register definitions      *
- ***********************************************/
-#define PCI_REG_DPTconfig	 0x40	 
-#define PCI_REG_PumpModeAddress	 0x44	 
-#define PCI_REG_PumpModeData	 0x48	 
-#define PCI_REG_ConfigParam1	 0x50	 
-#define PCI_REG_ConfigParam2	 0x54	 
-
-
-#define EATA_CMD_PIO_SETUPTEST	 0xc6
-#define EATA_CMD_PIO_READ_CONFIG 0xf0
-#define EATA_CMD_PIO_SET_CONFIG	 0xf1
-#define EATA_CMD_PIO_SEND_CP	 0xf2
-#define EATA_CMD_PIO_RECEIVE_SP	 0xf3
-#define EATA_CMD_PIO_TRUNC	 0xf4
-
-#define EATA_CMD_RESET		 0xf9
-#define EATA_CMD_IMMEDIATE	 0xfa
-
-#define EATA_CMD_DMA_READ_CONFIG 0xfd
-#define EATA_CMD_DMA_SET_CONFIG	 0xfe
-#define EATA_CMD_DMA_SEND_CP	 0xff
-
-#define ECS_EMULATE_SENSE	 0xd4
-
-#define EATA_GENERIC_ABORT       0x00 
-#define EATA_SPECIFIC_RESET      0x01
-#define EATA_BUS_RESET           0x02
-#define EATA_SPECIFIC_ABORT      0x03
-#define EATA_QUIET_INTR          0x04
-#define EATA_COLD_BOOT_HBA       0x06	   /* Only as a last resort	*/
-#define EATA_FORCE_IO            0x07
-
-#define HA_CTRLREG     0x206       /* control register for HBA    */
-#define HA_CTRL_DISINT 0x02        /* CTRLREG: disable interrupts */
-#define HA_CTRL_RESCPU 0x04        /* CTRLREG: reset processor    */
-#define HA_CTRL_8HEADS 0x08        /* CTRLREG: set for drives with* 
-				    * >=8 heads (WD1003 rudimentary :-) */
-
-#define HA_WCOMMAND    0x07	   /* command register offset	*/
-#define HA_WIFC        0x06	   /* immediate command offset  */
-#define HA_WCODE       0x05 
-#define HA_WCODE2      0x04 
-#define HA_WDMAADDR    0x02	   /* DMA address LSB offset	*/  
-#define HA_RAUXSTAT    0x08	   /* aux status register offset*/
-#define HA_RSTATUS     0x07	   /* status register offset	*/
-#define HA_RDATA       0x00	   /* data register (16bit)	*/
-#define HA_WDATA       0x00	   /* data register (16bit)	*/
-
-#define HA_ABUSY       0x01	   /* aux busy bit		*/
-#define HA_AIRQ	       0x02	   /* aux IRQ pending bit	*/
-#define HA_SERROR      0x01	   /* pr. command ended in error*/
-#define HA_SMORE       0x02	   /* more data soon to come	*/
-#define HA_SCORR       0x04	   /* data corrected		*/
-#define HA_SDRQ	       0x08	   /* data request active	*/
-#define HA_SSC	       0x10	   /* seek complete		*/
-#define HA_SFAULT      0x20	   /* write fault		*/
-#define HA_SREADY      0x40	   /* drive ready		*/
-#define HA_SBUSY       0x80	   /* drive busy		*/
-#define HA_SDRDY       HA_SSC+HA_SREADY+HA_SDRQ 
-
-/**********************************************
- * Message definitions			      *
- **********************************************/
-
-#define HA_NO_ERROR	 0x00	/* No Error				*/
-#define HA_ERR_SEL_TO	 0x01	/* Selection Timeout			*/
-#define HA_ERR_CMD_TO	 0x02	/* Command Timeout			*/
-#define HA_BUS_RESET	 0x03	/* SCSI Bus Reset Received		*/
-#define HA_INIT_POWERUP	 0x04	/* Initial Controller Power-up		*/
-#define HA_UNX_BUSPHASE	 0x05	/* Unexpected Bus Phase			*/
-#define HA_UNX_BUS_FREE	 0x06	/* Unexpected Bus Free			*/
-#define HA_BUS_PARITY	 0x07	/* Bus Parity Error			*/
-#define HA_SCSI_HUNG	 0x08	/* SCSI Hung				*/
-#define HA_UNX_MSGRJCT	 0x09	/* Unexpected Message Rejected		*/
-#define HA_RESET_STUCK	 0x0a	/* SCSI Bus Reset Stuck			*/
-#define HA_RSENSE_FAIL	 0x0b	/* Auto Request-Sense Failed		*/
-#define HA_PARITY_ERR	 0x0c	/* Controller Ram Parity Error		*/
-#define HA_CP_ABORT_NA	 0x0d	/* Abort Message sent to non-active cmd */
-#define HA_CP_ABORTED	 0x0e	/* Abort Message sent to active cmd	*/
-#define HA_CP_RESET_NA	 0x0f	/* Reset Message sent to non-active cmd */
-#define HA_CP_RESET	 0x10	/* Reset Message sent to active cmd	*/
-#define HA_ECC_ERR	 0x11	/* Controller Ram ECC Error		*/
-#define HA_PCI_PARITY	 0x12	/* PCI Parity Error			*/
-#define HA_PCI_MABORT	 0x13	/* PCI Master Abort			*/
-#define HA_PCI_TABORT	 0x14	/* PCI Target Abort			*/
-#define HA_PCI_STABORT	 0x15	/* PCI Signaled Target Abort		*/
-
-/**********************************************
- *  Other  definitions			      *
- **********************************************/
-
-struct reg_bit {      /* reading this one will clear the interrupt    */
-    __u8 error:1;     /* previous command ended in an error	      */
-    __u8 more:1;      /* more DATA coming soon, poll BSY & DRQ (PIO)  */
-    __u8 corr:1;      /* data read was successfully corrected with ECC*/
-    __u8 drq:1;	      /* data request active  */     
-    __u8 sc:1;	      /* seek complete	      */
-    __u8 fault:1;     /* write fault	      */
-    __u8 ready:1;     /* drive ready	      */
-    __u8 busy:1;      /* controller busy      */
-};
-
-struct reg_abit {     /* reading this won't clear the interrupt */
-    __u8 abusy:1;     /* auxiliary busy				*/
-    __u8 irq:1;	      /* set when drive interrupt is asserted	*/
-    __u8 dummy:6;
-};
-
-struct eata_register {	    /* EATA register set */
-    __u8 data_reg[2];	    /* R, couldn't figure this one out		*/
-    __u8 cp_addr[4];	    /* W, CP address register			*/
-    union { 
-	__u8 command;	    /* W, command code: [read|set] conf, send CP*/
-	struct reg_bit status;	/* R, see register_bit1			*/
-	__u8 statusbyte;
-    } ovr;   
-    struct reg_abit aux_stat; /* R, see register_bit2			*/
-};
-
-struct get_conf {	      /* Read Configuration Array		*/
-    __u32  len;		      /* Should return 0x22, 0x24, etc		*/
-    __u32 signature;	      /* Signature MUST be "EATA"		*/
-    __u8    version2:4,
-	     version:4;	      /* EATA Version level			*/
-    __u8 OCS_enabled:1,	      /* Overlap Command Support enabled	*/
-	 TAR_support:1,	      /* SCSI Target Mode supported		*/
-	      TRNXFR:1,	      /* Truncate Transfer Cmd not necessary	*
-			       * Only used in PIO Mode			*/
-	MORE_support:1,	      /* MORE supported (only PIO Mode)		*/
-	 DMA_support:1,	      /* DMA supported Driver uses only		*
-			       * this mode				*/
-	   DMA_valid:1,	      /* DRQ value in Byte 30 is valid		*/
-		 ATA:1,	      /* ATA device connected (not supported)	*/
-	   HAA_valid:1;	      /* Hostadapter Address is valid		*/
-
-    __u16 cppadlen;	      /* Number of pad bytes send after CD data *
-			       * set to zero for DMA commands		*/
-    __u8 scsi_id[4];	      /* SCSI ID of controller 2-0 Byte 0 res.	*
-			       * if not, zero is returned		*/
-    __u32  cplen;	      /* CP length: number of valid cp bytes	*/
-    __u32  splen;	      /* Number of bytes returned after		* 
-			       * Receive SP command			*/
-    __u16 queuesiz;	      /* max number of queueable CPs		*/
-    __u16 dummy;
-    __u16 SGsiz;	      /* max number of SG table entries		*/
-    __u8    IRQ:4,	      /* IRQ used this HA			*/
-	 IRQ_TR:1,	      /* IRQ Trigger: 0=edge, 1=level		*/
-	 SECOND:1,	      /* This is a secondary controller		*/
-    DMA_channel:2;	      /* DRQ index, DRQ is 2comp of DRQX	*/
-    __u8 sync;		      /* device at ID 7 tru 0 is running in	*
-			       * synchronous mode, this will disappear	*/
-    __u8   DSBLE:1,	      /* ISA i/o addressing is disabled		*/
-	 FORCADR:1,	      /* i/o address has been forced		*/
-	  SG_64K:1,
-	  SG_UAE:1,
-		:4;
-    __u8  MAX_ID:5,	      /* Max number of SCSI target IDs		*/
-	MAX_CHAN:3;	      /* Number of SCSI busses on HBA		*/
-    __u8 MAX_LUN;	      /* Max number of LUNs			*/
-    __u8	:3,
-	 AUTOTRM:1,
-	 M1_inst:1,
-	 ID_qest:1,	      /* Raidnum ID is questionable		*/
-	  is_PCI:1,	      /* HBA is PCI				*/
-	 is_EISA:1;	      /* HBA is EISA				*/
-    __u8 RAIDNUM;             /* unique HBA identifier                  */
-    __u8 unused[474]; 
-};
-
-struct eata_sg_list
-{
-    __u32 data;
-    __u32 len;
-};
-
-struct eata_ccb {	      /* Send Command Packet structure	    */
- 
-    __u8 SCSI_Reset:1,	      /* Cause a SCSI Bus reset on the cmd	*/
-	   HBA_Init:1,	      /* Cause Controller to reinitialize	*/
-       Auto_Req_Sen:1,	      /* Do Auto Request Sense on errors	*/
-	    scatter:1,	      /* Data Ptr points to a SG Packet		*/
-	     Resrvd:1,	      /* RFU					*/
-	  Interpret:1,	      /* Interpret the SCSI cdb of own use	*/
-	    DataOut:1,	      /* Data Out phase with command		*/
-	     DataIn:1;	      /* Data In phase with command		*/
-    __u8 reqlen;	      /* Request Sense Length			* 
-			       * Valid if Auto_Req_Sen=1		*/
-    __u8 unused[3];
-    __u8  FWNEST:1,	      /* send cmd to phys RAID component	*/
-	 unused2:7;
-    __u8 Phsunit:1,	      /* physical unit on mirrored pair		*/
-	    I_AT:1,	      /* inhibit address translation		*/
-	 I_HBA_C:1,	      /* HBA inhibit caching			*/
-	 unused3:5;
-
-    __u8     cp_id:5,	      /* SCSI Device ID of target		*/ 
-	cp_channel:3;	      /* SCSI Channel # of HBA			*/
-    __u8    cp_lun:3,
-		  :2,
-	 cp_luntar:1,	      /* CP is for target ROUTINE		*/
-	 cp_dispri:1,	      /* Grant disconnect privilege		*/
-       cp_identify:1;	      /* Always TRUE				*/
-    __u8 cp_msg1;	      /* Message bytes 0-3			*/
-    __u8 cp_msg2;
-    __u8 cp_msg3;
-    __u8 cp_cdb[12];	      /* Command Descriptor Block		*/
-    __u32 cp_datalen;	      /* Data Transfer Length			*
-			       * If scatter=1 len of sg package		*/
-    void *cp_viraddr;	      /* address of this ccb			*/
-    __u32 cp_dataDMA;	      /* Data Address, if scatter=1		*
-			       * address of scatter packet		*/
-    __u32 cp_statDMA;	      /* address for Status Packet		*/ 
-    __u32 cp_reqDMA;	      /* Request Sense Address, used if		*
-			       * CP command ends with error		*/
-    /* Additional CP info begins here */
-    __u32 timestamp;	      /* Needed to measure command latency	*/
-    __u32 timeout;
-    __u8 sizeindex;
-    __u8 rw_latency;
-    __u8 retries;
-    __u8 status;	      /* status of this queueslot		*/
-    struct scsi_cmnd *cmd;    /* address of cmd				*/
-    struct eata_sg_list *sg_list;
-};
-
-
-struct eata_sp {
-    __u8 hba_stat:7,	      /* HBA status				*/
-	      EOC:1;	      /* True if command finished		*/
-    __u8 scsi_stat;	      /* Target SCSI status			*/
-    __u8 reserved[2];
-    __u32  residue_len;	      /* Number of bytes not transferred	*/
-    struct eata_ccb *ccb;     /* Address set in COMMAND PACKET		*/
-    __u8 msg[12];
-};
-
-typedef struct hstd {
-    __u8   vendor[9];
-    __u8   name[18];
-    __u8   revision[6];
-    __u8   EATA_revision;
-    __u32  firmware_revision;
-    __u8   HBA_number;
-    __u8   bustype;		 /* bustype of HBA	       */
-    __u8   channel;		 /* # of avail. scsi channels  */
-    __u8   state;		 /* state of HBA	       */
-    __u8   primary;		 /* true if primary	       */
-    __u8        more_support:1,  /* HBA supports MORE flag     */
-           immediate_support:1,  /* HBA supports IMMEDIATE CMDs*/
-              broken_INQUIRY:1;	 /* This is an EISA HBA with   *
-				  * broken INQUIRY	       */
-    __u8   do_latency;		 /* Latency measurement flag   */
-    __u32  reads[13];
-    __u32  writes[13];
-    __u32  reads_lat[12][4];
-    __u32  writes_lat[12][4];
-    __u32  all_lat[4];
-    __u8   resetlevel[MAXCHANNEL]; 
-    __u32  last_ccb;		 /* Last used ccb	       */
-    __u32  cplen;		 /* size of CP in words	       */
-    __u16  cppadlen;		 /* pad length of cp in words  */
-    __u16  queuesize;
-    __u16  sgsize;               /* # of entries in the SG list*/
-    __u16  devflags;		 /* bits set for detected devices */
-    __u8   hostid;		 /* SCSI ID of HBA	       */
-    __u8   moresupport;		 /* HBA supports MORE flag     */
-    struct Scsi_Host *next;	    
-    struct Scsi_Host *prev;
-    struct pci_dev *pdev;	/* PCI device or NULL for non PCI */
-    struct eata_sp sp;		 /* status packet	       */ 
-    struct eata_ccb ccb[0];	 /* ccb array begins here      */
-}hostdata;
-
-/* structure for max. 2 emulated drives */
-struct drive_geom_emul {
-    __u8  trans;		 /* translation flag 1=transl */
-    __u8  channel;		 /* SCSI channel number	      */
-    __u8  HBA;			 /* HBA number (prim/sec)     */
-    __u8  id;			 /* drive id		      */
-    __u8  lun;			 /* drive lun		      */
-    __u32 heads;		 /* number of heads	      */
-    __u32 sectors;		 /* number of sectors	      */
-    __u32 cylinder;		 /* number of cylinders	      */
-};
-
-struct geom_emul {
-    __u8 bios_drives;		 /* number of emulated drives */
-    struct drive_geom_emul drv[2]; /* drive structures	      */
-};
-
-#endif /* _EATA_GENERIC_H */
-
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * tab-width: 8
- * End:
- */

+ 0 - 966
drivers/scsi/eata_pio.c

@@ -1,966 +0,0 @@
-/************************************************************
- *                                                          *
- *               Linux EATA SCSI PIO driver                 *
- *                                                          *
- *  based on the CAM document CAM/89-004 rev. 2.0c,         *
- *  DPT's driver kit, some internal documents and source,   *
- *  and several other Linux scsi drivers and kernel docs.   *
- *                                                          *
- *  The driver currently:                                   *
- *      -supports all EATA-PIO boards                       *
- *      -only supports DASD devices                         *
- *                                                          *
- *  (c)1993-96 Michael Neuffer, Alfred Arnold               *
- *             neuffer@goofy.zdv.uni-mainz.de               *
- *             a.arnold@kfa-juelich.de                      * 
- *                                                          *
- *  Updated 2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> for *
- *   Linux 2.5.x and the newer locking and error handling   *
- *                                                          *
- *  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.                               *
- *							    *
- *  For the avoidance of doubt the "preferred form" of this *
- *  code is one which is in an open non patent encumbered   *
- *  format. Where cryptographic key signing forms part of   *
- *  the process of creating an executable the information   *
- *  including keys needed to generate an equivalently       *
- *  functional executable are deemed to be part of the 	    *
- *  source code are deemed to be part of the source code.   *
- *                                                          *
- ************************************************************
- *  last change: 2002/11/02               OS: Linux 2.5.45  *
- ************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-
-#include "eata_generic.h"
-#include "eata_pio.h"
-
-
-static unsigned int ISAbases[MAXISA] =	{
-	 0x1F0, 0x170, 0x330, 0x230
-};
-
-static unsigned int ISAirqs[MAXISA] = {
-	14, 12, 15, 11
-};
-
-static unsigned char EISAbases[] = { 
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1 
-};
-
-static unsigned int registered_HBAs;
-static struct Scsi_Host *last_HBA;
-static struct Scsi_Host *first_HBA;
-static unsigned char reg_IRQ[16];
-static unsigned char reg_IRQL[16];
-static unsigned long int_counter;
-static unsigned long queue_counter;
-
-static struct scsi_host_template driver_template;
-
-static int eata_pio_show_info(struct seq_file *m, struct Scsi_Host *shost)
-{
-	seq_printf(m, "EATA (Extended Attachment) PIO driver version: "
-		   "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
-	seq_printf(m, "queued commands:     %10ld\n"
-		   "processed interrupts:%10ld\n", queue_counter, int_counter);
-	seq_printf(m, "\nscsi%-2d: HBA %.10s\n",
-		   shost->host_no, SD(shost)->name);
-	seq_printf(m, "Firmware revision: v%s\n",
-		   SD(shost)->revision);
-	seq_puts(m, "IO: PIO\n");
-	seq_printf(m, "Base IO : %#.4x\n", (u32) shost->base);
-	seq_printf(m, "Host Bus: %s\n",
-		   (SD(shost)->bustype == 'P')?"PCI ":
-		   (SD(shost)->bustype == 'E')?"EISA":"ISA ");
-	return 0;
-}
-
-static int eata_pio_release(struct Scsi_Host *sh)
-{
-	hostdata *hd = SD(sh);
-	if (sh->irq && reg_IRQ[sh->irq] == 1)
-		free_irq(sh->irq, NULL);
-	else
-		reg_IRQ[sh->irq]--;
-	if (SD(sh)->channel == 0) {
-		if (sh->io_port && sh->n_io_port)
-			release_region(sh->io_port, sh->n_io_port);
-	}
-	/* At this point the PCI reference can go */
-	if (hd->pdev)
-		pci_dev_put(hd->pdev);
-	return 1;
-}
-
-static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
-{
-	SCp->ptr += Increment;
-	if ((SCp->this_residual -= Increment) == 0) {
-		if ((--SCp->buffers_residual) == 0)
-			SCp->Status = 0;
-		else {
-			SCp->buffer++;
-			SCp->ptr = sg_virt(SCp->buffer);
-			SCp->this_residual = SCp->buffer->length;
-		}
-	}
-}
-
-static irqreturn_t eata_pio_int_handler(int irq, void *dev_id);
-
-static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id)
-{
-	unsigned long flags;
-	struct Scsi_Host *dev = dev_id;
-	irqreturn_t ret;
-
-	spin_lock_irqsave(dev->host_lock, flags);
-	ret = eata_pio_int_handler(irq, dev_id);
-	spin_unlock_irqrestore(dev->host_lock, flags);
-	return ret;
-}
-
-static irqreturn_t eata_pio_int_handler(int irq, void *dev_id)
-{
-	unsigned int eata_stat = 0xfffff;
-	struct scsi_cmnd *cmd;
-	hostdata *hd;
-	struct eata_ccb *cp;
-	unsigned long base;
-	unsigned int x, z;
-	struct Scsi_Host *sh;
-	unsigned short zwickel = 0;
-	unsigned char stat, odd;
-	irqreturn_t ret = IRQ_NONE;
-
-	for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) 
-	{
-		if (sh->irq != irq)
-			continue;
-		if (inb(sh->base + HA_RSTATUS) & HA_SBUSY)
-			continue;
-
-		int_counter++;
-		ret = IRQ_HANDLED;
-
-		hd = SD(sh);
-
-		cp = &hd->ccb[0];
-		cmd = cp->cmd;
-		base = cmd->device->host->base;
-
-		do {
-			stat = inb(base + HA_RSTATUS);
-			if (stat & HA_SDRQ) {
-				if (cp->DataIn) {
-					z = 256;
-					odd = 0;
-					while ((cmd->SCp.Status) && ((z > 0) || (odd))) {
-						if (odd) {
-							*(cmd->SCp.ptr) = zwickel >> 8;
-							IncStat(&cmd->SCp, 1);
-							odd = 0;
-						}
-						x = min_t(unsigned int, z, cmd->SCp.this_residual / 2);
-						insw(base + HA_RDATA, cmd->SCp.ptr, x);
-						z -= x;
-						IncStat(&cmd->SCp, 2 * x);
-						if ((z > 0) && (cmd->SCp.this_residual == 1)) {
-							zwickel = inw(base + HA_RDATA);
-							*(cmd->SCp.ptr) = zwickel & 0xff;
-							IncStat(&cmd->SCp, 1);
-							z--;
-							odd = 1;
-						}
-					}
-					while (z > 0) {
-						zwickel = inw(base + HA_RDATA);
-						z--;
-					}
-				} else {	/* cp->DataOut */
-
-					odd = 0;
-					z = 256;
-					while ((cmd->SCp.Status) && ((z > 0) || (odd))) {
-						if (odd) {
-							zwickel += *(cmd->SCp.ptr) << 8;
-							IncStat(&cmd->SCp, 1);
-							outw(zwickel, base + HA_RDATA);
-							z--;
-							odd = 0;
-						}
-						x = min_t(unsigned int, z, cmd->SCp.this_residual / 2);
-						outsw(base + HA_RDATA, cmd->SCp.ptr, x);
-						z -= x;
-						IncStat(&cmd->SCp, 2 * x);
-						if ((z > 0) && (cmd->SCp.this_residual == 1)) {
-							zwickel = *(cmd->SCp.ptr);
-							zwickel &= 0xff;
-							IncStat(&cmd->SCp, 1);
-							odd = 1;
-						}
-					}
-					while (z > 0 || odd) {
-						outw(zwickel, base + HA_RDATA);
-						z--;
-						odd = 0;
-					}
-				}
-			}
-		}
-		while ((stat & HA_SDRQ) || ((stat & HA_SMORE) && hd->moresupport));
-
-		/* terminate handler if HBA goes busy again, i.e. transfers
-		 * more data */
-
-		if (stat & HA_SBUSY)
-			break;
-
-		/* OK, this is quite stupid, but I haven't found any correct
-		 * way to get HBA&SCSI status so far */
-
-		if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {
-			cmd->result = (DID_OK << 16);
-			hd->devflags |= (1 << cp->cp_id);
-		} else if (hd->devflags & (1 << cp->cp_id))
-			cmd->result = (DID_OK << 16) + 0x02;
-		else
-			cmd->result = (DID_NO_CONNECT << 16);
-
-		if (cp->status == LOCKED) {
-			cp->status = FREE;
-			eata_stat = inb(base + HA_RSTATUS);
-			printk(KERN_CRIT "eata_pio: int_handler, freeing locked " "queueslot\n");
-			return ret;
-		}
-#if DBG_INTR2
-		if (stat != 0x50)
-			printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, cmd->result);
-#endif
-
-		cp->status = FREE;	/* now we can release the slot  */
-
-		cmd->scsi_done(cmd);
-	}
-
-	return ret;
-}
-
-static inline unsigned int eata_pio_send_command(unsigned long base, unsigned char command)
-{
-	unsigned int loop = 50;
-
-	while (inb(base + HA_RSTATUS) & HA_SBUSY)
-		if (--loop == 0)
-			return 1;
-
-	/* Enable interrupts for HBA.  It is not the best way to do it at this
-	 * place, but I hope that it doesn't interfere with the IDE driver 
-	 * initialization this way */
-
-	outb(HA_CTRL_8HEADS, base + HA_CTRLREG);
-
-	outb(command, base + HA_WCOMMAND);
-	return 0;
-}
-
-static int eata_pio_queue_lck(struct scsi_cmnd *cmd,
-		void (*done)(struct scsi_cmnd *))
-{
-	unsigned int x, y;
-	unsigned long base;
-
-	hostdata *hd;
-	struct Scsi_Host *sh;
-	struct eata_ccb *cp;
-
-	queue_counter++;
-
-	hd = HD(cmd);
-	sh = cmd->device->host;
-	base = sh->base;
-
-	/* use only slot 0, as 2001 can handle only one cmd at a time */
-
-	y = x = 0;
-
-	if (hd->ccb[y].status != FREE) {
-
-		DBG(DBG_QUEUE, printk(KERN_EMERG "can_queue %d, x %d, y %d\n", sh->can_queue, x, y));
-#if DEBUG_EATA
-		panic(KERN_EMERG "eata_pio: run out of queue slots cmdno:%ld " "intrno: %ld\n", queue_counter, int_counter);
-#else
-		panic(KERN_EMERG "eata_pio: run out of queue slots....\n");
-#endif
-	}
-
-	cp = &hd->ccb[y];
-
-	memset(cp, 0, sizeof(struct eata_ccb));
-
-	cp->status = USED;	/* claim free slot */
-
-	DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
-		"eata_pio_queue 0x%p, y %d\n", cmd, y));
-
-	cmd->scsi_done = (void *) done;
-
-	if (cmd->sc_data_direction == DMA_TO_DEVICE)
-		cp->DataOut = 1;	/* Output mode */
-	else
-		cp->DataIn = 0;	/* Input mode  */
-
-	cp->Interpret = (cmd->device->id == hd->hostid);
-	cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd));
-	cp->Auto_Req_Sen = 0;
-	cp->cp_reqDMA = 0;
-	cp->reqlen = 0;
-
-	cp->cp_id = cmd->device->id;
-	cp->cp_lun = cmd->device->lun;
-	cp->cp_dispri = 0;
-	cp->cp_identify = 1;
-	memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
-
-	cp->cp_statDMA = 0;
-
-	cp->cp_viraddr = cp;
-	cp->cmd = cmd;
-	cmd->host_scribble = (char *) &hd->ccb[y];
-
-	if (!scsi_bufflen(cmd)) {
-		cmd->SCp.buffers_residual = 1;
-		cmd->SCp.ptr = NULL;
-		cmd->SCp.this_residual = 0;
-		cmd->SCp.buffer = NULL;
-	} else {
-		cmd->SCp.buffer = scsi_sglist(cmd);
-		cmd->SCp.buffers_residual = scsi_sg_count(cmd);
-		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
-		cmd->SCp.this_residual = cmd->SCp.buffer->length;
-	}
-	cmd->SCp.Status = (cmd->SCp.this_residual != 0);	/* TRUE as long as bytes 
-								 * are to transfer */
-
-	if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) {
-		cmd->result = DID_BUS_BUSY << 16;
-		scmd_printk(KERN_NOTICE, cmd,
-			"eata_pio_queue pid 0x%p, HBA busy, "
-			"returning DID_BUS_BUSY, done.\n", cmd);
-		done(cmd);
-		cp->status = FREE;
-		return 0;
-	}
-	/* FIXME: timeout */
-	while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
-		cpu_relax();
-	outsw(base + HA_RDATA, cp, hd->cplen);
-	outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
-	for (x = 0; x < hd->cppadlen; x++)
-		outw(0, base + HA_RDATA);
-
-	DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
-		"Queued base %#.4lx cmd: 0x%p "
-		"slot %d irq %d\n", sh->base, cmd, y, sh->irq));
-
-	return 0;
-}
-
-static DEF_SCSI_QCMD(eata_pio_queue)
-
-static int eata_pio_abort(struct scsi_cmnd *cmd)
-{
-	unsigned int loop = 100;
-
-	DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
-		"eata_pio_abort called pid: 0x%p\n", cmd));
-
-	while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY)
-		if (--loop == 0) {
-			printk(KERN_WARNING "eata_pio: abort, timeout error.\n");
-			return FAILED;
-		}
-	if (CD(cmd)->status == FREE) {
-		DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_NOT_RUNNING\n"));
-		return FAILED;
-	}
-	if (CD(cmd)->status == USED) {
-		DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_BUSY\n"));
-		/* We want to sleep a bit more here */
-		return FAILED;		/* SNOOZE */
-	}
-	if (CD(cmd)->status == RESET) {
-		printk(KERN_WARNING "eata_pio: abort, command reset error.\n");
-		return FAILED;
-	}
-	if (CD(cmd)->status == LOCKED) {
-		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot " "locked.\n"));
-		return FAILED;
-	}
-	panic("eata_pio: abort: invalid slot status\n");
-}
-
-static int eata_pio_host_reset(struct scsi_cmnd *cmd)
-{
-	unsigned int x, limit = 0;
-	unsigned char success = 0;
-	struct scsi_cmnd *sp;
-	struct Scsi_Host *host = cmd->device->host;
-
-	DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
-		"eata_pio_reset called\n"));
-
-	spin_lock_irq(host->host_lock);
-
-	if (HD(cmd)->state == RESET) {
-		printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n");
-		spin_unlock_irq(host->host_lock);
-		return FAILED;
-	}
-
-	/* force all slots to be free */
-
-	for (x = 0; x < cmd->device->host->can_queue; x++) {
-
-		if (HD(cmd)->ccb[x].status == FREE)
-			continue;
-
-		sp = HD(cmd)->ccb[x].cmd;
-		HD(cmd)->ccb[x].status = RESET;
-		printk(KERN_WARNING "eata_pio_reset: slot %d in reset.\n", x);
-
-		if (sp == NULL)
-			panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
-	}
-
-	/* hard reset the HBA  */
-	outb(EATA_CMD_RESET, cmd->device->host->base + HA_WCOMMAND);
-
-	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
-	HD(cmd)->state = RESET;
-
-	spin_unlock_irq(host->host_lock);
-	msleep(3000);
-	spin_lock_irq(host->host_lock);
-
-	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, " "loops %d.\n", limit));
-
-	for (x = 0; x < cmd->device->host->can_queue; x++) {
-
-		/* Skip slots already set free by interrupt */
-		if (HD(cmd)->ccb[x].status != RESET)
-			continue;
-
-		sp = HD(cmd)->ccb[x].cmd;
-		sp->result = DID_RESET << 16;
-
-		/* This mailbox is terminated */
-		printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n", x);
-		HD(cmd)->ccb[x].status = FREE;
-
-		sp->scsi_done(sp);
-	}
-
-	HD(cmd)->state = 0;
-
-	spin_unlock_irq(host->host_lock);
-
-	if (success) {		/* hmmm... */
-		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n"));
-		return SUCCESS;
-	} else {
-		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n"));
-		return FAILED;
-	}
-}
-
-static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned int id, unsigned long cplen, unsigned short cppadlen)
-{
-	struct eata_ccb cp;
-	static char buff[256];
-	int z;
-
-	memset(&cp, 0, sizeof(struct eata_ccb));
-	memset(buff, 0, sizeof(buff));
-
-	cp.DataIn = 1;
-	cp.Interpret = 1;	/* Interpret command */
-
-	cp.cp_datalen = cpu_to_be32(254);
-	cp.cp_dataDMA = cpu_to_be32(0);
-
-	cp.cp_id = id;
-	cp.cp_lun = 0;
-
-	cp.cp_cdb[0] = INQUIRY;
-	cp.cp_cdb[1] = 0;
-	cp.cp_cdb[2] = 0;
-	cp.cp_cdb[3] = 0;
-	cp.cp_cdb[4] = 254;
-	cp.cp_cdb[5] = 0;
-
-	if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
-		return NULL;
-
-	while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
-		cpu_relax();
-
-	outsw(base + HA_RDATA, &cp, cplen);
-	outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
-	for (z = 0; z < cppadlen; z++)
-		outw(0, base + HA_RDATA);
-
-	while (inb(base + HA_RSTATUS) & HA_SBUSY)
-		cpu_relax();
-
-	if (inb(base + HA_RSTATUS) & HA_SERROR)
-		return NULL;
-	else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
-		return NULL;
-	else {
-		insw(base + HA_RDATA, &buff, 127);
-		while (inb(base + HA_RSTATUS) & HA_SDRQ)
-			inw(base + HA_RDATA);
-		return buff;
-	}
-}
-
-static int get_pio_conf_PIO(unsigned long base, struct get_conf *buf)
-{
-	unsigned long loop = HZ / 2;
-	int z;
-	unsigned short *p;
-
-	if (!request_region(base, 9, "eata_pio"))
-		return 0;
-
-	memset(buf, 0, sizeof(struct get_conf));
-
-	while (inb(base + HA_RSTATUS) & HA_SBUSY)
-		if (--loop == 0)
-			goto fail;
-
-	DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#lx\n", base));
-	eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
-
-	loop = 50;
-	for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) {
-		while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
-			if (--loop == 0)
-				goto fail;
-
-		loop = 50;
-		*p = inw(base + HA_RDATA);
-	}
-	if (inb(base + HA_RSTATUS) & HA_SERROR) {
-		DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during "
-					"transfer for HBA at %lx\n", base));
-		goto fail;
-	}
-
-	if (cpu_to_be32(EATA_SIGNATURE) != buf->signature)
-		goto fail;
-
-	DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found "
-				"at %#4lx EATA Level: %x\n",
-				base, (unsigned int) (buf->version)));
-
-	while (inb(base + HA_RSTATUS) & HA_SDRQ)
-		inw(base + HA_RDATA);
-
-	if (!ALLOW_DMA_BOARDS) {
-		for (z = 0; z < MAXISA; z++)
-			if (base == ISAbases[z]) {
-				buf->IRQ = ISAirqs[z];
-				break;
-			}
-	}
-
-	return 1;
-
- fail:
-	release_region(base, 9);
-	return 0;
-}
-
-static void print_pio_config(struct get_conf *gc)
-{
-	printk("Please check values: (read config data)\n");
-	printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", be32_to_cpu(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
-	printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], be16_to_cpu(gc->queuesiz), be16_to_cpu(gc->SGsiz), gc->SECOND);
-	printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n", gc->IRQ, gc->IRQ_TR, gc->FORCADR, gc->MAX_CHAN, gc->ID_qest);
-}
-
-static unsigned int print_selftest(unsigned int base)
-{
-	unsigned char buffer[512];
-#ifdef VERBOSE_SETUP
-	int z;
-#endif
-
-	printk("eata_pio: executing controller self test & setup...\n");
-	while (inb(base + HA_RSTATUS) & HA_SBUSY);
-	outb(EATA_CMD_PIO_SETUPTEST, base + HA_WCOMMAND);
-	do {
-		while (inb(base + HA_RSTATUS) & HA_SBUSY)
-			/* nothing */ ;
-		if (inb(base + HA_RSTATUS) & HA_SDRQ) {
-			insw(base + HA_RDATA, &buffer, 256);
-#ifdef VERBOSE_SETUP
-			/* no beeps please... */
-			for (z = 0; z < 511 && buffer[z]; z++)
-				if (buffer[z] != 7)
-					printk("%c", buffer[z]);
-#endif
-		}
-	} while (inb(base + HA_RSTATUS) & (HA_SBUSY | HA_SDRQ));
-
-	return (!(inb(base + HA_RSTATUS) & HA_SERROR));
-}
-
-static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev)
-{
-	unsigned long size = 0;
-	char *buff;
-	unsigned long cplen;
-	unsigned short cppadlen;
-	struct Scsi_Host *sh;
-	hostdata *hd;
-
-	DBG(DBG_REGISTER, print_pio_config(gc));
-
-	if (gc->DMA_support) {
-		printk("HBA at %#.4lx supports DMA. Please use EATA-DMA driver.\n", base);
-		if (!ALLOW_DMA_BOARDS)
-			return 0;
-	}
-
-	if ((buff = get_pio_board_data(base, gc->IRQ, gc->scsi_id[3], cplen = (cpu_to_be32(gc->cplen) + 1) / 2, cppadlen = (cpu_to_be16(gc->cppadlen) + 1) / 2)) == NULL) {
-		printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", base);
-		return 0;
-	}
-
-	if (!print_selftest(base) && !ALLOW_DMA_BOARDS) {
-		printk("HBA at %#lx failed while performing self test & setup.\n", base);
-		return 0;
-	}
-
-	size = sizeof(hostdata) + (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz));
-
-	sh = scsi_register(&driver_template, size);
-	if (sh == NULL)
-		return 0;
-
-	if (!reg_IRQ[gc->IRQ]) {	/* Interrupt already registered ? */
-		if (!request_irq(gc->IRQ, do_eata_pio_int_handler, 0, "EATA-PIO", sh)) {
-			reg_IRQ[gc->IRQ]++;
-			if (!gc->IRQ_TR)
-				reg_IRQL[gc->IRQ] = 1;	/* IRQ is edge triggered */
-		} else {
-			printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ);
-			return 0;
-		}
-	} else {		/* More than one HBA on this IRQ */
-		if (reg_IRQL[gc->IRQ]) {
-			printk("Can't support more than one HBA on this IRQ,\n" "  if the IRQ is edge triggered. Sorry.\n");
-			return 0;
-		} else
-			reg_IRQ[gc->IRQ]++;
-	}
-
-	hd = SD(sh);
-
-	memset(hd->ccb, 0, (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz)));
-	memset(hd->reads, 0, sizeof(hd->reads));
-
-	strlcpy(SD(sh)->vendor, &buff[8], sizeof(SD(sh)->vendor));
-	strlcpy(SD(sh)->name, &buff[16], sizeof(SD(sh)->name));
-	SD(sh)->revision[0] = buff[32];
-	SD(sh)->revision[1] = buff[33];
-	SD(sh)->revision[2] = buff[34];
-	SD(sh)->revision[3] = '.';
-	SD(sh)->revision[4] = buff[35];
-	SD(sh)->revision[5] = 0;
-
-	switch (be32_to_cpu(gc->len)) {
-	case 0x1c:
-		SD(sh)->EATA_revision = 'a';
-		break;
-	case 0x1e:
-		SD(sh)->EATA_revision = 'b';
-		break;
-	case 0x22:
-		SD(sh)->EATA_revision = 'c';
-		break;
-	case 0x24:
-		SD(sh)->EATA_revision = 'z';
-		break;
-	default:
-		SD(sh)->EATA_revision = '?';
-	}
-
-	if (be32_to_cpu(gc->len) >= 0x22) {
-		if (gc->is_PCI)
-			hd->bustype = IS_PCI;
-		else if (gc->is_EISA)
-			hd->bustype = IS_EISA;
-		else
-			hd->bustype = IS_ISA;
-	} else {
-		if (buff[21] == '4')
-			hd->bustype = IS_PCI;
-		else if (buff[21] == '2')
-			hd->bustype = IS_EISA;
-		else
-			hd->bustype = IS_ISA;
-	}
-
-	SD(sh)->cplen = cplen;
-	SD(sh)->cppadlen = cppadlen;
-	SD(sh)->hostid = gc->scsi_id[3];
-	SD(sh)->devflags = 1 << gc->scsi_id[3];
-	SD(sh)->moresupport = gc->MORE_support;
-	sh->unique_id = base;
-	sh->base = base;
-	sh->io_port = base;
-	sh->n_io_port = 9;
-	sh->irq = gc->IRQ;
-	sh->dma_channel = PIO;
-	sh->this_id = gc->scsi_id[3];
-	sh->can_queue = 1;
-	sh->cmd_per_lun = 1;
-	sh->sg_tablesize = SG_ALL;
-
-	hd->channel = 0;
-
-	hd->pdev = pci_dev_get(pdev);	/* Keep a PCI reference */
-
-	sh->max_id = 8;
-	sh->max_lun = 8;
-
-	if (gc->SECOND)
-		hd->primary = 0;
-	else
-		hd->primary = 1;
-
-	hd->next = NULL;	/* build a linked list of all HBAs */
-	hd->prev = last_HBA;
-	if (hd->prev != NULL)
-		SD(hd->prev)->next = sh;
-	last_HBA = sh;
-	if (first_HBA == NULL)
-		first_HBA = sh;
-	registered_HBAs++;
-	return (1);
-}
-
-static void find_pio_ISA(struct get_conf *buf)
-{
-	int i;
-
-	for (i = 0; i < MAXISA; i++) {
-		if (!ISAbases[i])
-			continue;
-		if (!get_pio_conf_PIO(ISAbases[i], buf))
-			continue;
-		if (!register_pio_HBA(ISAbases[i], buf, NULL))
-			release_region(ISAbases[i], 9);
-		else
-			ISAbases[i] = 0;
-	}
-	return;
-}
-
-static void find_pio_EISA(struct get_conf *buf)
-{
-	u32 base;
-	int i;
-
-#ifdef CHECKPAL
-	u8 pal1, pal2, pal3;
-#endif
-
-	for (i = 0; i < MAXEISA; i++) {
-		if (EISAbases[i]) {	/* Still a possibility ?          */
-
-			base = 0x1c88 + (i * 0x1000);
-#ifdef CHECKPAL
-			pal1 = inb((u16) base - 8);
-			pal2 = inb((u16) base - 7);
-			pal3 = inb((u16) base - 6);
-
-			if (((pal1 == 0x12) && (pal2 == 0x14)) || ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) || ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
-				DBG(DBG_PROBE, printk(KERN_NOTICE "EISA EATA id tags found: " "%x %x %x \n", (int) pal1, (int) pal2, (int) pal3));
-#endif
-				if (get_pio_conf_PIO(base, buf)) {
-					DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
-					if (buf->IRQ) {
-						if (!register_pio_HBA(base, buf, NULL))
-							release_region(base, 9);
-					} else {
-						printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n");
-						release_region(base, 9);
-					}
-				}
-				/* Nothing found here so we take it from the list */
-				EISAbases[i] = 0;
-#ifdef CHECKPAL
-			}
-#endif
-		}
-	}
-	return;
-}
-
-static void find_pio_PCI(struct get_conf *buf)
-{
-#ifndef CONFIG_PCI
-	printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
-#else
-	struct pci_dev *dev = NULL;
-	unsigned long base, x;
-
-	while ((dev = pci_get_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
-		DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", pci_name(dev)));
-		if (pci_enable_device(dev))
-			continue;
-		pci_set_master(dev);
-		base = pci_resource_flags(dev, 0);
-		if (base & IORESOURCE_MEM) {
-			printk("eata_pio: invalid base address of device %s\n", pci_name(dev));
-			continue;
-		}
-		base = pci_resource_start(dev, 0);
-		/* EISA tag there ? */
-		if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
-			continue;	/* Jep, it's forced, so move on  */
-		base += 0x10;	/* Now, THIS is the real address */
-		if (base != 0x1f8) {
-			/* We didn't find it in the primary search */
-			if (get_pio_conf_PIO(base, buf)) {
-				if (buf->FORCADR) {	/* If the address is forced */
-					release_region(base, 9);
-					continue;	/* we'll find it later      */
-				}
-
-				/* OK. We made it till here, so we can go now  
-				 * and register it. We  only have to check and 
-				 * eventually remove it from the EISA and ISA list 
-				 */
-
-				if (!register_pio_HBA(base, buf, dev)) {
-					release_region(base, 9);
-					continue;
-				}
-
-				if (base < 0x1000) {
-					for (x = 0; x < MAXISA; ++x) {
-						if (ISAbases[x] == base) {
-							ISAbases[x] = 0;
-							break;
-						}
-					}
-				} else if ((base & 0x0fff) == 0x0c88) {
-					x = (base >> 12) & 0x0f;
-					EISAbases[x] = 0;
-				}
-			}
-#ifdef CHECK_BLINK
-			else if (check_blink_state(base)) {
-				printk("eata_pio: HBA is in BLINK state.\n" "Consult your HBAs manual to correct this.\n");
-			}
-#endif
-		}
-	}
-#endif				/* #ifndef CONFIG_PCI */
-}
-
-static int eata_pio_detect(struct scsi_host_template *tpnt)
-{
-	struct Scsi_Host *HBA_ptr;
-	struct get_conf gc;
-	int i;
-
-	find_pio_PCI(&gc);
-	find_pio_EISA(&gc);
-	find_pio_ISA(&gc);
-
-	for (i = 0; i < MAXIRQ; i++)
-		if (reg_IRQ[i])
-			request_irq(i, do_eata_pio_int_handler, 0, "EATA-PIO", NULL);
-
-	HBA_ptr = first_HBA;
-
-	if (registered_HBAs != 0) {
-		printk("EATA (Extended Attachment) PIO driver version: %d.%d%s\n"
-		       "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n" "            Alfred Arnold,   a.arnold@kfa-juelich.de\n" "This release only supports DASD devices (harddisks)\n", VER_MAJOR, VER_MINOR, VER_SUB);
-
-		printk("Registered HBAs:\n");
-		printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:" " QS: SG: CPL:\n");
-		for (i = 1; i <= registered_HBAs; i++) {
-			printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4lx   %2d   %d   %d   %c"
-			       "  %2d  %2d  %2d\n",
-			       HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
-			       SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P') ?
-			       "PCI " : (SD(HBA_ptr)->bustype == 'E') ? "EISA" : "ISA ",
-			       HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id,
-			       SD(HBA_ptr)->primary ? 'Y' : 'N', HBA_ptr->can_queue,
-			       HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
-			HBA_ptr = SD(HBA_ptr)->next;
-		}
-	}
-	return (registered_HBAs);
-}
-
-static struct scsi_host_template driver_template = {
-	.proc_name		= "eata_pio",
-	.name              	= "EATA (Extended Attachment) PIO driver",
-	.show_info         	= eata_pio_show_info,
-	.detect            	= eata_pio_detect,
-	.release           	= eata_pio_release,
-	.queuecommand      	= eata_pio_queue,
-	.eh_abort_handler  	= eata_pio_abort,
-	.eh_host_reset_handler	= eata_pio_host_reset,
-	.use_clustering    	= ENABLE_CLUSTERING,
-};
-
-MODULE_AUTHOR("Michael Neuffer, Alfred Arnold");
-MODULE_DESCRIPTION("EATA SCSI PIO driver");
-MODULE_LICENSE("GPL");
-
-#include "scsi_module.c"

+ 0 - 54
drivers/scsi/eata_pio.h

@@ -1,54 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/********************************************************
-* Header file for eata_pio.c Linux EATA-PIO SCSI driver *
-* (c) 1993-96 Michael Neuffer  	                        *
-*********************************************************
-* last change: 2002/11/02				*
-********************************************************/
-
-
-#ifndef _EATA_PIO_H
-#define _EATA_PIO_H
-
-#define VER_MAJOR 0
-#define VER_MINOR 0
-#define VER_SUB	  "1b"
-
-/************************************************************************
- * Here you can switch parts of the code on and of			*
- ************************************************************************/
-
-#define VERBOSE_SETUP		/* show startup screen of 2001 */
-#define ALLOW_DMA_BOARDS 1
-
-/************************************************************************
- * Debug options.							* 
- * Enable DEBUG and whichever options you require.			*
- ************************************************************************/
-#define DEBUG_EATA	1	/* Enable debug code.                       */
-#define DPT_DEBUG	0	/* Bobs special                             */
-#define DBG_DELAY	0	/* Build in delays so debug messages can be
-				 * be read before they vanish of the top of
-				 * the screen!
-				 */
-#define DBG_PROBE	0	/* Debug probe routines.                    */
-#define DBG_ISA		0	/* Trace ISA routines                       */
-#define DBG_EISA	0	/* Trace EISA routines                      */
-#define DBG_PCI		0	/* Trace PCI routines                       */
-#define DBG_PIO		0	/* Trace get_config_PIO                     */
-#define DBG_COM		0	/* Trace command call                       */
-#define DBG_QUEUE	0	/* Trace command queueing.                  */
-#define DBG_INTR	0	/* Trace interrupt service routine.         */
-#define DBG_INTR2	0	/* Trace interrupt service routine.         */
-#define DBG_PROC	0	/* Debug proc-fs related statistics         */
-#define DBG_PROC_WRITE	0
-#define DBG_REGISTER	0	/* */
-#define DBG_ABNORM	1	/* Debug abnormal actions (reset, abort)    */
-
-#if DEBUG_EATA
-#define DBG(x, y)   if ((x)) {y;}
-#else
-#define DBG(x, y)
-#endif
-
-#endif				/* _EATA_PIO_H */

+ 0 - 2
drivers/scsi/esas2r/esas2r.h

@@ -962,7 +962,6 @@ struct esas2r_adapter {
  * Function Declarations
  * Function Declarations
  * SCSI functions
  * SCSI functions
  */
  */
-int esas2r_release(struct Scsi_Host *);
 const char *esas2r_info(struct Scsi_Host *);
 const char *esas2r_info(struct Scsi_Host *);
 int esas2r_write_params(struct esas2r_adapter *a, struct esas2r_request *rq,
 int esas2r_write_params(struct esas2r_adapter *a, struct esas2r_request *rq,
 			struct esas2r_sas_nvram *data);
 			struct esas2r_sas_nvram *data);
@@ -984,7 +983,6 @@ int esas2r_target_reset(struct scsi_cmnd *cmd);
 /* Internal functions */
 /* Internal functions */
 int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid,
 int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid,
 			int index);
 			int index);
-int esas2r_cleanup(struct Scsi_Host *host);
 int esas2r_read_fw(struct esas2r_adapter *a, char *buf, long off, int count);
 int esas2r_read_fw(struct esas2r_adapter *a, char *buf, long off, int count);
 int esas2r_write_fw(struct esas2r_adapter *a, const char *buf, long off,
 int esas2r_write_fw(struct esas2r_adapter *a, const char *buf, long off,
 		    int count);
 		    int count);

+ 0 - 21
drivers/scsi/esas2r/esas2r_init.c

@@ -661,27 +661,6 @@ void esas2r_kill_adapter(int i)
 	}
 	}
 }
 }
 
 
-int esas2r_cleanup(struct Scsi_Host *host)
-{
-	struct esas2r_adapter *a;
-	int index;
-
-	if (host == NULL) {
-		int i;
-
-		esas2r_debug("esas2r_cleanup everything");
-		for (i = 0; i < MAX_ADAPTERS; i++)
-			esas2r_kill_adapter(i);
-		return -1;
-	}
-
-	esas2r_debug("esas2r_cleanup called for host %p", host);
-	a = (struct esas2r_adapter *)host->hostdata;
-	index = a->index;
-	esas2r_kill_adapter(index);
-	return index;
-}
-
 int esas2r_suspend(struct pci_dev *pdev, pm_message_t state)
 int esas2r_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 {
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	struct Scsi_Host *host = pci_get_drvdata(pdev);

+ 4 - 68
drivers/scsi/esas2r/esas2r_main.c

@@ -235,7 +235,6 @@ static struct scsi_host_template driver_template = {
 	.module				= THIS_MODULE,
 	.module				= THIS_MODULE,
 	.show_info			= esas2r_show_info,
 	.show_info			= esas2r_show_info,
 	.name				= ESAS2R_LONGNAME,
 	.name				= ESAS2R_LONGNAME,
-	.release			= esas2r_release,
 	.info				= esas2r_info,
 	.info				= esas2r_info,
 	.ioctl				= esas2r_ioctl,
 	.ioctl				= esas2r_ioctl,
 	.queuecommand			= esas2r_queuecommand,
 	.queuecommand			= esas2r_queuecommand,
@@ -520,44 +519,16 @@ static int esas2r_probe(struct pci_dev *pcid,
 
 
 static void esas2r_remove(struct pci_dev *pdev)
 static void esas2r_remove(struct pci_dev *pdev)
 {
 {
-	struct Scsi_Host *host;
-	int index;
-
-	if (pdev == NULL) {
-		esas2r_log(ESAS2R_LOG_WARN, "esas2r_remove pdev==NULL");
-		return;
-	}
-
-	host = pci_get_drvdata(pdev);
-
-	if (host == NULL) {
-		/*
-		 * this can happen if pci_set_drvdata was already called
-		 * to clear the host pointer.  if this is the case, we
-		 * are okay; this channel has already been cleaned up.
-		 */
-
-		return;
-	}
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
 
 
 	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
 	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
 		       "esas2r_remove(%p) called; "
 		       "esas2r_remove(%p) called; "
 		       "host:%p", pdev,
 		       "host:%p", pdev,
 		       host);
 		       host);
 
 
-	index = esas2r_cleanup(host);
-
-	if (index < 0)
-		esas2r_log_dev(ESAS2R_LOG_WARN, &(pdev->dev),
-			       "unknown host in %s",
-			       __func__);
-
+	esas2r_kill_adapter(a->index);
 	found_adapters--;
 	found_adapters--;
-
-	/* if this was the last adapter, clean up the rest of the driver */
-
-	if (found_adapters == 0)
-		esas2r_cleanup(NULL);
 }
 }
 
 
 static int __init esas2r_init(void)
 static int __init esas2r_init(void)
@@ -638,30 +609,7 @@ static int __init esas2r_init(void)
 	for (i = 0; i < MAX_ADAPTERS; i++)
 	for (i = 0; i < MAX_ADAPTERS; i++)
 		esas2r_adapters[i] = NULL;
 		esas2r_adapters[i] = NULL;
 
 
-	/* initialize */
-
-	driver_template.module = THIS_MODULE;
-
-	if (pci_register_driver(&esas2r_pci_driver) != 0)
-		esas2r_log(ESAS2R_LOG_CRIT, "pci_register_driver FAILED");
-	else
-		esas2r_log(ESAS2R_LOG_INFO, "pci_register_driver() OK");
-
-	if (!found_adapters) {
-		pci_unregister_driver(&esas2r_pci_driver);
-		esas2r_cleanup(NULL);
-
-		esas2r_log(ESAS2R_LOG_CRIT,
-			   "driver will not be loaded because no ATTO "
-			   "%s devices were found",
-			   ESAS2R_DRVR_NAME);
-		return -1;
-	} else {
-		esas2r_log(ESAS2R_LOG_INFO, "found %d adapters",
-			   found_adapters);
-	}
-
-	return 0;
+	return pci_register_driver(&esas2r_pci_driver);
 }
 }
 
 
 /* Handle ioctl calls to "/proc/scsi/esas2r/ATTOnode" */
 /* Handle ioctl calls to "/proc/scsi/esas2r/ATTOnode" */
@@ -753,18 +701,6 @@ int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh)
 
 
 }
 }
 
 
-int esas2r_release(struct Scsi_Host *sh)
-{
-	esas2r_log_dev(ESAS2R_LOG_INFO, &(sh->shost_gendev),
-		       "esas2r_release() called");
-
-	esas2r_cleanup(sh);
-	if (sh->irq)
-		free_irq(sh->irq, NULL);
-	scsi_unregister(sh);
-	return 0;
-}
-
 const char *esas2r_info(struct Scsi_Host *sh)
 const char *esas2r_info(struct Scsi_Host *sh)
 {
 {
 	struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata;
 	struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata;

+ 0 - 1783
drivers/scsi/fdomain.c

@@ -1,1783 +0,0 @@
-/* fdomain.c -- Future Domain TMC-16x0 SCSI driver
- * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Mon Dec 28 21:59:02 1998 by faith@acm.org
- * Author: Rickard E. Faith, faith@cs.unc.edu
- * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org)
- * Shared IRQ supported added 7/7/2001  Alan Cox <alan@lxorguk.ukuu.org.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, 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.
-
- **************************************************************************
-
- SUMMARY:
-
- 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 are 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 ?
- LILO/INSMOD command-line options:
-    fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]
-
-
-    
- 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.
-
- 
- 
- THANKS:
-
- Thanks to Adaptec for providing PCI boards for testing.  This finally
- enabled me to test the PCI detection and correct it for PCI boards that do
- not have a BIOS at a standard ISA location.  For PCI boards, LILO/INSMOD
- command-line options should no longer be needed.  --RF 18Nov98
-
-
- 
- 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.  The latest and greatest board may not work with this driver.  If
- you have to patch this driver so that it will recognize your board's BIOS
- signature, then the driver may fail to function after the board is
- detected.
-
- 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.  If you have BIOS version 3.4 or 3.5, and have
- more than one drive, then the drive ordering will be the reverse of that
- which you see under DOS.  For example, under DOS SCSI ID 0 will be D: and
- SCSI ID 1 will be C: (the boot device).  Under Linux, SCSI ID 0 will be
- /dev/sda and SCSI ID 1 will be /dev/sdb.  The Linux ordering is consistent
- with that provided by all the other SCSI drivers for Linux.  If you want
- this changed, you will probably have to patch the higher level SCSI code.
- If you do so, please send me patches that are protected by #ifdefs.
-
- If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
- your board.  Please refer to the Seagate driver for more information and
- possible support.
-
- 
- 
- HISTORY:
-
- Linux       Driver      Driver
- Version     Version     Date         Support/Notes
-
-             0.0          3 May 1992  V2.0 BIOS; 1800 chip
- 0.97        1.9         28 Jul 1992
- 0.98.6      3.1         27 Nov 1992
- 0.99        3.2          9 Dec 1992
-
- 0.99.3      3.3         10 Jan 1993  V3.0 BIOS
- 0.99.5      3.5         18 Feb 1993
- 0.99.10     3.6         15 May 1993  V3.2 BIOS; 18C50 chip
- 0.99.11     3.17         3 Jul 1993  (now under RCS)
- 0.99.12     3.18        13 Aug 1993
- 0.99.14     5.6         31 Oct 1993  (reselection code removed)
-
- 0.99.15     5.9         23 Jan 1994  V3.4 BIOS (preliminary)
- 1.0.8/1.1.1 5.15         1 Apr 1994  V3.4 BIOS; 18C30 chip (preliminary)
- 1.0.9/1.1.3 5.16         7 Apr 1994  V3.4 BIOS; 18C30 chip
- 1.1.38      5.18        30 Jul 1994  36C70 chip (PCI version of 18C30)
- 1.1.62      5.20         2 Nov 1994  V3.5 BIOS
- 1.1.73      5.22         7 Dec 1994  Quantum ISA-200S board; V2.0 BIOS
-
- 1.1.82      5.26        14 Jan 1995  V3.5 BIOS; TMC-1610M/MER/MEX board
- 1.2.10      5.28         5 Jun 1995  Quantum ISA-250MG board; V2.0, V2.01 BIOS
- 1.3.4       5.31        23 Jun 1995  PCI BIOS-32 detection (preliminary)
- 1.3.7       5.33         4 Jul 1995  PCI BIOS-32 detection
- 1.3.28      5.36        17 Sep 1995  V3.61 BIOS; LILO command-line support
- 1.3.34      5.39        12 Oct 1995  V3.60 BIOS; /proc
- 1.3.72      5.39         8 Feb 1996  Adaptec AHA-2920 board
- 1.3.85      5.41         4 Apr 1996
- 2.0.12      5.44         8 Aug 1996  Use ID 7 for all PCI cards
- 2.1.1       5.45         2 Oct 1996  Update ROM accesses for 2.1.x
- 2.1.97      5.46	 23 Apr 1998  Rewritten PCI detection routines [mj]
- 2.1.11x     5.47	  9 Aug 1998  Touched for 8 SCSI disk majors support
-             5.48        18 Nov 1998  BIOS no longer needed for PCI detection
- 2.2.0       5.50        28 Dec 1998  Support insmod parameters
- 
-
- 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.
-
-
- 
- NOTES ON REFERENCES:
-
- The Maxtor manuals were free.  Maxtor telephone technical support is
- great!
-
- The Future Domain manuals were $25 and $35.  They document the chip, not
- the TMC-16x0 boards, so some information I had to guess at.  In 1992,
- Future Domain sold DOS BIOS source for $250 and the UN*X driver source was
- $750, but these required a non-disclosure agreement, so even if I could
- have afforded them, they would *not* have been useful for writing this
- publicly distributable driver.  Future Domain technical support has
- provided some information on the phone and have sent a few useful FAXs.
- They have been much more helpful since they started to recognize that the
- word "Linux" refers to an operating system :-).
-
- 
-
- ALPHA TESTERS:
-
- There are many other alpha testers that come and go as the driver
- develops.  The people listed here were most helpful in times of greatest
- need (mostly early on -- I've probably left out a few worthy people in
- more recent times):
-
- Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken
- Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@bruin@sterbbs.nl), Sakari
- Aaltonen (sakaria@vipunen.hit.fi), John Rice (rice@xanth.cs.odu.edu), Brad
- Yearwood (brad@optilink.com), and Ray Toy (toy@soho.crd.ge.com).
-
- Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me
- his 18C50-based card for debugging.  He is the sole reason that this
- driver works with the 18C50 chip.
-
- Thanks to Dave Newman (dnewman@crl.com) for providing initial patches for
- the version 3.4 BIOS.
-
- Thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for providing
- patches that support the TMC-3260, a PCI bus card with the 36C70 chip.
- The 36C70 chip appears to be "completely compatible" with the 18C30 chip.
-
- Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the
- patch for the version 3.5 BIOS.
-
- Thanks for Stephen Henson (shenson@nyx10.cs.du.edu) for providing the
- patch for the Quantum ISA-200S SCSI adapter.
- 
- Thanks to Adam Bowen for the signature to the 1610M/MER/MEX scsi cards, to
- Martin Andrews (andrewm@ccfadm.eeg.ccf.org) for the signature to some
- random TMC-1680 repackaged by IBM; and to Mintak Ng (mintak@panix.com) for
- the version 3.61 BIOS signature.
-
- Thanks for Mark Singer (elf@netcom.com) and Richard Simpson
- (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective
- work on the Quantum RAM layout.
-
- Special thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for
- providing patches for proper PCI BIOS32-mediated detection of the TMC-3260
- card (a PCI bus card with the 36C70 chip).  Please send James PCI-related
- bug reports.
-
- Thanks to Tom Cavin (tec@usa1.com) for preliminary command-line option
- patches.
-
- New PCI detection code written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
-
- Insmod parameter code based on patches from Daniel Graham
- <graham@balance.uoregon.edu>. 
- 
- All of the alpha testers deserve much thanks.
-
-
-
- NOTES ON USER DEFINABLE OPTIONS:
-
- DEBUG: This turns on the printing of various debug information.
-
- ENABLE_PARITY: This turns on SCSI parity checking.  With the current
- driver, all attached devices must support SCSI parity.  If none of your
- devices support parity, then you can probably get the driver to work by
- turning this option off.  I have no way of testing this, however, and it
- would appear that no one ever uses this option.
-
- 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.  I have found that 2 is a good number, but throughput may
- be increased by changing this value to values which are close to 2.
- Please let me know if you try any different values.
-
- RESELECTION: This is no longer an option, since I gave up trying to
- implement it in version 4.x of this driver.  It did not improve
- performance at all and made the driver unstable (because I never found one
- of the two race conditions which were introduced by the multiple
- outstanding command code).  The instability seems a very high price to pay
- just so that you don't have to wait for the tape to rewind.  If you want
- this feature implemented, send me patches.  I'll be happy to send a copy
- of my (broken) driver to anyone who would like to see a copy.
-
- **************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/proc_fs.h>
-#include <linux/pci.h>
-#include <linux/stat.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <scsi/scsicam.h>
-
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_ioctl.h>
-#include "fdomain.h"
-
-#ifndef PCMCIA
-MODULE_AUTHOR("Rickard E. Faith");
-MODULE_DESCRIPTION("Future domain SCSI driver");
-MODULE_LICENSE("GPL");
-#endif
-
-  
-#define VERSION          "$Revision: 5.51 $"
-
-/* START OF USER DEFINABLE OPTIONS */
-
-#define DEBUG            0	/* Enable debugging output */
-#define ENABLE_PARITY    1	/* Enable SCSI Parity */
-#define FIFO_COUNT       2	/* Number of 512 byte blocks before INTR */
-
-/* END OF USER DEFINABLE OPTIONS */
-
-#if DEBUG
-#define EVERY_ACCESS     0	/* Write a line on every scsi access */
-#define ERRORS_ONLY      1	/* Only write a line if there is an error */
-#define DEBUG_DETECT     0	/* Debug fdomain_16x0_detect() */
-#define DEBUG_MESSAGES   1	/* Debug MESSAGE IN phase */
-#define DEBUG_ABORT      1	/* Debug abort() routine */
-#define DEBUG_RESET      1	/* Debug reset() routine */
-#define DEBUG_RACE       1      /* Debug interrupt-driven race condition */
-#else
-#define EVERY_ACCESS     0	/* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
-#define ERRORS_ONLY      0
-#define DEBUG_DETECT     0
-#define DEBUG_MESSAGES   0
-#define DEBUG_ABORT      0
-#define DEBUG_RESET      0
-#define DEBUG_RACE       0
-#endif
-
-/* Errors are reported on the line, so we don't need to report them again */
-#if EVERY_ACCESS
-#undef ERRORS_ONLY
-#define ERRORS_ONLY      0
-#endif
-
-#if ENABLE_PARITY
-#define PARITY_MASK      0x08
-#else
-#define PARITY_MASK      0x00
-#endif
-
-enum chip_type {
-   unknown          = 0x00,
-   tmc1800          = 0x01,
-   tmc18c50         = 0x02,
-   tmc18c30         = 0x03,
-};
-
-enum {
-   in_arbitration   = 0x02,
-   in_selection     = 0x04,
-   in_other         = 0x08,
-   disconnect       = 0x10,
-   aborted          = 0x20,
-   sent_ident       = 0x40,
-};
-
-enum in_port_type {
-   Read_SCSI_Data   =  0,
-   SCSI_Status      =  1,
-   TMC_Status       =  2,
-   FIFO_Status      =  3,	/* tmc18c50/tmc18c30 only */
-   Interrupt_Cond   =  4,	/* tmc18c50/tmc18c30 only */
-   LSB_ID_Code      =  5,
-   MSB_ID_Code      =  6,
-   Read_Loopback    =  7,
-   SCSI_Data_NoACK  =  8,
-   Interrupt_Status =  9,
-   Configuration1   = 10,
-   Configuration2   = 11,	/* tmc18c50/tmc18c30 only */
-   Read_FIFO        = 12,
-   FIFO_Data_Count  = 14
-};
-
-enum out_port_type {
-   Write_SCSI_Data  =  0,
-   SCSI_Cntl        =  1,
-   Interrupt_Cntl   =  2,
-   SCSI_Mode_Cntl   =  3,
-   TMC_Cntl         =  4,
-   Memory_Cntl      =  5,	/* tmc18c50/tmc18c30 only */
-   Write_Loopback   =  7,
-   IO_Control       = 11,	/* tmc18c30 only */
-   Write_FIFO       = 12
-};
-
-/* .bss will zero all the static variables below */
-static int               port_base;
-static unsigned long     bios_base;
-static void __iomem *    bios_mem;
-static int               bios_major;
-static int               bios_minor;
-static int               PCI_bus;
-#ifdef CONFIG_PCI
-static struct pci_dev	*PCI_dev;
-#endif
-static int               Quantum;	/* Quantum board variant */
-static int               interrupt_level;
-static volatile int      in_command;
-static struct scsi_cmnd  *current_SC;
-static enum chip_type    chip              = unknown;
-static int               adapter_mask;
-static int               this_id;
-static int               setup_called;
-
-#if DEBUG_RACE
-static volatile int      in_interrupt_flag;
-#endif
-
-static int               FIFO_Size = 0x2000; /* 8k FIFO for
-						pre-tmc18c30 chips */
-
-static irqreturn_t       do_fdomain_16x0_intr( int irq, void *dev_id );
-/* Allow insmod parameters to be like LILO parameters.  For example:
-   insmod fdomain fdomain=0x140,11 */
-static char * fdomain = NULL;
-module_param(fdomain, charp, 0);
-
-#ifndef PCMCIA
-
-static unsigned long addresses[] = {
-   0xc8000,
-   0xca000,
-   0xce000,
-   0xde000,
-   0xcc000,		/* Extra addresses for PCI boards */
-   0xd0000,
-   0xe0000,
-};
-#define ADDRESS_COUNT ARRAY_SIZE(addresses)
-
-static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
-#define PORT_COUNT ARRAY_SIZE(ports)
-
-static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
-
-#endif /* !PCMCIA */
-
-/*
-
-  READ THIS BEFORE YOU ADD A SIGNATURE!
-
-  READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME!
-
-  READ EVERY WORD, ESPECIALLY THE WORD *NOT*
-
-  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.
-
-  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.)
-
-*/
-
-#ifndef PCMCIA
-
-static struct signature {
-   const char *signature;
-   int  sig_offset;
-   int  sig_length;
-   int  major_bios_version;
-   int  minor_bios_version;
-   int  flag; /* 1 == PCI_bus, 2 == ISA_200S, 3 == ISA_250MG, 4 == ISA_200S */
-} signatures[] = {
-   /*          1         2         3         4         5         6 */
-   /* 123456789012345678901234567890123456789012345678901234567890 */
-   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89",  5, 50,  2,  0, 0 },
-   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89",  5, 50,  2,  0, 0 },
-   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50,  2,  0, 2 },
-   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0",        73, 43,  2,  0, 3 },
-   { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.",            72, 39,  2,  0, 4 },
-   { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92",        5, 44,  3,  0, 0 },
-   { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93",        5, 44,  3,  2, 0 },
-   { "IBM F1 P2 BIOS v1.0104/29/93",                        5, 28,  3, -1, 0 },
-   { "Future Domain Corp. V1.0008/18/93",                   5, 33,  3,  4, 0 },
-   { "Future Domain Corp. V1.0008/18/93",                  26, 33,  3,  4, 1 },
-   { "Adaptec AHA-2920 PCI-SCSI Card",                     42, 31,  3, -1, 1 },
-   { "IBM F1 P264/32",                                      5, 14,  3, -1, 1 },
-				/* This next signature may not be a 3.5 bios */
-   { "Future Domain Corp. V2.0108/18/93",                   5, 33,  3,  5, 0 },
-   { "FUTURE DOMAIN CORP.  V3.5008/18/93",                  5, 34,  3,  5, 0 },
-   { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5",        5, 44,  3,  5, 0 },
-   { "FUTURE DOMAIN CORP.  V3.6008/18/93",                  5, 34,  3,  6, 0 },
-   { "FUTURE DOMAIN CORP.  V3.6108/18/93",                  5, 34,  3,  6, 0 },
-   { "FUTURE DOMAIN TMC-18XX",                              5, 22, -1, -1, 0 },
-
-   /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGNATURE
-    Also, fix the disk geometry code for your signature and send your
-    changes for faith@cs.unc.edu.  Above all, do *NOT* change any old
-    signatures!
-
-    Note that the last line will match a "generic" 18XX bios.  Because
-    Future Domain has changed the host SCSI ID and/or the location of the
-    geometry information in the on-board RAM area for each of the first
-    three BIOS's, it is still important to enter a fully qualified
-    signature in the table for any new BIOS's (after the host SCSI ID and
-    geometry location are verified). */
-};
-
-#define SIGNATURE_COUNT ARRAY_SIZE(signatures)
-
-#endif /* !PCMCIA */
-
-static void print_banner( struct Scsi_Host *shpnt )
-{
-   if (!shpnt) return;		/* This won't ever happen */
-
-   if (bios_major < 0 && bios_minor < 0) {
-      printk(KERN_INFO "scsi%d: <fdomain> No BIOS; using scsi id %d\n",
-	      shpnt->host_no, shpnt->this_id);
-   } else {
-      printk(KERN_INFO "scsi%d: <fdomain> BIOS version ", shpnt->host_no);
-
-      if (bios_major >= 0) printk("%d.", bios_major);
-      else                 printk("?.");
-
-      if (bios_minor >= 0) printk("%d", bios_minor);
-      else                 printk("?.");
-
-      printk( " at 0x%lx using scsi id %d\n",
-	      bios_base, shpnt->this_id );
-   }
-
-				/* If this driver works for later FD PCI
-				   boards, we will have to modify banner
-				   for additional PCI cards, but for now if
-				   it's PCI it's a TMC-3260 - JTM */
-   printk(KERN_INFO "scsi%d: <fdomain> %s chip at 0x%x irq ",
-	   shpnt->host_no,
-	   chip == tmc1800 ? "TMC-1800" : (chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30") : "Unknown")),
-	   port_base);
-
-   if (interrupt_level)
-   	printk("%d", interrupt_level);
-   else
-        printk("<none>");
-
-   printk( "\n" );
-}
-
-int fdomain_setup(char *str)
-{
-	int ints[4];
-
-	(void)get_options(str, ARRAY_SIZE(ints), ints);
-
-	if (setup_called++ || ints[0] < 2 || ints[0] > 3) {
-		printk(KERN_INFO "scsi: <fdomain> Usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n");
-		printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
-		return 0;
-	}
-
-	port_base       = ints[0] >= 1 ? ints[1] : 0;
-	interrupt_level = ints[0] >= 2 ? ints[2] : 0;
-	this_id         = ints[0] >= 3 ? ints[3] : 0;
-   
-	bios_major = bios_minor = -1; /* Use geometry for BIOS version >= 3.4 */
-	++setup_called;
-	return 1;
-}
-
-__setup("fdomain=", fdomain_setup);
-
-
-static void do_pause(unsigned amount)	/* Pause for amount*10 milliseconds */
-{
-	mdelay(10*amount);
-}
-
-static inline void fdomain_make_bus_idle( void )
-{
-   outb(0, port_base + SCSI_Cntl);
-   outb(0, port_base + SCSI_Mode_Cntl);
-   if (chip == tmc18c50 || chip == tmc18c30)
-	 outb(0x21 | PARITY_MASK, port_base + TMC_Cntl); /* Clear forced intr. */
-   else
-	 outb(0x01 | PARITY_MASK, port_base + TMC_Cntl);
-}
-
-static int fdomain_is_valid_port( int port )
-{
-#if DEBUG_DETECT 
-   printk( " (%x%x),",
-	   inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
-#endif
-
-   /* The MCA ID is a unique id for each MCA compatible board.  We
-      are using ISA boards, but Future Domain provides the MCA ID
-      anyway.  We can use this ID to ensure that this is a Future
-      Domain TMC-1660/TMC-1680.
-    */
-
-   if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */
-      if (inb( port + LSB_ID_Code ) != 0x27) return 0;
-      if (inb( port + MSB_ID_Code ) != 0x61) return 0;
-      chip = tmc1800;
-   } else {				    /* test for 0xe960 id */
-      if (inb( port + MSB_ID_Code ) != 0x60) return 0;
-      chip = tmc18c50;
-
-				/* Try to toggle 32-bit mode.  This only
-				   works on an 18c30 chip.  (User reports
-				   say this works, so we should switch to
-				   it in the near future.) */
-
-      outb( 0x80, port + IO_Control );
-      if ((inb( port + Configuration2 ) & 0x80) == 0x80) {
-	 outb( 0x00, port + IO_Control );
-	 if ((inb( port + Configuration2 ) & 0x80) == 0x00) {
-	    chip = tmc18c30;
-	    FIFO_Size = 0x800;	/* 2k FIFO */
-	 }
-      }
-				/* If that failed, we are an 18c50. */
-   }
-
-   return 1;
-}
-
-static int fdomain_test_loopback( void )
-{
-   int i;
-   int result;
-
-   for (i = 0; i < 255; i++) {
-      outb( i, port_base + Write_Loopback );
-      result = inb( port_base + Read_Loopback );
-      if (i != result)
-	    return 1;
-   }
-   return 0;
-}
-
-#ifndef PCMCIA
-
-/* fdomain_get_irq assumes that we have a valid MCA ID for a
-   TMC-1660/TMC-1680 Future Domain board.  Now, check to be sure the
-   bios_base matches these ports.  If someone was unlucky enough to have
-   purchased more than one Future Domain board, then they will have to
-   modify this code, as we only detect one board here.  [The one with the
-   lowest bios_base.]
-
-   Note that this routine is only used for systems without a PCI BIOS32
-   (e.g., ISA bus).  For PCI bus systems, this routine will likely fail
-   unless one of the IRQs listed in the ints array is used by the board.
-   Sometimes it is possible to use the computer's BIOS setup screen to
-   configure a PCI system so that one of these IRQs will be used by the
-   Future Domain card. */
-
-static int fdomain_get_irq( int base )
-{
-   int options = inb(base + Configuration1);
-
-#if DEBUG_DETECT
-   printk("scsi: <fdomain> Options = %x\n", options);
-#endif
- 
-   /* Check for board with lowest bios_base --
-      this isn't valid for the 18c30 or for
-      boards on the PCI bus, so just assume we
-      have the right board. */
-
-   if (chip != tmc18c30 && !PCI_bus && addresses[(options & 0xc0) >> 6 ] != bios_base)
-   	return 0;
-   return ints[(options & 0x0e) >> 1];
-}
-
-static int fdomain_isa_detect( int *irq, int *iobase )
-{
-   int i, j;
-   int base = 0xdeadbeef;
-   int flag = 0;
-
-#if DEBUG_DETECT
-   printk( "scsi: <fdomain> fdomain_isa_detect:" );
-#endif
-
-   for (i = 0; i < ADDRESS_COUNT; i++) {
-      void __iomem *p = ioremap(addresses[i], 0x2000);
-      if (!p)
-	continue;
-#if DEBUG_DETECT
-      printk( " %lx(%lx),", addresses[i], bios_base );
-#endif
-      for (j = 0; j < SIGNATURE_COUNT; j++) {
-	 if (check_signature(p + signatures[j].sig_offset,
-			     signatures[j].signature,
-			     signatures[j].sig_length )) {
-	    bios_major = signatures[j].major_bios_version;
-	    bios_minor = signatures[j].minor_bios_version;
-	    PCI_bus    = (signatures[j].flag == 1);
-	    Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
-	    bios_base  = addresses[i];
-	    bios_mem   = p;
-	    goto found;
-	 }
-      }
-      iounmap(p);
-   }
- 
-found:
-   if (bios_major == 2) {
-      /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
-	 Assuming the ROM is enabled (otherwise we wouldn't have been
-	 able to read the ROM signature :-), then the ROM sets up the
-	 RAM area with some magic numbers, such as a list of port
-	 base addresses and a list of the disk "geometry" reported to
-	 DOS (this geometry has nothing to do with physical geometry).
-       */
-
-      switch (Quantum) {
-      case 2:			/* ISA_200S */
-      case 3:			/* ISA_250MG */
-	 base = readb(bios_mem + 0x1fa2) + (readb(bios_mem + 0x1fa3) << 8);
-	 break;
-      case 4:			/* ISA_200S (another one) */
-	 base = readb(bios_mem + 0x1fa3) + (readb(bios_mem + 0x1fa4) << 8);
-	 break;
-      default:
-	 base = readb(bios_mem + 0x1fcc) + (readb(bios_mem + 0x1fcd) << 8);
-	 break;
-      }
-   
-#if DEBUG_DETECT
-      printk( " %x,", base );
-#endif
-
-      for (i = 0; i < PORT_COUNT; i++) {
-	if (base == ports[i]) {
-		if (!request_region(base, 0x10, "fdomain"))
-			break;
-		if (!fdomain_is_valid_port(base)) {
-			release_region(base, 0x10);
-			break;
-		}
-		*irq    = fdomain_get_irq( base );
-		*iobase = base;
-		return 1;
-	}
-      }
-
-      /* This is a bad sign.  It usually means that someone patched the
-	 BIOS signature list (the signatures variable) to contain a BIOS
-	 signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */
-      
-#if DEBUG_DETECT
-      printk( " RAM FAILED, " );
-#endif
-   }
-
-   /* Anyway, the alternative to finding the address in the RAM is to just
-      search through every possible port address for one that is attached
-      to the Future Domain card.  Don't panic, though, about reading all
-      these random port addresses -- there are rumors that the Future
-      Domain BIOS does something very similar.
-
-      Do not, however, check ports which the kernel knows are being used by
-      another driver. */
-
-   for (i = 0; i < PORT_COUNT; i++) {
-      base = ports[i];
-      if (!request_region(base, 0x10, "fdomain")) {
-#if DEBUG_DETECT
-	 printk( " (%x inuse),", base );
-#endif
-	 continue;
-      }
-#if DEBUG_DETECT
-      printk( " %x,", base );
-#endif
-      flag = fdomain_is_valid_port(base);
-      if (flag)
-	break;
-      release_region(base, 0x10);
-   }
-
-#if DEBUG_DETECT
-   if (flag) printk( " SUCCESS\n" );
-   else      printk( " FAILURE\n" );
-#endif
-
-   if (!flag) return 0;		/* iobase not found */
-
-   *irq    = fdomain_get_irq( base );
-   *iobase = base;
-
-   return 1;			/* success */
-}
-
-#else /* PCMCIA */
-
-static int fdomain_isa_detect( int *irq, int *iobase )
-{
-	if (irq)
-		*irq = 0;
-	if (iobase)
-		*iobase = 0;
-	return 0;
-}
-
-#endif /* !PCMCIA */
-
-
-/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int*
-   iobase) This function gets the Interrupt Level and I/O base address from
-   the PCI configuration registers. */
-
-#ifdef CONFIG_PCI
-static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_pdev )
-{
-   unsigned int     pci_irq;                /* PCI interrupt line */
-   unsigned long    pci_base;               /* PCI I/O base address */
-   struct pci_dev   *pdev = NULL;
-
-#if DEBUG_DETECT
-   /* Tell how to print a list of the known PCI devices from bios32 and
-      list vendor and device IDs being used if in debug mode.  */
-      
-   printk( "scsi: <fdomain> INFO: use lspci -v to see list of PCI devices\n" );
-   printk( "scsi: <fdomain> TMC-3260 detect:"
-	   " Using Vendor ID: 0x%x and Device ID: 0x%x\n",
-	   PCI_VENDOR_ID_FD, 
-	   PCI_DEVICE_ID_FD_36C70 );
-#endif 
-
-   if ((pdev = pci_get_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
-		return 0;
-   if (pci_enable_device(pdev))
-   	goto fail;
-       
-#if DEBUG_DETECT
-   printk( "scsi: <fdomain> TMC-3260 detect:"
-	   " PCI bus %u, device %u, function %u\n",
-	   pdev->bus->number,
-	   PCI_SLOT(pdev->devfn),
-	   PCI_FUNC(pdev->devfn));
-#endif
-
-   /* We now have the appropriate device function for the FD board so we
-      just read the PCI config info from the registers.  */
-
-   pci_base = pci_resource_start(pdev, 0);
-   pci_irq = pdev->irq;
-
-   if (!request_region( pci_base, 0x10, "fdomain" ))
-   	goto fail;
-
-   /* Now we have the I/O base address and interrupt from the PCI
-      configuration registers. */
-
-   *irq    = pci_irq;
-   *iobase = pci_base;
-   *ret_pdev = pdev;
-
-#if DEBUG_DETECT
-   printk( "scsi: <fdomain> TMC-3260 detect:"
-	   " IRQ = %d, I/O base = 0x%x [0x%lx]\n", *irq, *iobase, pci_base );
-#endif
-
-   if (!fdomain_is_valid_port(pci_base)) {
-      printk(KERN_ERR "scsi: <fdomain> PCI card detected, but driver not loaded (invalid port)\n" );
-      release_region(pci_base, 0x10);
-      goto fail;
-   }
-
-				/* Fill in a few global variables.  Ugh. */
-   bios_major = bios_minor = -1;
-   PCI_bus    = 1;
-   PCI_dev    = pdev;
-   Quantum    = 0;
-   bios_base  = 0;
-   
-   return 1;
-fail:
-   pci_dev_put(pdev);
-   return 0;
-}
-
-#endif
-
-struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
-{
-   int              retcode;
-   struct Scsi_Host *shpnt;
-   struct pci_dev *pdev = NULL;
-
-   if (setup_called) {
-#if DEBUG_DETECT
-      printk( "scsi: <fdomain> No BIOS, using port_base = 0x%x, irq = %d\n",
-	      port_base, interrupt_level );
-#endif
-      if (!request_region(port_base, 0x10, "fdomain")) {
-	 printk( "scsi: <fdomain> port 0x%x is busy\n", port_base );
-	 printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
-	 return NULL;
-      }
-      if (!fdomain_is_valid_port( port_base )) {
-	 printk( "scsi: <fdomain> Cannot locate chip at port base 0x%x\n",
-		 port_base );
-	 printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
-	 release_region(port_base, 0x10);
-	 return NULL;
-      }
-   } else {
-      int flag = 0;
-
-#ifdef CONFIG_PCI
-				/* Try PCI detection first */
-      flag = fdomain_pci_bios_detect( &interrupt_level, &port_base, &pdev );
-#endif
-      if (!flag) {
-				/* Then try ISA bus detection */
-	 flag = fdomain_isa_detect( &interrupt_level, &port_base );
-
-	 if (!flag) {
-	    printk( "scsi: <fdomain> Detection failed (no card)\n" );
-	    return NULL;
-	 }
-      }
-   }
-
-   fdomain_16x0_host_reset(NULL);
-
-   if (fdomain_test_loopback()) {
-      printk(KERN_ERR  "scsi: <fdomain> Detection failed (loopback test failed at port base 0x%x)\n", port_base);
-      if (setup_called) {
-	 printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
-      }
-      goto fail;
-   }
-
-   if (this_id) {
-      tpnt->this_id = (this_id & 0x07);
-      adapter_mask  = (1 << tpnt->this_id);
-   } else {
-      if (PCI_bus || (bios_major == 3 && bios_minor >= 2) || bios_major < 0) {
-	 tpnt->this_id = 7;
-	 adapter_mask  = 0x80;
-      } else {
-	 tpnt->this_id = 6;
-	 adapter_mask  = 0x40;
-      }
-   }
-
-/* Print out a banner here in case we can't
-   get resources.  */
-
-   shpnt = scsi_register( tpnt, 0 );
-   if(shpnt == NULL) {
-	release_region(port_base, 0x10);
-   	return NULL;
-   }
-   shpnt->irq = interrupt_level;
-   shpnt->io_port = port_base;
-   shpnt->n_io_port = 0x10;
-   print_banner( shpnt );
-
-   /* Log IRQ with kernel */   
-   if (!interrupt_level) {
-      printk(KERN_ERR "scsi: <fdomain> Card Detected, but driver not loaded (no IRQ)\n" );
-      goto fail;
-   } else {
-      /* Register the IRQ with the kernel */
-
-      retcode = request_irq( interrupt_level,
-			     do_fdomain_16x0_intr, pdev?IRQF_SHARED:0, "fdomain", shpnt);
-
-      if (retcode < 0) {
-	 if (retcode == -EINVAL) {
-	    printk(KERN_ERR "scsi: <fdomain> IRQ %d is bad!\n", interrupt_level );
-	    printk(KERN_ERR "                This shouldn't happen!\n" );
-	    printk(KERN_ERR "                Send mail to faith@acm.org\n" );
-	 } else if (retcode == -EBUSY) {
-	    printk(KERN_ERR "scsi: <fdomain> IRQ %d is already in use!\n", interrupt_level );
-	    printk(KERN_ERR "                Please use another IRQ!\n" );
-	 } else {
-	    printk(KERN_ERR "scsi: <fdomain> Error getting IRQ %d\n", interrupt_level );
-	    printk(KERN_ERR "                This shouldn't happen!\n" );
-	    printk(KERN_ERR "                Send mail to faith@acm.org\n" );
-	 }
-	 printk(KERN_ERR "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" );
-	 goto fail;
-      }
-   }
-   return shpnt;
-fail:
-   pci_dev_put(pdev);
-   release_region(port_base, 0x10);
-   return NULL;
-}
-
-static int fdomain_16x0_detect(struct scsi_host_template *tpnt)
-{
-	if (fdomain)
-		fdomain_setup(fdomain);
-	return (__fdomain_16x0_detect(tpnt) != NULL);
-}
-
-static const char *fdomain_16x0_info( struct Scsi_Host *ignore )
-{
-   static char buffer[128];
-   char        *pt;
-   
-   strcpy( buffer, "Future Domain 16-bit SCSI Driver Version" );
-   if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */
-      strcat( buffer, strchr( VERSION, ':' ) + 1 );
-      pt = strrchr( buffer, '$') - 1;
-      if (!pt)  		/* Stripped RCS Revision string? */
-	    pt = buffer + strlen( buffer ) - 1;
-      if (*pt != ' ')
-	    ++pt;
-      *pt = '\0';
-   } else {			/* Assume VERSION is a number */
-      strcat( buffer, " " VERSION );
-   }
-      
-   return buffer;
-}
-
-#if 0
-static int fdomain_arbitrate( void )
-{
-   int           status = 0;
-   unsigned long timeout;
-
-#if EVERY_ACCESS
-   printk( "fdomain_arbitrate()\n" );
-#endif
-   
-   outb(0x00, port_base + SCSI_Cntl);              /* Disable data drivers */
-   outb(adapter_mask, port_base + SCSI_Data_NoACK); /* Set our id bit */
-   outb(0x04 | PARITY_MASK, port_base + TMC_Cntl); /* Start arbitration */
-
-   timeout = 500;
-   do {
-      status = inb(port_base + TMC_Status);        /* Read adapter status */
-      if (status & 0x02)		      /* Arbitration complete */
-	    return 0;
-      mdelay(1);			/* Wait one millisecond */
-   } while (--timeout);
-
-   /* Make bus idle */
-   fdomain_make_bus_idle();
-
-#if EVERY_ACCESS
-   printk( "Arbitration failed, status = %x\n", status );
-#endif
-#if ERRORS_ONLY
-   printk( "scsi: <fdomain> Arbitration failed, status = %x\n", status );
-#endif
-   return 1;
-}
-#endif
-
-static int fdomain_select( int target )
-{
-   int           status;
-   unsigned long timeout;
-#if ERRORS_ONLY
-   static int    flag = 0;
-#endif
-
-   outb(0x82, port_base + SCSI_Cntl); /* Bus Enable + Select */
-   outb(adapter_mask | (1 << target), port_base + SCSI_Data_NoACK);
-
-   /* Stop arbitration and enable parity */
-   outb(PARITY_MASK, port_base + TMC_Cntl); 
-
-   timeout = 350;			/* 350 msec */
-
-   do {
-      status = inb(port_base + SCSI_Status); /* Read adapter status */
-      if (status & 1) {			/* Busy asserted */
-	 /* Enable SCSI Bus (on error, should make bus idle with 0) */
-	 outb(0x80, port_base + SCSI_Cntl);
-	 return 0;
-      }
-      mdelay(1);			/* wait one msec */
-   } while (--timeout);
-   /* Make bus idle */
-   fdomain_make_bus_idle();
-#if EVERY_ACCESS
-   if (!target) printk( "Selection failed\n" );
-#endif
-#if ERRORS_ONLY
-   if (!target) {
-      if (!flag) /* Skip first failure for all chips. */
-	    ++flag;
-      else
-	    printk( "scsi: <fdomain> Selection failed\n" );
-   }
-#endif
-   return 1;
-}
-
-static void my_done(int error)
-{
-   if (in_command) {
-      in_command = 0;
-      outb(0x00, port_base + Interrupt_Cntl);
-      fdomain_make_bus_idle();
-      current_SC->result = error;
-      if (current_SC->scsi_done)
-	    current_SC->scsi_done( current_SC );
-      else panic( "scsi: <fdomain> current_SC->scsi_done() == NULL" );
-   } else {
-      panic( "scsi: <fdomain> my_done() called outside of command\n" );
-   }
-#if DEBUG_RACE
-   in_interrupt_flag = 0;
-#endif
-}
-
-static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
-{
-   unsigned long flags;
-   int      status;
-   int      done = 0;
-   unsigned data_count;
-
-				/* The fdomain_16x0_intr is only called via
-				   the interrupt handler.  The goal of the
-				   sti() here is to allow other
-				   interruptions while this routine is
-				   running. */
-
-   /* Check for other IRQ sources */
-   if ((inb(port_base + TMC_Status) & 0x01) == 0)
-   	return IRQ_NONE;
-
-   /* It is our IRQ */   	
-   outb(0x00, port_base + Interrupt_Cntl);
-
-   /* We usually have one spurious interrupt after each command.  Ignore it. */
-   if (!in_command || !current_SC) {	/* Spurious interrupt */
-#if EVERY_ACCESS
-      printk( "Spurious interrupt, in_command = %d, current_SC = %x\n",
-	      in_command, current_SC );
-#endif
-      return IRQ_NONE;
-   }
-
-   /* Abort calls my_done, so we do nothing here. */
-   if (current_SC->SCp.phase & aborted) {
-#if DEBUG_ABORT
-      printk( "scsi: <fdomain> Interrupt after abort, ignoring\n" );
-#endif
-      /*
-      return IRQ_HANDLED; */
-   }
-
-#if DEBUG_RACE
-   ++in_interrupt_flag;
-#endif
-
-   if (current_SC->SCp.phase & in_arbitration) {
-      status = inb(port_base + TMC_Status);        /* Read adapter status */
-      if (!(status & 0x02)) {
-#if EVERY_ACCESS
-	 printk( " AFAIL " );
-#endif
-         spin_lock_irqsave(current_SC->device->host->host_lock, flags);
-	 my_done( DID_BUS_BUSY << 16 );
-         spin_unlock_irqrestore(current_SC->device->host->host_lock, flags);
-	 return IRQ_HANDLED;
-      }
-      current_SC->SCp.phase = in_selection;
-      
-      outb(0x40 | FIFO_COUNT, port_base + Interrupt_Cntl);
-
-      outb(0x82, port_base + SCSI_Cntl); /* Bus Enable + Select */
-      outb(adapter_mask | (1 << scmd_id(current_SC)), port_base + SCSI_Data_NoACK);
-      
-      /* Stop arbitration and enable parity */
-      outb(0x10 | PARITY_MASK, port_base + TMC_Cntl);
-#if DEBUG_RACE
-      in_interrupt_flag = 0;
-#endif
-      return IRQ_HANDLED;
-   } else if (current_SC->SCp.phase & in_selection) {
-      status = inb(port_base + SCSI_Status);
-      if (!(status & 0x01)) {
-	 /* Try again, for slow devices */
-	 if (fdomain_select( scmd_id(current_SC) )) {
-#if EVERY_ACCESS
-	    printk( " SFAIL " );
-#endif
-            spin_lock_irqsave(current_SC->device->host->host_lock, flags);
-	    my_done( DID_NO_CONNECT << 16 );
-            spin_unlock_irqrestore(current_SC->device->host->host_lock, flags);
-	    return IRQ_HANDLED;
-	 } else {
-#if EVERY_ACCESS
-	    printk( " AltSel " );
-#endif
-	    /* Stop arbitration and enable parity */
-	    outb(0x10 | PARITY_MASK, port_base + TMC_Cntl);
-	 }
-      }
-      current_SC->SCp.phase = in_other;
-      outb(0x90 | FIFO_COUNT, port_base + Interrupt_Cntl);
-      outb(0x80, port_base + SCSI_Cntl);
-#if DEBUG_RACE
-      in_interrupt_flag = 0;
-#endif
-      return IRQ_HANDLED;
-   }
-   
-   /* current_SC->SCp.phase == in_other: this is the body of the routine */
-   
-   status = inb(port_base + SCSI_Status);
-   
-   if (status & 0x10) {	/* REQ */
-      
-      switch (status & 0x0e) {
-       
-      case 0x08:		/* COMMAND OUT */
-	 outb(current_SC->cmnd[current_SC->SCp.sent_command++],
-	      port_base + Write_SCSI_Data);
-#if EVERY_ACCESS
-	 printk( "CMD = %x,",
-		 current_SC->cmnd[ current_SC->SCp.sent_command - 1] );
-#endif
-	 break;
-      case 0x00:		/* DATA OUT -- tmc18c50/tmc18c30 only */
-	 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
-	    current_SC->SCp.have_data_in = -1;
-	    outb(0xd0 | PARITY_MASK, port_base + TMC_Cntl);
-	 }
-	 break;
-      case 0x04:		/* DATA IN -- tmc18c50/tmc18c30 only */
-	 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
-	    current_SC->SCp.have_data_in = 1;
-	    outb(0x90 | PARITY_MASK, port_base + TMC_Cntl);
-	 }
-	 break;
-      case 0x0c:		/* STATUS IN */
-	 current_SC->SCp.Status = inb(port_base + Read_SCSI_Data);
-#if EVERY_ACCESS
-	 printk( "Status = %x, ", current_SC->SCp.Status );
-#endif
-#if ERRORS_ONLY
-	 if (current_SC->SCp.Status
-	     && current_SC->SCp.Status != 2
-	     && current_SC->SCp.Status != 8) {
-	    printk( "scsi: <fdomain> target = %d, command = %x, status = %x\n",
-		    current_SC->device->id,
-		    current_SC->cmnd[0],
-		    current_SC->SCp.Status );
-	 }
-#endif
-	       break;
-      case 0x0a:		/* MESSAGE OUT */
-	 outb(MESSAGE_REJECT, port_base + Write_SCSI_Data); /* Reject */
-	 break;
-      case 0x0e:		/* MESSAGE IN */
-	 current_SC->SCp.Message = inb(port_base + Read_SCSI_Data);
-#if EVERY_ACCESS
-	 printk( "Message = %x, ", current_SC->SCp.Message );
-#endif
-	 if (!current_SC->SCp.Message) ++done;
-#if DEBUG_MESSAGES || EVERY_ACCESS
-	 if (current_SC->SCp.Message) {
-	    printk( "scsi: <fdomain> message = %x\n",
-		    current_SC->SCp.Message );
-	 }
-#endif
-	 break;
-      }
-   }
-
-   if (chip == tmc1800 && !current_SC->SCp.have_data_in
-       && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
-      
-      if(current_SC->sc_data_direction == DMA_TO_DEVICE)
-      {
-	 current_SC->SCp.have_data_in = -1;
-	 outb(0xd0 | PARITY_MASK, port_base + TMC_Cntl);
-      }
-      else
-      {
-	 current_SC->SCp.have_data_in = 1;
-	 outb(0x90 | PARITY_MASK, port_base + TMC_Cntl);
-      }
-   }
-
-   if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */
-      while ((data_count = FIFO_Size - inw(port_base + FIFO_Data_Count)) > 512) {
-#if EVERY_ACCESS
-	 printk( "DC=%d, ", data_count ) ;
-#endif
-	 if (data_count > current_SC->SCp.this_residual)
-	       data_count = current_SC->SCp.this_residual;
-	 if (data_count > 0) {
-#if EVERY_ACCESS
-	    printk( "%d OUT, ", data_count );
-#endif
-	    if (data_count == 1) {
-	       outb(*current_SC->SCp.ptr++, port_base + Write_FIFO);
-	       --current_SC->SCp.this_residual;
-	    } else {
-	       data_count >>= 1;
-	       outsw(port_base + Write_FIFO, current_SC->SCp.ptr, data_count);
-	       current_SC->SCp.ptr += 2 * data_count;
-	       current_SC->SCp.this_residual -= 2 * data_count;
-	    }
-	 }
-	 if (!current_SC->SCp.this_residual) {
-	    if (current_SC->SCp.buffers_residual) {
-	       --current_SC->SCp.buffers_residual;
-	       ++current_SC->SCp.buffer;
-	       current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
-	       current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
-	    } else
-		  break;
-	 }
-      }
-   }
-   
-   if (current_SC->SCp.have_data_in == 1) { /* DATA IN */
-      while ((data_count = inw(port_base + FIFO_Data_Count)) > 0) {
-#if EVERY_ACCESS
-	 printk( "DC=%d, ", data_count );
-#endif
-	 if (data_count > current_SC->SCp.this_residual)
-	       data_count = current_SC->SCp.this_residual;
-	 if (data_count) {
-#if EVERY_ACCESS
-	    printk( "%d IN, ", data_count );
-#endif
-	    if (data_count == 1) {
-	       *current_SC->SCp.ptr++ = inb(port_base + Read_FIFO);
-	       --current_SC->SCp.this_residual;
-	    } else {
-	       data_count >>= 1; /* Number of words */
-	       insw(port_base + Read_FIFO, current_SC->SCp.ptr, data_count);
-	       current_SC->SCp.ptr += 2 * data_count;
-	       current_SC->SCp.this_residual -= 2 * data_count;
-	    }
-	 }
-	 if (!current_SC->SCp.this_residual
-	     && current_SC->SCp.buffers_residual) {
-	    --current_SC->SCp.buffers_residual;
-	    ++current_SC->SCp.buffer;
-	    current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
-	    current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
-	 }
-      }
-   }
-   
-   if (done) {
-#if EVERY_ACCESS
-      printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in );
-#endif
-
-#if ERRORS_ONLY
-      if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
-	      char *buf = scsi_sglist(current_SC);
-	 if ((unsigned char)(*(buf + 2)) & 0x0f) {
-	    unsigned char key;
-	    unsigned char code;
-	    unsigned char qualifier;
-
-	    key = (unsigned char)(*(buf + 2)) & 0x0f;
-	    code = (unsigned char)(*(buf + 12));
-	    qualifier = (unsigned char)(*(buf + 13));
-
-	    if (key != UNIT_ATTENTION
-		&& !(key == NOT_READY
-		     && code == 0x04
-		     && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
-		&& !(key == ILLEGAL_REQUEST && (code == 0x25
-						|| code == 0x24
-						|| !code)))
-		  
-		  printk( "scsi: <fdomain> REQUEST SENSE"
-			  " Key = %x, Code = %x, Qualifier = %x\n",
-			  key, code, qualifier );
-	 }
-      }
-#endif
-#if EVERY_ACCESS
-      printk( "BEFORE MY_DONE. . ." );
-#endif
-      spin_lock_irqsave(current_SC->device->host->host_lock, flags);
-      my_done( (current_SC->SCp.Status & 0xff)
-	       | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
-      spin_unlock_irqrestore(current_SC->device->host->host_lock, flags);
-#if EVERY_ACCESS
-      printk( "RETURNING.\n" );
-#endif
-      
-   } else {
-      if (current_SC->SCp.phase & disconnect) {
-	 outb(0xd0 | FIFO_COUNT, port_base + Interrupt_Cntl);
-	 outb(0x00, port_base + SCSI_Cntl);
-      } else {
-	 outb(0x90 | FIFO_COUNT, port_base + Interrupt_Cntl);
-      }
-   }
-#if DEBUG_RACE
-   in_interrupt_flag = 0;
-#endif
-   return IRQ_HANDLED;
-}
-
-static int fdomain_16x0_queue_lck(struct scsi_cmnd *SCpnt,
-		void (*done)(struct scsi_cmnd *))
-{
-   if (in_command) {
-      panic( "scsi: <fdomain> fdomain_16x0_queue() NOT REENTRANT!\n" );
-   }
-#if EVERY_ACCESS
-   printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
-	   SCpnt->target,
-	   *(unsigned char *)SCpnt->cmnd,
-	   scsi_sg_count(SCpnt),
-	   scsi_bufflen(SCpnt));
-#endif
-
-   fdomain_make_bus_idle();
-
-   current_SC            = SCpnt; /* Save this for the done function */
-   current_SC->scsi_done = done;
-
-   /* Initialize static data */
-
-   if (scsi_sg_count(current_SC)) {
-	   current_SC->SCp.buffer = scsi_sglist(current_SC);
-	   current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
-	   current_SC->SCp.this_residual    = current_SC->SCp.buffer->length;
-	   current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
-   } else {
-	   current_SC->SCp.ptr              = NULL;
-	   current_SC->SCp.this_residual    = 0;
-	   current_SC->SCp.buffer           = NULL;
-	   current_SC->SCp.buffers_residual = 0;
-   }
-
-   current_SC->SCp.Status              = 0;
-   current_SC->SCp.Message             = 0;
-   current_SC->SCp.have_data_in        = 0;
-   current_SC->SCp.sent_command        = 0;
-   current_SC->SCp.phase               = in_arbitration;
-
-   /* Start arbitration */
-   outb(0x00, port_base + Interrupt_Cntl);
-   outb(0x00, port_base + SCSI_Cntl);              /* Disable data drivers */
-   outb(adapter_mask, port_base + SCSI_Data_NoACK); /* Set our id bit */
-   ++in_command;
-   outb(0x20, port_base + Interrupt_Cntl);
-   outb(0x14 | PARITY_MASK, port_base + TMC_Cntl); /* Start arbitration */
-
-   return 0;
-}
-
-static DEF_SCSI_QCMD(fdomain_16x0_queue)
-
-#if DEBUG_ABORT
-static void print_info(struct scsi_cmnd *SCpnt)
-{
-   unsigned int imr;
-   unsigned int irr;
-   unsigned int isr;
-
-   if (!SCpnt || !SCpnt->device || !SCpnt->device->host) {
-      printk(KERN_WARNING "scsi: <fdomain> Cannot provide detailed information\n");
-      return;
-   }
-   
-   printk(KERN_INFO "%s\n", fdomain_16x0_info( SCpnt->device->host ) );
-   print_banner(SCpnt->device->host);
-   switch (SCpnt->SCp.phase) {
-   case in_arbitration: printk("arbitration"); break;
-   case in_selection:   printk("selection");   break;
-   case in_other:       printk("other");       break;
-   default:             printk("unknown");     break;
-   }
-
-   printk( " (%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
-	   SCpnt->SCp.phase,
-	   SCpnt->device->id,
-	   *(unsigned char *)SCpnt->cmnd,
-	   scsi_sg_count(SCpnt),
-	   scsi_bufflen(SCpnt));
-   printk( "sent_command = %d, have_data_in = %d, timeout = %d\n",
-	   SCpnt->SCp.sent_command,
-	   SCpnt->SCp.have_data_in,
-	   SCpnt->timeout );
-#if DEBUG_RACE
-   printk( "in_interrupt_flag = %d\n", in_interrupt_flag );
-#endif
-
-   imr = (inb( 0x0a1 ) << 8) + inb( 0x21 );
-   outb( 0x0a, 0xa0 );
-   irr = inb( 0xa0 ) << 8;
-   outb( 0x0a, 0x20 );
-   irr += inb( 0x20 );
-   outb( 0x0b, 0xa0 );
-   isr = inb( 0xa0 ) << 8;
-   outb( 0x0b, 0x20 );
-   isr += inb( 0x20 );
-
-				/* Print out interesting information */
-   printk( "IMR = 0x%04x", imr );
-   if (imr & (1 << interrupt_level))
-	 printk( " (masked)" );
-   printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr );
-
-   printk( "SCSI Status      = 0x%02x\n", inb(port_base + SCSI_Status));
-   printk( "TMC Status       = 0x%02x", inb(port_base + TMC_Status));
-   if (inb((port_base + TMC_Status) & 1))
-	 printk( " (interrupt)" );
-   printk( "\n" );
-   printk("Interrupt Status = 0x%02x", inb(port_base + Interrupt_Status));
-   if (inb(port_base + Interrupt_Status) & 0x08)
-	 printk( " (enabled)" );
-   printk( "\n" );
-   if (chip == tmc18c50 || chip == tmc18c30) {
-      printk("FIFO Status      = 0x%02x\n", inb(port_base + FIFO_Status));
-      printk( "Int. Condition   = 0x%02x\n",
-	      inb( port_base + Interrupt_Cond ) );
-   }
-   printk( "Configuration 1  = 0x%02x\n", inb( port_base + Configuration1 ) );
-   if (chip == tmc18c50 || chip == tmc18c30)
-	 printk( "Configuration 2  = 0x%02x\n",
-		 inb( port_base + Configuration2 ) );
-}
-#endif
-
-static int fdomain_16x0_abort(struct scsi_cmnd *SCpnt)
-{
-#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
-   printk( "scsi: <fdomain> abort " );
-#endif
-
-   if (!in_command) {
-#if EVERY_ACCESS || ERRORS_ONLY
-      printk( " (not in command)\n" );
-#endif
-      return FAILED;
-   } else printk( "\n" );
-
-#if DEBUG_ABORT
-   print_info( SCpnt );
-#endif
-
-   fdomain_make_bus_idle();
-   current_SC->SCp.phase |= aborted;
-   current_SC->result = DID_ABORT << 16;
-   
-   /* Aborts are not done well. . . */
-   my_done(DID_ABORT << 16);
-   return SUCCESS;
-}
-
-int fdomain_16x0_host_reset(struct scsi_cmnd *SCpnt)
-{
-   unsigned long flags;
-
-   local_irq_save(flags);
-
-   outb(1, port_base + SCSI_Cntl);
-   do_pause( 2 );
-   outb(0, port_base + SCSI_Cntl);
-   do_pause( 115 );
-   outb(0, port_base + SCSI_Mode_Cntl);
-   outb(PARITY_MASK, port_base + TMC_Cntl);
-
-   local_irq_restore(flags);
-   return SUCCESS;
-}
-
-static int fdomain_16x0_biosparam(struct scsi_device *sdev,
-		struct block_device *bdev,
-		sector_t capacity, int *info_array)
-{
-   int              drive;
-   int		    size      = capacity;
-   unsigned long    offset;
-   struct drive_info {
-      unsigned short cylinders;
-      unsigned char  heads;
-      unsigned char  sectors;
-   } i;
-   
-   /* NOTES:
-      The RAM area starts at 0x1f00 from the bios_base address.
-
-      For BIOS Version 2.0:
-      
-      The drive parameter table seems to start at 0x1f30.
-      The first byte's purpose is not known.
-      Next is the cylinder, head, and sector information.
-      The last 4 bytes appear to be the drive's size in sectors.
-      The other bytes in the drive parameter table are unknown.
-      If anyone figures them out, please send me mail, and I will
-      update these notes.
-
-      Tape drives do not get placed in this table.
-
-      There is another table at 0x1fea:
-      If the byte is 0x01, then the SCSI ID is not in use.
-      If the byte is 0x18 or 0x48, then the SCSI ID is in use,
-      although tapes don't seem to be in this table.  I haven't
-      seen any other numbers (in a limited sample).
-
-      0x1f2d is a drive count (i.e., not including tapes)
-
-      The table at 0x1fcc are I/O ports addresses for the various
-      operations.  I calculate these by hand in this driver code.
-
-      
-      
-      For the ISA-200S version of BIOS Version 2.0:
-
-      The drive parameter table starts at 0x1f33.
-
-      WARNING: Assume that the table entry is 25 bytes long.  Someone needs
-      to check this for the Quantum ISA-200S card.
-
-      
-      
-      For BIOS Version 3.2:
-
-      The drive parameter table starts at 0x1f70.  Each entry is
-      0x0a bytes long.  Heads are one less than we need to report.
-    */
-
-   if (MAJOR(bdev->bd_dev) != SCSI_DISK0_MAJOR) {
-      printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks");
-      return 0;
-   }
-   drive = MINOR(bdev->bd_dev) >> 4;
-
-   if (bios_major == 2) {
-      switch (Quantum) {
-      case 2:			/* ISA_200S */
-				/* The value of 25 has never been verified.
-				   It should probably be 15. */
-	 offset = 0x1f33 + drive * 25;
-	 break;
-      case 3:			/* ISA_250MG */
-	 offset = 0x1f36 + drive * 15;
-	 break;
-      case 4:			/* ISA_200S (another one) */
-	 offset = 0x1f34 + drive * 15;
-	 break;
-      default:
-	 offset = 0x1f31 + drive * 25;
-	 break;
-      }
-      memcpy_fromio( &i, bios_mem + offset, sizeof( struct drive_info ) );
-      info_array[0] = i.heads;
-      info_array[1] = i.sectors;
-      info_array[2] = i.cylinders;
-   } else if (bios_major == 3
-	      && bios_minor >= 0
-	      && bios_minor < 4) { /* 3.0 and 3.2 BIOS */
-      memcpy_fromio( &i, bios_mem + 0x1f71 + drive * 10,
-		     sizeof( struct drive_info ) );
-      info_array[0] = i.heads + 1;
-      info_array[1] = i.sectors;
-      info_array[2] = i.cylinders;
-   } else {			/* 3.4 BIOS (and up?) */
-      /* This algorithm was provided by Future Domain (much thanks!). */
-      unsigned char *p = scsi_bios_ptable(bdev);
-
-      if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
-	  && p[4]) {			    /* Partition type */
-
-	 /* The partition table layout is as follows:
-
-	    Start: 0x1b3h
-	    Offset: 0 = partition status
-		    1 = starting head
-		    2 = starting sector and cylinder (word, encoded)
-		    4 = partition type
-		    5 = ending head
-		    6 = ending sector and cylinder (word, encoded)
-		    8 = starting absolute sector (double word)
-		    c = number of sectors (double word)
-	    Signature: 0x1fe = 0x55aa
-
-	    So, this algorithm assumes:
-	    1) the first partition table is in use,
-	    2) the data in the first entry is correct, and
-	    3) partitions never divide cylinders
-
-	    Note that (1) may be FALSE for NetBSD (and other BSD flavors),
-	    as well as for Linux.  Note also, that Linux doesn't pay any
-	    attention to the fields that are used by this algorithm -- it
-	    only uses the absolute sector data.  Recent versions of Linux's
-	    fdisk(1) will fill this data in correctly, and forthcoming
-	    versions will check for consistency.
-
-	    Checking for a non-zero partition type is not part of the
-	    Future Domain algorithm, but it seemed to be a reasonable thing
-	    to do, especially in the Linux and BSD worlds. */
-
-	 info_array[0] = p[5] + 1;	    /* heads */
-	 info_array[1] = p[6] & 0x3f;	    /* sectors */
-      } else {
-
- 	 /* Note that this new method guarantees that there will always be
-	    less than 1024 cylinders on a platter.  This is good for drives
-	    up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
-
-	 if ((unsigned int)size >= 0x7e0000U) {
-	    info_array[0] = 0xff; /* heads   = 255 */
-	    info_array[1] = 0x3f; /* sectors =  63 */
-	 } else if ((unsigned int)size >= 0x200000U) {
-	    info_array[0] = 0x80; /* heads   = 128 */
-	    info_array[1] = 0x3f; /* sectors =  63 */
-	 } else {
-	    info_array[0] = 0x40; /* heads   =  64 */
-	    info_array[1] = 0x20; /* sectors =  32 */
-	 }
-      }
-				/* For both methods, compute the cylinders */
-      info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] );
-      kfree(p);
-   }
-   
-   return 0;
-}
-
-static int fdomain_16x0_release(struct Scsi_Host *shpnt)
-{
-	if (shpnt->irq)
-		free_irq(shpnt->irq, shpnt);
-	if (shpnt->io_port && shpnt->n_io_port)
-		release_region(shpnt->io_port, shpnt->n_io_port);
-	if (PCI_bus)
-		pci_dev_put(PCI_dev);
-	return 0;
-}
-
-struct scsi_host_template fdomain_driver_template = {
-	.module			= THIS_MODULE,
-	.name			= "fdomain",
-	.proc_name		= "fdomain",
-	.detect			= fdomain_16x0_detect,
-	.info			= fdomain_16x0_info,
-	.queuecommand		= fdomain_16x0_queue,
-	.eh_abort_handler	= fdomain_16x0_abort,
-	.eh_host_reset_handler	= fdomain_16x0_host_reset,
-	.bios_param		= fdomain_16x0_biosparam,
-	.release		= fdomain_16x0_release,
-	.can_queue		= 1,
-	.this_id		= 6,
-	.sg_tablesize		= 64,
-	.use_clustering		= DISABLE_CLUSTERING,
-};
-
-#ifndef PCMCIA
-#if defined(CONFIG_PCI) && defined(MODULE)
-
-static struct pci_device_id fdomain_pci_tbl[] = {
-	{ PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
-	{ }
-};
-MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl);
-#endif
-#define driver_template fdomain_driver_template
-#include "scsi_module.c"
-
-#endif

+ 0 - 24
drivers/scsi/fdomain.h

@@ -1,24 +0,0 @@
-/*
- * fdomain.c -- Future Domain TMC-16x0 SCSI driver
- * Author: Rickard E. Faith, faith@cs.unc.edu
- * Copyright 1992-1996, 1998 Rickard E. Faith (faith@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; 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; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-extern struct scsi_host_template fdomain_driver_template;
-extern int fdomain_setup(char *str);
-extern struct Scsi_Host *__fdomain_16x0_detect(struct  scsi_host_template *tpnt );
-extern int fdomain_16x0_host_reset(struct scsi_cmnd *SCpnt);

+ 1 - 1
drivers/scsi/hisi_sas/Kconfig

@@ -1,6 +1,6 @@
 config SCSI_HISI_SAS
 config SCSI_HISI_SAS
 	tristate "HiSilicon SAS"
 	tristate "HiSilicon SAS"
-	depends on HAS_DMA && HAS_IOMEM
+	depends on HAS_IOMEM
 	depends on ARM64 || COMPILE_TEST
 	depends on ARM64 || COMPILE_TEST
 	select SCSI_SAS_LIBSAS
 	select SCSI_SAS_LIBSAS
 	select BLK_DEV_INTEGRITY
 	select BLK_DEV_INTEGRITY

+ 0 - 1
drivers/scsi/hisi_sas/hisi_sas.h

@@ -175,7 +175,6 @@ struct hisi_sas_device {
 	struct hisi_sas_dq	*dq;
 	struct hisi_sas_dq	*dq;
 	struct list_head	list;
 	struct list_head	list;
 	u64 attached_phy;
 	u64 attached_phy;
-	atomic64_t running_req;
 	enum sas_device_type	dev_type;
 	enum sas_device_type	dev_type;
 	int device_id;
 	int device_id;
 	int sata_idx;
 	int sata_idx;

+ 14 - 20
drivers/scsi/hisi_sas/hisi_sas_main.c

@@ -33,7 +33,7 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction)
 	case ATA_CMD_FPDMA_RECV:
 	case ATA_CMD_FPDMA_RECV:
 	case ATA_CMD_FPDMA_SEND:
 	case ATA_CMD_FPDMA_SEND:
 	case ATA_CMD_NCQ_NON_DATA:
 	case ATA_CMD_NCQ_NON_DATA:
-	return HISI_SAS_SATA_PROTOCOL_FPDMA;
+		return HISI_SAS_SATA_PROTOCOL_FPDMA;
 
 
 	case ATA_CMD_DOWNLOAD_MICRO:
 	case ATA_CMD_DOWNLOAD_MICRO:
 	case ATA_CMD_ID_ATA:
 	case ATA_CMD_ID_ATA:
@@ -45,7 +45,7 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction)
 	case ATA_CMD_WRITE_LOG_EXT:
 	case ATA_CMD_WRITE_LOG_EXT:
 	case ATA_CMD_PIO_WRITE:
 	case ATA_CMD_PIO_WRITE:
 	case ATA_CMD_PIO_WRITE_EXT:
 	case ATA_CMD_PIO_WRITE_EXT:
-	return HISI_SAS_SATA_PROTOCOL_PIO;
+		return HISI_SAS_SATA_PROTOCOL_PIO;
 
 
 	case ATA_CMD_DSM:
 	case ATA_CMD_DSM:
 	case ATA_CMD_DOWNLOAD_MICRO_DMA:
 	case ATA_CMD_DOWNLOAD_MICRO_DMA:
@@ -64,7 +64,7 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction)
 	case ATA_CMD_WRITE_LOG_DMA_EXT:
 	case ATA_CMD_WRITE_LOG_DMA_EXT:
 	case ATA_CMD_WRITE_STREAM_DMA_EXT:
 	case ATA_CMD_WRITE_STREAM_DMA_EXT:
 	case ATA_CMD_ZAC_MGMT_IN:
 	case ATA_CMD_ZAC_MGMT_IN:
-	return HISI_SAS_SATA_PROTOCOL_DMA;
+		return HISI_SAS_SATA_PROTOCOL_DMA;
 
 
 	case ATA_CMD_CHK_POWER:
 	case ATA_CMD_CHK_POWER:
 	case ATA_CMD_DEV_RESET:
 	case ATA_CMD_DEV_RESET:
@@ -77,21 +77,21 @@ u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction)
 	case ATA_CMD_STANDBY:
 	case ATA_CMD_STANDBY:
 	case ATA_CMD_STANDBYNOW1:
 	case ATA_CMD_STANDBYNOW1:
 	case ATA_CMD_ZAC_MGMT_OUT:
 	case ATA_CMD_ZAC_MGMT_OUT:
-	return HISI_SAS_SATA_PROTOCOL_NONDATA;
+		return HISI_SAS_SATA_PROTOCOL_NONDATA;
 	default:
 	default:
 	{
 	{
 		if (fis->command == ATA_CMD_SET_MAX) {
 		if (fis->command == ATA_CMD_SET_MAX) {
 			switch (fis->features) {
 			switch (fis->features) {
 			case ATA_SET_MAX_PASSWD:
 			case ATA_SET_MAX_PASSWD:
 			case ATA_SET_MAX_LOCK:
 			case ATA_SET_MAX_LOCK:
-			return HISI_SAS_SATA_PROTOCOL_PIO;
+				return HISI_SAS_SATA_PROTOCOL_PIO;
 
 
 			case ATA_SET_MAX_PASSWD_DMA:
 			case ATA_SET_MAX_PASSWD_DMA:
 			case ATA_SET_MAX_UNLOCK_DMA:
 			case ATA_SET_MAX_UNLOCK_DMA:
-			return HISI_SAS_SATA_PROTOCOL_DMA;
+				return HISI_SAS_SATA_PROTOCOL_DMA;
 
 
 			default:
 			default:
-			return HISI_SAS_SATA_PROTOCOL_NONDATA;
+				return HISI_SAS_SATA_PROTOCOL_NONDATA;
 			}
 			}
 		}
 		}
 		if (direction == DMA_NONE)
 		if (direction == DMA_NONE)
@@ -200,8 +200,6 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
 
 
 	if (task) {
 	if (task) {
 		struct device *dev = hisi_hba->dev;
 		struct device *dev = hisi_hba->dev;
-		struct domain_device *device = task->dev;
-		struct hisi_sas_device *sas_dev = device->lldd_dev;
 
 
 		if (!task->lldd_task)
 		if (!task->lldd_task)
 			return;
 			return;
@@ -213,9 +211,6 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
 				dma_unmap_sg(dev, task->scatter,
 				dma_unmap_sg(dev, task->scatter,
 					     task->num_scatter,
 					     task->num_scatter,
 					     task->data_dir);
 					     task->data_dir);
-
-		if (sas_dev)
-			atomic64_dec(&sas_dev->running_req);
 	}
 	}
 
 
 	if (slot->buf)
 	if (slot->buf)
@@ -321,7 +316,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
 		 */
 		 */
 		if (device->dev_type != SAS_SATA_DEV)
 		if (device->dev_type != SAS_SATA_DEV)
 			task->task_done(task);
 			task->task_done(task);
-		return SAS_PHY_DOWN;
+		return -ECOMM;
 	}
 	}
 
 
 	if (DEV_IS_GONE(sas_dev)) {
 	if (DEV_IS_GONE(sas_dev)) {
@@ -332,7 +327,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
 			dev_info(dev, "task prep: device %016llx not ready\n",
 			dev_info(dev, "task prep: device %016llx not ready\n",
 				 SAS_ADDR(device->sas_addr));
 				 SAS_ADDR(device->sas_addr));
 
 
-		return SAS_PHY_DOWN;
+		return -ECOMM;
 	}
 	}
 
 
 	port = to_hisi_sas_port(sas_port);
 	port = to_hisi_sas_port(sas_port);
@@ -342,7 +337,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
 			 "SATA/STP" : "SAS",
 			 "SATA/STP" : "SAS",
 			 device->port->id);
 			 device->port->id);
 
 
-		return SAS_PHY_DOWN;
+		return -ECOMM;
 	}
 	}
 
 
 	if (!sas_protocol_ata(task->task_proto)) {
 	if (!sas_protocol_ata(task->task_proto)) {
@@ -431,8 +426,6 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
 
 	dq->slot_prep = slot;
 	dq->slot_prep = slot;
-
-	atomic64_inc(&sas_dev->running_req);
 	++(*pass);
 	++(*pass);
 
 
 	return 0;
 	return 0;
@@ -683,6 +676,8 @@ static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
 
 
 	phy->hisi_hba = hisi_hba;
 	phy->hisi_hba = hisi_hba;
 	phy->port = NULL;
 	phy->port = NULL;
+	phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+	phy->maximum_linkrate = hisi_hba->hw->phy_get_max_linkrate();
 	sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0;
 	sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0;
 	sas_phy->class = SAS;
 	sas_phy->class = SAS;
 	sas_phy->iproto = SAS_PROTOCOL_ALL;
 	sas_phy->iproto = SAS_PROTOCOL_ALL;
@@ -869,6 +864,7 @@ static void hisi_sas_tmf_timedout(struct timer_list *t)
 
 
 #define TASK_TIMEOUT 20
 #define TASK_TIMEOUT 20
 #define TASK_RETRY 3
 #define TASK_RETRY 3
+#define INTERNAL_ABORT_TIMEOUT 6
 static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
 static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
 					   void *parameter, u32 para_len,
 					   void *parameter, u32 para_len,
 					   struct hisi_sas_tmf_task *tmf)
 					   struct hisi_sas_tmf_task *tmf)
@@ -1514,8 +1510,6 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
 
 
 	dq->slot_prep = slot;
 	dq->slot_prep = slot;
 
 
-	atomic64_inc(&sas_dev->running_req);
-
 	/* send abort command to the chip */
 	/* send abort command to the chip */
 	hisi_hba->hw->start_delivery(dq);
 	hisi_hba->hw->start_delivery(dq);
 	spin_unlock_irqrestore(&dq->lock, flags_dq);
 	spin_unlock_irqrestore(&dq->lock, flags_dq);
@@ -1572,7 +1566,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
 	task->task_proto = device->tproto;
 	task->task_proto = device->tproto;
 	task->task_done = hisi_sas_task_done;
 	task->task_done = hisi_sas_task_done;
 	task->slow_task->timer.function = hisi_sas_tmf_timedout;
 	task->slow_task->timer.function = hisi_sas_tmf_timedout;
-	task->slow_task->timer.expires = jiffies + msecs_to_jiffies(110);
+	task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT*HZ;
 	add_timer(&task->slow_task->timer);
 	add_timer(&task->slow_task->timer);
 
 
 	res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
 	res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,

+ 6 - 7
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c

@@ -651,8 +651,10 @@ static int reset_hw_v1_hw(struct hisi_hba *hisi_hba)
 			dev_err(dev, "De-reset failed\n");
 			dev_err(dev, "De-reset failed\n");
 			return -EIO;
 			return -EIO;
 		}
 		}
-	} else
+	} else {
 		dev_warn(dev, "no reset method\n");
 		dev_warn(dev, "no reset method\n");
+		return -EINVAL;
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -873,7 +875,6 @@ static void phy_set_linkrate_v1_hw(struct hisi_hba *hisi_hba, int phy_no,
 	sas_phy->phy->maximum_linkrate = max;
 	sas_phy->phy->maximum_linkrate = max;
 	sas_phy->phy->minimum_linkrate = min;
 	sas_phy->phy->minimum_linkrate = min;
 
 
-	min -= SAS_LINK_RATE_1_5_GBPS;
 	max -= SAS_LINK_RATE_1_5_GBPS;
 	max -= SAS_LINK_RATE_1_5_GBPS;
 
 
 	for (i = 0; i <= max; i++)
 	for (i = 0; i <= max; i++)
@@ -882,10 +883,11 @@ static void phy_set_linkrate_v1_hw(struct hisi_hba *hisi_hba, int phy_no,
 	prog_phy_link_rate &= ~0xff;
 	prog_phy_link_rate &= ~0xff;
 	prog_phy_link_rate |= rate_mask;
 	prog_phy_link_rate |= rate_mask;
 
 
+	disable_phy_v1_hw(hisi_hba, phy_no);
+	msleep(100);
 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
 			prog_phy_link_rate);
 			prog_phy_link_rate);
-
-	phy_hard_reset_v1_hw(hisi_hba, phy_no);
+	start_phy_v1_hw(hisi_hba, phy_no);
 }
 }
 
 
 static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
 static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
@@ -1407,9 +1409,6 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
 	}
 	}
 
 
 out:
 out:
-	if (sas_dev)
-		atomic64_dec(&sas_dev->running_req);
-
 	hisi_sas_slot_task_free(hisi_hba, task, slot);
 	hisi_sas_slot_task_free(hisi_hba, task, slot);
 	sts = ts->stat;
 	sts = ts->stat;
 
 

+ 48 - 14
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c

@@ -406,6 +406,17 @@ struct hisi_sas_err_record_v2 {
 	__le32 dma_rx_err_type;
 	__le32 dma_rx_err_type;
 };
 };
 
 
+struct signal_attenuation_s {
+	u32 de_emphasis;
+	u32 preshoot;
+	u32 boost;
+};
+
+struct sig_atten_lu_s {
+	const struct signal_attenuation_s *att;
+	u32 sas_phy_ctrl;
+};
+
 static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
 static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
 	{
 	{
 		.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
 		.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
@@ -1084,8 +1095,10 @@ static int reset_hw_v2_hw(struct hisi_hba *hisi_hba)
 			dev_err(dev, "SAS de-reset fail.\n");
 			dev_err(dev, "SAS de-reset fail.\n");
 			return -EIO;
 			return -EIO;
 		}
 		}
-	} else
-		dev_warn(dev, "no reset method\n");
+	} else {
+		dev_err(dev, "no reset method\n");
+		return -EINVAL;
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1130,9 +1143,16 @@ static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba)
 	}
 	}
 }
 }
 
 
+static const struct signal_attenuation_s x6000 = {9200, 0, 10476};
+static const struct sig_atten_lu_s sig_atten_lu[] = {
+	{ &x6000, 0x3016a68 },
+};
+
 static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 {
 {
 	struct device *dev = hisi_hba->dev;
 	struct device *dev = hisi_hba->dev;
+	u32 sas_phy_ctrl = 0x30b9908;
+	u32 signal[3];
 	int i;
 	int i;
 
 
 	/* Global registers init */
 	/* Global registers init */
@@ -1176,9 +1196,28 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
 	hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
 	hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
 	hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
 	hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
 
 
+	/* Get sas_phy_ctrl value to deal with TX FFE issue. */
+	if (!device_property_read_u32_array(dev, "hisilicon,signal-attenuation",
+					    signal, ARRAY_SIZE(signal))) {
+		for (i = 0; i < ARRAY_SIZE(sig_atten_lu); i++) {
+			const struct sig_atten_lu_s *lookup = &sig_atten_lu[i];
+			const struct signal_attenuation_s *att = lookup->att;
+
+			if ((signal[0] == att->de_emphasis) &&
+			    (signal[1] == att->preshoot) &&
+			    (signal[2] == att->boost)) {
+				sas_phy_ctrl = lookup->sas_phy_ctrl;
+				break;
+			}
+		}
+
+		if (i == ARRAY_SIZE(sig_atten_lu))
+			dev_warn(dev, "unknown signal attenuation values, using default PHY ctrl config\n");
+	}
+
 	for (i = 0; i < hisi_hba->n_phy; i++) {
 	for (i = 0; i < hisi_hba->n_phy; i++) {
 		hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
 		hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
-		hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908);
+		hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl);
 		hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
 		hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
 		hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
 		hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
 		hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2);
 		hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2);
@@ -1566,7 +1605,6 @@ static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no,
 	sas_phy->phy->maximum_linkrate = max;
 	sas_phy->phy->maximum_linkrate = max;
 	sas_phy->phy->minimum_linkrate = min;
 	sas_phy->phy->minimum_linkrate = min;
 
 
-	min -= SAS_LINK_RATE_1_5_GBPS;
 	max -= SAS_LINK_RATE_1_5_GBPS;
 	max -= SAS_LINK_RATE_1_5_GBPS;
 
 
 	for (i = 0; i <= max; i++)
 	for (i = 0; i <= max; i++)
@@ -1575,10 +1613,11 @@ static void phy_set_linkrate_v2_hw(struct hisi_hba *hisi_hba, int phy_no,
 	prog_phy_link_rate &= ~0xff;
 	prog_phy_link_rate &= ~0xff;
 	prog_phy_link_rate |= rate_mask;
 	prog_phy_link_rate |= rate_mask;
 
 
+	disable_phy_v2_hw(hisi_hba, phy_no);
+	msleep(100);
 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
 			prog_phy_link_rate);
 			prog_phy_link_rate);
-
-	phy_hard_reset_v2_hw(hisi_hba, phy_no);
+	start_phy_v2_hw(hisi_hba, phy_no);
 }
 }
 
 
 static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
 static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id)
@@ -2371,7 +2410,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		hisi_sas_slot_task_free(hisi_hba, task, slot);
 		hisi_sas_slot_task_free(hisi_hba, task, slot);
 		spin_unlock_irqrestore(&hisi_hba->lock, flags);
 		spin_unlock_irqrestore(&hisi_hba->lock, flags);
-		return -1;
+		return ts->stat;
 	}
 	}
 
 
 	if (unlikely(!sas_dev)) {
 	if (unlikely(!sas_dev)) {
@@ -2630,7 +2669,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
 	/* dw0 */
 	/* dw0 */
 	hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
 	hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
 			       (port->id << CMD_HDR_PORT_OFF) |
 			       (port->id << CMD_HDR_PORT_OFF) |
-			       ((dev_is_sata(dev) ? 1:0) <<
+			       (dev_is_sata(dev) <<
 				CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
 				CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
 			       (abort_flag << CMD_HDR_ABORT_FLAG_OFF));
 			       (abort_flag << CMD_HDR_ABORT_FLAG_OFF));
 
 
@@ -2647,7 +2686,7 @@ static int prep_abort_v2_hw(struct hisi_hba *hisi_hba,
 static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
 {
 	int i, res = IRQ_HANDLED;
 	int i, res = IRQ_HANDLED;
-	u32 port_id, link_rate, hard_phy_linkrate;
+	u32 port_id, link_rate;
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 	struct device *dev = hisi_hba->dev;
 	struct device *dev = hisi_hba->dev;
@@ -2686,11 +2725,6 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 	}
 	}
 
 
 	sas_phy->linkrate = link_rate;
 	sas_phy->linkrate = link_rate;
-	hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
-						HARD_PHY_LINKRATE);
-	phy->maximum_linkrate = hard_phy_linkrate & 0xf;
-	phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
-
 	sas_phy->oob_mode = SAS_OOB_MODE;
 	sas_phy->oob_mode = SAS_OOB_MODE;
 	memcpy(sas_phy->attached_sas_addr, &id->sas_addr, SAS_ADDR_SIZE);
 	memcpy(sas_phy->attached_sas_addr, &id->sas_addr, SAS_ADDR_SIZE);
 	dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
 	dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);

+ 34 - 38
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

@@ -172,6 +172,7 @@
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
 #define CHL_INT1_MSK			(PORT_BASE + 0x1c4)
 #define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
 #define CHL_INT2_MSK			(PORT_BASE + 0x1c8)
 #define CHL_INT_COAL_EN			(PORT_BASE + 0x1d0)
 #define CHL_INT_COAL_EN			(PORT_BASE + 0x1d0)
+#define SAS_RX_TRAIN_TIMER		(PORT_BASE + 0x2a4)
 #define PHY_CTRL_RDY_MSK		(PORT_BASE + 0x2b0)
 #define PHY_CTRL_RDY_MSK		(PORT_BASE + 0x2b0)
 #define PHYCTRL_NOT_RDY_MSK		(PORT_BASE + 0x2b4)
 #define PHYCTRL_NOT_RDY_MSK		(PORT_BASE + 0x2b4)
 #define PHYCTRL_DWS_RESET_MSK		(PORT_BASE + 0x2b8)
 #define PHYCTRL_DWS_RESET_MSK		(PORT_BASE + 0x2b8)
@@ -184,6 +185,8 @@
 #define DMA_RX_STATUS			(PORT_BASE + 0x2e8)
 #define DMA_RX_STATUS			(PORT_BASE + 0x2e8)
 #define DMA_RX_STATUS_BUSY_OFF		0
 #define DMA_RX_STATUS_BUSY_OFF		0
 #define DMA_RX_STATUS_BUSY_MSK		(0x1 << DMA_RX_STATUS_BUSY_OFF)
 #define DMA_RX_STATUS_BUSY_MSK		(0x1 << DMA_RX_STATUS_BUSY_OFF)
+
+#define COARSETUNE_TIME			(PORT_BASE + 0x304)
 #define ERR_CNT_DWS_LOST		(PORT_BASE + 0x380)
 #define ERR_CNT_DWS_LOST		(PORT_BASE + 0x380)
 #define ERR_CNT_RESET_PROB		(PORT_BASE + 0x384)
 #define ERR_CNT_RESET_PROB		(PORT_BASE + 0x384)
 #define ERR_CNT_INVLD_DW		(PORT_BASE + 0x390)
 #define ERR_CNT_INVLD_DW		(PORT_BASE + 0x390)
@@ -340,12 +343,6 @@ struct hisi_sas_err_record_v3 {
 #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096
 #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096
 #define HISI_SAS_MSI_COUNT_V3_HW 32
 #define HISI_SAS_MSI_COUNT_V3_HW 32
 
 
-enum {
-	HISI_SAS_PHY_PHY_UPDOWN,
-	HISI_SAS_PHY_CHNL_INT,
-	HISI_SAS_PHY_INT_NR
-};
-
 #define DIR_NO_DATA 0
 #define DIR_NO_DATA 0
 #define DIR_TO_INI 1
 #define DIR_TO_INI 1
 #define DIR_TO_DEVICE 2
 #define DIR_TO_DEVICE 2
@@ -423,10 +420,10 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
 		hisi_sas_write32(hisi_hba, OQ0_INT_SRC_MSK+0x4*i, 0);
 
 
 	hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
 	hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
-	hisi_sas_write32(hisi_hba, AXI_MASTER_CFG_BASE, 0x30000);
 
 
 	for (i = 0; i < hisi_hba->n_phy; i++) {
 	for (i = 0; i < hisi_hba->n_phy; i++) {
-		hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x801);
+		hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
+		hisi_sas_phy_write32(hisi_hba, i, SAS_RX_TRAIN_TIMER, 0x13e80);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
 		hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, 0xffffffff);
@@ -438,17 +435,13 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
 		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0);
 		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0);
 		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_PHY_ENA_MSK, 0x0);
 		hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0);
 		hisi_sas_phy_write32(hisi_hba, i, SL_RX_BCAST_CHK_MSK, 0x0);
-		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x0);
-		hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, 0x199b4fa);
-		hisi_sas_phy_write32(hisi_hba, i, SAS_SSP_CON_TIMER_CFG,
-				     0xa03e8);
-		hisi_sas_phy_write32(hisi_hba, i, SAS_STP_CON_TIMER_CFG,
-				     0xa03e8);
-		hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER,
-				     0x7f7a120);
-		hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER,
-				     0x2a0a80);
+		hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x1);
+		hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7f7a120);
+
+		/* used for 12G negotiate */
+		hisi_sas_phy_write32(hisi_hba, i, COARSETUNE_TIME, 0x1e);
 	}
 	}
+
 	for (i = 0; i < hisi_hba->queue_count; i++) {
 	for (i = 0; i < hisi_hba->queue_count; i++) {
 		/* Delivery queue */
 		/* Delivery queue */
 		hisi_sas_write32(hisi_hba,
 		hisi_sas_write32(hisi_hba,
@@ -676,8 +669,10 @@ static int reset_hw_v3_hw(struct hisi_hba *hisi_hba)
 			dev_err(dev, "Reset failed\n");
 			dev_err(dev, "Reset failed\n");
 			return -EIO;
 			return -EIO;
 		}
 		}
-	} else
+	} else {
 		dev_err(dev, "no reset method!\n");
 		dev_err(dev, "no reset method!\n");
+		return -EINVAL;
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -737,7 +732,7 @@ static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
 	start_phy_v3_hw(hisi_hba, phy_no);
 	start_phy_v3_hw(hisi_hba, phy_no);
 }
 }
 
 
-enum sas_linkrate phy_get_max_linkrate_v3_hw(void)
+static enum sas_linkrate phy_get_max_linkrate_v3_hw(void)
 {
 {
 	return SAS_LINK_RATE_12_0_GBPS;
 	return SAS_LINK_RATE_12_0_GBPS;
 }
 }
@@ -1102,7 +1097,7 @@ static int prep_abort_v3_hw(struct hisi_hba *hisi_hba,
 	/* dw0 */
 	/* dw0 */
 	hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
 	hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
 			       (port->id << CMD_HDR_PORT_OFF) |
 			       (port->id << CMD_HDR_PORT_OFF) |
-				   ((dev_is_sata(dev) ? 1:0)
+				   (dev_is_sata(dev)
 					<< CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
 					<< CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
 					(abort_flag
 					(abort_flag
 					 << CMD_HDR_ABORT_FLAG_OFF));
 					 << CMD_HDR_ABORT_FLAG_OFF));
@@ -1118,10 +1113,10 @@ static int prep_abort_v3_hw(struct hisi_hba *hisi_hba,
 	return 0;
 	return 0;
 }
 }
 
 
-static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
+static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
 {
-	int i, res = 0;
-	u32 context, port_id, link_rate, hard_phy_linkrate;
+	int i, res;
+	u32 context, port_id, link_rate;
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 	struct device *dev = hisi_hba->dev;
 	struct device *dev = hisi_hba->dev;
@@ -1139,10 +1134,6 @@ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 		goto end;
 		goto end;
 	}
 	}
 	sas_phy->linkrate = link_rate;
 	sas_phy->linkrate = link_rate;
-	hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
-						HARD_PHY_LINKRATE);
-	phy->maximum_linkrate = hard_phy_linkrate & 0xf;
-	phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
 	phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
 	phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
 
 
 	/* Check for SATA dev */
 	/* Check for SATA dev */
@@ -1196,7 +1187,7 @@ static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 	phy->port_id = port_id;
 	phy->port_id = port_id;
 	phy->phy_attached = 1;
 	phy->phy_attached = 1;
 	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
 	hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
-
+	res = IRQ_HANDLED;
 end:
 end:
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
 			     CHL_INT0_SL_PHY_ENABLE_MSK);
 			     CHL_INT0_SL_PHY_ENABLE_MSK);
@@ -1205,7 +1196,7 @@ end:
 	return res;
 	return res;
 }
 }
 
 
-static int phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
+static irqreturn_t phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
 {
 	u32 phy_state, sl_ctrl, txid_auto;
 	u32 phy_state, sl_ctrl, txid_auto;
 	struct device *dev = hisi_hba->dev;
 	struct device *dev = hisi_hba->dev;
@@ -1227,10 +1218,10 @@ static int phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_NOT_RDY_MSK);
 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
 	hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 0);
 
 
-	return 0;
+	return IRQ_HANDLED;
 }
 }
 
 
-static void phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
+static irqreturn_t phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
 {
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
@@ -1241,6 +1232,8 @@ static void phy_bcast_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
 	hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
 			     CHL_INT0_SL_RX_BCST_ACK_MSK);
 			     CHL_INT0_SL_RX_BCST_ACK_MSK);
 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
 	hisi_sas_phy_write32(hisi_hba, phy_no, SL_RX_BCAST_CHK_MSK, 0);
+
+	return IRQ_HANDLED;
 }
 }
 
 
 static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p)
 static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p)
@@ -1267,7 +1260,9 @@ static irqreturn_t int_phy_up_down_bcast_v3_hw(int irq_no, void *p)
 						res = IRQ_HANDLED;
 						res = IRQ_HANDLED;
 				if (irq_value & CHL_INT0_SL_RX_BCST_ACK_MSK)
 				if (irq_value & CHL_INT0_SL_RX_BCST_ACK_MSK)
 					/* phy bcast */
 					/* phy bcast */
-					phy_bcast_v3_hw(phy_no, hisi_hba);
+					if (phy_bcast_v3_hw(phy_no, hisi_hba)
+							== IRQ_HANDLED)
+						res = IRQ_HANDLED;
 			} else {
 			} else {
 				if (irq_value & CHL_INT0_NOT_RDY_MSK)
 				if (irq_value & CHL_INT0_NOT_RDY_MSK)
 					/* phy down */
 					/* phy down */
@@ -1583,7 +1578,7 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		spin_lock_irqsave(&hisi_hba->lock, flags);
 		hisi_sas_slot_task_free(hisi_hba, task, slot);
 		hisi_sas_slot_task_free(hisi_hba, task, slot);
 		spin_unlock_irqrestore(&hisi_hba->lock, flags);
 		spin_unlock_irqrestore(&hisi_hba->lock, flags);
-		return -1;
+		return ts->stat;
 	}
 	}
 
 
 	if (unlikely(!sas_dev)) {
 	if (unlikely(!sas_dev)) {
@@ -1864,7 +1859,6 @@ static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no,
 	sas_phy->phy->maximum_linkrate = max;
 	sas_phy->phy->maximum_linkrate = max;
 	sas_phy->phy->minimum_linkrate = min;
 	sas_phy->phy->minimum_linkrate = min;
 
 
-	min -= SAS_LINK_RATE_1_5_GBPS;
 	max -= SAS_LINK_RATE_1_5_GBPS;
 	max -= SAS_LINK_RATE_1_5_GBPS;
 
 
 	for (i = 0; i <= max; i++)
 	for (i = 0; i <= max; i++)
@@ -1873,10 +1867,11 @@ static void phy_set_linkrate_v3_hw(struct hisi_hba *hisi_hba, int phy_no,
 	prog_phy_link_rate &= ~0xff;
 	prog_phy_link_rate &= ~0xff;
 	prog_phy_link_rate |= rate_mask;
 	prog_phy_link_rate |= rate_mask;
 
 
+	disable_phy_v3_hw(hisi_hba, phy_no);
+	msleep(100);
 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
 	hisi_sas_phy_write32(hisi_hba, phy_no, PROG_PHY_LINK_RATE,
 			prog_phy_link_rate);
 			prog_phy_link_rate);
-
-	phy_hard_reset_v3_hw(hisi_hba, phy_no);
+	start_phy_v3_hw(hisi_hba, phy_no);
 }
 }
 
 
 static void interrupt_disable_v3_hw(struct hisi_hba *hisi_hba)
 static void interrupt_disable_v3_hw(struct hisi_hba *hisi_hba)
@@ -2399,6 +2394,7 @@ static const struct pci_device_id sas_v3_pci_table[] = {
 	{ PCI_VDEVICE(HUAWEI, 0xa230), hip08 },
 	{ PCI_VDEVICE(HUAWEI, 0xa230), hip08 },
 	{}
 	{}
 };
 };
+MODULE_DEVICE_TABLE(pci, sas_v3_pci_table);
 
 
 static const struct pci_error_handlers hisi_sas_err_handler = {
 static const struct pci_error_handlers hisi_sas_err_handler = {
 	.error_detected	= hisi_sas_error_detected_v3_hw,
 	.error_detected	= hisi_sas_error_detected_v3_hw,
@@ -2421,4 +2417,4 @@ module_pci_driver(sas_v3_pci_driver);
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
 MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
 MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci device");
 MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci device");
-MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_ALIAS("pci:" DRV_NAME);

+ 6 - 30
drivers/scsi/hosts.c

@@ -42,6 +42,12 @@
 #include "scsi_logging.h"
 #include "scsi_logging.h"
 
 
 
 
+static int shost_eh_deadline = -1;
+
+module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(eh_deadline,
+		 "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
+
 static DEFINE_IDA(host_index_ida);
 static DEFINE_IDA(host_index_ida);
 
 
 
 
@@ -148,7 +154,6 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
 					     scsi_host_state_name(state)));
 					     scsi_host_state_name(state)));
 	return -EINVAL;
 	return -EINVAL;
 }
 }
-EXPORT_SYMBOL(scsi_host_set_state);
 
 
 /**
 /**
  * scsi_remove_host - remove a scsi host
  * scsi_remove_host - remove a scsi host
@@ -356,12 +361,6 @@ static void scsi_host_dev_release(struct device *dev)
 	kfree(shost);
 	kfree(shost);
 }
 }
 
 
-static int shost_eh_deadline = -1;
-
-module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(eh_deadline,
-		 "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
-
 static struct device_type scsi_host_type = {
 static struct device_type scsi_host_type = {
 	.name =		"scsi_host",
 	.name =		"scsi_host",
 	.release =	scsi_host_dev_release,
 	.release =	scsi_host_dev_release,
@@ -517,29 +516,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
 }
 }
 EXPORT_SYMBOL(scsi_host_alloc);
 EXPORT_SYMBOL(scsi_host_alloc);
 
 
-struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize)
-{
-	struct Scsi_Host *shost = scsi_host_alloc(sht, privsize);
-
-	if (!sht->detect) {
-		printk(KERN_WARNING "scsi_register() called on new-style "
-				    "template for driver %s\n", sht->name);
-		dump_stack();
-	}
-
-	if (shost)
-		list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts);
-	return shost;
-}
-EXPORT_SYMBOL(scsi_register);
-
-void scsi_unregister(struct Scsi_Host *shost)
-{
-	list_del(&shost->sht_legacy_list);
-	scsi_host_put(shost);
-}
-EXPORT_SYMBOL(scsi_unregister);
-
 static int __scsi_host_match(struct device *dev, const void *data)
 static int __scsi_host_match(struct device *dev, const void *data)
 {
 {
 	struct Scsi_Host *p;
 	struct Scsi_Host *p;

+ 10 - 43
drivers/scsi/ipr.c

@@ -3816,10 +3816,8 @@ static struct device_attribute ipr_iopoll_weight_attr = {
  **/
  **/
 static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
 static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
 {
 {
-	int sg_size, order, bsize_elem, num_elem, i, j;
+	int sg_size, order;
 	struct ipr_sglist *sglist;
 	struct ipr_sglist *sglist;
-	struct scatterlist *scatterlist;
-	struct page *page;
 
 
 	/* Get the minimum size per scatter/gather element */
 	/* Get the minimum size per scatter/gather element */
 	sg_size = buf_len / (IPR_MAX_SGLIST - 1);
 	sg_size = buf_len / (IPR_MAX_SGLIST - 1);
@@ -3827,45 +3825,18 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
 	/* Get the actual size per element */
 	/* Get the actual size per element */
 	order = get_order(sg_size);
 	order = get_order(sg_size);
 
 
-	/* Determine the actual number of bytes per element */
-	bsize_elem = PAGE_SIZE * (1 << order);
-
-	/* Determine the actual number of sg entries needed */
-	if (buf_len % bsize_elem)
-		num_elem = (buf_len / bsize_elem) + 1;
-	else
-		num_elem = buf_len / bsize_elem;
-
 	/* Allocate a scatter/gather list for the DMA */
 	/* Allocate a scatter/gather list for the DMA */
-	sglist = kzalloc(sizeof(struct ipr_sglist) +
-			 (sizeof(struct scatterlist) * (num_elem - 1)),
-			 GFP_KERNEL);
-
+	sglist = kzalloc(sizeof(struct ipr_sglist), GFP_KERNEL);
 	if (sglist == NULL) {
 	if (sglist == NULL) {
 		ipr_trace;
 		ipr_trace;
 		return NULL;
 		return NULL;
 	}
 	}
-
-	scatterlist = sglist->scatterlist;
-	sg_init_table(scatterlist, num_elem);
-
 	sglist->order = order;
 	sglist->order = order;
-	sglist->num_sg = num_elem;
-
-	/* Allocate a bunch of sg elements */
-	for (i = 0; i < num_elem; i++) {
-		page = alloc_pages(GFP_KERNEL, order);
-		if (!page) {
-			ipr_trace;
-
-			/* Free up what we already allocated */
-			for (j = i - 1; j >= 0; j--)
-				__free_pages(sg_page(&scatterlist[j]), order);
-			kfree(sglist);
-			return NULL;
-		}
-
-		sg_set_page(&scatterlist[i], page, 0, 0);
+	sglist->scatterlist = sgl_alloc_order(buf_len, order, false, GFP_KERNEL,
+					      &sglist->num_sg);
+	if (!sglist->scatterlist) {
+		kfree(sglist);
+		return NULL;
 	}
 	}
 
 
 	return sglist;
 	return sglist;
@@ -3883,11 +3854,7 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
  **/
  **/
 static void ipr_free_ucode_buffer(struct ipr_sglist *sglist)
 static void ipr_free_ucode_buffer(struct ipr_sglist *sglist)
 {
 {
-	int i;
-
-	for (i = 0; i < sglist->num_sg; i++)
-		__free_pages(sg_page(&sglist->scatterlist[i]), sglist->order);
-
+	sgl_free_order(sglist->scatterlist, sglist->order);
 	kfree(sglist);
 	kfree(sglist);
 }
 }
 
 
@@ -9684,14 +9651,14 @@ static int ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
 	}
 	}
 
 
 	for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
 	for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
-		ipr_cmd = dma_pool_alloc(ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr);
+		ipr_cmd = dma_pool_zalloc(ioa_cfg->ipr_cmd_pool,
+				GFP_KERNEL, &dma_addr);
 
 
 		if (!ipr_cmd) {
 		if (!ipr_cmd) {
 			ipr_free_cmd_blks(ioa_cfg);
 			ipr_free_cmd_blks(ioa_cfg);
 			return -ENOMEM;
 			return -ENOMEM;
 		}
 		}
 
 
-		memset(ipr_cmd, 0, sizeof(*ipr_cmd));
 		ioa_cfg->ipr_cmnd_list[i] = ipr_cmd;
 		ioa_cfg->ipr_cmnd_list[i] = ipr_cmd;
 		ioa_cfg->ipr_cmnd_list_dma[i] = dma_addr;
 		ioa_cfg->ipr_cmnd_list_dma[i] = dma_addr;
 
 

+ 1 - 1
drivers/scsi/ipr.h

@@ -1454,7 +1454,7 @@ struct ipr_sglist {
 	u32 num_sg;
 	u32 num_sg;
 	u32 num_dma_sg;
 	u32 num_dma_sg;
 	u32 buffer_len;
 	u32 buffer_len;
-	struct scatterlist scatterlist[1];
+	struct scatterlist *scatterlist;
 };
 };
 
 
 enum ipr_sdt_state {
 enum ipr_sdt_state {

+ 0 - 4
drivers/scsi/ips.c

@@ -224,8 +224,6 @@ module_param(ips, charp, 0);
 /*
 /*
  * Function prototypes
  * Function prototypes
  */
  */
-static int ips_detect(struct scsi_host_template *);
-static int ips_release(struct Scsi_Host *);
 static int ips_eh_abort(struct scsi_cmnd *);
 static int ips_eh_abort(struct scsi_cmnd *);
 static int ips_eh_reset(struct scsi_cmnd *);
 static int ips_eh_reset(struct scsi_cmnd *);
 static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *);
 static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *);
@@ -355,8 +353,6 @@ static dma_addr_t ips_flashbusaddr;
 static long ips_FlashDataInUse;		/* CD Boot - Flash Data In Use Flag */
 static long ips_FlashDataInUse;		/* CD Boot - Flash Data In Use Flag */
 static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */
 static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */
 static struct scsi_host_template ips_driver_template = {
 static struct scsi_host_template ips_driver_template = {
-	.detect			= ips_detect,
-	.release		= ips_release,
 	.info			= ips_info,
 	.info			= ips_info,
 	.queuecommand		= ips_queue,
 	.queuecommand		= ips_queue,
 	.eh_abort_handler	= ips_eh_abort,
 	.eh_abort_handler	= ips_eh_abort,

+ 1 - 1
drivers/scsi/isci/host.c

@@ -2766,7 +2766,7 @@ static int sci_write_gpio_tx_gp(struct isci_host *ihost, u8 reg_index, u8 reg_co
 		int i;
 		int i;
 
 
 		for (i = 0; i < 3; i++) {
 		for (i = 0; i < 3; i++) {
-			int bit = (i << 2) + 2;
+			int bit;
 
 
 			bit = try_test_sas_gpio_gp_bit(to_sas_gpio_od(d, i),
 			bit = try_test_sas_gpio_gp_bit(to_sas_gpio_od(d, i),
 						       write_data, reg_index,
 						       write_data, reg_index,

+ 1 - 1
drivers/scsi/jazz_esp.c

@@ -147,7 +147,7 @@ static int esp_jazz_probe(struct platform_device *dev)
 	esp = shost_priv(host);
 	esp = shost_priv(host);
 
 
 	esp->host = host;
 	esp->host = host;
-	esp->dev = dev;
+	esp->dev = &dev->dev;
 	esp->ops = &jazz_esp_ops;
 	esp->ops = &jazz_esp_ops;
 
 
 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);

+ 1 - 1
drivers/scsi/libfc/fc_disc.c

@@ -731,7 +731,7 @@ static void fc_disc_stop_final(struct fc_lport *lport)
  */
  */
 void fc_disc_config(struct fc_lport *lport, void *priv)
 void fc_disc_config(struct fc_lport *lport, void *priv)
 {
 {
-	struct fc_disc *disc = &lport->disc;
+	struct fc_disc *disc;
 
 
 	if (!lport->tt.disc_start)
 	if (!lport->tt.disc_start)
 		lport->tt.disc_start = fc_disc_start;
 		lport->tt.disc_start = fc_disc_start;

+ 1 - 1
drivers/scsi/libsas/sas_ata.c

@@ -709,7 +709,7 @@ void sas_resume_sata(struct asd_sas_port *port)
 }
 }
 
 
 /**
 /**
- * sas_discover_sata -- discover an STP/SATA domain device
+ * sas_discover_sata - discover an STP/SATA domain device
  * @dev: pointer to struct domain_device of interest
  * @dev: pointer to struct domain_device of interest
  *
  *
  * Devices directly attached to a HA port, have no parents.  All other
  * Devices directly attached to a HA port, have no parents.  All other

+ 7 - 6
drivers/scsi/libsas/sas_discover.c

@@ -55,7 +55,7 @@ void sas_init_dev(struct domain_device *dev)
 /* ---------- Domain device discovery ---------- */
 /* ---------- Domain device discovery ---------- */
 
 
 /**
 /**
- * sas_get_port_device -- Discover devices which caused port creation
+ * sas_get_port_device - Discover devices which caused port creation
  * @port: pointer to struct sas_port of interest
  * @port: pointer to struct sas_port of interest
  *
  *
  * Devices directly attached to a HA port, have no parent.  This is
  * Devices directly attached to a HA port, have no parent.  This is
@@ -278,8 +278,8 @@ static void sas_resume_devices(struct work_struct *work)
 }
 }
 
 
 /**
 /**
- * sas_discover_end_dev -- discover an end device (SSP, etc)
- * @end: pointer to domain device of interest
+ * sas_discover_end_dev - discover an end device (SSP, etc)
+ * @dev: pointer to domain device of interest
  *
  *
  * See comment in sas_discover_sata().
  * See comment in sas_discover_sata().
  */
  */
@@ -428,8 +428,8 @@ void sas_device_set_phy(struct domain_device *dev, struct sas_port *port)
 /* ---------- Discovery and Revalidation ---------- */
 /* ---------- Discovery and Revalidation ---------- */
 
 
 /**
 /**
- * sas_discover_domain -- discover the domain
- * @port: port to the domain of interest
+ * sas_discover_domain - discover the domain
+ * @work: work structure embedded in port domain device.
  *
  *
  * NOTE: this process _must_ quit (return) as soon as any connection
  * NOTE: this process _must_ quit (return) as soon as any connection
  * errors are encountered.  Connection recovery is done elsewhere.
  * errors are encountered.  Connection recovery is done elsewhere.
@@ -572,7 +572,8 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
 }
 }
 
 
 /**
 /**
- * sas_init_disc -- initialize the discovery struct in the port
+ * sas_init_disc - initialize the discovery struct in the port
+ * @disc: port discovery structure
  * @port: pointer to struct port
  * @port: pointer to struct port
  *
  *
  * Called when the ports are being initialized.
  * Called when the ports are being initialized.

+ 15 - 14
drivers/scsi/libsas/sas_expander.c

@@ -1170,9 +1170,9 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev)
 	return 0;
 	return 0;
 }
 }
 /**
 /**
- * sas_ex_discover_devices -- discover devices attached to this expander
- * dev: pointer to the expander domain device
- * single: if you want to do a single phy, else set to -1;
+ * sas_ex_discover_devices - discover devices attached to this expander
+ * @dev: pointer to the expander domain device
+ * @single: if you want to do a single phy, else set to -1;
  *
  *
  * Configure this expander for use with its devices and register the
  * Configure this expander for use with its devices and register the
  * devices of this expander.
  * devices of this expander.
@@ -1528,10 +1528,11 @@ static int sas_configure_phy(struct domain_device *dev, int phy_id,
 }
 }
 
 
 /**
 /**
- * sas_configure_parent -- configure routing table of parent
- * parent: parent expander
- * child: child expander
- * sas_addr: SAS port identifier of device directly attached to child
+ * sas_configure_parent - configure routing table of parent
+ * @parent: parent expander
+ * @child: child expander
+ * @sas_addr: SAS port identifier of device directly attached to child
+ * @include: whether or not to include @child in the expander routing table
  */
  */
 static int sas_configure_parent(struct domain_device *parent,
 static int sas_configure_parent(struct domain_device *parent,
 				struct domain_device *child,
 				struct domain_device *child,
@@ -1570,9 +1571,9 @@ static int sas_configure_parent(struct domain_device *parent,
 }
 }
 
 
 /**
 /**
- * sas_configure_routing -- configure routing
- * dev: expander device
- * sas_addr: port identifier of device directly attached to the expander device
+ * sas_configure_routing - configure routing
+ * @dev: expander device
+ * @sas_addr: port identifier of device directly attached to the expander device
  */
  */
 static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr)
 static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr)
 {
 {
@@ -1589,8 +1590,8 @@ static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr)
 }
 }
 
 
 /**
 /**
- * sas_discover_expander -- expander discovery
- * @ex: pointer to expander domain device
+ * sas_discover_expander - expander discovery
+ * @dev: pointer to expander domain device
  *
  *
  * See comment in sas_discover_sata().
  * See comment in sas_discover_sata().
  */
  */
@@ -2111,8 +2112,8 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id)
 }
 }
 
 
 /**
 /**
- * sas_revalidate_domain -- revalidate the domain
- * @port: port to the domain of interest
+ * sas_ex_revalidate_domain - revalidate the domain
+ * @port_dev: port domain device.
  *
  *
  * NOTE: this process _must_ quit (return) as soon as any connection
  * NOTE: this process _must_ quit (return) as soon as any connection
  * errors are encountered.  Connection recovery is done elsewhere.
  * errors are encountered.  Connection recovery is done elsewhere.

+ 1 - 1
drivers/scsi/libsas/sas_init.c

@@ -234,7 +234,7 @@ int sas_try_ata_reset(struct asd_sas_phy *asd_phy)
 	return -ENODEV;
 	return -ENODEV;
 }
 }
 
 
-/**
+/*
  * transport_sas_phy_reset - reset a phy and permit libata to manage the link
  * transport_sas_phy_reset - reset a phy and permit libata to manage the link
  *
  *
  * phy reset request via sysfs in host workqueue context so we know we
  * phy reset request via sysfs in host workqueue context so we know we

+ 3 - 2
drivers/scsi/libsas/sas_port.c

@@ -84,7 +84,7 @@ static void sas_resume_port(struct asd_sas_phy *phy)
 }
 }
 
 
 /**
 /**
- * sas_form_port -- add this phy to a port
+ * sas_form_port - add this phy to a port
  * @phy: the phy of interest
  * @phy: the phy of interest
  *
  *
  * This function adds this phy to an existing port, thus creating a wide
  * This function adds this phy to an existing port, thus creating a wide
@@ -197,8 +197,9 @@ static void sas_form_port(struct asd_sas_phy *phy)
 }
 }
 
 
 /**
 /**
- * sas_deform_port -- remove this phy from the port it belongs to
+ * sas_deform_port - remove this phy from the port it belongs to
  * @phy: the phy of interest
  * @phy: the phy of interest
+ * @gone: whether or not the PHY is gone
  *
  *
  * This is called when the physical link to the other phy has been
  * This is called when the physical link to the other phy has been
  * lost (on this phy), in Event thread context. We cannot delay here.
  * lost (on this phy), in Event thread context. We cannot delay here.

+ 11 - 12
drivers/scsi/lpfc/lpfc.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -544,16 +544,10 @@ struct unsol_rcv_ct_ctx {
 #define LPFC_USER_LINK_SPEED_10G	10	/* 10 Gigabaud */
 #define LPFC_USER_LINK_SPEED_10G	10	/* 10 Gigabaud */
 #define LPFC_USER_LINK_SPEED_16G	16	/* 16 Gigabaud */
 #define LPFC_USER_LINK_SPEED_16G	16	/* 16 Gigabaud */
 #define LPFC_USER_LINK_SPEED_32G	32	/* 32 Gigabaud */
 #define LPFC_USER_LINK_SPEED_32G	32	/* 32 Gigabaud */
-#define LPFC_USER_LINK_SPEED_MAX	LPFC_USER_LINK_SPEED_32G
-#define LPFC_USER_LINK_SPEED_BITMAP  ((1ULL << LPFC_USER_LINK_SPEED_32G) | \
-				     (1 << LPFC_USER_LINK_SPEED_16G) | \
-				     (1 << LPFC_USER_LINK_SPEED_10G) | \
-				     (1 << LPFC_USER_LINK_SPEED_8G) | \
-				     (1 << LPFC_USER_LINK_SPEED_4G) | \
-				     (1 << LPFC_USER_LINK_SPEED_2G) | \
-				     (1 << LPFC_USER_LINK_SPEED_1G) | \
-				     (1 << LPFC_USER_LINK_SPEED_AUTO))
-#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32"
+#define LPFC_USER_LINK_SPEED_64G	64	/* 64 Gigabaud */
+#define LPFC_USER_LINK_SPEED_MAX	LPFC_USER_LINK_SPEED_64G
+
+#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32, 64"
 
 
 enum nemb_type {
 enum nemb_type {
 	nemb_mse = 1,
 	nemb_mse = 1,
@@ -760,6 +754,7 @@ struct lpfc_hba {
 	uint8_t  mds_diags_support;
 	uint8_t  mds_diags_support;
 	uint32_t initial_imax;
 	uint32_t initial_imax;
 	uint8_t  bbcredit_support;
 	uint8_t  bbcredit_support;
+	uint8_t  enab_exp_wqcq_pages;
 
 
 	/* HBA Config Parameters */
 	/* HBA Config Parameters */
 	uint32_t cfg_ack0;
 	uint32_t cfg_ack0;
@@ -787,6 +782,7 @@ struct lpfc_hba {
 	uint32_t cfg_fcp_io_channel;
 	uint32_t cfg_fcp_io_channel;
 	uint32_t cfg_suppress_rsp;
 	uint32_t cfg_suppress_rsp;
 	uint32_t cfg_nvme_oas;
 	uint32_t cfg_nvme_oas;
+	uint32_t cfg_nvme_embed_cmd;
 	uint32_t cfg_nvme_io_channel;
 	uint32_t cfg_nvme_io_channel;
 	uint32_t cfg_nvmet_mrq;
 	uint32_t cfg_nvmet_mrq;
 	uint32_t cfg_enable_nvmet;
 	uint32_t cfg_enable_nvmet;
@@ -839,11 +835,14 @@ struct lpfc_hba {
 	uint32_t cfg_enable_SmartSAN;
 	uint32_t cfg_enable_SmartSAN;
 	uint32_t cfg_enable_mds_diags;
 	uint32_t cfg_enable_mds_diags;
 	uint32_t cfg_enable_fc4_type;
 	uint32_t cfg_enable_fc4_type;
-	uint32_t cfg_enable_bbcr;	/*Enable BB Credit Recovery*/
+	uint32_t cfg_enable_bbcr;	/* Enable BB Credit Recovery */
+	uint32_t cfg_enable_dpp;	/* Enable Direct Packet Push */
 	uint32_t cfg_xri_split;
 	uint32_t cfg_xri_split;
 #define LPFC_ENABLE_FCP  1
 #define LPFC_ENABLE_FCP  1
 #define LPFC_ENABLE_NVME 2
 #define LPFC_ENABLE_NVME 2
 #define LPFC_ENABLE_BOTH 3
 #define LPFC_ENABLE_BOTH 3
+	uint32_t nvme_embed_pbde;
+	uint32_t fcp_embed_pbde;
 	uint32_t io_channel_irqs;	/* number of irqs for io channels */
 	uint32_t io_channel_irqs;	/* number of irqs for io channels */
 	struct nvmet_fc_target_port *targetport;
 	struct nvmet_fc_target_port *targetport;
 	lpfc_vpd_t vpd;		/* vital product data */
 	lpfc_vpd_t vpd;		/* vital product data */

+ 86 - 21
drivers/scsi/lpfc/lpfc_attr.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -259,6 +259,12 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
 				atomic_read(&tgtp->xmt_abort_rsp),
 				atomic_read(&tgtp->xmt_abort_rsp),
 				atomic_read(&tgtp->xmt_abort_rsp_error));
 				atomic_read(&tgtp->xmt_abort_rsp_error));
 
 
+		len += snprintf(buf + len, PAGE_SIZE - len,
+				"DELAY: ctx %08x  fod %08x wqfull %08x\n",
+				atomic_read(&tgtp->defer_ctx),
+				atomic_read(&tgtp->defer_fod),
+				atomic_read(&tgtp->defer_wqfull));
+
 		/* Calculate outstanding IOs */
 		/* Calculate outstanding IOs */
 		tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
 		tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
 		tot += atomic_read(&tgtp->xmt_fcp_release);
 		tot += atomic_read(&tgtp->xmt_fcp_release);
@@ -905,7 +911,12 @@ lpfc_issue_lip(struct Scsi_Host *shost)
 	LPFC_MBOXQ_t *pmboxq;
 	LPFC_MBOXQ_t *pmboxq;
 	int mbxstatus = MBXERR_ERROR;
 	int mbxstatus = MBXERR_ERROR;
 
 
+	/*
+	 * If the link is offline, disabled or BLOCK_MGMT_IO
+	 * it doesn't make any sense to allow issue_lip
+	 */
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+	    (phba->hba_flag & LINK_DISABLED) ||
 	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
 	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
 		return -EPERM;
 		return -EPERM;
 
 
@@ -3458,8 +3469,8 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512,
 # tgt_queue_depth:  This parameter is used to limit the number of outstanding
 # tgt_queue_depth:  This parameter is used to limit the number of outstanding
 # commands per target port. Value range is [10,65535]. Default value is 65535.
 # commands per target port. Value range is [10,65535]. Default value is 65535.
 */
 */
-LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
-		  "Max number of FCP commands we can queue to a specific target port");
+LPFC_VPORT_ATTR_RW(tgt_queue_depth, 65535, 10, 65535,
+		   "Max number of FCP commands we can queue to a specific target port");
 
 
 /*
 /*
 # hba_queue_depth:  This parameter is used to limit the number of outstanding
 # hba_queue_depth:  This parameter is used to limit the number of outstanding
@@ -4104,23 +4115,32 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
 	    ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
 	    ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
 	    ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) ||
 	    ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) ||
 	    ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb)) ||
 	    ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb)) ||
-	    ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb))) {
+	    ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb)) ||
+	    ((val == LPFC_USER_LINK_SPEED_64G) && !(phba->lmt & LMT_64Gb))) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"2879 lpfc_link_speed attribute cannot be set "
 				"2879 lpfc_link_speed attribute cannot be set "
 				"to %d. Speed is not supported by this port.\n",
 				"to %d. Speed is not supported by this port.\n",
 				val);
 				val);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
-	if (val == LPFC_USER_LINK_SPEED_16G &&
-		 phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
+	if (val >= LPFC_USER_LINK_SPEED_16G &&
+	    phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"3112 lpfc_link_speed attribute cannot be set "
 				"3112 lpfc_link_speed attribute cannot be set "
 				"to %d. Speed is not supported in loop mode.\n",
 				"to %d. Speed is not supported in loop mode.\n",
 				val);
 				val);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
-	if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) &&
-	    (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) {
+
+	switch (val) {
+	case LPFC_USER_LINK_SPEED_AUTO:
+	case LPFC_USER_LINK_SPEED_1G:
+	case LPFC_USER_LINK_SPEED_2G:
+	case LPFC_USER_LINK_SPEED_4G:
+	case LPFC_USER_LINK_SPEED_8G:
+	case LPFC_USER_LINK_SPEED_16G:
+	case LPFC_USER_LINK_SPEED_32G:
+	case LPFC_USER_LINK_SPEED_64G:
 		prev_val = phba->cfg_link_speed;
 		prev_val = phba->cfg_link_speed;
 		phba->cfg_link_speed = val;
 		phba->cfg_link_speed = val;
 		if (nolip)
 		if (nolip)
@@ -4130,13 +4150,18 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
 		if (err) {
 		if (err) {
 			phba->cfg_link_speed = prev_val;
 			phba->cfg_link_speed = prev_val;
 			return -EINVAL;
 			return -EINVAL;
-		} else
-			return strlen(buf);
+		}
+		return strlen(buf);
+	default:
+		break;
 	}
 	}
+
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-		"0469 lpfc_link_speed attribute cannot be set to %d, "
-		"allowed values are ["LPFC_LINK_SPEED_STRING"]\n", val);
+			"0469 lpfc_link_speed attribute cannot be set to %d, "
+			"allowed values are [%s]\n",
+			val, LPFC_LINK_SPEED_STRING);
 	return -EINVAL;
 	return -EINVAL;
+
 }
 }
 
 
 static int lpfc_link_speed = 0;
 static int lpfc_link_speed = 0;
@@ -4163,24 +4188,33 @@ lpfc_param_show(link_speed)
 static int
 static int
 lpfc_link_speed_init(struct lpfc_hba *phba, int val)
 lpfc_link_speed_init(struct lpfc_hba *phba, int val)
 {
 {
-	if (val == LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) {
+	if (val >= LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"3111 lpfc_link_speed of %d cannot "
 			"3111 lpfc_link_speed of %d cannot "
 			"support loop mode, setting topology to default.\n",
 			"support loop mode, setting topology to default.\n",
 			 val);
 			 val);
 		phba->cfg_topology = 0;
 		phba->cfg_topology = 0;
 	}
 	}
-	if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) &&
-	    (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) {
+
+	switch (val) {
+	case LPFC_USER_LINK_SPEED_AUTO:
+	case LPFC_USER_LINK_SPEED_1G:
+	case LPFC_USER_LINK_SPEED_2G:
+	case LPFC_USER_LINK_SPEED_4G:
+	case LPFC_USER_LINK_SPEED_8G:
+	case LPFC_USER_LINK_SPEED_16G:
+	case LPFC_USER_LINK_SPEED_32G:
+	case LPFC_USER_LINK_SPEED_64G:
 		phba->cfg_link_speed = val;
 		phba->cfg_link_speed = val;
 		return 0;
 		return 0;
+	default:
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0405 lpfc_link_speed attribute cannot "
+				"be set to %d, allowed values are "
+				"["LPFC_LINK_SPEED_STRING"]\n", val);
+		phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
+		return -EINVAL;
 	}
 	}
-	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"0405 lpfc_link_speed attribute cannot "
-			"be set to %d, allowed values are "
-			"["LPFC_LINK_SPEED_STRING"]\n", val);
-	phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
-	return -EINVAL;
 }
 }
 
 
 static DEVICE_ATTR_RW(lpfc_link_speed);
 static DEVICE_ATTR_RW(lpfc_link_speed);
@@ -5007,6 +5041,18 @@ LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or "
 LPFC_ATTR_RW(nvme_oas, 0, 0, 1,
 LPFC_ATTR_RW(nvme_oas, 0, 0, 1,
 	     "Use OAS bit on NVME IOs");
 	     "Use OAS bit on NVME IOs");
 
 
+/*
+ * lpfc_nvme_embed_cmd: Use the oas bit when sending NVME/NVMET IOs
+ *
+ *      0  = Put NVME Command in SGL
+ *      1  = Embed NVME Command in WQE (unless G7)
+ *      2 =  Embed NVME Command in WQE (force)
+ *
+ * Value range is [0,2]. Default value is 1.
+ */
+LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2,
+	     "Embed NVME Command in WQE");
+
 /*
 /*
  * lpfc_fcp_io_channel: Set the number of FCP IO channels the driver
  * lpfc_fcp_io_channel: Set the number of FCP IO channels the driver
  * will advertise it supports to the SCSI layer. This also will map to
  * will advertise it supports to the SCSI layer. This also will map to
@@ -5175,6 +5221,14 @@ LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics");
  */
  */
 LPFC_BBCR_ATTR_RW(enable_bbcr, 1, 0, 1, "Enable BBC Recovery");
 LPFC_BBCR_ATTR_RW(enable_bbcr, 1, 0, 1, "Enable BBC Recovery");
 
 
+/*
+ * lpfc_enable_dpp: Enable DPP on G7
+ *       0  = DPP on G7 disabled
+ *       1  = DPP on G7 enabled (default)
+ * Value range is [0,1]. Default value is 1.
+ */
+LPFC_ATTR_RW(enable_dpp, 1, 0, 1, "Enable Direct Packet Push");
+
 struct device_attribute *lpfc_hba_attrs[] = {
 struct device_attribute *lpfc_hba_attrs[] = {
 	&dev_attr_nvme_info,
 	&dev_attr_nvme_info,
 	&dev_attr_bg_info,
 	&dev_attr_bg_info,
@@ -5240,6 +5294,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
 	&dev_attr_lpfc_task_mgmt_tmo,
 	&dev_attr_lpfc_task_mgmt_tmo,
 	&dev_attr_lpfc_use_msi,
 	&dev_attr_lpfc_use_msi,
 	&dev_attr_lpfc_nvme_oas,
 	&dev_attr_lpfc_nvme_oas,
+	&dev_attr_lpfc_nvme_embed_cmd,
 	&dev_attr_lpfc_auto_imax,
 	&dev_attr_lpfc_auto_imax,
 	&dev_attr_lpfc_fcp_imax,
 	&dev_attr_lpfc_fcp_imax,
 	&dev_attr_lpfc_fcp_cpu_map,
 	&dev_attr_lpfc_fcp_cpu_map,
@@ -5283,6 +5338,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
 	&dev_attr_lpfc_xlane_supported,
 	&dev_attr_lpfc_xlane_supported,
 	&dev_attr_lpfc_enable_mds_diags,
 	&dev_attr_lpfc_enable_mds_diags,
 	&dev_attr_lpfc_enable_bbcr,
 	&dev_attr_lpfc_enable_bbcr,
+	&dev_attr_lpfc_enable_dpp,
 	NULL,
 	NULL,
 };
 };
 
 
@@ -5696,6 +5752,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
 		case LPFC_LINK_SPEED_32GHZ:
 		case LPFC_LINK_SPEED_32GHZ:
 			fc_host_speed(shost) = FC_PORTSPEED_32GBIT;
 			fc_host_speed(shost) = FC_PORTSPEED_32GBIT;
 			break;
 			break;
+		case LPFC_LINK_SPEED_64GHZ:
+			fc_host_speed(shost) = FC_PORTSPEED_64GBIT;
+			break;
 		default:
 		default:
 			fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 			fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 			break;
 			break;
@@ -6260,6 +6319,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
 	lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
 	lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
 	lpfc_nvme_oas_init(phba, lpfc_nvme_oas);
 	lpfc_nvme_oas_init(phba, lpfc_nvme_oas);
+	lpfc_nvme_embed_cmd_init(phba, lpfc_nvme_embed_cmd);
 	lpfc_auto_imax_init(phba, lpfc_auto_imax);
 	lpfc_auto_imax_init(phba, lpfc_auto_imax);
 	lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
 	lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
 	lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
 	lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
@@ -6284,6 +6344,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
 		phba->cfg_poll = 0;
 		phba->cfg_poll = 0;
 	else
 	else
 		phba->cfg_poll = lpfc_poll;
 		phba->cfg_poll = lpfc_poll;
+
+	if (phba->cfg_enable_bg)
+		phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
+
 	lpfc_suppress_rsp_init(phba, lpfc_suppress_rsp);
 	lpfc_suppress_rsp_init(phba, lpfc_suppress_rsp);
 
 
 	lpfc_enable_fc4_type_init(phba, lpfc_enable_fc4_type);
 	lpfc_enable_fc4_type_init(phba, lpfc_enable_fc4_type);
@@ -6295,6 +6359,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
 	lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
 	lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
 	lpfc_nvme_io_channel_init(phba, lpfc_nvme_io_channel);
 	lpfc_nvme_io_channel_init(phba, lpfc_nvme_io_channel);
 	lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr);
 	lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr);
+	lpfc_enable_dpp_init(phba, lpfc_enable_dpp);
 
 
 	if (phba->sli_rev != LPFC_SLI_REV4) {
 	if (phba->sli_rev != LPFC_SLI_REV4) {
 		/* NVME only supported on SLI4 */
 		/* NVME only supported on SLI4 */

+ 3 - 3
drivers/scsi/lpfc/lpfc_bsg.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2009-2015 Emulex.  All rights reserved.           *
  * Copyright (C) 2009-2015 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -3867,7 +3867,7 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job,
 				"ext_buf_cnt:%d\n", ext_buf_cnt);
 				"ext_buf_cnt:%d\n", ext_buf_cnt);
 	} else {
 	} else {
 		/* sanity check on interface type for support */
 		/* sanity check on interface type for support */
-		if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+		if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
 		    LPFC_SLI_INTF_IF_TYPE_2) {
 		    LPFC_SLI_INTF_IF_TYPE_2) {
 			rc = -ENODEV;
 			rc = -ENODEV;
 			goto job_error;
 			goto job_error;
@@ -4053,7 +4053,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct bsg_job *job,
 				"ext_buf_cnt:%d\n", ext_buf_cnt);
 				"ext_buf_cnt:%d\n", ext_buf_cnt);
 	} else {
 	} else {
 		/* sanity check on interface type for support */
 		/* sanity check on interface type for support */
-		if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+		if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
 		    LPFC_SLI_INTF_IF_TYPE_2)
 		    LPFC_SLI_INTF_IF_TYPE_2)
 			return -ENODEV;
 			return -ENODEV;
 		/* nemb_tp == nemb_hbd */
 		/* nemb_tp == nemb_hbd */

+ 4 - 1
drivers/scsi/lpfc/lpfc_crtn.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -254,6 +254,7 @@ void lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba,
 			    struct lpfc_nvmet_ctxbuf *ctxp);
 			    struct lpfc_nvmet_ctxbuf *ctxp);
 int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
 int lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
 			       struct fc_frame_header *fc_hdr);
 			       struct fc_frame_header *fc_hdr);
+void lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, struct lpfc_queue *wq);
 void lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba);
 void lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba);
 void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba);
 void lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba);
 void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *,
 void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *,
@@ -564,6 +565,8 @@ void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba);
 void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba,
 void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba,
 				struct lpfc_iocbq *cmdiocb,
 				struct lpfc_iocbq *cmdiocb,
 				struct lpfc_wcqe_complete *abts_cmpl);
 				struct lpfc_wcqe_complete *abts_cmpl);
+void lpfc_nvme_cmd_template(void);
+void lpfc_nvmet_cmd_template(void);
 extern int lpfc_enable_nvmet_cnt;
 extern int lpfc_enable_nvmet_cnt;
 extern unsigned long long lpfc_enable_nvmet[];
 extern unsigned long long lpfc_enable_nvmet[];
 extern int lpfc_no_hba_reset_cnt;
 extern int lpfc_no_hba_reset_cnt;

+ 6 - 2
drivers/scsi/lpfc/lpfc_ct.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -471,7 +471,6 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type)
 				"Parse GID_FTrsp: did:x%x flg:x%x x%x",
 				"Parse GID_FTrsp: did:x%x flg:x%x x%x",
 				Did, ndlp->nlp_flag, vport->fc_flag);
 				Did, ndlp->nlp_flag, vport->fc_flag);
 
 
-			ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
 			/* By default, the driver expects to support FCP FC4 */
 			/* By default, the driver expects to support FCP FC4 */
 			if (fc4_type == FC_TYPE_FCP)
 			if (fc4_type == FC_TYPE_FCP)
 				ndlp->nlp_fc4_type |= NLP_FC4_FCP;
 				ndlp->nlp_fc4_type |= NLP_FC4_FCP;
@@ -2130,6 +2129,8 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
 
 
 	ae->un.AttrInt = 0;
 	ae->un.AttrInt = 0;
 	if (!(phba->hba_flag & HBA_FCOE_MODE)) {
 	if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+		if (phba->lmt & LMT_64Gb)
+			ae->un.AttrInt |= HBA_PORTSPEED_64GFC;
 		if (phba->lmt & LMT_32Gb)
 		if (phba->lmt & LMT_32Gb)
 			ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
 			ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
 		if (phba->lmt & LMT_16Gb)
 		if (phba->lmt & LMT_16Gb)
@@ -2201,6 +2202,9 @@ lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
 		case LPFC_LINK_SPEED_32GHZ:
 		case LPFC_LINK_SPEED_32GHZ:
 			ae->un.AttrInt = HBA_PORTSPEED_32GFC;
 			ae->un.AttrInt = HBA_PORTSPEED_32GFC;
 			break;
 			break;
+		case LPFC_LINK_SPEED_64GHZ:
+			ae->un.AttrInt = HBA_PORTSPEED_64GFC;
+			break;
 		default:
 		default:
 			ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
 			ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
 			break;
 			break;

+ 15 - 7
drivers/scsi/lpfc/lpfc_debugfs.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2007-2015 Emulex.  All rights reserved.           *
  * Copyright (C) 2007-2015 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -3944,10 +3944,15 @@ lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
 		return 0;
 		return 0;
 
 
 	switch (drbregid) {
 	switch (drbregid) {
-	case LPFC_DRB_EQCQ:
-		len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
-				"EQCQ-DRB-REG: 0x%08x\n",
-				readl(phba->sli4_hba.EQCQDBregaddr));
+	case LPFC_DRB_EQ:
+		len += snprintf(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,
+				"CQ-DRB-REG: 0x%08x\n",
+				readl(phba->sli4_hba.CQDBregaddr));
 		break;
 		break;
 	case LPFC_DRB_MQ:
 	case LPFC_DRB_MQ:
 		len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
 		len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len,
@@ -4086,8 +4091,11 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
 	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) {
 		switch (drb_reg_id) {
 		switch (drb_reg_id) {
-		case LPFC_DRB_EQCQ:
-			drb_reg = phba->sli4_hba.EQCQDBregaddr;
+		case LPFC_DRB_EQ:
+			drb_reg = phba->sli4_hba.EQDBregaddr;
+			break;
+		case LPFC_DRB_CQ:
+			drb_reg = phba->sli4_hba.CQDBregaddr;
 			break;
 			break;
 		case LPFC_DRB_MQ:
 		case LPFC_DRB_MQ:
 			drb_reg = phba->sli4_hba.MQDBregaddr;
 			drb_reg = phba->sli4_hba.MQDBregaddr;

+ 7 - 6
drivers/scsi/lpfc/lpfc_debugfs.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2007-2011 Emulex.  All rights reserved.           *
  * Copyright (C) 2007-2011 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -126,12 +126,13 @@
 #define LPFC_DRB_ACC_WR_CMD_ARG 2
 #define LPFC_DRB_ACC_WR_CMD_ARG 2
 #define LPFC_DRB_ACC_BUF_SIZE 256
 #define LPFC_DRB_ACC_BUF_SIZE 256
 
 
-#define LPFC_DRB_EQCQ 1
-#define LPFC_DRB_MQ   2
-#define LPFC_DRB_WQ   3
-#define LPFC_DRB_RQ   4
+#define LPFC_DRB_EQ   1
+#define LPFC_DRB_CQ   2
+#define LPFC_DRB_MQ   3
+#define LPFC_DRB_WQ   4
+#define LPFC_DRB_RQ   5
 
 
-#define LPFC_DRB_MAX  4
+#define LPFC_DRB_MAX  5
 
 
 #define IDIAG_DRBACC_REGID_INDX 0
 #define IDIAG_DRBACC_REGID_INDX 0
 #define IDIAG_DRBACC_VALUE_INDX 1
 #define IDIAG_DRBACC_VALUE_INDX 1

+ 9 - 2
drivers/scsi/lpfc/lpfc_els.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -1661,6 +1661,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 		if (ndlp->nrport) {
 		if (ndlp->nrport) {
 			ndlp->nrport = NULL;
 			ndlp->nrport = NULL;
 			lpfc_nlp_put(ndlp);
 			lpfc_nlp_put(ndlp);
+			new_ndlp->nlp_fc4_type = ndlp->nlp_fc4_type;
 		}
 		}
 
 
 		/* We shall actually free the ndlp with both nlp_DID and
 		/* We shall actually free the ndlp with both nlp_DID and
@@ -2293,10 +2294,11 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		if (phba->nvmet_support) {
 		if (phba->nvmet_support) {
 			bf_set(prli_tgt, npr_nvme, 1);
 			bf_set(prli_tgt, npr_nvme, 1);
 			bf_set(prli_disc, npr_nvme, 1);
 			bf_set(prli_disc, npr_nvme, 1);
-
 		} else {
 		} else {
 			bf_set(prli_init, npr_nvme, 1);
 			bf_set(prli_init, npr_nvme, 1);
+			bf_set(prli_conf, npr_nvme, 1);
 		}
 		}
+
 		npr_nvme->word1 = cpu_to_be32(npr_nvme->word1);
 		npr_nvme->word1 = cpu_to_be32(npr_nvme->word1);
 		npr_nvme->word4 = cpu_to_be32(npr_nvme->word4);
 		npr_nvme->word4 = cpu_to_be32(npr_nvme->word4);
 		elsiocb->iocb_flag |= LPFC_PRLI_NVME_REQ;
 		elsiocb->iocb_flag |= LPFC_PRLI_NVME_REQ;
@@ -5269,6 +5271,9 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
 	case LPFC_LINK_SPEED_32GHZ:
 	case LPFC_LINK_SPEED_32GHZ:
 		rdp_speed = RDP_PS_32GB;
 		rdp_speed = RDP_PS_32GB;
 		break;
 		break;
+	case LPFC_LINK_SPEED_64GHZ:
+		rdp_speed = RDP_PS_64GB;
+		break;
 	default:
 	default:
 		rdp_speed = RDP_PS_UNKNOWN;
 		rdp_speed = RDP_PS_UNKNOWN;
 		break;
 		break;
@@ -5276,6 +5281,8 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
 
 
 	desc->info.port_speed.speed = cpu_to_be16(rdp_speed);
 	desc->info.port_speed.speed = cpu_to_be16(rdp_speed);
 
 
+	if (phba->lmt & LMT_64Gb)
+		rdp_cap |= RDP_PS_64GB;
 	if (phba->lmt & LMT_32Gb)
 	if (phba->lmt & LMT_32Gb)
 		rdp_cap |= RDP_PS_32GB;
 		rdp_cap |= RDP_PS_32GB;
 	if (phba->lmt & LMT_16Gb)
 	if (phba->lmt & LMT_16Gb)

+ 10 - 3
drivers/scsi/lpfc/lpfc_hbadisc.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -696,8 +696,9 @@ lpfc_work_done(struct lpfc_hba *phba)
 		      phba->hba_flag & HBA_SP_QUEUE_EVT)) {
 		      phba->hba_flag & HBA_SP_QUEUE_EVT)) {
 		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
 		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
 			pring->flag |= LPFC_DEFERRED_RING_EVENT;
 			pring->flag |= LPFC_DEFERRED_RING_EVENT;
-			/* Set the lpfc data pending flag */
-			set_bit(LPFC_DATA_READY, &phba->data_flags);
+			/* Preserve legacy behavior. */
+			if (!(phba->hba_flag & HBA_SP_QUEUE_EVT))
+				set_bit(LPFC_DATA_READY, &phba->data_flags);
 		} else {
 		} else {
 			if (phba->link_state >= LPFC_LINK_UP ||
 			if (phba->link_state >= LPFC_LINK_UP ||
 			    phba->link_flag & LS_MDS_LOOPBACK) {
 			    phba->link_flag & LS_MDS_LOOPBACK) {
@@ -958,6 +959,7 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport)
 	struct lpfc_nodelist *ndlp;
 	struct lpfc_nodelist *ndlp;
 
 
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+		ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
 		if (!NLP_CHK_NODE_ACT(ndlp))
 		if (!NLP_CHK_NODE_ACT(ndlp))
 			continue;
 			continue;
 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
@@ -3083,6 +3085,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
 		case LPFC_LINK_SPEED_10GHZ:
 		case LPFC_LINK_SPEED_10GHZ:
 		case LPFC_LINK_SPEED_16GHZ:
 		case LPFC_LINK_SPEED_16GHZ:
 		case LPFC_LINK_SPEED_32GHZ:
 		case LPFC_LINK_SPEED_32GHZ:
+		case LPFC_LINK_SPEED_64GHZ:
 			break;
 			break;
 		default:
 		default:
 			phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
 			phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
@@ -3873,6 +3876,10 @@ int
 lpfc_issue_gidft(struct lpfc_vport *vport)
 lpfc_issue_gidft(struct lpfc_vport *vport)
 {
 {
 	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_hba *phba = vport->phba;
+	struct lpfc_nodelist *ndlp;
+
+	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
+		ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
 
 
 	/* Good status, issue CT Request to NameServer */
 	/* Good status, issue CT Request to NameServer */
 	if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
 	if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||

+ 14 - 1
drivers/scsi/lpfc/lpfc_hw.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -1177,6 +1177,9 @@ struct fc_rdp_link_error_status_desc {
 #define RDP_PS_8GB             0x0800
 #define RDP_PS_8GB             0x0800
 #define RDP_PS_16GB            0x0400
 #define RDP_PS_16GB            0x0400
 #define RDP_PS_32GB            0x0200
 #define RDP_PS_32GB            0x0200
+#define RDP_PS_64GB            0x0100
+#define RDP_PS_128GB           0x0080
+#define RDP_PS_256GB           0x0040
 
 
 #define RDP_CAP_USER_CONFIGURED 0x0002
 #define RDP_CAP_USER_CONFIGURED 0x0002
 #define RDP_CAP_UNKNOWN         0x0001
 #define RDP_CAP_UNKNOWN         0x0001
@@ -1580,6 +1583,7 @@ struct lpfc_fdmi_reg_portattr {
 #define PCI_DEVICE_ID_LANCER_FCOE   0xe260
 #define PCI_DEVICE_ID_LANCER_FCOE   0xe260
 #define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268
 #define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268
 #define PCI_DEVICE_ID_LANCER_G6_FC  0xe300
 #define PCI_DEVICE_ID_LANCER_G6_FC  0xe300
+#define PCI_DEVICE_ID_LANCER_G7_FC  0xf400
 #define PCI_DEVICE_ID_SAT_SMB       0xf011
 #define PCI_DEVICE_ID_SAT_SMB       0xf011
 #define PCI_DEVICE_ID_SAT_MID       0xf015
 #define PCI_DEVICE_ID_SAT_MID       0xf015
 #define PCI_DEVICE_ID_RFLY          0xf095
 #define PCI_DEVICE_ID_RFLY          0xf095
@@ -2257,6 +2261,9 @@ typedef struct {
 #define LINK_SPEED_10G  0x10    /* 10 Gigabaud */
 #define LINK_SPEED_10G  0x10    /* 10 Gigabaud */
 #define LINK_SPEED_16G  0x11    /* 16 Gigabaud */
 #define LINK_SPEED_16G  0x11    /* 16 Gigabaud */
 #define LINK_SPEED_32G  0x14    /* 32 Gigabaud */
 #define LINK_SPEED_32G  0x14    /* 32 Gigabaud */
+#define LINK_SPEED_64G  0x17    /* 64 Gigabaud */
+#define LINK_SPEED_128G 0x1A    /* 128 Gigabaud */
+#define LINK_SPEED_256G 0x1D    /* 256 Gigabaud */
 
 
 } INIT_LINK_VAR;
 } INIT_LINK_VAR;
 
 
@@ -2441,6 +2448,9 @@ typedef struct {
 #define LMT_10Gb      0x100
 #define LMT_10Gb      0x100
 #define LMT_16Gb      0x200
 #define LMT_16Gb      0x200
 #define LMT_32Gb      0x400
 #define LMT_32Gb      0x400
+#define LMT_64Gb      0x800
+#define LMT_128Gb     0x1000
+#define LMT_256Gb     0x2000
 	uint32_t rsvd2;
 	uint32_t rsvd2;
 	uint32_t rsvd3;
 	uint32_t rsvd3;
 	uint32_t max_xri;
 	uint32_t max_xri;
@@ -2965,6 +2975,9 @@ struct lpfc_mbx_read_top {
 #define LPFC_LINK_SPEED_10GHZ	0x40
 #define LPFC_LINK_SPEED_10GHZ	0x40
 #define LPFC_LINK_SPEED_16GHZ	0x80
 #define LPFC_LINK_SPEED_16GHZ	0x80
 #define LPFC_LINK_SPEED_32GHZ	0x90
 #define LPFC_LINK_SPEED_32GHZ	0x90
+#define LPFC_LINK_SPEED_64GHZ	0xA0
+#define LPFC_LINK_SPEED_128GHZ	0xB0
+#define LPFC_LINK_SPEED_256GHZ	0xC0
 };
 };
 
 
 /* Structure for MB Command CLEAR_LA (22) */
 /* Structure for MB Command CLEAR_LA (22) */

+ 126 - 15
drivers/scsi/lpfc/lpfc_hw4.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2009-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2009-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -84,6 +84,7 @@ struct lpfc_sli_intf {
 #define LPFC_SLI_INTF_IF_TYPE_0		0
 #define LPFC_SLI_INTF_IF_TYPE_0		0
 #define LPFC_SLI_INTF_IF_TYPE_1		1
 #define LPFC_SLI_INTF_IF_TYPE_1		1
 #define LPFC_SLI_INTF_IF_TYPE_2		2
 #define LPFC_SLI_INTF_IF_TYPE_2		2
+#define LPFC_SLI_INTF_IF_TYPE_6		6
 #define lpfc_sli_intf_sli_family_SHIFT		8
 #define lpfc_sli_intf_sli_family_SHIFT		8
 #define lpfc_sli_intf_sli_family_MASK		0x0000000F
 #define lpfc_sli_intf_sli_family_MASK		0x0000000F
 #define lpfc_sli_intf_sli_family_WORD		word0
 #define lpfc_sli_intf_sli_family_WORD		word0
@@ -731,11 +732,13 @@ struct lpfc_register {
  * register sets depending on the UCNA Port's reported if_type
  * register sets depending on the UCNA Port's reported if_type
  * value.  For UCNA ports running SLI4 and if_type 0, they reside in
  * value.  For UCNA ports running SLI4 and if_type 0, they reside in
  * BAR4.  For UCNA ports running SLI4 and if_type 2, they reside in
  * BAR4.  For UCNA ports running SLI4 and if_type 2, they reside in
- * BAR0.  The offsets are the same so the driver must account for
- * any base address difference.
+ * BAR0.  For FC ports running SLI4 and if_type 6, they reside in
+ * BAR2. The offsets and base address are different,  so the driver
+ * has to compute the register addresses accordingly
  */
  */
 #define LPFC_ULP0_RQ_DOORBELL		0x00A0
 #define LPFC_ULP0_RQ_DOORBELL		0x00A0
 #define LPFC_ULP1_RQ_DOORBELL		0x00C0
 #define LPFC_ULP1_RQ_DOORBELL		0x00C0
+#define LPFC_IF6_RQ_DOORBELL		0x0080
 #define lpfc_rq_db_list_fm_num_posted_SHIFT	24
 #define lpfc_rq_db_list_fm_num_posted_SHIFT	24
 #define lpfc_rq_db_list_fm_num_posted_MASK	0x00FF
 #define lpfc_rq_db_list_fm_num_posted_MASK	0x00FF
 #define lpfc_rq_db_list_fm_num_posted_WORD	word0
 #define lpfc_rq_db_list_fm_num_posted_WORD	word0
@@ -770,6 +773,20 @@ struct lpfc_register {
 #define lpfc_wq_db_ring_fm_id_MASK              0xFFFF
 #define lpfc_wq_db_ring_fm_id_MASK              0xFFFF
 #define lpfc_wq_db_ring_fm_id_WORD              word0
 #define lpfc_wq_db_ring_fm_id_WORD              word0
 
 
+#define LPFC_IF6_WQ_DOORBELL		0x0040
+#define lpfc_if6_wq_db_list_fm_num_posted_SHIFT	24
+#define lpfc_if6_wq_db_list_fm_num_posted_MASK	0x00FF
+#define lpfc_if6_wq_db_list_fm_num_posted_WORD	word0
+#define lpfc_if6_wq_db_list_fm_dpp_SHIFT	23
+#define lpfc_if6_wq_db_list_fm_dpp_MASK		0x0001
+#define lpfc_if6_wq_db_list_fm_dpp_WORD		word0
+#define lpfc_if6_wq_db_list_fm_dpp_id_SHIFT	16
+#define lpfc_if6_wq_db_list_fm_dpp_id_MASK	0x001F
+#define lpfc_if6_wq_db_list_fm_dpp_id_WORD	word0
+#define lpfc_if6_wq_db_list_fm_id_SHIFT		0
+#define lpfc_if6_wq_db_list_fm_id_MASK		0xFFFF
+#define lpfc_if6_wq_db_list_fm_id_WORD		word0
+
 #define LPFC_EQCQ_DOORBELL		0x0120
 #define LPFC_EQCQ_DOORBELL		0x0120
 #define lpfc_eqcq_doorbell_se_SHIFT		31
 #define lpfc_eqcq_doorbell_se_SHIFT		31
 #define lpfc_eqcq_doorbell_se_MASK		0x0001
 #define lpfc_eqcq_doorbell_se_MASK		0x0001
@@ -805,6 +822,38 @@ struct lpfc_register {
 #define LPFC_CQID_HI_FIELD_SHIFT		10
 #define LPFC_CQID_HI_FIELD_SHIFT		10
 #define LPFC_EQID_HI_FIELD_SHIFT		9
 #define LPFC_EQID_HI_FIELD_SHIFT		9
 
 
+#define LPFC_IF6_CQ_DOORBELL			0x00C0
+#define lpfc_if6_cq_doorbell_se_SHIFT		31
+#define lpfc_if6_cq_doorbell_se_MASK		0x0001
+#define lpfc_if6_cq_doorbell_se_WORD		word0
+#define LPFC_IF6_CQ_SOLICIT_ENABLE_OFF		0
+#define LPFC_IF6_CQ_SOLICIT_ENABLE_ON		1
+#define lpfc_if6_cq_doorbell_arm_SHIFT		29
+#define lpfc_if6_cq_doorbell_arm_MASK		0x0001
+#define lpfc_if6_cq_doorbell_arm_WORD		word0
+#define lpfc_if6_cq_doorbell_num_released_SHIFT	16
+#define lpfc_if6_cq_doorbell_num_released_MASK	0x1FFF
+#define lpfc_if6_cq_doorbell_num_released_WORD	word0
+#define lpfc_if6_cq_doorbell_cqid_SHIFT		0
+#define lpfc_if6_cq_doorbell_cqid_MASK		0xFFFF
+#define lpfc_if6_cq_doorbell_cqid_WORD		word0
+
+#define LPFC_IF6_EQ_DOORBELL			0x0120
+#define lpfc_if6_eq_doorbell_io_SHIFT		31
+#define lpfc_if6_eq_doorbell_io_MASK		0x0001
+#define lpfc_if6_eq_doorbell_io_WORD		word0
+#define LPFC_IF6_EQ_INTR_OVERRIDE_OFF		0
+#define LPFC_IF6_EQ_INTR_OVERRIDE_ON		1
+#define lpfc_if6_eq_doorbell_arm_SHIFT		29
+#define lpfc_if6_eq_doorbell_arm_MASK		0x0001
+#define lpfc_if6_eq_doorbell_arm_WORD		word0
+#define lpfc_if6_eq_doorbell_num_released_SHIFT	16
+#define lpfc_if6_eq_doorbell_num_released_MASK	0x1FFF
+#define lpfc_if6_eq_doorbell_num_released_WORD	word0
+#define lpfc_if6_eq_doorbell_eqid_SHIFT		0
+#define lpfc_if6_eq_doorbell_eqid_MASK		0x0FFF
+#define lpfc_if6_eq_doorbell_eqid_WORD		word0
+
 #define LPFC_BMBX			0x0160
 #define LPFC_BMBX			0x0160
 #define lpfc_bmbx_addr_SHIFT		2
 #define lpfc_bmbx_addr_SHIFT		2
 #define lpfc_bmbx_addr_MASK		0x3FFFFFFF
 #define lpfc_bmbx_addr_MASK		0x3FFFFFFF
@@ -817,6 +866,7 @@ struct lpfc_register {
 #define lpfc_bmbx_rdy_WORD		word0
 #define lpfc_bmbx_rdy_WORD		word0
 
 
 #define LPFC_MQ_DOORBELL			0x0140
 #define LPFC_MQ_DOORBELL			0x0140
+#define LPFC_IF6_MQ_DOORBELL			0x0160
 #define lpfc_mq_doorbell_num_posted_SHIFT	16
 #define lpfc_mq_doorbell_num_posted_SHIFT	16
 #define lpfc_mq_doorbell_num_posted_MASK	0x3FFF
 #define lpfc_mq_doorbell_num_posted_MASK	0x3FFF
 #define lpfc_mq_doorbell_num_posted_WORD	word0
 #define lpfc_mq_doorbell_num_posted_WORD	word0
@@ -990,6 +1040,9 @@ struct eq_context {
 #define lpfc_eq_context_valid_SHIFT	29
 #define lpfc_eq_context_valid_SHIFT	29
 #define lpfc_eq_context_valid_MASK	0x00000001
 #define lpfc_eq_context_valid_MASK	0x00000001
 #define lpfc_eq_context_valid_WORD	word0
 #define lpfc_eq_context_valid_WORD	word0
+#define lpfc_eq_context_autovalid_SHIFT 28
+#define lpfc_eq_context_autovalid_MASK  0x00000001
+#define lpfc_eq_context_autovalid_WORD  word0
 	uint32_t word1;
 	uint32_t word1;
 #define lpfc_eq_context_count_SHIFT	26
 #define lpfc_eq_context_count_SHIFT	26
 #define lpfc_eq_context_count_MASK	0x00000003
 #define lpfc_eq_context_count_MASK	0x00000003
@@ -1123,6 +1176,9 @@ struct cq_context {
 #define LPFC_CQ_CNT_512		0x1
 #define LPFC_CQ_CNT_512		0x1
 #define LPFC_CQ_CNT_1024	0x2
 #define LPFC_CQ_CNT_1024	0x2
 #define LPFC_CQ_CNT_WORD7	0x3
 #define LPFC_CQ_CNT_WORD7	0x3
+#define lpfc_cq_context_autovalid_SHIFT 15
+#define lpfc_cq_context_autovalid_MASK  0x00000001
+#define lpfc_cq_context_autovalid_WORD  word0
 	uint32_t word1;
 	uint32_t word1;
 #define lpfc_cq_eq_id_SHIFT		22	/* Version 0 Only */
 #define lpfc_cq_eq_id_SHIFT		22	/* Version 0 Only */
 #define lpfc_cq_eq_id_MASK		0x000000FF
 #define lpfc_cq_eq_id_MASK		0x000000FF
@@ -1181,9 +1237,9 @@ struct lpfc_mbx_cq_create_set {
 #define lpfc_mbx_cq_create_set_cqe_size_SHIFT	25
 #define lpfc_mbx_cq_create_set_cqe_size_SHIFT	25
 #define lpfc_mbx_cq_create_set_cqe_size_MASK	0x00000003
 #define lpfc_mbx_cq_create_set_cqe_size_MASK	0x00000003
 #define lpfc_mbx_cq_create_set_cqe_size_WORD	word1
 #define lpfc_mbx_cq_create_set_cqe_size_WORD	word1
-#define lpfc_mbx_cq_create_set_auto_SHIFT	15
-#define lpfc_mbx_cq_create_set_auto_MASK	0x0000001
-#define lpfc_mbx_cq_create_set_auto_WORD	word1
+#define lpfc_mbx_cq_create_set_autovalid_SHIFT	15
+#define lpfc_mbx_cq_create_set_autovalid_MASK	0x0000001
+#define lpfc_mbx_cq_create_set_autovalid_WORD	word1
 #define lpfc_mbx_cq_create_set_nodelay_SHIFT	14
 #define lpfc_mbx_cq_create_set_nodelay_SHIFT	14
 #define lpfc_mbx_cq_create_set_nodelay_MASK	0x00000001
 #define lpfc_mbx_cq_create_set_nodelay_MASK	0x00000001
 #define lpfc_mbx_cq_create_set_nodelay_WORD	word1
 #define lpfc_mbx_cq_create_set_nodelay_WORD	word1
@@ -1322,6 +1378,15 @@ struct lpfc_mbx_wq_create {
 #define lpfc_mbx_wq_create_page_size_MASK	0x000000FF
 #define lpfc_mbx_wq_create_page_size_MASK	0x000000FF
 #define lpfc_mbx_wq_create_page_size_WORD	word1
 #define lpfc_mbx_wq_create_page_size_WORD	word1
 #define LPFC_WQ_PAGE_SIZE_4096	0x1
 #define LPFC_WQ_PAGE_SIZE_4096	0x1
+#define lpfc_mbx_wq_create_dpp_req_SHIFT	15
+#define lpfc_mbx_wq_create_dpp_req_MASK		0x00000001
+#define lpfc_mbx_wq_create_dpp_req_WORD		word1
+#define lpfc_mbx_wq_create_doe_SHIFT		14
+#define lpfc_mbx_wq_create_doe_MASK		0x00000001
+#define lpfc_mbx_wq_create_doe_WORD		word1
+#define lpfc_mbx_wq_create_toe_SHIFT		13
+#define lpfc_mbx_wq_create_toe_MASK		0x00000001
+#define lpfc_mbx_wq_create_toe_WORD		word1
 #define lpfc_mbx_wq_create_wqe_size_SHIFT	8
 #define lpfc_mbx_wq_create_wqe_size_SHIFT	8
 #define lpfc_mbx_wq_create_wqe_size_MASK	0x0000000F
 #define lpfc_mbx_wq_create_wqe_size_MASK	0x0000000F
 #define lpfc_mbx_wq_create_wqe_size_WORD	word1
 #define lpfc_mbx_wq_create_wqe_size_WORD	word1
@@ -1350,6 +1415,28 @@ struct lpfc_mbx_wq_create {
 #define lpfc_mbx_wq_create_db_format_MASK	0x0000FFFF
 #define lpfc_mbx_wq_create_db_format_MASK	0x0000FFFF
 #define lpfc_mbx_wq_create_db_format_WORD	word2
 #define lpfc_mbx_wq_create_db_format_WORD	word2
 		} response;
 		} response;
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_wq_create_dpp_rsp_SHIFT	31
+#define lpfc_mbx_wq_create_dpp_rsp_MASK		0x00000001
+#define lpfc_mbx_wq_create_dpp_rsp_WORD		word0
+#define lpfc_mbx_wq_create_v1_q_id_SHIFT	0
+#define lpfc_mbx_wq_create_v1_q_id_MASK		0x0000FFFF
+#define lpfc_mbx_wq_create_v1_q_id_WORD		word0
+			uint32_t word1;
+#define lpfc_mbx_wq_create_v1_bar_set_SHIFT	0
+#define lpfc_mbx_wq_create_v1_bar_set_MASK	0x0000000F
+#define lpfc_mbx_wq_create_v1_bar_set_WORD	word1
+			uint32_t doorbell_offset;
+			uint32_t word3;
+#define lpfc_mbx_wq_create_dpp_id_SHIFT		16
+#define lpfc_mbx_wq_create_dpp_id_MASK		0x0000001F
+#define lpfc_mbx_wq_create_dpp_id_WORD		word3
+#define lpfc_mbx_wq_create_dpp_bar_SHIFT	0
+#define lpfc_mbx_wq_create_dpp_bar_MASK		0x0000000F
+#define lpfc_mbx_wq_create_dpp_bar_WORD		word3
+			uint32_t dpp_offset;
+		} response_1;
 	} u;
 	} u;
 };
 };
 
 
@@ -2154,6 +2241,7 @@ struct lpfc_mbx_redisc_fcf_tbl {
  * command.
  * command.
  */
  */
 #define ADD_STATUS_OPERATION_ALREADY_ACTIVE		0x67
 #define ADD_STATUS_OPERATION_ALREADY_ACTIVE		0x67
+#define ADD_STATUS_FW_NOT_SUPPORTED			0xEB
 
 
 struct lpfc_mbx_sli4_config {
 struct lpfc_mbx_sli4_config {
 	struct mbox_header header;
 	struct mbox_header header;
@@ -2590,6 +2678,7 @@ struct lpfc_mbx_read_rev {
 #define lpfc_mbx_rd_rev_vpd_MASK		0x00000001
 #define lpfc_mbx_rd_rev_vpd_MASK		0x00000001
 #define lpfc_mbx_rd_rev_vpd_WORD		word1
 #define lpfc_mbx_rd_rev_vpd_WORD		word1
 	uint32_t first_hw_rev;
 	uint32_t first_hw_rev;
+#define LPFC_G7_ASIC_1				0xd
 	uint32_t second_hw_rev;
 	uint32_t second_hw_rev;
 	uint32_t word4_rsvd;
 	uint32_t word4_rsvd;
 	uint32_t third_hw_rev;
 	uint32_t third_hw_rev;
@@ -3207,11 +3296,20 @@ struct lpfc_sli4_parameters {
 #define cfg_sli_hint_2_MASK			0x0000001f
 #define cfg_sli_hint_2_MASK			0x0000001f
 #define cfg_sli_hint_2_WORD			word1
 #define cfg_sli_hint_2_WORD			word1
 	uint32_t word2;
 	uint32_t word2;
+#define cfg_eqav_SHIFT				31
+#define cfg_eqav_MASK				0x00000001
+#define cfg_eqav_WORD				word2
 	uint32_t word3;
 	uint32_t word3;
 	uint32_t word4;
 	uint32_t word4;
 #define cfg_cqv_SHIFT				14
 #define cfg_cqv_SHIFT				14
 #define cfg_cqv_MASK				0x00000003
 #define cfg_cqv_MASK				0x00000003
 #define cfg_cqv_WORD				word4
 #define cfg_cqv_WORD				word4
+#define cfg_cqpsize_SHIFT			16
+#define cfg_cqpsize_MASK			0x000000ff
+#define cfg_cqpsize_WORD			word4
+#define cfg_cqav_SHIFT				31
+#define cfg_cqav_MASK				0x00000001
+#define cfg_cqav_WORD				word4
 	uint32_t word5;
 	uint32_t word5;
 	uint32_t word6;
 	uint32_t word6;
 #define cfg_mqv_SHIFT				14
 #define cfg_mqv_SHIFT				14
@@ -3290,6 +3388,9 @@ struct lpfc_sli4_parameters {
 #define cfg_eqdr_SHIFT				8
 #define cfg_eqdr_SHIFT				8
 #define cfg_eqdr_MASK				0x00000001
 #define cfg_eqdr_MASK				0x00000001
 #define cfg_eqdr_WORD				word19
 #define cfg_eqdr_WORD				word19
+#define cfg_nosr_SHIFT				9
+#define cfg_nosr_MASK				0x00000001
+#define cfg_nosr_WORD				word19
 #define LPFC_NODELAY_MAX_IO		32
 #define LPFC_NODELAY_MAX_IO		32
 };
 };
 
 
@@ -3874,6 +3975,9 @@ struct lpfc_acqe_fc_la {
 #define LPFC_FC_LA_SPEED_10G		0xA
 #define LPFC_FC_LA_SPEED_10G		0xA
 #define LPFC_FC_LA_SPEED_16G		0x10
 #define LPFC_FC_LA_SPEED_16G		0x10
 #define LPFC_FC_LA_SPEED_32G            0x20
 #define LPFC_FC_LA_SPEED_32G            0x20
+#define LPFC_FC_LA_SPEED_64G            0x21
+#define LPFC_FC_LA_SPEED_128G           0x22
+#define LPFC_FC_LA_SPEED_256G           0x23
 #define lpfc_acqe_fc_la_topology_SHIFT		16
 #define lpfc_acqe_fc_la_topology_SHIFT		16
 #define lpfc_acqe_fc_la_topology_MASK		0x000000FF
 #define lpfc_acqe_fc_la_topology_MASK		0x000000FF
 #define lpfc_acqe_fc_la_topology_WORD		word0
 #define lpfc_acqe_fc_la_topology_WORD		word0
@@ -4079,6 +4183,7 @@ struct wqe_common {
 #define wqe_iod_SHIFT         13
 #define wqe_iod_SHIFT         13
 #define wqe_iod_MASK          0x00000001
 #define wqe_iod_MASK          0x00000001
 #define wqe_iod_WORD          word10
 #define wqe_iod_WORD          word10
+#define LPFC_WQE_IOD_NONE	0
 #define LPFC_WQE_IOD_WRITE	0
 #define LPFC_WQE_IOD_WRITE	0
 #define LPFC_WQE_IOD_READ	1
 #define LPFC_WQE_IOD_READ	1
 #define wqe_dbde_SHIFT        14
 #define wqe_dbde_SHIFT        14
@@ -4123,6 +4228,9 @@ struct wqe_common {
 #define wqe_irsp_SHIFT        4
 #define wqe_irsp_SHIFT        4
 #define wqe_irsp_MASK         0x00000001
 #define wqe_irsp_MASK         0x00000001
 #define wqe_irsp_WORD         word11
 #define wqe_irsp_WORD         word11
+#define wqe_pbde_SHIFT        5
+#define wqe_pbde_MASK         0x00000001
+#define wqe_pbde_WORD         word11
 #define wqe_sup_SHIFT         6
 #define wqe_sup_SHIFT         6
 #define wqe_sup_MASK          0x00000001
 #define wqe_sup_MASK          0x00000001
 #define wqe_sup_WORD          word11
 #define wqe_sup_WORD          word11
@@ -4343,9 +4451,9 @@ struct lpfc_nvme_prli {
 #define prli_init_SHIFT                 5
 #define prli_init_SHIFT                 5
 #define prli_init_MASK                  0x00000001
 #define prli_init_MASK                  0x00000001
 #define prli_init_WORD                  word4
 #define prli_init_WORD                  word4
-#define prli_recov_SHIFT                8
-#define prli_recov_MASK                 0x00000001
-#define prli_recov_WORD                 word4
+#define prli_conf_SHIFT                 7
+#define prli_conf_MASK                  0x00000001
+#define prli_conf_WORD                  word4
 	uint32_t word5;
 	uint32_t word5;
 #define prli_fb_sz_SHIFT                0
 #define prli_fb_sz_SHIFT                0
 #define prli_fb_sz_MASK                 0x0000ffff
 #define prli_fb_sz_MASK                 0x0000ffff
@@ -4494,17 +4602,20 @@ union lpfc_wqe128 {
 	struct fcp_icmnd64_wqe fcp_icmd;
 	struct fcp_icmnd64_wqe fcp_icmd;
 	struct fcp_iread64_wqe fcp_iread;
 	struct fcp_iread64_wqe fcp_iread;
 	struct fcp_iwrite64_wqe fcp_iwrite;
 	struct fcp_iwrite64_wqe fcp_iwrite;
+	struct abort_cmd_wqe abort_cmd;
+	struct create_xri_wqe create_xri;
+	struct xmit_bcast64_wqe xmit_bcast64;
+	struct xmit_seq64_wqe xmit_sequence;
+	struct xmit_bls_rsp64_wqe xmit_bls_rsp;
+	struct xmit_els_rsp64_wqe xmit_els_rsp;
+	struct els_request64_wqe els_req;
+	struct gen_req64_wqe gen_req;
 	struct fcp_trsp64_wqe fcp_trsp;
 	struct fcp_trsp64_wqe fcp_trsp;
 	struct fcp_tsend64_wqe fcp_tsend;
 	struct fcp_tsend64_wqe fcp_tsend;
 	struct fcp_treceive64_wqe fcp_treceive;
 	struct fcp_treceive64_wqe fcp_treceive;
-	struct xmit_seq64_wqe xmit_sequence;
-	struct gen_req64_wqe gen_req;
+	struct send_frame_wqe send_frame;
 };
 };
 
 
-#define LPFC_GROUP_OJECT_MAGIC_G5		0xfeaa0001
-#define LPFC_GROUP_OJECT_MAGIC_G6		0xfeaa0003
-#define LPFC_FILE_TYPE_GROUP			0xf7
-#define LPFC_FILE_ID_GROUP			0xa2
 struct lpfc_grp_hdr {
 struct lpfc_grp_hdr {
 	uint32_t size;
 	uint32_t size;
 	uint32_t magic_number;
 	uint32_t magic_number;

+ 3 - 1
drivers/scsi/lpfc/lpfc_ids.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -116,6 +116,8 @@ const struct pci_device_id lpfc_id_table[] = {
 		PCI_ANY_ID, PCI_ANY_ID, },
 		PCI_ANY_ID, PCI_ANY_ID, },
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC,
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC,
 		PCI_ANY_ID, PCI_ANY_ID, },
 		PCI_ANY_ID, PCI_ANY_ID, },
+	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G7_FC,
+		PCI_ANY_ID, PCI_ANY_ID, },
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK,
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK,
 		PCI_ANY_ID, PCI_ANY_ID, },
 		PCI_ANY_ID, PCI_ANY_ID, },
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF,
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF,

+ 263 - 57
drivers/scsi/lpfc/lpfc_init.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -731,7 +731,9 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology,
 	    ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) &&
 	    ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) &&
 	     !(phba->lmt & LMT_16Gb)) ||
 	     !(phba->lmt & LMT_16Gb)) ||
 	    ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_32G) &&
 	    ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_32G) &&
-	     !(phba->lmt & LMT_32Gb))) {
+	     !(phba->lmt & LMT_32Gb)) ||
+	    ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_64G) &&
+	     !(phba->lmt & LMT_64Gb))) {
 		/* Reset link speed to auto */
 		/* Reset link speed to auto */
 		lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
 		lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
 			"1302 Invalid speed for this board:%d "
 			"1302 Invalid speed for this board:%d "
@@ -958,6 +960,7 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
 	struct lpfc_sli_ring *pring;
 	struct lpfc_sli_ring *pring;
 	LIST_HEAD(completions);
 	LIST_HEAD(completions);
 	int i;
 	int i;
+	struct lpfc_iocbq *piocb, *next_iocb;
 
 
 	if (phba->sli_rev != LPFC_SLI_REV4) {
 	if (phba->sli_rev != LPFC_SLI_REV4) {
 		for (i = 0; i < psli->num_rings; i++) {
 		for (i = 0; i < psli->num_rings; i++) {
@@ -983,6 +986,9 @@ lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
 		if (!pring)
 		if (!pring)
 			continue;
 			continue;
 		spin_lock_irq(&pring->ring_lock);
 		spin_lock_irq(&pring->ring_lock);
+		list_for_each_entry_safe(piocb, next_iocb,
+					 &pring->txcmplq, list)
+			piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
 		list_splice_init(&pring->txcmplq, &completions);
 		list_splice_init(&pring->txcmplq, &completions);
 		pring->txcmplq_cnt = 0;
 		pring->txcmplq_cnt = 0;
 		spin_unlock_irq(&pring->ring_lock);
 		spin_unlock_irq(&pring->ring_lock);
@@ -1757,7 +1763,7 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action,
 	int rc;
 	int rc;
 	uint32_t intr_mode;
 	uint32_t intr_mode;
 
 
-	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
 	    LPFC_SLI_INTF_IF_TYPE_2) {
 	    LPFC_SLI_INTF_IF_TYPE_2) {
 		/*
 		/*
 		 * On error status condition, driver need to wait for port
 		 * On error status condition, driver need to wait for port
@@ -1888,6 +1894,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
 		break;
 		break;
 
 
 	case LPFC_SLI_INTF_IF_TYPE_2:
 	case LPFC_SLI_INTF_IF_TYPE_2:
+	case LPFC_SLI_INTF_IF_TYPE_6:
 		pci_rd_rc1 = lpfc_readl(
 		pci_rd_rc1 = lpfc_readl(
 				phba->sli4_hba.u.if_type2.STATUSregaddr,
 				phba->sli4_hba.u.if_type2.STATUSregaddr,
 				&portstat_reg.word0);
 				&portstat_reg.word0);
@@ -2269,7 +2276,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
 		&& descp && descp[0] != '\0')
 		&& descp && descp[0] != '\0')
 		return;
 		return;
 
 
-	if (phba->lmt & LMT_32Gb)
+	if (phba->lmt & LMT_64Gb)
+		max_speed = 64;
+	else if (phba->lmt & LMT_32Gb)
 		max_speed = 32;
 		max_speed = 32;
 	else if (phba->lmt & LMT_16Gb)
 	else if (phba->lmt & LMT_16Gb)
 		max_speed = 16;
 		max_speed = 16;
@@ -2468,6 +2477,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
 	case PCI_DEVICE_ID_LANCER_G6_FC:
 	case PCI_DEVICE_ID_LANCER_G6_FC:
 		m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"};
 		m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"};
 		break;
 		break;
+	case PCI_DEVICE_ID_LANCER_G7_FC:
+		m = (typeof(m)){"LPe36000", "PCIe", "Fibre Channel Adapter"};
+		break;
 	case PCI_DEVICE_ID_SKYHAWK:
 	case PCI_DEVICE_ID_SKYHAWK:
 	case PCI_DEVICE_ID_SKYHAWK_VF:
 	case PCI_DEVICE_ID_SKYHAWK_VF:
 		oneConnect = 1;
 		oneConnect = 1;
@@ -4104,6 +4116,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
 				 sizeof fc_host_symbolic_name(shost));
 				 sizeof fc_host_symbolic_name(shost));
 
 
 	fc_host_supported_speeds(shost) = 0;
 	fc_host_supported_speeds(shost) = 0;
+	if (phba->lmt & LMT_64Gb)
+		fc_host_supported_speeds(shost) |= FC_PORTSPEED_64GBIT;
 	if (phba->lmt & LMT_32Gb)
 	if (phba->lmt & LMT_32Gb)
 		fc_host_supported_speeds(shost) |= FC_PORTSPEED_32GBIT;
 		fc_host_supported_speeds(shost) |= FC_PORTSPEED_32GBIT;
 	if (phba->lmt & LMT_16Gb)
 	if (phba->lmt & LMT_16Gb)
@@ -4440,6 +4454,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code,
 		case LPFC_FC_LA_SPEED_32G:
 		case LPFC_FC_LA_SPEED_32G:
 			port_speed = 32000;
 			port_speed = 32000;
 			break;
 			break;
+		case LPFC_FC_LA_SPEED_64G:
+			port_speed = 64000;
+			break;
 		default:
 		default:
 			port_speed = 0;
 			port_speed = 0;
 		}
 		}
@@ -5895,7 +5912,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
 	 * Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size
 	 * Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size
 	 * used to create the sg_dma_buf_pool must be calculated.
 	 * used to create the sg_dma_buf_pool must be calculated.
 	 */
 	 */
-	if (phba->cfg_enable_bg) {
+	if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
 		/*
 		/*
 		 * The scsi_buf for a T10-DIF I/O holds the FCP cmnd,
 		 * The scsi_buf for a T10-DIF I/O holds the FCP cmnd,
 		 * the FCP rsp, and a SGE. Sice we have no control
 		 * the FCP rsp, and a SGE. Sice we have no control
@@ -6014,7 +6031,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	/* IF Type 2 ports get initialized now. */
 	/* IF Type 2 ports get initialized now. */
-	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
 	    LPFC_SLI_INTF_IF_TYPE_2) {
 	    LPFC_SLI_INTF_IF_TYPE_2) {
 		rc = lpfc_pci_function_reset(phba);
 		rc = lpfc_pci_function_reset(phba);
 		if (unlikely(rc)) {
 		if (unlikely(rc)) {
@@ -7344,6 +7361,7 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
 			}
 			}
 			break;
 			break;
 		case LPFC_SLI_INTF_IF_TYPE_2:
 		case LPFC_SLI_INTF_IF_TYPE_2:
+		case LPFC_SLI_INTF_IF_TYPE_6:
 			/* Final checks.  The port status should be clean. */
 			/* Final checks.  The port status should be clean. */
 			if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
 			if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
 				&reg_data.word0) ||
 				&reg_data.word0) ||
@@ -7426,13 +7444,36 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
 		phba->sli4_hba.WQDBregaddr =
 		phba->sli4_hba.WQDBregaddr =
 			phba->sli4_hba.conf_regs_memmap_p +
 			phba->sli4_hba.conf_regs_memmap_p +
 						LPFC_ULP0_WQ_DOORBELL;
 						LPFC_ULP0_WQ_DOORBELL;
-		phba->sli4_hba.EQCQDBregaddr =
+		phba->sli4_hba.CQDBregaddr =
 			phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL;
 			phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL;
+		phba->sli4_hba.EQDBregaddr = phba->sli4_hba.CQDBregaddr;
 		phba->sli4_hba.MQDBregaddr =
 		phba->sli4_hba.MQDBregaddr =
 			phba->sli4_hba.conf_regs_memmap_p + LPFC_MQ_DOORBELL;
 			phba->sli4_hba.conf_regs_memmap_p + LPFC_MQ_DOORBELL;
 		phba->sli4_hba.BMBXregaddr =
 		phba->sli4_hba.BMBXregaddr =
 			phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX;
 			phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX;
 		break;
 		break;
+	case LPFC_SLI_INTF_IF_TYPE_6:
+		phba->sli4_hba.u.if_type2.EQDregaddr =
+			phba->sli4_hba.conf_regs_memmap_p +
+						LPFC_CTL_PORT_EQ_DELAY_OFFSET;
+		phba->sli4_hba.u.if_type2.ERR1regaddr =
+			phba->sli4_hba.conf_regs_memmap_p +
+						LPFC_CTL_PORT_ER1_OFFSET;
+		phba->sli4_hba.u.if_type2.ERR2regaddr =
+			phba->sli4_hba.conf_regs_memmap_p +
+						LPFC_CTL_PORT_ER2_OFFSET;
+		phba->sli4_hba.u.if_type2.CTRLregaddr =
+			phba->sli4_hba.conf_regs_memmap_p +
+						LPFC_CTL_PORT_CTL_OFFSET;
+		phba->sli4_hba.u.if_type2.STATUSregaddr =
+			phba->sli4_hba.conf_regs_memmap_p +
+						LPFC_CTL_PORT_STA_OFFSET;
+		phba->sli4_hba.PSMPHRregaddr =
+			phba->sli4_hba.conf_regs_memmap_p +
+						LPFC_CTL_PORT_SEM_OFFSET;
+		phba->sli4_hba.BMBXregaddr =
+			phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX;
+		break;
 	case LPFC_SLI_INTF_IF_TYPE_1:
 	case LPFC_SLI_INTF_IF_TYPE_1:
 	default:
 	default:
 		dev_printk(KERN_ERR, &phba->pcidev->dev,
 		dev_printk(KERN_ERR, &phba->pcidev->dev,
@@ -7446,20 +7487,43 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
  * lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map.
  * lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map.
  * @phba: pointer to lpfc hba data structure.
  * @phba: pointer to lpfc hba data structure.
  *
  *
- * This routine is invoked to set up SLI4 BAR1 control status register (CSR)
- * memory map.
+ * This routine is invoked to set up SLI4 BAR1 register memory map.
  **/
  **/
 static void
 static void
-lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba)
+lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
 {
 {
-	phba->sli4_hba.PSMPHRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
-		LPFC_SLIPORT_IF0_SMPHR;
-	phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
-		LPFC_HST_ISR0;
-	phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
-		LPFC_HST_IMR0;
-	phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
-		LPFC_HST_ISCR0;
+	switch (if_type) {
+	case LPFC_SLI_INTF_IF_TYPE_0:
+		phba->sli4_hba.PSMPHRregaddr =
+			phba->sli4_hba.ctrl_regs_memmap_p +
+			LPFC_SLIPORT_IF0_SMPHR;
+		phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+			LPFC_HST_ISR0;
+		phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+			LPFC_HST_IMR0;
+		phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p +
+			LPFC_HST_ISCR0;
+		break;
+	case LPFC_SLI_INTF_IF_TYPE_6:
+		phba->sli4_hba.RQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+			LPFC_IF6_RQ_DOORBELL;
+		phba->sli4_hba.WQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+			LPFC_IF6_WQ_DOORBELL;
+		phba->sli4_hba.CQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+			LPFC_IF6_CQ_DOORBELL;
+		phba->sli4_hba.EQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+			LPFC_IF6_EQ_DOORBELL;
+		phba->sli4_hba.MQDBregaddr = phba->sli4_hba.drbl_regs_memmap_p +
+			LPFC_IF6_MQ_DOORBELL;
+		break;
+	case LPFC_SLI_INTF_IF_TYPE_2:
+	case LPFC_SLI_INTF_IF_TYPE_1:
+	default:
+		dev_err(&phba->pcidev->dev,
+			   "FATAL - unsupported SLI4 interface type - %d\n",
+			   if_type);
+		break;
+	}
 }
 }
 
 
 /**
 /**
@@ -7484,8 +7548,10 @@ lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf)
 	phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
 	phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
 				vf * LPFC_VFR_PAGE_SIZE +
 				vf * LPFC_VFR_PAGE_SIZE +
 					LPFC_ULP0_WQ_DOORBELL);
 					LPFC_ULP0_WQ_DOORBELL);
-	phba->sli4_hba.EQCQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
-				vf * LPFC_VFR_PAGE_SIZE + LPFC_EQCQ_DOORBELL);
+	phba->sli4_hba.CQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
+				vf * LPFC_VFR_PAGE_SIZE +
+					LPFC_EQCQ_DOORBELL);
+	phba->sli4_hba.EQDBregaddr = phba->sli4_hba.CQDBregaddr;
 	phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
 	phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
 				vf * LPFC_VFR_PAGE_SIZE + LPFC_MQ_DOORBELL);
 				vf * LPFC_VFR_PAGE_SIZE + LPFC_MQ_DOORBELL);
 	phba->sli4_hba.BMBXregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
 	phba->sli4_hba.BMBXregaddr = (phba->sli4_hba.drbl_regs_memmap_p +
@@ -7722,7 +7788,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
 
 
 	/* Update link speed if forced link speed is supported */
 	/* Update link speed if forced link speed is supported */
 	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
 	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
-	if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+	if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
 		forced_link_speed =
 		forced_link_speed =
 			bf_get(lpfc_mbx_rd_conf_link_speed, rd_config);
 			bf_get(lpfc_mbx_rd_conf_link_speed, rd_config);
 		if (forced_link_speed) {
 		if (forced_link_speed) {
@@ -7757,6 +7823,10 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
 				phba->cfg_link_speed =
 				phba->cfg_link_speed =
 					LPFC_USER_LINK_SPEED_32G;
 					LPFC_USER_LINK_SPEED_32G;
 				break;
 				break;
+			case LINK_SPEED_64G:
+				phba->cfg_link_speed =
+					LPFC_USER_LINK_SPEED_64G;
+				break;
 			case 0xffff:
 			case 0xffff:
 				phba->cfg_link_speed =
 				phba->cfg_link_speed =
 					LPFC_USER_LINK_SPEED_AUTO;
 					LPFC_USER_LINK_SPEED_AUTO;
@@ -7782,7 +7852,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
 		phba->cfg_hba_queue_depth = length;
 		phba->cfg_hba_queue_depth = length;
 	}
 	}
 
 
-	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
 	    LPFC_SLI_INTF_IF_TYPE_2)
 	    LPFC_SLI_INTF_IF_TYPE_2)
 		goto read_cfg_out;
 		goto read_cfg_out;
 
 
@@ -7896,6 +7966,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba)
 		}
 		}
 		mempool_free(mboxq, phba->mbox_mem_pool);
 		mempool_free(mboxq, phba->mbox_mem_pool);
 		break;
 		break;
+	case LPFC_SLI_INTF_IF_TYPE_6:
 	case LPFC_SLI_INTF_IF_TYPE_2:
 	case LPFC_SLI_INTF_IF_TYPE_2:
 	case LPFC_SLI_INTF_IF_TYPE_1:
 	case LPFC_SLI_INTF_IF_TYPE_1:
 	default:
 	default:
@@ -7992,6 +8063,7 @@ lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx)
 				wqidx);
 				wqidx);
 		return 1;
 		return 1;
 	}
 	}
+	qdesc->qe_valid = 1;
 	phba->sli4_hba.nvme_cq[wqidx] = qdesc;
 	phba->sli4_hba.nvme_cq[wqidx] = qdesc;
 
 
 	qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
 	qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
@@ -8011,9 +8083,10 @@ static int
 lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
 lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
 {
 {
 	struct lpfc_queue *qdesc;
 	struct lpfc_queue *qdesc;
+	uint32_t wqesize;
 
 
 	/* Create Fast Path FCP CQs */
 	/* Create Fast Path FCP CQs */
-	if (phba->fcp_embed_io)
+	if (phba->enab_exp_wqcq_pages)
 		/* Increase the CQ size when WQEs contain an embedded cdb */
 		/* Increase the CQ size when WQEs contain an embedded cdb */
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
 					      phba->sli4_hba.cq_esize,
 					      phba->sli4_hba.cq_esize,
@@ -8028,18 +8101,22 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx)
 			"0499 Failed allocate fast-path FCP CQ (%d)\n", wqidx);
 			"0499 Failed allocate fast-path FCP CQ (%d)\n", wqidx);
 		return 1;
 		return 1;
 	}
 	}
+	qdesc->qe_valid = 1;
 	phba->sli4_hba.fcp_cq[wqidx] = qdesc;
 	phba->sli4_hba.fcp_cq[wqidx] = qdesc;
 
 
 	/* Create Fast Path FCP WQs */
 	/* Create Fast Path FCP WQs */
-	if (phba->fcp_embed_io)
+	if (phba->enab_exp_wqcq_pages) {
 		/* Increase the WQ size when WQEs contain an embedded cdb */
 		/* Increase the WQ size when WQEs contain an embedded cdb */
+		wqesize = (phba->fcp_embed_io) ?
+			LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize;
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE,
-					      LPFC_WQE128_SIZE,
+					      wqesize,
 					      LPFC_WQE_EXP_COUNT);
 					      LPFC_WQE_EXP_COUNT);
-	else
+	} else
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
 		qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
 					      phba->sli4_hba.wq_esize,
 					      phba->sli4_hba.wq_esize,
 					      phba->sli4_hba.wq_ecount);
 					      phba->sli4_hba.wq_ecount);
+
 	if (!qdesc) {
 	if (!qdesc) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"0503 Failed allocate fast-path FCP WQ (%d)\n",
 				"0503 Failed allocate fast-path FCP WQ (%d)\n",
@@ -8218,6 +8295,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
 					"0497 Failed allocate EQ (%d)\n", idx);
 					"0497 Failed allocate EQ (%d)\n", idx);
 			goto out_error;
 			goto out_error;
 		}
 		}
+		qdesc->qe_valid = 1;
 		phba->sli4_hba.hba_eq[idx] = qdesc;
 		phba->sli4_hba.hba_eq[idx] = qdesc;
 	}
 	}
 
 
@@ -8243,6 +8321,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
 					"CQ Set (%d)\n", idx);
 					"CQ Set (%d)\n", idx);
 				goto out_error;
 				goto out_error;
 			}
 			}
+			qdesc->qe_valid = 1;
 			phba->sli4_hba.nvmet_cqset[idx] = qdesc;
 			phba->sli4_hba.nvmet_cqset[idx] = qdesc;
 		}
 		}
 	}
 	}
@@ -8260,6 +8339,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
 				"0500 Failed allocate slow-path mailbox CQ\n");
 				"0500 Failed allocate slow-path mailbox CQ\n");
 		goto out_error;
 		goto out_error;
 	}
 	}
+	qdesc->qe_valid = 1;
 	phba->sli4_hba.mbx_cq = qdesc;
 	phba->sli4_hba.mbx_cq = qdesc;
 
 
 	/* Create slow-path ELS Complete Queue */
 	/* Create slow-path ELS Complete Queue */
@@ -8271,6 +8351,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
 				"0501 Failed allocate slow-path ELS CQ\n");
 				"0501 Failed allocate slow-path ELS CQ\n");
 		goto out_error;
 		goto out_error;
 	}
 	}
+	qdesc->qe_valid = 1;
 	phba->sli4_hba.els_cq = qdesc;
 	phba->sli4_hba.els_cq = qdesc;
 
 
 
 
@@ -8316,6 +8397,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)
 					"6079 Failed allocate NVME LS CQ\n");
 					"6079 Failed allocate NVME LS CQ\n");
 			goto out_error;
 			goto out_error;
 		}
 		}
+		qdesc->qe_valid = 1;
 		phba->sli4_hba.nvmels_cq = qdesc;
 		phba->sli4_hba.nvmels_cq = qdesc;
 
 
 		/* Create NVME LS Work Queue */
 		/* Create NVME LS Work Queue */
@@ -9303,6 +9385,7 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
 		}
 		}
 		break;
 		break;
 	case LPFC_SLI_INTF_IF_TYPE_2:
 	case LPFC_SLI_INTF_IF_TYPE_2:
+	case LPFC_SLI_INTF_IF_TYPE_6:
 wait:
 wait:
 		/*
 		/*
 		 * Poll the Port Status Register and wait for RDY for
 		 * Poll the Port Status Register and wait for RDY for
@@ -9458,7 +9541,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
 	} else {
 	} else {
 		phba->pci_bar0_map = pci_resource_start(pdev, 1);
 		phba->pci_bar0_map = pci_resource_start(pdev, 1);
 		bar0map_len = pci_resource_len(pdev, 1);
 		bar0map_len = pci_resource_len(pdev, 1);
-		if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+		if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
 			dev_printk(KERN_ERR, &pdev->dev,
 			dev_printk(KERN_ERR, &pdev->dev,
 			   "FATAL - No BAR0 mapping for SLI4, if_type 2\n");
 			   "FATAL - No BAR0 mapping for SLI4, if_type 2\n");
 			goto out;
 			goto out;
@@ -9495,13 +9578,32 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
 			}
 			}
 			phba->pci_bar2_memmap_p =
 			phba->pci_bar2_memmap_p =
 					 phba->sli4_hba.ctrl_regs_memmap_p;
 					 phba->sli4_hba.ctrl_regs_memmap_p;
-			lpfc_sli4_bar1_register_memmap(phba);
+			lpfc_sli4_bar1_register_memmap(phba, if_type);
 		} else {
 		} else {
 			error = -ENOMEM;
 			error = -ENOMEM;
 			goto out_iounmap_conf;
 			goto out_iounmap_conf;
 		}
 		}
 	}
 	}
 
 
+	if ((if_type == LPFC_SLI_INTF_IF_TYPE_6) &&
+	    (pci_resource_start(pdev, PCI_64BIT_BAR2))) {
+		/*
+		 * Map SLI4 if type 6 HBA Doorbell Register base to a kernel
+		 * virtual address and setup the registers.
+		 */
+		phba->pci_bar1_map = pci_resource_start(pdev, PCI_64BIT_BAR2);
+		bar1map_len = pci_resource_len(pdev, PCI_64BIT_BAR2);
+		phba->sli4_hba.drbl_regs_memmap_p =
+				ioremap(phba->pci_bar1_map, bar1map_len);
+		if (!phba->sli4_hba.drbl_regs_memmap_p) {
+			dev_err(&pdev->dev,
+			   "ioremap failed for SLI4 HBA doorbell registers.\n");
+			goto out_iounmap_conf;
+		}
+		phba->pci_bar2_memmap_p = phba->sli4_hba.drbl_regs_memmap_p;
+		lpfc_sli4_bar1_register_memmap(phba, if_type);
+	}
+
 	if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
 	if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
 		if (pci_resource_start(pdev, PCI_64BIT_BAR4)) {
 		if (pci_resource_start(pdev, PCI_64BIT_BAR4)) {
 			/*
 			/*
@@ -9532,6 +9634,41 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
 		}
 		}
 	}
 	}
 
 
+	if (if_type == LPFC_SLI_INTF_IF_TYPE_6 &&
+	    pci_resource_start(pdev, PCI_64BIT_BAR4)) {
+		/*
+		 * Map SLI4 if type 6 HBA DPP Register base to a kernel
+		 * virtual address and setup the registers.
+		 */
+		phba->pci_bar2_map = pci_resource_start(pdev, PCI_64BIT_BAR4);
+		bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4);
+		phba->sli4_hba.dpp_regs_memmap_p =
+				ioremap(phba->pci_bar2_map, bar2map_len);
+		if (!phba->sli4_hba.dpp_regs_memmap_p) {
+			dev_err(&pdev->dev,
+			   "ioremap failed for SLI4 HBA dpp registers.\n");
+			goto out_iounmap_ctrl;
+		}
+		phba->pci_bar4_memmap_p = phba->sli4_hba.dpp_regs_memmap_p;
+	}
+
+	/* Set up the EQ/CQ register handeling functions now */
+	switch (if_type) {
+	case LPFC_SLI_INTF_IF_TYPE_0:
+	case LPFC_SLI_INTF_IF_TYPE_2:
+		phba->sli4_hba.sli4_eq_clr_intr = lpfc_sli4_eq_clr_intr;
+		phba->sli4_hba.sli4_eq_release = lpfc_sli4_eq_release;
+		phba->sli4_hba.sli4_cq_release = lpfc_sli4_cq_release;
+		break;
+	case LPFC_SLI_INTF_IF_TYPE_6:
+		phba->sli4_hba.sli4_eq_clr_intr = lpfc_sli4_if6_eq_clr_intr;
+		phba->sli4_hba.sli4_eq_release = lpfc_sli4_if6_eq_release;
+		phba->sli4_hba.sli4_cq_release = lpfc_sli4_if6_cq_release;
+		break;
+	default:
+		break;
+	}
+
 	return 0;
 	return 0;
 
 
 out_iounmap_all:
 out_iounmap_all:
@@ -9566,6 +9703,10 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
 	case LPFC_SLI_INTF_IF_TYPE_2:
 	case LPFC_SLI_INTF_IF_TYPE_2:
 		iounmap(phba->sli4_hba.conf_regs_memmap_p);
 		iounmap(phba->sli4_hba.conf_regs_memmap_p);
 		break;
 		break;
+	case LPFC_SLI_INTF_IF_TYPE_6:
+		iounmap(phba->sli4_hba.drbl_regs_memmap_p);
+		iounmap(phba->sli4_hba.conf_regs_memmap_p);
+		break;
 	case LPFC_SLI_INTF_IF_TYPE_1:
 	case LPFC_SLI_INTF_IF_TYPE_1:
 	default:
 	default:
 		dev_printk(KERN_ERR, &phba->pcidev->dev,
 		dev_printk(KERN_ERR, &phba->pcidev->dev,
@@ -10435,6 +10576,8 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 	sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
 	sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
 	sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
 	sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
 	sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters);
 	sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters);
+	sli4_params->eqav = bf_get(cfg_eqav, mbx_sli4_parameters);
+	sli4_params->cqav = bf_get(cfg_cqav, mbx_sli4_parameters);
 	sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters);
 	sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters);
 	sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt,
 	sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt,
 					    mbx_sli4_parameters);
 					    mbx_sli4_parameters);
@@ -10465,8 +10608,32 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 		phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
 		phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
 	}
 	}
 
 
-	if (bf_get(cfg_xib, mbx_sli4_parameters) && phba->cfg_suppress_rsp)
+	/* Only embed PBDE for if_type 6 */
+	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+	    LPFC_SLI_INTF_IF_TYPE_6) {
+		phba->fcp_embed_pbde = 1;
+		phba->nvme_embed_pbde = 1;
+	}
+
+	/* PBDE support requires xib be set */
+	if (!bf_get(cfg_xib, mbx_sli4_parameters)) {
+		phba->fcp_embed_pbde = 0;
+		phba->nvme_embed_pbde = 0;
+	}
+
+	/*
+	 * To support Suppress Response feature we must satisfy 3 conditions.
+	 * lpfc_suppress_rsp module parameter must be set (default).
+	 * In SLI4-Parameters Descriptor:
+	 * Extended Inline Buffers (XIB) must be supported.
+	 * Suppress Response IU Not Supported (SRIUNS) must NOT be supported
+	 * (double negative).
+	 */
+	if (phba->cfg_suppress_rsp && bf_get(cfg_xib, mbx_sli4_parameters) &&
+	    !(bf_get(cfg_nosr, mbx_sli4_parameters)))
 		phba->sli.sli_flag |= LPFC_SLI_SUPPRESS_RSP;
 		phba->sli.sli_flag |= LPFC_SLI_SUPPRESS_RSP;
+	else
+		phba->cfg_suppress_rsp = 0;
 
 
 	if (bf_get(cfg_eqdr, mbx_sli4_parameters))
 	if (bf_get(cfg_eqdr, mbx_sli4_parameters))
 		phba->sli.sli_flag |= LPFC_SLI_USE_EQDR;
 		phba->sli.sli_flag |= LPFC_SLI_USE_EQDR;
@@ -10476,15 +10643,28 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 		sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
 		sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE;
 
 
 	/*
 	/*
-	 * Issue IOs with CDB embedded in WQE to minimized the number
-	 * of DMAs the firmware has to do. Setting this to 1 also forces
-	 * the driver to use 128 bytes WQEs for FCP IOs.
+	 * Check whether the adapter supports an embedded copy of the
+	 * FCP CMD IU within the WQE for FCP_Ixxx commands. In order
+	 * to use this option, 128-byte WQEs must be used.
 	 */
 	 */
 	if (bf_get(cfg_ext_embed_cb, mbx_sli4_parameters))
 	if (bf_get(cfg_ext_embed_cb, mbx_sli4_parameters))
 		phba->fcp_embed_io = 1;
 		phba->fcp_embed_io = 1;
 	else
 	else
 		phba->fcp_embed_io = 0;
 		phba->fcp_embed_io = 0;
 
 
+	lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME,
+			"6422 XIB %d: FCP %d %d NVME %d %d %d %d\n",
+			bf_get(cfg_xib, mbx_sli4_parameters),
+			phba->fcp_embed_pbde, phba->fcp_embed_io,
+			phba->nvme_support, phba->nvme_embed_pbde,
+			phba->cfg_nvme_embed_cmd, phba->cfg_suppress_rsp);
+
+	if ((bf_get(cfg_cqpsize, mbx_sli4_parameters) & LPFC_CQ_16K_PAGE_SZ) &&
+	    (bf_get(cfg_wqpsize, mbx_sli4_parameters) & LPFC_WQ_16K_PAGE_SZ) &&
+	    (sli4_params->wqsize & LPFC_WQ_SZ128_SUPPORT))
+		phba->enab_exp_wqcq_pages = 1;
+	else
+		phba->enab_exp_wqcq_pages = 0;
 	/*
 	/*
 	 * Check if the SLI port supports MDS Diagnostics
 	 * Check if the SLI port supports MDS Diagnostics
 	 */
 	 */
@@ -11137,6 +11317,27 @@ lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba)
 }
 }
 
 
 
 
+static void
+lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset,
+	uint32_t magic_number, uint32_t ftype, uint32_t fid, uint32_t fsize,
+	const struct firmware *fw)
+{
+	if (offset == ADD_STATUS_FW_NOT_SUPPORTED)
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"3030 This firmware version is not supported on "
+			"this HBA model. Device:%x Magic:%x Type:%x "
+			"ID:%x Size %d %zd\n",
+			phba->pcidev->device, magic_number, ftype, fid,
+			fsize, fw->size);
+	else
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"3022 FW Download failed. Device:%x Magic:%x Type:%x "
+			"ID:%x Size %d %zd\n",
+			phba->pcidev->device, magic_number, ftype, fid,
+			fsize, fw->size);
+}
+
+
 /**
 /**
  * lpfc_write_firmware - attempt to write a firmware image to the port
  * lpfc_write_firmware - attempt to write a firmware image to the port
  * @fw: pointer to firmware image returned from request_firmware.
  * @fw: pointer to firmware image returned from request_firmware.
@@ -11164,20 +11365,10 @@ lpfc_write_firmware(const struct firmware *fw, void *context)
 
 
 	magic_number = be32_to_cpu(image->magic_number);
 	magic_number = be32_to_cpu(image->magic_number);
 	ftype = bf_get_be32(lpfc_grp_hdr_file_type, image);
 	ftype = bf_get_be32(lpfc_grp_hdr_file_type, image);
-	fid = bf_get_be32(lpfc_grp_hdr_id, image),
+	fid = bf_get_be32(lpfc_grp_hdr_id, image);
 	fsize = be32_to_cpu(image->size);
 	fsize = be32_to_cpu(image->size);
 
 
 	INIT_LIST_HEAD(&dma_buffer_list);
 	INIT_LIST_HEAD(&dma_buffer_list);
-	if ((magic_number != LPFC_GROUP_OJECT_MAGIC_G5 &&
-	     magic_number != LPFC_GROUP_OJECT_MAGIC_G6) ||
-	    ftype != LPFC_FILE_TYPE_GROUP || fsize != fw->size) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"3022 Invalid FW image found. "
-				"Magic:%x Type:%x ID:%x Size %d %zd\n",
-				magic_number, ftype, fid, fsize, fw->size);
-		rc = -EINVAL;
-		goto release_out;
-	}
 	lpfc_decode_firmware_rev(phba, fwrev, 1);
 	lpfc_decode_firmware_rev(phba, fwrev, 1);
 	if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
 	if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -11218,11 +11409,18 @@ lpfc_write_firmware(const struct firmware *fw, void *context)
 			}
 			}
 			rc = lpfc_wr_object(phba, &dma_buffer_list,
 			rc = lpfc_wr_object(phba, &dma_buffer_list,
 				    (fw->size - offset), &offset);
 				    (fw->size - offset), &offset);
-			if (rc)
+			if (rc) {
+				lpfc_log_write_firmware_error(phba, offset,
+					magic_number, ftype, fid, fsize, fw);
 				goto release_out;
 				goto release_out;
+			}
 		}
 		}
 		rc = offset;
 		rc = offset;
-	}
+	} else
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"3029 Skipped Firmware update, Current "
+				"Version:%s New Version:%s\n",
+				fwrev, image->revision);
 
 
 release_out:
 release_out:
 	list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) {
 	list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) {
@@ -11253,7 +11451,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade)
 	const struct firmware *fw;
 	const struct firmware *fw;
 
 
 	/* Only supported on SLI4 interface type 2 for now */
 	/* Only supported on SLI4 interface type 2 for now */
-	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
+	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
 	    LPFC_SLI_INTF_IF_TYPE_2)
 	    LPFC_SLI_INTF_IF_TYPE_2)
 		return -EPERM;
 		return -EPERM;
 
 
@@ -11493,13 +11691,6 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
 	/* Remove FC host and then SCSI host with the physical port */
 	/* Remove FC host and then SCSI host with the physical port */
 	fc_remove_host(shost);
 	fc_remove_host(shost);
 	scsi_remove_host(shost);
 	scsi_remove_host(shost);
-	/*
-	 * Bring down the SLI Layer. This step disables all interrupts,
-	 * clears the rings, discards all mailbox commands, and resets
-	 * the HBA FCoE function.
-	 */
-	lpfc_debugfs_terminate(vport);
-	lpfc_sli4_hba_unset(phba);
 
 
 	/* Perform ndlp cleanup on the physical port.  The nvme and nvmet
 	/* Perform ndlp cleanup on the physical port.  The nvme and nvmet
 	 * localports are destroyed after to cleanup all transport memory.
 	 * localports are destroyed after to cleanup all transport memory.
@@ -11508,6 +11699,13 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
 	lpfc_nvmet_destroy_targetport(phba);
 	lpfc_nvmet_destroy_targetport(phba);
 	lpfc_nvme_destroy_localport(vport);
 	lpfc_nvme_destroy_localport(vport);
 
 
+	/*
+	 * Bring down the SLI Layer. This step disables all interrupts,
+	 * clears the rings, discards all mailbox commands, and resets
+	 * the HBA FCoE function.
+	 */
+	lpfc_debugfs_terminate(vport);
+	lpfc_sli4_hba_unset(phba);
 
 
 	lpfc_stop_hba_timers(phba);
 	lpfc_stop_hba_timers(phba);
 	spin_lock_irq(&phba->hbalock);
 	spin_lock_irq(&phba->hbalock);
@@ -12227,6 +12425,7 @@ int
 lpfc_fof_queue_create(struct lpfc_hba *phba)
 lpfc_fof_queue_create(struct lpfc_hba *phba)
 {
 {
 	struct lpfc_queue *qdesc;
 	struct lpfc_queue *qdesc;
+	uint32_t wqesize;
 
 
 	/* Create FOF EQ */
 	/* Create FOF EQ */
 	qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
 	qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE,
@@ -12235,12 +12434,13 @@ lpfc_fof_queue_create(struct lpfc_hba *phba)
 	if (!qdesc)
 	if (!qdesc)
 		goto out_error;
 		goto out_error;
 
 
+	qdesc->qe_valid = 1;
 	phba->sli4_hba.fof_eq = qdesc;
 	phba->sli4_hba.fof_eq = qdesc;
 
 
 	if (phba->cfg_fof) {
 	if (phba->cfg_fof) {
 
 
 		/* Create OAS CQ */
 		/* Create OAS CQ */
-		if (phba->fcp_embed_io)
+		if (phba->enab_exp_wqcq_pages)
 			qdesc = lpfc_sli4_queue_alloc(phba,
 			qdesc = lpfc_sli4_queue_alloc(phba,
 						      LPFC_EXPANDED_PAGE_SIZE,
 						      LPFC_EXPANDED_PAGE_SIZE,
 						      phba->sli4_hba.cq_esize,
 						      phba->sli4_hba.cq_esize,
@@ -12253,19 +12453,23 @@ lpfc_fof_queue_create(struct lpfc_hba *phba)
 		if (!qdesc)
 		if (!qdesc)
 			goto out_error;
 			goto out_error;
 
 
+		qdesc->qe_valid = 1;
 		phba->sli4_hba.oas_cq = qdesc;
 		phba->sli4_hba.oas_cq = qdesc;
 
 
 		/* Create OAS WQ */
 		/* Create OAS WQ */
-		if (phba->fcp_embed_io)
+		if (phba->enab_exp_wqcq_pages) {
+			wqesize = (phba->fcp_embed_io) ?
+				LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize;
 			qdesc = lpfc_sli4_queue_alloc(phba,
 			qdesc = lpfc_sli4_queue_alloc(phba,
 						      LPFC_EXPANDED_PAGE_SIZE,
 						      LPFC_EXPANDED_PAGE_SIZE,
-						      LPFC_WQE128_SIZE,
+						      wqesize,
 						      LPFC_WQE_EXP_COUNT);
 						      LPFC_WQE_EXP_COUNT);
-		else
+		} else
 			qdesc = lpfc_sli4_queue_alloc(phba,
 			qdesc = lpfc_sli4_queue_alloc(phba,
 						      LPFC_DEFAULT_PAGE_SIZE,
 						      LPFC_DEFAULT_PAGE_SIZE,
 						      phba->sli4_hba.wq_esize,
 						      phba->sli4_hba.wq_esize,
 						      phba->sli4_hba.wq_ecount);
 						      phba->sli4_hba.wq_ecount);
+
 		if (!qdesc)
 		if (!qdesc)
 			goto out_error;
 			goto out_error;
 
 
@@ -12379,6 +12583,8 @@ lpfc_init(void)
 		fc_release_transport(lpfc_transport_template);
 		fc_release_transport(lpfc_transport_template);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
+	lpfc_nvme_cmd_template();
+	lpfc_nvmet_cmd_template();
 
 
 	/* Initialize in case vector mapping is needed */
 	/* Initialize in case vector mapping is needed */
 	lpfc_used_cpu = NULL;
 	lpfc_used_cpu = NULL;

+ 6 - 4
drivers/scsi/lpfc/lpfc_mbox.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -557,6 +557,10 @@ lpfc_init_link(struct lpfc_hba * phba,
 			mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
 			mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
 			mb->un.varInitLnk.link_speed = LINK_SPEED_32G;
 			mb->un.varInitLnk.link_speed = LINK_SPEED_32G;
 			break;
 			break;
+		case LPFC_USER_LINK_SPEED_64G:
+			mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
+			mb->un.varInitLnk.link_speed = LINK_SPEED_64G;
+			break;
 		case LPFC_USER_LINK_SPEED_AUTO:
 		case LPFC_USER_LINK_SPEED_AUTO:
 		default:
 		default:
 			mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
 			mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO;
@@ -2170,10 +2174,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
 	/* Only FC supports upd bit */
 	/* Only FC supports upd bit */
 	if ((phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) &&
 	if ((phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) &&
 	    (vport->fc_flag & FC_VFI_REGISTERED) &&
 	    (vport->fc_flag & FC_VFI_REGISTERED) &&
-	    (!phba->fc_topology_changed)) {
-		bf_set(lpfc_reg_vfi_vp, reg_vfi, 0);
+	    (!phba->fc_topology_changed))
 		bf_set(lpfc_reg_vfi_upd, reg_vfi, 1);
 		bf_set(lpfc_reg_vfi_upd, reg_vfi, 1);
-	}
 
 
 	bf_set(lpfc_reg_vfi_bbcr, reg_vfi, 0);
 	bf_set(lpfc_reg_vfi_bbcr, reg_vfi, 0);
 	bf_set(lpfc_reg_vfi_bbscn, reg_vfi, 0);
 	bf_set(lpfc_reg_vfi_bbscn, reg_vfi, 0);

+ 8 - 4
drivers/scsi/lpfc/lpfc_mem.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -753,12 +753,16 @@ lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
 	drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys);
 	drqe.address_hi = putPaddrHigh(rqb_entry->dbuf.phys);
 	rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe);
 	rc = lpfc_sli4_rq_put(rqb_entry->hrq, rqb_entry->drq, &hrqe, &drqe);
 	if (rc < 0) {
 	if (rc < 0) {
+		(rqbp->rqb_free_buffer)(phba, rqb_entry);
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"6409 Cannot post to RQ %d: %x %x\n",
+				"6409 Cannot post to HRQ %d: %x %x %x "
+				"DRQ %x %x\n",
 				rqb_entry->hrq->queue_id,
 				rqb_entry->hrq->queue_id,
 				rqb_entry->hrq->host_index,
 				rqb_entry->hrq->host_index,
-				rqb_entry->hrq->hba_index);
-		(rqbp->rqb_free_buffer)(phba, rqb_entry);
+				rqb_entry->hrq->hba_index,
+				rqb_entry->hrq->entry_count,
+				rqb_entry->drq->host_index,
+				rqb_entry->drq->hba_index);
 	} else {
 	} else {
 		list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list);
 		list_add_tail(&rqb_entry->hbuf.list, &rqbp->rqb_buffer_list);
 		rqbp->buffer_count++;
 		rqbp->buffer_count++;

+ 16 - 6
drivers/scsi/lpfc/lpfc_nportdisc.c

@@ -1,7 +1,7 @@
- /*******************************************************************
+/*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -1998,8 +1998,14 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			ndlp->nlp_type |= NLP_NVME_TARGET;
 			ndlp->nlp_type |= NLP_NVME_TARGET;
 			if (bf_get_be32(prli_disc, nvpr))
 			if (bf_get_be32(prli_disc, nvpr))
 				ndlp->nlp_type |= NLP_NVME_DISCOVERY;
 				ndlp->nlp_type |= NLP_NVME_DISCOVERY;
+
+			/*
+			 * If prli_fba is set, the Target supports FirstBurst.
+			 * If prli_fb_sz is 0, the FirstBurst size is unlimited,
+			 * otherwise it defines the actual size supported by
+			 * the NVME Target.
+			 */
 			if ((bf_get_be32(prli_fba, nvpr) == 1) &&
 			if ((bf_get_be32(prli_fba, nvpr) == 1) &&
-			    (bf_get_be32(prli_fb_sz, nvpr) > 0) &&
 			    (phba->cfg_nvme_enable_fb) &&
 			    (phba->cfg_nvme_enable_fb) &&
 			    (!phba->nvmet_support)) {
 			    (!phba->nvmet_support)) {
 				/* Both sides support FB. The target's first
 				/* Both sides support FB. The target's first
@@ -2008,12 +2014,16 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 				ndlp->nlp_flag |= NLP_FIRSTBURST;
 				ndlp->nlp_flag |= NLP_FIRSTBURST;
 				ndlp->nvme_fb_size = bf_get_be32(prli_fb_sz,
 				ndlp->nvme_fb_size = bf_get_be32(prli_fb_sz,
 								 nvpr);
 								 nvpr);
+
+				/* Expressed in units of 512 bytes */
+				if (ndlp->nvme_fb_size)
+					ndlp->nvme_fb_size <<=
+						LPFC_NVME_FB_SHIFT;
+				else
+					ndlp->nvme_fb_size = LPFC_NVME_MAX_FB;
 			}
 			}
 		}
 		}
 
 
-		if (bf_get_be32(prli_recov, nvpr))
-			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
-
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
 				 "6029 NVME PRLI Cmpl w1 x%08x "
 				 "6029 NVME PRLI Cmpl w1 x%08x "
 				 "w4 x%08x w5 x%08x flag x%x, "
 				 "w4 x%08x w5 x%08x flag x%x, "

+ 270 - 157
drivers/scsi/lpfc/lpfc_nvme.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -65,6 +65,136 @@ lpfc_release_nvme_buf(struct lpfc_hba *, struct lpfc_nvme_buf *);
 
 
 static struct nvme_fc_port_template lpfc_nvme_template;
 static struct nvme_fc_port_template lpfc_nvme_template;
 
 
+static union lpfc_wqe128 lpfc_iread_cmd_template;
+static union lpfc_wqe128 lpfc_iwrite_cmd_template;
+static union lpfc_wqe128 lpfc_icmnd_cmd_template;
+
+/* Setup WQE templates for NVME IOs */
+void
+lpfc_nvme_cmd_template(void)
+{
+	union lpfc_wqe128 *wqe;
+
+	/* IREAD template */
+	wqe = &lpfc_iread_cmd_template;
+	memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+	/* Word 0, 1, 2 - BDE is variable */
+
+	/* Word 3 - cmd_buff_len, payload_offset_len is zero */
+
+	/* Word 4 - total_xfer_len is variable */
+
+	/* Word 5 - is zero */
+
+	/* Word 6 - ctxt_tag, xri_tag is variable */
+
+	/* Word 7 */
+	bf_set(wqe_cmnd, &wqe->fcp_iread.wqe_com, CMD_FCP_IREAD64_WQE);
+	bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, PARM_READ_CHECK);
+	bf_set(wqe_class, &wqe->fcp_iread.wqe_com, CLASS3);
+	bf_set(wqe_ct, &wqe->fcp_iread.wqe_com, SLI4_CT_RPI);
+
+	/* Word 8 - abort_tag is variable */
+
+	/* Word 9  - reqtag is variable */
+
+	/* Word 10 - dbde, wqes is variable */
+	bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0);
+	bf_set(wqe_nvme, &wqe->fcp_iread.wqe_com, 1);
+	bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ);
+	bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, LPFC_WQE_LENLOC_WORD4);
+	bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0);
+	bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1);
+
+	/* Word 11 - pbde is variable */
+	bf_set(wqe_cmd_type, &wqe->fcp_iread.wqe_com, NVME_READ_CMD);
+	bf_set(wqe_cqid, &wqe->fcp_iread.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+	bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1);
+
+	/* Word 12 - is zero */
+
+	/* Word 13, 14, 15 - PBDE is variable */
+
+	/* IWRITE template */
+	wqe = &lpfc_iwrite_cmd_template;
+	memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+	/* Word 0, 1, 2 - BDE is variable */
+
+	/* Word 3 - cmd_buff_len, payload_offset_len is zero */
+
+	/* Word 4 - total_xfer_len is variable */
+
+	/* Word 5 - initial_xfer_len is variable */
+
+	/* Word 6 - ctxt_tag, xri_tag is variable */
+
+	/* Word 7 */
+	bf_set(wqe_cmnd, &wqe->fcp_iwrite.wqe_com, CMD_FCP_IWRITE64_WQE);
+	bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, PARM_READ_CHECK);
+	bf_set(wqe_class, &wqe->fcp_iwrite.wqe_com, CLASS3);
+	bf_set(wqe_ct, &wqe->fcp_iwrite.wqe_com, SLI4_CT_RPI);
+
+	/* Word 8 - abort_tag is variable */
+
+	/* Word 9  - reqtag is variable */
+
+	/* Word 10 - dbde, wqes is variable */
+	bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0);
+	bf_set(wqe_nvme, &wqe->fcp_iwrite.wqe_com, 1);
+	bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE);
+	bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_LENLOC_WORD4);
+	bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0);
+	bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
+
+	/* Word 11 - pbde is variable */
+	bf_set(wqe_cmd_type, &wqe->fcp_iwrite.wqe_com, NVME_WRITE_CMD);
+	bf_set(wqe_cqid, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+	bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1);
+
+	/* Word 12 - is zero */
+
+	/* Word 13, 14, 15 - PBDE is variable */
+
+	/* ICMND template */
+	wqe = &lpfc_icmnd_cmd_template;
+	memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+	/* Word 0, 1, 2 - BDE is variable */
+
+	/* Word 3 - payload_offset_len is variable */
+
+	/* Word 4, 5 - is zero */
+
+	/* Word 6 - ctxt_tag, xri_tag is variable */
+
+	/* Word 7 */
+	bf_set(wqe_cmnd, &wqe->fcp_icmd.wqe_com, CMD_FCP_ICMND64_WQE);
+	bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0);
+	bf_set(wqe_class, &wqe->fcp_icmd.wqe_com, CLASS3);
+	bf_set(wqe_ct, &wqe->fcp_icmd.wqe_com, SLI4_CT_RPI);
+
+	/* Word 8 - abort_tag is variable */
+
+	/* Word 9  - reqtag is variable */
+
+	/* Word 10 - dbde, wqes is variable */
+	bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1);
+	bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1);
+	bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_NONE);
+	bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, LPFC_WQE_LENLOC_NONE);
+	bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0);
+	bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1);
+
+	/* Word 11 */
+	bf_set(wqe_cmd_type, &wqe->fcp_icmd.wqe_com, FCP_COMMAND);
+	bf_set(wqe_cqid, &wqe->fcp_icmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+	bf_set(wqe_pbde, &wqe->fcp_icmd.wqe_com, 0);
+
+	/* Word 12, 13, 14, 15 - is zero */
+}
+
 /**
 /**
  * lpfc_nvme_create_queue -
  * lpfc_nvme_create_queue -
  * @lpfc_pnvme: Pointer to the driver's nvme instance data
  * @lpfc_pnvme: Pointer to the driver's nvme instance data
@@ -241,10 +371,11 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
 	ndlp = (struct lpfc_nodelist *)cmdwqe->context1;
 	ndlp = (struct lpfc_nodelist *)cmdwqe->context1;
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
 			 "6047 nvme cmpl Enter "
 			 "6047 nvme cmpl Enter "
-			 "Data %p DID %x Xri: %x status %x cmd:%p lsreg:%p "
-			 "bmp:%p ndlp:%p\n",
+			 "Data %p DID %x Xri: %x status %x reason x%x cmd:%p "
+			 "lsreg:%p bmp:%p ndlp:%p\n",
 			 pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0,
 			 pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0,
 			 cmdwqe->sli4_xritag, status,
 			 cmdwqe->sli4_xritag, status,
+			 (wcqe->parameter & 0xffff),
 			 cmdwqe, pnvme_lsreq, cmdwqe->context3, ndlp);
 			 cmdwqe, pnvme_lsreq, cmdwqe->context3, ndlp);
 
 
 	lpfc_nvmeio_data(phba, "NVME LS  CMPL: xri x%x stat x%x parm x%x\n",
 	lpfc_nvmeio_data(phba, "NVME LS  CMPL: xri x%x stat x%x parm x%x\n",
@@ -274,14 +405,14 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
 static int
 static int
 lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
 lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
 		  struct lpfc_dmabuf *inp,
 		  struct lpfc_dmabuf *inp,
-		 struct nvmefc_ls_req *pnvme_lsreq,
-	     void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
-			   struct lpfc_wcqe_complete *),
-	     struct lpfc_nodelist *ndlp, uint32_t num_entry,
-	     uint32_t tmo, uint8_t retry)
+		  struct nvmefc_ls_req *pnvme_lsreq,
+		  void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
+			       struct lpfc_wcqe_complete *),
+		  struct lpfc_nodelist *ndlp, uint32_t num_entry,
+		  uint32_t tmo, uint8_t retry)
 {
 {
-	struct lpfc_hba  *phba = vport->phba;
-	union lpfc_wqe *wqe;
+	struct lpfc_hba *phba = vport->phba;
+	union lpfc_wqe128 *wqe;
 	struct lpfc_iocbq *genwqe;
 	struct lpfc_iocbq *genwqe;
 	struct ulp_bde64 *bpl;
 	struct ulp_bde64 *bpl;
 	struct ulp_bde64 bde;
 	struct ulp_bde64 bde;
@@ -419,6 +550,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
 {
 {
 	int ret = 0;
 	int ret = 0;
 	struct lpfc_nvme_lport *lport;
 	struct lpfc_nvme_lport *lport;
+	struct lpfc_nvme_rport *rport;
 	struct lpfc_vport *vport;
 	struct lpfc_vport *vport;
 	struct lpfc_nodelist *ndlp;
 	struct lpfc_nodelist *ndlp;
 	struct ulp_bde64 *bpl;
 	struct ulp_bde64 *bpl;
@@ -437,19 +569,18 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
 	 */
 	 */
 
 
 	lport = (struct lpfc_nvme_lport *)pnvme_lport->private;
 	lport = (struct lpfc_nvme_lport *)pnvme_lport->private;
+	rport = (struct lpfc_nvme_rport *)pnvme_rport->private;
 	vport = lport->vport;
 	vport = lport->vport;
 
 
 	if (vport->load_flag & FC_UNLOADING)
 	if (vport->load_flag & FC_UNLOADING)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (vport->load_flag & FC_UNLOADING)
-		return -ENODEV;
-
-	ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id);
+	/* Need the ndlp.  It is stored in the driver's rport. */
+	ndlp = rport->ndlp;
 	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
 	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR,
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR,
-				 "6051 DID x%06x not an active rport.\n",
-				 pnvme_rport->port_id);
+				 "6051 Remoteport %p, rport has invalid ndlp. "
+				 "Failing LS Req\n", pnvme_rport);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -500,8 +631,9 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
 
 
 	/* Expand print to include key fields. */
 	/* Expand print to include key fields. */
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
-			 "6149 ENTER.  lport %p, rport %p lsreq%p rqstlen:%d "
-			 "rsplen:%d %pad %pad\n",
+			 "6149 Issue LS Req to DID 0x%06x lport %p, rport %p "
+			 "lsreq%p rqstlen:%d rsplen:%d %pad %pad\n",
+			 ndlp->nlp_DID,
 			 pnvme_lport, pnvme_rport,
 			 pnvme_lport, pnvme_rport,
 			 pnvme_lsreq, pnvme_lsreq->rqstlen,
 			 pnvme_lsreq, pnvme_lsreq->rqstlen,
 			 pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma,
 			 pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma,
@@ -517,7 +649,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
 				ndlp, 2, 30, 0);
 				ndlp, 2, 30, 0);
 	if (ret != WQE_SUCCESS) {
 	if (ret != WQE_SUCCESS) {
 		atomic_inc(&lport->xmt_ls_err);
 		atomic_inc(&lport->xmt_ls_err);
-		lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC,
 				 "6052 EXIT. issue ls wqe failed lport %p, "
 				 "6052 EXIT. issue ls wqe failed lport %p, "
 				 "rport %p lsreq%p Status %x DID %x\n",
 				 "rport %p lsreq%p Status %x DID %x\n",
 				 pnvme_lport, pnvme_rport, pnvme_lsreq,
 				 pnvme_lport, pnvme_rport, pnvme_lsreq,
@@ -610,15 +742,24 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport,
 }
 }
 
 
 /* Fix up the existing sgls for NVME IO. */
 /* Fix up the existing sgls for NVME IO. */
-static void
+static inline void
 lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
 lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
 		       struct lpfc_nvme_buf *lpfc_ncmd,
 		       struct lpfc_nvme_buf *lpfc_ncmd,
 		       struct nvmefc_fcp_req *nCmd)
 		       struct nvmefc_fcp_req *nCmd)
 {
 {
+	struct lpfc_hba  *phba = vport->phba;
 	struct sli4_sge *sgl;
 	struct sli4_sge *sgl;
 	union lpfc_wqe128 *wqe;
 	union lpfc_wqe128 *wqe;
 	uint32_t *wptr, *dptr;
 	uint32_t *wptr, *dptr;
 
 
+	/*
+	 * Get a local pointer to the built-in wqe and correct
+	 * the cmd size to match NVME's 96 bytes and fix
+	 * the dma address.
+	 */
+
+	wqe = &lpfc_ncmd->cur_iocbq.wqe;
+
 	/*
 	/*
 	 * Adjust the FCP_CMD and FCP_RSP DMA data and sge_len to
 	 * Adjust the FCP_CMD and FCP_RSP DMA data and sge_len to
 	 * match NVME.  NVME sends 96 bytes. Also, use the
 	 * match NVME.  NVME sends 96 bytes. Also, use the
@@ -628,6 +769,60 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
 	 */
 	 */
 	sgl = lpfc_ncmd->nvme_sgl;
 	sgl = lpfc_ncmd->nvme_sgl;
 	sgl->sge_len = cpu_to_le32(nCmd->cmdlen);
 	sgl->sge_len = cpu_to_le32(nCmd->cmdlen);
+	if (phba->cfg_nvme_embed_cmd) {
+		sgl->addr_hi = 0;
+		sgl->addr_lo = 0;
+
+		/* Word 0-2 - NVME CMND IU (embedded payload) */
+		wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED;
+		wqe->generic.bde.tus.f.bdeSize = 56;
+		wqe->generic.bde.addrHigh = 0;
+		wqe->generic.bde.addrLow =  64;  /* Word 16 */
+
+		/* Word 10  - dbde is 0, wqes is 1 in template */
+
+		/*
+		 * Embed the payload in the last half of the WQE
+		 * WQE words 16-30 get the NVME CMD IU payload
+		 *
+		 * WQE words 16-19 get payload Words 1-4
+		 * WQE words 20-21 get payload Words 6-7
+		 * WQE words 22-29 get payload Words 16-23
+		 */
+		wptr = &wqe->words[16];  /* WQE ptr */
+		dptr = (uint32_t *)nCmd->cmdaddr;  /* payload ptr */
+		dptr++;			/* Skip Word 0 in payload */
+
+		*wptr++ = *dptr++;	/* Word 1 */
+		*wptr++ = *dptr++;	/* Word 2 */
+		*wptr++ = *dptr++;	/* Word 3 */
+		*wptr++ = *dptr++;	/* Word 4 */
+		dptr++;			/* Skip Word 5 in payload */
+		*wptr++ = *dptr++;	/* Word 6 */
+		*wptr++ = *dptr++;	/* Word 7 */
+		dptr += 8;		/* Skip Words 8-15 in payload */
+		*wptr++ = *dptr++;	/* Word 16 */
+		*wptr++ = *dptr++;	/* Word 17 */
+		*wptr++ = *dptr++;	/* Word 18 */
+		*wptr++ = *dptr++;	/* Word 19 */
+		*wptr++ = *dptr++;	/* Word 20 */
+		*wptr++ = *dptr++;	/* Word 21 */
+		*wptr++ = *dptr++;	/* Word 22 */
+		*wptr   = *dptr;	/* Word 23 */
+	} else {
+		sgl->addr_hi = cpu_to_le32(putPaddrHigh(nCmd->cmddma));
+		sgl->addr_lo = cpu_to_le32(putPaddrLow(nCmd->cmddma));
+
+		/* Word 0-2 - NVME CMND IU Inline BDE */
+		wqe->generic.bde.tus.f.bdeFlags =  BUFF_TYPE_BDE_64;
+		wqe->generic.bde.tus.f.bdeSize = nCmd->cmdlen;
+		wqe->generic.bde.addrHigh = sgl->addr_hi;
+		wqe->generic.bde.addrLow =  sgl->addr_lo;
+
+		/* Word 10 */
+		bf_set(wqe_dbde, &wqe->generic.wqe_com, 1);
+		bf_set(wqe_wqes, &wqe->generic.wqe_com, 0);
+	}
 
 
 	sgl++;
 	sgl++;
 
 
@@ -641,58 +836,6 @@ lpfc_nvme_adj_fcp_sgls(struct lpfc_vport *vport,
 		bf_set(lpfc_sli4_sge_last, sgl, 1);
 		bf_set(lpfc_sli4_sge_last, sgl, 1);
 	sgl->word2 = cpu_to_le32(sgl->word2);
 	sgl->word2 = cpu_to_le32(sgl->word2);
 	sgl->sge_len = cpu_to_le32(nCmd->rsplen);
 	sgl->sge_len = cpu_to_le32(nCmd->rsplen);
-
-	/*
-	 * Get a local pointer to the built-in wqe and correct
-	 * the cmd size to match NVME's 96 bytes and fix
-	 * the dma address.
-	 */
-
-	/* 128 byte wqe support here */
-	wqe = (union lpfc_wqe128 *)&lpfc_ncmd->cur_iocbq.wqe;
-
-	/* Word 0-2 - NVME CMND IU (embedded payload) */
-	wqe->generic.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_IMMED;
-	wqe->generic.bde.tus.f.bdeSize = 60;
-	wqe->generic.bde.addrHigh = 0;
-	wqe->generic.bde.addrLow =  64;  /* Word 16 */
-
-	/* Word 3 */
-	bf_set(payload_offset_len, &wqe->fcp_icmd,
-	       (nCmd->rsplen + nCmd->cmdlen));
-
-	/* Word 10 */
-	bf_set(wqe_nvme, &wqe->fcp_icmd.wqe_com, 1);
-	bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1);
-
-	/*
-	 * Embed the payload in the last half of the WQE
-	 * WQE words 16-30 get the NVME CMD IU payload
-	 *
-	 * WQE words 16-19 get payload Words 1-4
-	 * WQE words 20-21 get payload Words 6-7
-	 * WQE words 22-29 get payload Words 16-23
-	 */
-	wptr = &wqe->words[16];  /* WQE ptr */
-	dptr = (uint32_t *)nCmd->cmdaddr;  /* payload ptr */
-	dptr++;			/* Skip Word 0 in payload */
-
-	*wptr++ = *dptr++;	/* Word 1 */
-	*wptr++ = *dptr++;	/* Word 2 */
-	*wptr++ = *dptr++;	/* Word 3 */
-	*wptr++ = *dptr++;	/* Word 4 */
-	dptr++;			/* Skip Word 5 in payload */
-	*wptr++ = *dptr++;	/* Word 6 */
-	*wptr++ = *dptr++;	/* Word 7 */
-	dptr += 8;		/* Skip Words 8-15 in payload */
-	*wptr++ = *dptr++;	/* Word 16 */
-	*wptr++ = *dptr++;	/* Word 17 */
-	*wptr++ = *dptr++;	/* Word 18 */
-	*wptr++ = *dptr++;	/* Word 19 */
-	*wptr++ = *dptr++;	/* Word 20 */
-	*wptr++ = *dptr++;	/* Word 21 */
-	*wptr++ = *dptr++;	/* Word 22 */
-	*wptr   = *dptr;	/* Word 23 */
 }
 }
 
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
@@ -980,14 +1123,14 @@ out_err:
 			phba->cpucheck_cmpl_io[lpfc_ncmd->cpu]++;
 			phba->cpucheck_cmpl_io[lpfc_ncmd->cpu]++;
 	}
 	}
 #endif
 #endif
-	freqpriv = nCmd->private;
-	freqpriv->nvme_buf = NULL;
 
 
 	/* NVME targets need completion held off until the abort exchange
 	/* NVME targets need completion held off until the abort exchange
 	 * completes unless the NVME Rport is getting unregistered.
 	 * completes unless the NVME Rport is getting unregistered.
 	 */
 	 */
 
 
 	if (!(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) {
 	if (!(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) {
+		freqpriv = nCmd->private;
+		freqpriv->nvme_buf = NULL;
 		nCmd->done(nCmd);
 		nCmd->done(nCmd);
 		lpfc_ncmd->nvmeCmd = NULL;
 		lpfc_ncmd->nvmeCmd = NULL;
 	}
 	}
@@ -1025,7 +1168,7 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
 	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_hba *phba = vport->phba;
 	struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd;
 	struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd;
 	struct lpfc_iocbq *pwqeq = &(lpfc_ncmd->cur_iocbq);
 	struct lpfc_iocbq *pwqeq = &(lpfc_ncmd->cur_iocbq);
-	union lpfc_wqe128 *wqe = (union lpfc_wqe128 *)&pwqeq->wqe;
+	union lpfc_wqe128 *wqe = &pwqeq->wqe;
 	uint32_t req_len;
 	uint32_t req_len;
 
 
 	if (!pnode || !NLP_CHK_NODE_ACT(pnode))
 	if (!pnode || !NLP_CHK_NODE_ACT(pnode))
@@ -1035,9 +1178,16 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
 	 * There are three possibilities here - use scatter-gather segment, use
 	 * There are three possibilities here - use scatter-gather segment, use
 	 * the single mapping, or neither.
 	 * the single mapping, or neither.
 	 */
 	 */
-	wqe->fcp_iwrite.initial_xfer_len = 0;
 	if (nCmd->sg_cnt) {
 	if (nCmd->sg_cnt) {
 		if (nCmd->io_dir == NVMEFC_FCP_WRITE) {
 		if (nCmd->io_dir == NVMEFC_FCP_WRITE) {
+			/* From the iwrite template, initialize words 7 - 11 */
+			memcpy(&wqe->words[7],
+			       &lpfc_iwrite_cmd_template.words[7],
+			       sizeof(uint32_t) * 5);
+
+			/* Word 4 */
+			wqe->fcp_iwrite.total_xfer_len = nCmd->payload_length;
+
 			/* Word 5 */
 			/* Word 5 */
 			if ((phba->cfg_nvme_enable_fb) &&
 			if ((phba->cfg_nvme_enable_fb) &&
 			    (pnode->nlp_flag & NLP_FIRSTBURST)) {
 			    (pnode->nlp_flag & NLP_FIRSTBURST)) {
@@ -1048,69 +1198,28 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
 				else
 				else
 					wqe->fcp_iwrite.initial_xfer_len =
 					wqe->fcp_iwrite.initial_xfer_len =
 						pnode->nvme_fb_size;
 						pnode->nvme_fb_size;
+			} else {
+				wqe->fcp_iwrite.initial_xfer_len = 0;
 			}
 			}
-
-			/* Word 7 */
-			bf_set(wqe_cmnd, &wqe->generic.wqe_com,
-			       CMD_FCP_IWRITE64_WQE);
-			bf_set(wqe_pu, &wqe->generic.wqe_com,
-			       PARM_READ_CHECK);
-
-			/* Word 10 */
-			bf_set(wqe_qosd, &wqe->fcp_iwrite.wqe_com, 0);
-			bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com,
-			       LPFC_WQE_IOD_WRITE);
-			bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com,
-			       LPFC_WQE_LENLOC_WORD4);
-			if (phba->cfg_nvme_oas)
-				bf_set(wqe_oas, &wqe->fcp_iwrite.wqe_com, 1);
-
-			/* Word 11 */
-			bf_set(wqe_cmd_type, &wqe->generic.wqe_com,
-			       NVME_WRITE_CMD);
-
 			atomic_inc(&phba->fc4NvmeOutputRequests);
 			atomic_inc(&phba->fc4NvmeOutputRequests);
 		} else {
 		} else {
-			/* Word 7 */
-			bf_set(wqe_cmnd, &wqe->generic.wqe_com,
-			       CMD_FCP_IREAD64_WQE);
-			bf_set(wqe_pu, &wqe->generic.wqe_com,
-			       PARM_READ_CHECK);
-
-			/* Word 10 */
-			bf_set(wqe_qosd, &wqe->fcp_iread.wqe_com, 0);
-			bf_set(wqe_iod, &wqe->fcp_iread.wqe_com,
-			       LPFC_WQE_IOD_READ);
-			bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com,
-			       LPFC_WQE_LENLOC_WORD4);
-			if (phba->cfg_nvme_oas)
-				bf_set(wqe_oas, &wqe->fcp_iread.wqe_com, 1);
-
-			/* Word 11 */
-			bf_set(wqe_cmd_type, &wqe->generic.wqe_com,
-			       NVME_READ_CMD);
+			/* From the iread template, initialize words 7 - 11 */
+			memcpy(&wqe->words[7],
+			       &lpfc_iread_cmd_template.words[7],
+			       sizeof(uint32_t) * 5);
+
+			/* Word 4 */
+			wqe->fcp_iread.total_xfer_len = nCmd->payload_length;
+
+			/* Word 5 */
+			wqe->fcp_iread.rsrvd5 = 0;
 
 
 			atomic_inc(&phba->fc4NvmeInputRequests);
 			atomic_inc(&phba->fc4NvmeInputRequests);
 		}
 		}
 	} else {
 	} else {
-		/* Word 4 */
-		wqe->fcp_icmd.rsrvd4 = 0;
-
-		/* Word 7 */
-		bf_set(wqe_cmnd, &wqe->generic.wqe_com, CMD_FCP_ICMND64_WQE);
-		bf_set(wqe_pu, &wqe->generic.wqe_com, 0);
-
-		/* Word 10 */
-		bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1);
-		bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_WRITE);
-		bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com,
-		       LPFC_WQE_LENLOC_NONE);
-		if (phba->cfg_nvme_oas)
-			bf_set(wqe_oas, &wqe->fcp_icmd.wqe_com, 1);
-
-		/* Word 11 */
-		bf_set(wqe_cmd_type, &wqe->generic.wqe_com, NVME_READ_CMD);
-
+		/* From the icmnd template, initialize words 4 - 11 */
+		memcpy(&wqe->words[4], &lpfc_icmnd_cmd_template.words[4],
+		       sizeof(uint32_t) * 8);
 		atomic_inc(&phba->fc4NvmeControlRequests);
 		atomic_inc(&phba->fc4NvmeControlRequests);
 	}
 	}
 	/*
 	/*
@@ -1118,25 +1227,21 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
 	 * of the nvme_cmnd request_buffer
 	 * of the nvme_cmnd request_buffer
 	 */
 	 */
 
 
+	/* Word 3 */
+	bf_set(payload_offset_len, &wqe->fcp_icmd,
+	       (nCmd->rsplen + nCmd->cmdlen));
+
 	/* Word 6 */
 	/* Word 6 */
 	bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com,
 	bf_set(wqe_ctxt_tag, &wqe->generic.wqe_com,
 	       phba->sli4_hba.rpi_ids[pnode->nlp_rpi]);
 	       phba->sli4_hba.rpi_ids[pnode->nlp_rpi]);
 	bf_set(wqe_xri_tag, &wqe->generic.wqe_com, pwqeq->sli4_xritag);
 	bf_set(wqe_xri_tag, &wqe->generic.wqe_com, pwqeq->sli4_xritag);
 
 
-	/* Word 7 */
-	/* Preserve Class data in the ndlp. */
-	bf_set(wqe_class, &wqe->generic.wqe_com,
-	       (pnode->nlp_fcp_info & 0x0f));
-
 	/* Word 8 */
 	/* Word 8 */
 	wqe->generic.wqe_com.abort_tag = pwqeq->iotag;
 	wqe->generic.wqe_com.abort_tag = pwqeq->iotag;
 
 
 	/* Word 9 */
 	/* Word 9 */
 	bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag);
 	bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag);
 
 
-	/* Word 11 */
-	bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
-
 	pwqeq->vport = vport;
 	pwqeq->vport = vport;
 	return 0;
 	return 0;
 }
 }
@@ -1164,10 +1269,11 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
 {
 {
 	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_hba *phba = vport->phba;
 	struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd;
 	struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd;
-	union lpfc_wqe128 *wqe = (union lpfc_wqe128 *)&lpfc_ncmd->cur_iocbq.wqe;
+	union lpfc_wqe128 *wqe = &lpfc_ncmd->cur_iocbq.wqe;
 	struct sli4_sge *sgl = lpfc_ncmd->nvme_sgl;
 	struct sli4_sge *sgl = lpfc_ncmd->nvme_sgl;
 	struct scatterlist *data_sg;
 	struct scatterlist *data_sg;
 	struct sli4_sge *first_data_sgl;
 	struct sli4_sge *first_data_sgl;
+	struct ulp_bde64 *bde;
 	dma_addr_t physaddr;
 	dma_addr_t physaddr;
 	uint32_t num_bde = 0;
 	uint32_t num_bde = 0;
 	uint32_t dma_len;
 	uint32_t dma_len;
@@ -1235,7 +1341,26 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
 			data_sg = sg_next(data_sg);
 			data_sg = sg_next(data_sg);
 			sgl++;
 			sgl++;
 		}
 		}
+		if (phba->nvme_embed_pbde) {
+			/* Use PBDE support for first SGL only, offset == 0 */
+			/* Words 13-15 */
+			bde = (struct ulp_bde64 *)
+				&wqe->words[13];
+			bde->addrLow = first_data_sgl->addr_lo;
+			bde->addrHigh = first_data_sgl->addr_hi;
+			bde->tus.f.bdeSize =
+				le32_to_cpu(first_data_sgl->sge_len);
+			bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+			bde->tus.w = cpu_to_le32(bde->tus.w);
+			/* wqe_pbde is 1 in template */
+		} else {
+			memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3));
+			bf_set(wqe_pbde, &wqe->generic.wqe_com, 0);
+		}
 	} else {
 	} else {
+		bf_set(wqe_pbde, &wqe->generic.wqe_com, 0);
+		memset(&wqe->words[13], 0, (sizeof(uint32_t) * 3));
+
 		/* For this clause to be valid, the payload_length
 		/* For this clause to be valid, the payload_length
 		 * and sg_cnt must zero.
 		 * and sg_cnt must zero.
 		 */
 		 */
@@ -1247,12 +1372,6 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
 			return 1;
 			return 1;
 		}
 		}
 	}
 	}
-
-	/*
-	 * Due to difference in data length between DIF/non-DIF paths,
-	 * we need to set word 4 of WQE here
-	 */
-	wqe->fcp_iread.total_xfer_len = nCmd->payload_length;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1554,7 +1673,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
 	struct lpfc_iocbq *abts_buf;
 	struct lpfc_iocbq *abts_buf;
 	struct lpfc_iocbq *nvmereq_wqe;
 	struct lpfc_iocbq *nvmereq_wqe;
 	struct lpfc_nvme_fcpreq_priv *freqpriv;
 	struct lpfc_nvme_fcpreq_priv *freqpriv;
-	union lpfc_wqe *abts_wqe;
+	union lpfc_wqe128 *abts_wqe;
 	unsigned long flags;
 	unsigned long flags;
 	int ret_val;
 	int ret_val;
 
 
@@ -2098,7 +2217,7 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc)
 			break;
 			break;
 		}
 		}
 		pwqeq = &(lpfc_ncmd->cur_iocbq);
 		pwqeq = &(lpfc_ncmd->cur_iocbq);
-		wqe = (union lpfc_wqe128 *)&pwqeq->wqe;
+		wqe = &pwqeq->wqe;
 
 
 		/* Allocate iotag for lpfc_ncmd->cur_iocbq. */
 		/* Allocate iotag for lpfc_ncmd->cur_iocbq. */
 		iotag = lpfc_sli_next_iotag(phba, pwqeq);
 		iotag = lpfc_sli_next_iotag(phba, pwqeq);
@@ -2135,14 +2254,8 @@ lpfc_new_nvme_buf(struct lpfc_vport *vport, int num_to_alloc)
 
 
 		lpfc_ncmd->cur_iocbq.context1 = lpfc_ncmd;
 		lpfc_ncmd->cur_iocbq.context1 = lpfc_ncmd;
 
 
-		/* Word 7 */
-		bf_set(wqe_erp, &wqe->generic.wqe_com, 0);
-		/* NVME upper layers will time things out, if needed */
-		bf_set(wqe_tmo, &wqe->generic.wqe_com, 0);
-
-		/* Word 10 */
-		bf_set(wqe_ebde_cnt, &wqe->generic.wqe_com, 0);
-		bf_set(wqe_dbde, &wqe->generic.wqe_com, 1);
+		/* Initialize WQE */
+		memset(wqe, 0, sizeof(union lpfc_wqe));
 
 
 		/* add the nvme buffer to a post list */
 		/* add the nvme buffer to a post list */
 		list_add_tail(&lpfc_ncmd->list, &post_nblist);
 		list_add_tail(&lpfc_ncmd->list, &post_nblist);

+ 3 - 1
drivers/scsi/lpfc/lpfc_nvme.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -27,6 +27,8 @@
 
 
 #define LPFC_NVME_WAIT_TMO              10
 #define LPFC_NVME_WAIT_TMO              10
 #define LPFC_NVME_EXPEDITE_XRICNT	8
 #define LPFC_NVME_EXPEDITE_XRICNT	8
+#define LPFC_NVME_FB_SHIFT		9
+#define LPFC_NVME_MAX_FB		(1 << 20)	/* 1M */
 
 
 struct lpfc_nvme_qhandle {
 struct lpfc_nvme_qhandle {
 	uint32_t index;		/* WQ index to use */
 	uint32_t index;		/* WQ index to use */

+ 354 - 116
drivers/scsi/lpfc/lpfc_nvmet.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channsel Host Bus Adapters.                               *
  * Fibre Channsel Host Bus Adapters.                               *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -36,7 +36,7 @@
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/fc/fc_fs.h>
 #include <scsi/fc/fc_fs.h>
 
 
-#include <../drivers/nvme/host/nvme.h>
+#include <linux/nvme.h>
 #include <linux/nvme-fc-driver.h>
 #include <linux/nvme-fc-driver.h>
 #include <linux/nvme-fc.h>
 #include <linux/nvme-fc.h>
 
 
@@ -71,6 +71,151 @@ static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *,
 static int lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *,
 static int lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *,
 					   struct lpfc_nvmet_rcv_ctx *,
 					   struct lpfc_nvmet_rcv_ctx *,
 					   uint32_t, uint16_t);
 					   uint32_t, uint16_t);
+static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *, struct lpfc_queue *,
+				    struct lpfc_nvmet_rcv_ctx *);
+
+static union lpfc_wqe128 lpfc_tsend_cmd_template;
+static union lpfc_wqe128 lpfc_treceive_cmd_template;
+static union lpfc_wqe128 lpfc_trsp_cmd_template;
+
+/* Setup WQE templates for NVME IOs */
+void
+lpfc_nvmet_cmd_template(void)
+{
+	union lpfc_wqe128 *wqe;
+
+	/* TSEND template */
+	wqe = &lpfc_tsend_cmd_template;
+	memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+	/* Word 0, 1, 2 - BDE is variable */
+
+	/* Word 3 - payload_offset_len is zero */
+
+	/* Word 4 - relative_offset is variable */
+
+	/* Word 5 - is zero */
+
+	/* Word 6 - ctxt_tag, xri_tag is variable */
+
+	/* Word 7 - wqe_ar is variable */
+	bf_set(wqe_cmnd, &wqe->fcp_tsend.wqe_com, CMD_FCP_TSEND64_WQE);
+	bf_set(wqe_pu, &wqe->fcp_tsend.wqe_com, PARM_REL_OFF);
+	bf_set(wqe_class, &wqe->fcp_tsend.wqe_com, CLASS3);
+	bf_set(wqe_ct, &wqe->fcp_tsend.wqe_com, SLI4_CT_RPI);
+	bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 1);
+
+	/* Word 8 - abort_tag is variable */
+
+	/* Word 9  - reqtag, rcvoxid is variable */
+
+	/* Word 10 - wqes, xc is variable */
+	bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1);
+	bf_set(wqe_dbde, &wqe->fcp_tsend.wqe_com, 1);
+	bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0);
+	bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1);
+	bf_set(wqe_iod, &wqe->fcp_tsend.wqe_com, LPFC_WQE_IOD_WRITE);
+	bf_set(wqe_lenloc, &wqe->fcp_tsend.wqe_com, LPFC_WQE_LENLOC_WORD12);
+
+	/* Word 11 - sup, irsp, irsplen is variable */
+	bf_set(wqe_cmd_type, &wqe->fcp_tsend.wqe_com, FCP_COMMAND_TSEND);
+	bf_set(wqe_cqid, &wqe->fcp_tsend.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+	bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
+	bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0);
+	bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0);
+	bf_set(wqe_pbde, &wqe->fcp_tsend.wqe_com, 0);
+
+	/* Word 12 - fcp_data_len is variable */
+
+	/* Word 13, 14, 15 - PBDE is zero */
+
+	/* TRECEIVE template */
+	wqe = &lpfc_treceive_cmd_template;
+	memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+	/* Word 0, 1, 2 - BDE is variable */
+
+	/* Word 3 */
+	wqe->fcp_treceive.payload_offset_len = TXRDY_PAYLOAD_LEN;
+
+	/* Word 4 - relative_offset is variable */
+
+	/* Word 5 - is zero */
+
+	/* Word 6 - ctxt_tag, xri_tag is variable */
+
+	/* Word 7 */
+	bf_set(wqe_cmnd, &wqe->fcp_treceive.wqe_com, CMD_FCP_TRECEIVE64_WQE);
+	bf_set(wqe_pu, &wqe->fcp_treceive.wqe_com, PARM_REL_OFF);
+	bf_set(wqe_class, &wqe->fcp_treceive.wqe_com, CLASS3);
+	bf_set(wqe_ct, &wqe->fcp_treceive.wqe_com, SLI4_CT_RPI);
+	bf_set(wqe_ar, &wqe->fcp_treceive.wqe_com, 0);
+
+	/* Word 8 - abort_tag is variable */
+
+	/* Word 9  - reqtag, rcvoxid is variable */
+
+	/* Word 10 - xc is variable */
+	bf_set(wqe_dbde, &wqe->fcp_treceive.wqe_com, 1);
+	bf_set(wqe_wqes, &wqe->fcp_treceive.wqe_com, 0);
+	bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1);
+	bf_set(wqe_iod, &wqe->fcp_treceive.wqe_com, LPFC_WQE_IOD_READ);
+	bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com, LPFC_WQE_LENLOC_WORD12);
+	bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 1);
+
+	/* Word 11 - pbde is variable */
+	bf_set(wqe_cmd_type, &wqe->fcp_treceive.wqe_com, FCP_COMMAND_TRECEIVE);
+	bf_set(wqe_cqid, &wqe->fcp_treceive.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+	bf_set(wqe_sup, &wqe->fcp_treceive.wqe_com, 0);
+	bf_set(wqe_irsp, &wqe->fcp_treceive.wqe_com, 0);
+	bf_set(wqe_irsplen, &wqe->fcp_treceive.wqe_com, 0);
+	bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 1);
+
+	/* Word 12 - fcp_data_len is variable */
+
+	/* Word 13, 14, 15 - PBDE is variable */
+
+	/* TRSP template */
+	wqe = &lpfc_trsp_cmd_template;
+	memset(wqe, 0, sizeof(union lpfc_wqe128));
+
+	/* Word 0, 1, 2 - BDE is variable */
+
+	/* Word 3 - response_len is variable */
+
+	/* Word 4, 5 - is zero */
+
+	/* Word 6 - ctxt_tag, xri_tag is variable */
+
+	/* Word 7 */
+	bf_set(wqe_cmnd, &wqe->fcp_trsp.wqe_com, CMD_FCP_TRSP64_WQE);
+	bf_set(wqe_pu, &wqe->fcp_trsp.wqe_com, PARM_UNUSED);
+	bf_set(wqe_class, &wqe->fcp_trsp.wqe_com, CLASS3);
+	bf_set(wqe_ct, &wqe->fcp_trsp.wqe_com, SLI4_CT_RPI);
+	bf_set(wqe_ag, &wqe->fcp_trsp.wqe_com, 1); /* wqe_ar */
+
+	/* Word 8 - abort_tag is variable */
+
+	/* Word 9  - reqtag is variable */
+
+	/* Word 10 wqes, xc is variable */
+	bf_set(wqe_dbde, &wqe->fcp_trsp.wqe_com, 1);
+	bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1);
+	bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 0);
+	bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, 0);
+	bf_set(wqe_iod, &wqe->fcp_trsp.wqe_com, LPFC_WQE_IOD_NONE);
+	bf_set(wqe_lenloc, &wqe->fcp_trsp.wqe_com, LPFC_WQE_LENLOC_WORD3);
+
+	/* Word 11 irsp, irsplen is variable */
+	bf_set(wqe_cmd_type, &wqe->fcp_trsp.wqe_com, FCP_COMMAND_TRSP);
+	bf_set(wqe_cqid, &wqe->fcp_trsp.wqe_com, LPFC_WQE_CQ_ID_DEFAULT);
+	bf_set(wqe_sup, &wqe->fcp_trsp.wqe_com, 0);
+	bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 0);
+	bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com, 0);
+	bf_set(wqe_pbde, &wqe->fcp_trsp.wqe_com, 0);
+
+	/* Word 12, 13, 14, 15 - is zero */
+}
 
 
 void
 void
 lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp)
 lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp)
@@ -130,7 +275,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
 	if (tgtp) {
 	if (tgtp) {
 		if (status) {
 		if (status) {
 			atomic_inc(&tgtp->xmt_ls_rsp_error);
 			atomic_inc(&tgtp->xmt_ls_rsp_error);
-			if (status == IOERR_ABORT_REQUESTED)
+			if (result == IOERR_ABORT_REQUESTED)
 				atomic_inc(&tgtp->xmt_ls_rsp_aborted);
 				atomic_inc(&tgtp->xmt_ls_rsp_aborted);
 			if (bf_get(lpfc_wcqe_c_xb, wcqe))
 			if (bf_get(lpfc_wcqe_c_xb, wcqe))
 				atomic_inc(&tgtp->xmt_ls_rsp_xb_set);
 				atomic_inc(&tgtp->xmt_ls_rsp_xb_set);
@@ -268,8 +413,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf)
 					 "NVMET RCV BUSY: xri x%x sz %d "
 					 "NVMET RCV BUSY: xri x%x sz %d "
 					 "from %06x\n",
 					 "from %06x\n",
 					 oxid, size, sid);
 					 oxid, size, sid);
-			/* defer repost rcv buffer till .defer_rcv callback */
-			ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST;
 			atomic_inc(&tgtp->rcv_fcp_cmd_out);
 			atomic_inc(&tgtp->rcv_fcp_cmd_out);
 			return;
 			return;
 		}
 		}
@@ -541,7 +684,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
 		rsp->transferred_length = 0;
 		rsp->transferred_length = 0;
 		if (tgtp) {
 		if (tgtp) {
 			atomic_inc(&tgtp->xmt_fcp_rsp_error);
 			atomic_inc(&tgtp->xmt_fcp_rsp_error);
-			if (status == IOERR_ABORT_REQUESTED)
+			if (result == IOERR_ABORT_REQUESTED)
 				atomic_inc(&tgtp->xmt_fcp_rsp_aborted);
 				atomic_inc(&tgtp->xmt_fcp_rsp_aborted);
 		}
 		}
 
 
@@ -741,7 +884,10 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
 	struct lpfc_nvmet_rcv_ctx *ctxp =
 	struct lpfc_nvmet_rcv_ctx *ctxp =
 		container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req);
 		container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req);
 	struct lpfc_hba *phba = ctxp->phba;
 	struct lpfc_hba *phba = ctxp->phba;
+	struct lpfc_queue *wq;
 	struct lpfc_iocbq *nvmewqeq;
 	struct lpfc_iocbq *nvmewqeq;
+	struct lpfc_sli_ring *pring;
+	unsigned long iflags;
 	int rc;
 	int rc;
 
 
 	if (phba->pport->load_flag & FC_UNLOADING) {
 	if (phba->pport->load_flag & FC_UNLOADING) {
@@ -820,6 +966,22 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
 		return 0;
 		return 0;
 	}
 	}
 
 
+	if (rc == -EBUSY) {
+		/*
+		 * WQ was full, so queue nvmewqeq to be sent after
+		 * WQE release CQE
+		 */
+		ctxp->flag |= LPFC_NVMET_DEFER_WQFULL;
+		wq = phba->sli4_hba.nvme_wq[rsp->hwqid];
+		pring = wq->pring;
+		spin_lock_irqsave(&pring->ring_lock, iflags);
+		list_add_tail(&nvmewqeq->list, &wq->wqfull_list);
+		wq->q_flag |= HBA_NVMET_WQFULL;
+		spin_unlock_irqrestore(&pring->ring_lock, iflags);
+		atomic_inc(&lpfc_nvmep->defer_wqfull);
+		return 0;
+	}
+
 	/* Give back resources */
 	/* Give back resources */
 	atomic_inc(&lpfc_nvmep->xmt_fcp_drop);
 	atomic_inc(&lpfc_nvmep->xmt_fcp_drop);
 	lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
 	lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
@@ -851,6 +1013,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
 	struct lpfc_nvmet_rcv_ctx *ctxp =
 	struct lpfc_nvmet_rcv_ctx *ctxp =
 		container_of(req, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req);
 		container_of(req, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req);
 	struct lpfc_hba *phba = ctxp->phba;
 	struct lpfc_hba *phba = ctxp->phba;
+	struct lpfc_queue *wq;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	if (phba->pport->load_flag & FC_UNLOADING)
 	if (phba->pport->load_flag & FC_UNLOADING)
@@ -880,6 +1043,15 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport,
 	}
 	}
 	ctxp->flag |= LPFC_NVMET_ABORT_OP;
 	ctxp->flag |= LPFC_NVMET_ABORT_OP;
 
 
+	if (ctxp->flag & LPFC_NVMET_DEFER_WQFULL) {
+		lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid,
+						 ctxp->oxid);
+		wq = phba->sli4_hba.nvme_wq[ctxp->wqeq->hba_wqidx];
+		spin_unlock_irqrestore(&ctxp->ctxlock, flags);
+		lpfc_nvmet_wqfull_flush(phba, wq, ctxp);
+		return;
+	}
+
 	/* An state of LPFC_NVMET_STE_RCV means we have just received
 	/* An state of LPFC_NVMET_STE_RCV means we have just received
 	 * the NVME command and have not started processing it.
 	 * the NVME command and have not started processing it.
 	 * (by issuing any IO WQEs on this exchange yet)
 	 * (by issuing any IO WQEs on this exchange yet)
@@ -946,11 +1118,9 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport,
 
 
 	tgtp = phba->targetport->private;
 	tgtp = phba->targetport->private;
 	atomic_inc(&tgtp->rcv_fcp_cmd_defer);
 	atomic_inc(&tgtp->rcv_fcp_cmd_defer);
-	if (ctxp->flag & LPFC_NVMET_DEFER_RCV_REPOST)
-		lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */
-	else
-		nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
-	ctxp->flag &= ~LPFC_NVMET_DEFER_RCV_REPOST;
+
+	/* Free the nvmebuf since a new buffer already replaced it */
+	nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf);
 }
 }
 
 
 static struct nvmet_fc_target_template lpfc_tgttemplate = {
 static struct nvmet_fc_target_template lpfc_tgttemplate = {
@@ -1124,16 +1294,10 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba)
 		}
 		}
 		ctx_buf->iocbq->iocb_flag = LPFC_IO_NVMET;
 		ctx_buf->iocbq->iocb_flag = LPFC_IO_NVMET;
 		nvmewqe = ctx_buf->iocbq;
 		nvmewqe = ctx_buf->iocbq;
-		wqe = (union lpfc_wqe128 *)&nvmewqe->wqe;
+		wqe = &nvmewqe->wqe;
+
 		/* Initialize WQE */
 		/* Initialize WQE */
 		memset(wqe, 0, sizeof(union lpfc_wqe));
 		memset(wqe, 0, sizeof(union lpfc_wqe));
-		/* Word 7 */
-		bf_set(wqe_ct, &wqe->generic.wqe_com, SLI4_CT_RPI);
-		bf_set(wqe_class, &wqe->generic.wqe_com, CLASS3);
-		/* Word 10 */
-		bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1);
-		bf_set(wqe_ebde_cnt, &wqe->generic.wqe_com, 0);
-		bf_set(wqe_qosd, &wqe->generic.wqe_com, 0);
 
 
 		ctx_buf->iocbq->context1 = NULL;
 		ctx_buf->iocbq->context1 = NULL;
 		spin_lock(&phba->sli4_hba.sgl_list_lock);
 		spin_lock(&phba->sli4_hba.sgl_list_lock);
@@ -1280,6 +1444,9 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba)
 		atomic_set(&tgtp->xmt_abort_sol, 0);
 		atomic_set(&tgtp->xmt_abort_sol, 0);
 		atomic_set(&tgtp->xmt_abort_rsp, 0);
 		atomic_set(&tgtp->xmt_abort_rsp, 0);
 		atomic_set(&tgtp->xmt_abort_rsp_error, 0);
 		atomic_set(&tgtp->xmt_abort_rsp_error, 0);
+		atomic_set(&tgtp->defer_ctx, 0);
+		atomic_set(&tgtp->defer_fod, 0);
+		atomic_set(&tgtp->defer_wqfull, 0);
 	}
 	}
 	return error;
 	return error;
 }
 }
@@ -1435,16 +1602,103 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport,
 	return 0;
 	return 0;
 }
 }
 
 
+static void
+lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq,
+			struct lpfc_nvmet_rcv_ctx *ctxp)
+{
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *nvmewqeq;
+	struct lpfc_iocbq *next_nvmewqeq;
+	unsigned long iflags;
+	struct lpfc_wcqe_complete wcqe;
+	struct lpfc_wcqe_complete *wcqep;
+
+	pring = wq->pring;
+	wcqep = &wcqe;
+
+	/* Fake an ABORT error code back to cmpl routine */
+	memset(wcqep, 0, sizeof(struct lpfc_wcqe_complete));
+	bf_set(lpfc_wcqe_c_status, wcqep, IOSTAT_LOCAL_REJECT);
+	wcqep->parameter = IOERR_ABORT_REQUESTED;
+
+	spin_lock_irqsave(&pring->ring_lock, iflags);
+	list_for_each_entry_safe(nvmewqeq, next_nvmewqeq,
+				 &wq->wqfull_list, list) {
+		if (ctxp) {
+			/* Checking for a specific IO to flush */
+			if (nvmewqeq->context2 == ctxp) {
+				list_del(&nvmewqeq->list);
+				spin_unlock_irqrestore(&pring->ring_lock,
+						       iflags);
+				lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq,
+							  wcqep);
+				return;
+			}
+			continue;
+		} else {
+			/* Flush all IOs */
+			list_del(&nvmewqeq->list);
+			spin_unlock_irqrestore(&pring->ring_lock, iflags);
+			lpfc_nvmet_xmt_fcp_op_cmp(phba, nvmewqeq, wcqep);
+			spin_lock_irqsave(&pring->ring_lock, iflags);
+		}
+	}
+	if (!ctxp)
+		wq->q_flag &= ~HBA_NVMET_WQFULL;
+	spin_unlock_irqrestore(&pring->ring_lock, iflags);
+}
+
+void
+lpfc_nvmet_wqfull_process(struct lpfc_hba *phba,
+			  struct lpfc_queue *wq)
+{
+#if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
+	struct lpfc_sli_ring *pring;
+	struct lpfc_iocbq *nvmewqeq;
+	unsigned long iflags;
+	int rc;
+
+	/*
+	 * Some WQE slots are available, so try to re-issue anything
+	 * on the WQ wqfull_list.
+	 */
+	pring = wq->pring;
+	spin_lock_irqsave(&pring->ring_lock, iflags);
+	while (!list_empty(&wq->wqfull_list)) {
+		list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq,
+				 list);
+		spin_unlock_irqrestore(&pring->ring_lock, iflags);
+		rc = lpfc_sli4_issue_wqe(phba, LPFC_FCP_RING, nvmewqeq);
+		spin_lock_irqsave(&pring->ring_lock, iflags);
+		if (rc == -EBUSY) {
+			/* WQ was full again, so put it back on the list */
+			list_add(&nvmewqeq->list, &wq->wqfull_list);
+			spin_unlock_irqrestore(&pring->ring_lock, iflags);
+			return;
+		}
+	}
+	wq->q_flag &= ~HBA_NVMET_WQFULL;
+	spin_unlock_irqrestore(&pring->ring_lock, iflags);
+
+#endif
+}
+
 void
 void
 lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
 lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba)
 {
 {
 #if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
 #if (IS_ENABLED(CONFIG_NVME_TARGET_FC))
 	struct lpfc_nvmet_tgtport *tgtp;
 	struct lpfc_nvmet_tgtport *tgtp;
+	struct lpfc_queue *wq;
+	uint32_t qidx;
 
 
 	if (phba->nvmet_support == 0)
 	if (phba->nvmet_support == 0)
 		return;
 		return;
 	if (phba->targetport) {
 	if (phba->targetport) {
 		tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
 		tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+		for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++) {
+			wq = phba->sli4_hba.nvme_wq[qidx];
+			lpfc_nvmet_wqfull_flush(phba, wq, NULL);
+		}
 		init_completion(&tgtp->tport_unreg_done);
 		init_completion(&tgtp->tport_unreg_done);
 		nvmet_fc_unregister_targetport(phba->targetport);
 		nvmet_fc_unregister_targetport(phba->targetport);
 		wait_for_completion_timeout(&tgtp->tport_unreg_done, 5);
 		wait_for_completion_timeout(&tgtp->tport_unreg_done, 5);
@@ -1694,6 +1948,8 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
 	lpfc_nvmeio_data(phba, "NVMET FCP  RCV: xri x%x sz %d CPU %02x\n",
 	lpfc_nvmeio_data(phba, "NVMET FCP  RCV: xri x%x sz %d CPU %02x\n",
 			 oxid, size, smp_processor_id());
 			 oxid, size, smp_processor_id());
 
 
+	tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
+
 	if (!ctx_buf) {
 	if (!ctx_buf) {
 		/* Queue this NVME IO to process later */
 		/* Queue this NVME IO to process later */
 		spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag);
 		spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag);
@@ -1709,10 +1965,11 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
 		lpfc_post_rq_buffer(
 		lpfc_post_rq_buffer(
 			phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
 			phba, phba->sli4_hba.nvmet_mrq_hdr[qno],
 			phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
 			phba->sli4_hba.nvmet_mrq_data[qno], 1, qno);
+
+		atomic_inc(&tgtp->defer_ctx);
 		return;
 		return;
 	}
 	}
 
 
-	tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
 	payload = (uint32_t *)(nvmebuf->dbuf.virt);
 	payload = (uint32_t *)(nvmebuf->dbuf.virt);
 	sid = sli4_sid_from_fc_hdr(fc_hdr);
 	sid = sli4_sid_from_fc_hdr(fc_hdr);
 
 
@@ -1776,12 +2033,20 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba,
 
 
 	/* Processing of FCP command is deferred */
 	/* Processing of FCP command is deferred */
 	if (rc == -EOVERFLOW) {
 	if (rc == -EOVERFLOW) {
+		/*
+		 * Post a brand new 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);
+
 		lpfc_nvmeio_data(phba,
 		lpfc_nvmeio_data(phba,
 				 "NVMET RCV BUSY: xri x%x sz %d from %06x\n",
 				 "NVMET RCV BUSY: xri x%x sz %d from %06x\n",
 				 oxid, size, sid);
 				 oxid, size, sid);
-		/* defer reposting rcv buffer till .defer_rcv callback */
-		ctxp->flag |= LPFC_NVMET_DEFER_RCV_REPOST;
 		atomic_inc(&tgtp->rcv_fcp_cmd_out);
 		atomic_inc(&tgtp->rcv_fcp_cmd_out);
+		atomic_inc(&tgtp->defer_fod);
 		return;
 		return;
 	}
 	}
 	ctxp->rqb_buffer = nvmebuf;
 	ctxp->rqb_buffer = nvmebuf;
@@ -1897,7 +2162,7 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba,
 {
 {
 	struct lpfc_nodelist *ndlp;
 	struct lpfc_nodelist *ndlp;
 	struct lpfc_iocbq *nvmewqe;
 	struct lpfc_iocbq *nvmewqe;
-	union lpfc_wqe *wqe;
+	union lpfc_wqe128 *wqe;
 
 
 	if (!lpfc_is_link_up(phba)) {
 	if (!lpfc_is_link_up(phba)) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC,
 		lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC,
@@ -2023,9 +2288,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 	struct lpfc_iocbq *nvmewqe;
 	struct lpfc_iocbq *nvmewqe;
 	struct scatterlist *sgel;
 	struct scatterlist *sgel;
 	union lpfc_wqe128 *wqe;
 	union lpfc_wqe128 *wqe;
+	struct ulp_bde64 *bde;
 	uint32_t *txrdy;
 	uint32_t *txrdy;
 	dma_addr_t physaddr;
 	dma_addr_t physaddr;
 	int i, cnt;
 	int i, cnt;
+	int do_pbde;
 	int xc = 1;
 	int xc = 1;
 
 
 	if (!lpfc_is_link_up(phba)) {
 	if (!lpfc_is_link_up(phba)) {
@@ -2078,7 +2345,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 	if (((ctxp->state == LPFC_NVMET_STE_RCV) &&
 	if (((ctxp->state == LPFC_NVMET_STE_RCV) &&
 	    (ctxp->entry_cnt == 1)) ||
 	    (ctxp->entry_cnt == 1)) ||
 	    (ctxp->state == LPFC_NVMET_STE_DATA)) {
 	    (ctxp->state == LPFC_NVMET_STE_DATA)) {
-		wqe = (union lpfc_wqe128 *)&nvmewqe->wqe;
+		wqe = &nvmewqe->wqe;
 	} else {
 	} else {
 		lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
 		lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR,
 				"6111 Wrong state NVMET FCP: %d  cnt %d\n",
 				"6111 Wrong state NVMET FCP: %d  cnt %d\n",
@@ -2090,6 +2357,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 	switch (rsp->op) {
 	switch (rsp->op) {
 	case NVMET_FCOP_READDATA:
 	case NVMET_FCOP_READDATA:
 	case NVMET_FCOP_READDATA_RSP:
 	case NVMET_FCOP_READDATA_RSP:
+		/* From the tsend template, initialize words 7 - 11 */
+		memcpy(&wqe->words[7],
+		       &lpfc_tsend_cmd_template.words[7],
+		       sizeof(uint32_t) * 5);
+
 		/* Words 0 - 2 : The first sg segment */
 		/* Words 0 - 2 : The first sg segment */
 		sgel = &rsp->sg[0];
 		sgel = &rsp->sg[0];
 		physaddr = sg_dma_address(sgel);
 		physaddr = sg_dma_address(sgel);
@@ -2106,6 +2378,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		wqe->fcp_tsend.relative_offset = ctxp->offset;
 		wqe->fcp_tsend.relative_offset = ctxp->offset;
 
 
 		/* Word 5 */
 		/* Word 5 */
+		wqe->fcp_tsend.reserved = 0;
 
 
 		/* Word 6 */
 		/* Word 6 */
 		bf_set(wqe_ctxt_tag, &wqe->fcp_tsend.wqe_com,
 		bf_set(wqe_ctxt_tag, &wqe->fcp_tsend.wqe_com,
@@ -2113,9 +2386,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		bf_set(wqe_xri_tag, &wqe->fcp_tsend.wqe_com,
 		bf_set(wqe_xri_tag, &wqe->fcp_tsend.wqe_com,
 		       nvmewqe->sli4_xritag);
 		       nvmewqe->sli4_xritag);
 
 
-		/* Word 7 */
-		bf_set(wqe_pu, &wqe->fcp_tsend.wqe_com, 1);
-		bf_set(wqe_cmnd, &wqe->fcp_tsend.wqe_com, CMD_FCP_TSEND64_WQE);
+		/* Word 7 - set ar later */
 
 
 		/* Word 8 */
 		/* Word 8 */
 		wqe->fcp_tsend.wqe_com.abort_tag = nvmewqe->iotag;
 		wqe->fcp_tsend.wqe_com.abort_tag = nvmewqe->iotag;
@@ -2124,23 +2395,12 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		bf_set(wqe_reqtag, &wqe->fcp_tsend.wqe_com, nvmewqe->iotag);
 		bf_set(wqe_reqtag, &wqe->fcp_tsend.wqe_com, nvmewqe->iotag);
 		bf_set(wqe_rcvoxid, &wqe->fcp_tsend.wqe_com, ctxp->oxid);
 		bf_set(wqe_rcvoxid, &wqe->fcp_tsend.wqe_com, ctxp->oxid);
 
 
-		/* Word 10 */
-		bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1);
-		bf_set(wqe_dbde, &wqe->fcp_tsend.wqe_com, 1);
-		bf_set(wqe_iod, &wqe->fcp_tsend.wqe_com, LPFC_WQE_IOD_WRITE);
-		bf_set(wqe_lenloc, &wqe->fcp_tsend.wqe_com,
-		       LPFC_WQE_LENLOC_WORD12);
-		bf_set(wqe_ebde_cnt, &wqe->fcp_tsend.wqe_com, 0);
-		bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, xc);
-		bf_set(wqe_nvme, &wqe->fcp_tsend.wqe_com, 1);
-		if (phba->cfg_nvme_oas)
-			bf_set(wqe_oas, &wqe->fcp_tsend.wqe_com, 1);
+		/* Word 10 - set wqes later, in template xc=1 */
+		if (!xc)
+			bf_set(wqe_xc, &wqe->fcp_tsend.wqe_com, 0);
 
 
-		/* Word 11 */
-		bf_set(wqe_cqid, &wqe->fcp_tsend.wqe_com,
-		       LPFC_WQE_CQ_ID_DEFAULT);
-		bf_set(wqe_cmd_type, &wqe->fcp_tsend.wqe_com,
-		       FCP_COMMAND_TSEND);
+		/* Word 11 - set sup, irsp, irsplen later */
+		do_pbde = 0;
 
 
 		/* Word 12 */
 		/* Word 12 */
 		wqe->fcp_tsend.fcp_data_len = rsp->transfer_length;
 		wqe->fcp_tsend.fcp_data_len = rsp->transfer_length;
@@ -2162,15 +2422,14 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		sgl++;
 		sgl++;
 		if (rsp->op == NVMET_FCOP_READDATA_RSP) {
 		if (rsp->op == NVMET_FCOP_READDATA_RSP) {
 			atomic_inc(&tgtp->xmt_fcp_read_rsp);
 			atomic_inc(&tgtp->xmt_fcp_read_rsp);
-			bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 1);
-			if ((ndlp->nlp_flag & NLP_SUPPRESS_RSP) &&
-			    (rsp->rsplen == 12)) {
-				bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 1);
-				bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0);
-				bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0);
-				bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0);
+
+			/* In template ar=1 wqes=0 sup=0 irsp=0 irsplen=0 */
+
+			if (rsp->rsplen == LPFC_NVMET_SUCCESS_LEN) {
+				if (ndlp->nlp_flag & NLP_SUPPRESS_RSP)
+					bf_set(wqe_sup,
+					       &wqe->fcp_tsend.wqe_com, 1);
 			} else {
 			} else {
-				bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
 				bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 1);
 				bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 1);
 				bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 1);
 				bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 1);
 				bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com,
 				bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com,
@@ -2181,15 +2440,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		} else {
 		} else {
 			atomic_inc(&tgtp->xmt_fcp_read);
 			atomic_inc(&tgtp->xmt_fcp_read);
 
 
-			bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
-			bf_set(wqe_wqes, &wqe->fcp_tsend.wqe_com, 0);
-			bf_set(wqe_irsp, &wqe->fcp_tsend.wqe_com, 0);
+			/* In template ar=1 wqes=0 sup=0 irsp=0 irsplen=0 */
 			bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 0);
 			bf_set(wqe_ar, &wqe->fcp_tsend.wqe_com, 0);
-			bf_set(wqe_irsplen, &wqe->fcp_tsend.wqe_com, 0);
 		}
 		}
 		break;
 		break;
 
 
 	case NVMET_FCOP_WRITEDATA:
 	case NVMET_FCOP_WRITEDATA:
+		/* From the treceive template, initialize words 3 - 11 */
+		memcpy(&wqe->words[3],
+		       &lpfc_treceive_cmd_template.words[3],
+		       sizeof(uint32_t) * 9);
+
 		/* Words 0 - 2 : The first sg segment */
 		/* Words 0 - 2 : The first sg segment */
 		txrdy = dma_pool_alloc(phba->txrdy_payload_pool,
 		txrdy = dma_pool_alloc(phba->txrdy_payload_pool,
 				       GFP_KERNEL, &physaddr);
 				       GFP_KERNEL, &physaddr);
@@ -2208,14 +2469,9 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		wqe->fcp_treceive.bde.addrHigh =
 		wqe->fcp_treceive.bde.addrHigh =
 			cpu_to_le32(putPaddrHigh(physaddr));
 			cpu_to_le32(putPaddrHigh(physaddr));
 
 
-		/* Word 3 */
-		wqe->fcp_treceive.payload_offset_len = TXRDY_PAYLOAD_LEN;
-
 		/* Word 4 */
 		/* Word 4 */
 		wqe->fcp_treceive.relative_offset = ctxp->offset;
 		wqe->fcp_treceive.relative_offset = ctxp->offset;
 
 
-		/* Word 5 */
-
 		/* Word 6 */
 		/* Word 6 */
 		bf_set(wqe_ctxt_tag, &wqe->fcp_treceive.wqe_com,
 		bf_set(wqe_ctxt_tag, &wqe->fcp_treceive.wqe_com,
 		       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
 		       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
@@ -2223,10 +2479,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		       nvmewqe->sli4_xritag);
 		       nvmewqe->sli4_xritag);
 
 
 		/* Word 7 */
 		/* Word 7 */
-		bf_set(wqe_pu, &wqe->fcp_treceive.wqe_com, 1);
-		bf_set(wqe_ar, &wqe->fcp_treceive.wqe_com, 0);
-		bf_set(wqe_cmnd, &wqe->fcp_treceive.wqe_com,
-		       CMD_FCP_TRECEIVE64_WQE);
 
 
 		/* Word 8 */
 		/* Word 8 */
 		wqe->fcp_treceive.wqe_com.abort_tag = nvmewqe->iotag;
 		wqe->fcp_treceive.wqe_com.abort_tag = nvmewqe->iotag;
@@ -2235,26 +2487,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		bf_set(wqe_reqtag, &wqe->fcp_treceive.wqe_com, nvmewqe->iotag);
 		bf_set(wqe_reqtag, &wqe->fcp_treceive.wqe_com, nvmewqe->iotag);
 		bf_set(wqe_rcvoxid, &wqe->fcp_treceive.wqe_com, ctxp->oxid);
 		bf_set(wqe_rcvoxid, &wqe->fcp_treceive.wqe_com, ctxp->oxid);
 
 
-		/* Word 10 */
-		bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1);
-		bf_set(wqe_dbde, &wqe->fcp_treceive.wqe_com, 1);
-		bf_set(wqe_iod, &wqe->fcp_treceive.wqe_com, LPFC_WQE_IOD_READ);
-		bf_set(wqe_lenloc, &wqe->fcp_treceive.wqe_com,
-		       LPFC_WQE_LENLOC_WORD12);
-		bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, xc);
-		bf_set(wqe_wqes, &wqe->fcp_treceive.wqe_com, 0);
-		bf_set(wqe_irsp, &wqe->fcp_treceive.wqe_com, 0);
-		bf_set(wqe_irsplen, &wqe->fcp_treceive.wqe_com, 0);
-		bf_set(wqe_nvme, &wqe->fcp_treceive.wqe_com, 1);
-		if (phba->cfg_nvme_oas)
-			bf_set(wqe_oas, &wqe->fcp_treceive.wqe_com, 1);
+		/* Word 10 - in template xc=1 */
+		if (!xc)
+			bf_set(wqe_xc, &wqe->fcp_treceive.wqe_com, 0);
 
 
-		/* Word 11 */
-		bf_set(wqe_cqid, &wqe->fcp_treceive.wqe_com,
-		       LPFC_WQE_CQ_ID_DEFAULT);
-		bf_set(wqe_cmd_type, &wqe->fcp_treceive.wqe_com,
-		       FCP_COMMAND_TRECEIVE);
-		bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
+		/* Word 11 - set pbde later */
+		if (phba->nvme_embed_pbde) {
+			do_pbde = 1;
+		} else {
+			bf_set(wqe_pbde, &wqe->fcp_treceive.wqe_com, 0);
+			do_pbde = 0;
+		}
 
 
 		/* Word 12 */
 		/* Word 12 */
 		wqe->fcp_tsend.fcp_data_len = rsp->transfer_length;
 		wqe->fcp_tsend.fcp_data_len = rsp->transfer_length;
@@ -2282,6 +2525,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		break;
 		break;
 
 
 	case NVMET_FCOP_RSP:
 	case NVMET_FCOP_RSP:
+		/* From the treceive template, initialize words 4 - 11 */
+		memcpy(&wqe->words[4],
+		       &lpfc_trsp_cmd_template.words[4],
+		       sizeof(uint32_t) * 8);
+
 		/* Words 0 - 2 */
 		/* Words 0 - 2 */
 		physaddr = rsp->rspdma;
 		physaddr = rsp->rspdma;
 		wqe->fcp_trsp.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
 		wqe->fcp_trsp.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
@@ -2294,12 +2542,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		/* Word 3 */
 		/* Word 3 */
 		wqe->fcp_trsp.response_len = rsp->rsplen;
 		wqe->fcp_trsp.response_len = rsp->rsplen;
 
 
-		/* Word 4 */
-		wqe->fcp_trsp.rsvd_4_5[0] = 0;
-
-
-		/* Word 5 */
-
 		/* Word 6 */
 		/* Word 6 */
 		bf_set(wqe_ctxt_tag, &wqe->fcp_trsp.wqe_com,
 		bf_set(wqe_ctxt_tag, &wqe->fcp_trsp.wqe_com,
 		       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
 		       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
@@ -2307,9 +2549,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		       nvmewqe->sli4_xritag);
 		       nvmewqe->sli4_xritag);
 
 
 		/* Word 7 */
 		/* Word 7 */
-		bf_set(wqe_pu, &wqe->fcp_trsp.wqe_com, 0);
-		bf_set(wqe_ag, &wqe->fcp_trsp.wqe_com, 1);
-		bf_set(wqe_cmnd, &wqe->fcp_trsp.wqe_com, CMD_FCP_TRSP64_WQE);
 
 
 		/* Word 8 */
 		/* Word 8 */
 		wqe->fcp_trsp.wqe_com.abort_tag = nvmewqe->iotag;
 		wqe->fcp_trsp.wqe_com.abort_tag = nvmewqe->iotag;
@@ -2319,35 +2558,23 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 		bf_set(wqe_rcvoxid, &wqe->fcp_trsp.wqe_com, ctxp->oxid);
 		bf_set(wqe_rcvoxid, &wqe->fcp_trsp.wqe_com, ctxp->oxid);
 
 
 		/* Word 10 */
 		/* Word 10 */
-		bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1);
-		bf_set(wqe_dbde, &wqe->fcp_trsp.wqe_com, 0);
-		bf_set(wqe_iod, &wqe->fcp_trsp.wqe_com, LPFC_WQE_IOD_WRITE);
-		bf_set(wqe_lenloc, &wqe->fcp_trsp.wqe_com,
-		       LPFC_WQE_LENLOC_WORD3);
-		bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, xc);
-		bf_set(wqe_nvme, &wqe->fcp_trsp.wqe_com, 1);
-		if (phba->cfg_nvme_oas)
-			bf_set(wqe_oas, &wqe->fcp_trsp.wqe_com, 1);
+		if (xc)
+			bf_set(wqe_xc, &wqe->fcp_trsp.wqe_com, 1);
 
 
 		/* Word 11 */
 		/* Word 11 */
-		bf_set(wqe_cqid, &wqe->fcp_trsp.wqe_com,
-		       LPFC_WQE_CQ_ID_DEFAULT);
-		bf_set(wqe_cmd_type, &wqe->fcp_trsp.wqe_com,
-		       FCP_COMMAND_TRSP);
-		bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 0);
-
-		if (rsp->rsplen == LPFC_NVMET_SUCCESS_LEN) {
-			/* Good response - all zero's on wire */
-			bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 0);
-			bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 0);
-			bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com, 0);
-		} else {
+		/* In template wqes=0 irsp=0 irsplen=0 - good response */
+		if (rsp->rsplen != LPFC_NVMET_SUCCESS_LEN) {
+			/* Bad response - embed it */
 			bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 1);
 			bf_set(wqe_wqes, &wqe->fcp_trsp.wqe_com, 1);
 			bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 1);
 			bf_set(wqe_irsp, &wqe->fcp_trsp.wqe_com, 1);
 			bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com,
 			bf_set(wqe_irsplen, &wqe->fcp_trsp.wqe_com,
 			       ((rsp->rsplen >> 2) - 1));
 			       ((rsp->rsplen >> 2) - 1));
 			memcpy(&wqe->words[16], rsp->rspaddr, rsp->rsplen);
 			memcpy(&wqe->words[16], rsp->rspaddr, rsp->rsplen);
 		}
 		}
+		do_pbde = 0;
+
+		/* Word 12 */
+		wqe->fcp_trsp.rsvd_12_15[0] = 0;
 
 
 		/* Use rspbuf, NOT sg list */
 		/* Use rspbuf, NOT sg list */
 		rsp->sg_cnt = 0;
 		rsp->sg_cnt = 0;
@@ -2380,6 +2607,17 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
 			bf_set(lpfc_sli4_sge_last, sgl, 1);
 			bf_set(lpfc_sli4_sge_last, sgl, 1);
 		sgl->word2 = cpu_to_le32(sgl->word2);
 		sgl->word2 = cpu_to_le32(sgl->word2);
 		sgl->sge_len = cpu_to_le32(cnt);
 		sgl->sge_len = cpu_to_le32(cnt);
+		if (do_pbde && i == 0) {
+			bde = (struct ulp_bde64 *)&wqe->words[13];
+			memset(bde, 0, sizeof(struct ulp_bde64));
+			/* Words 13-15  (PBDE)*/
+			bde->addrLow = sgl->addr_lo;
+			bde->addrHigh = sgl->addr_hi;
+			bde->tus.f.bdeSize =
+				le32_to_cpu(sgl->sge_len);
+			bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+			bde->tus.w = cpu_to_le32(bde->tus.w);
+		}
 		sgl++;
 		sgl++;
 		ctxp->offset += cnt;
 		ctxp->offset += cnt;
 	}
 	}
@@ -2597,7 +2835,7 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba,
 {
 {
 	struct lpfc_nvmet_tgtport *tgtp;
 	struct lpfc_nvmet_tgtport *tgtp;
 	struct lpfc_iocbq *abts_wqeq;
 	struct lpfc_iocbq *abts_wqeq;
-	union lpfc_wqe *wqe_abts;
+	union lpfc_wqe128 *wqe_abts;
 	struct lpfc_nodelist *ndlp;
 	struct lpfc_nodelist *ndlp;
 
 
 	lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
 	lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS,
@@ -2692,7 +2930,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba,
 {
 {
 	struct lpfc_nvmet_tgtport *tgtp;
 	struct lpfc_nvmet_tgtport *tgtp;
 	struct lpfc_iocbq *abts_wqeq;
 	struct lpfc_iocbq *abts_wqeq;
-	union lpfc_wqe *abts_wqe;
+	union lpfc_wqe128 *abts_wqe;
 	struct lpfc_nodelist *ndlp;
 	struct lpfc_nodelist *ndlp;
 	unsigned long flags;
 	unsigned long flags;
 	int rc;
 	int rc;
@@ -2882,7 +3120,7 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba,
 {
 {
 	struct lpfc_nvmet_tgtport *tgtp;
 	struct lpfc_nvmet_tgtport *tgtp;
 	struct lpfc_iocbq *abts_wqeq;
 	struct lpfc_iocbq *abts_wqeq;
-	union lpfc_wqe *wqe_abts;
+	union lpfc_wqe128 *wqe_abts;
 	unsigned long flags;
 	unsigned long flags;
 	int rc;
 	int rc;
 
 

+ 7 - 3
drivers/scsi/lpfc/lpfc_nvmet.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -72,7 +72,6 @@ struct lpfc_nvmet_tgtport {
 	atomic_t xmt_fcp_rsp_aborted;
 	atomic_t xmt_fcp_rsp_aborted;
 	atomic_t xmt_fcp_rsp_drop;
 	atomic_t xmt_fcp_rsp_drop;
 
 
-
 	/* Stats counters - lpfc_nvmet_xmt_fcp_abort */
 	/* Stats counters - lpfc_nvmet_xmt_fcp_abort */
 	atomic_t xmt_fcp_xri_abort_cqe;
 	atomic_t xmt_fcp_xri_abort_cqe;
 	atomic_t xmt_fcp_abort;
 	atomic_t xmt_fcp_abort;
@@ -81,6 +80,11 @@ struct lpfc_nvmet_tgtport {
 	atomic_t xmt_abort_unsol;
 	atomic_t xmt_abort_unsol;
 	atomic_t xmt_abort_rsp;
 	atomic_t xmt_abort_rsp;
 	atomic_t xmt_abort_rsp_error;
 	atomic_t xmt_abort_rsp_error;
+
+	/* Stats counters - defer IO */
+	atomic_t defer_ctx;
+	atomic_t defer_fod;
+	atomic_t defer_wqfull;
 };
 };
 
 
 struct lpfc_nvmet_ctx_info {
 struct lpfc_nvmet_ctx_info {
@@ -131,7 +135,7 @@ struct lpfc_nvmet_rcv_ctx {
 #define LPFC_NVMET_XBUSY		0x4  /* XB bit set on IO cmpl */
 #define LPFC_NVMET_XBUSY		0x4  /* XB bit set on IO cmpl */
 #define LPFC_NVMET_CTX_RLS		0x8  /* ctx free requested */
 #define LPFC_NVMET_CTX_RLS		0x8  /* ctx free requested */
 #define LPFC_NVMET_ABTS_RCV		0x10  /* ABTS received on exchange */
 #define LPFC_NVMET_ABTS_RCV		0x10  /* ABTS received on exchange */
-#define LPFC_NVMET_DEFER_RCV_REPOST	0x20  /* repost to RQ on defer rcv */
+#define LPFC_NVMET_DEFER_WQFULL		0x40  /* Waiting on a free WQE */
 	struct rqb_dmabuf *rqb_buffer;
 	struct rqb_dmabuf *rqb_buffer;
 	struct lpfc_nvmet_ctxbuf *ctxbuf;
 	struct lpfc_nvmet_ctxbuf *ctxbuf;
 
 

+ 44 - 20
drivers/scsi/lpfc/lpfc_scsi.c

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -837,8 +837,13 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
 		 * 4K Page alignment is CRITICAL to BlockGuard, double check
 		 * 4K Page alignment is CRITICAL to BlockGuard, double check
 		 * to be sure.
 		 * to be sure.
 		 */
 		 */
-		if (phba->cfg_enable_bg  && (((unsigned long)(psb->data) &
+		if ((phba->sli3_options & LPFC_SLI3_BG_ENABLED) &&
+		    (((unsigned long)(psb->data) &
 		    (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) {
 		    (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+					"3369 Memory alignment error "
+					"addr=%lx\n",
+					(unsigned long)psb->data);
 			dma_pool_free(phba->lpfc_sg_dma_buf_pool,
 			dma_pool_free(phba->lpfc_sg_dma_buf_pool,
 				      psb->data, psb->dma_handle);
 				      psb->data, psb->dma_handle);
 			kfree(psb);
 			kfree(psb);
@@ -3304,8 +3309,12 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 			dma_offset += dma_len;
 			dma_offset += dma_len;
 			sgl++;
 			sgl++;
 		}
 		}
-		/* setup the performance hint (first data BDE) if enabled */
-		if (phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) {
+		/*
+		 * Setup the first Payload BDE. For FCoE we just key off
+		 * Performance Hints, for FC we utilize fcp_embed_pbde.
+		 */
+		if ((phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) ||
+		    phba->fcp_embed_pbde) {
 			bde = (struct ulp_bde64 *)
 			bde = (struct ulp_bde64 *)
 					&(iocb_cmd->unsli3.sli3Words[5]);
 					&(iocb_cmd->unsli3.sli3Words[5]);
 			bde->addrLow = first_data_sgl->addr_lo;
 			bde->addrLow = first_data_sgl->addr_lo;
@@ -3772,20 +3781,18 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
 		scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
 
 
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
-				 "9025 FCP Read Underrun, expected %d, "
+				 "9025 FCP Underrun, expected %d, "
 				 "residual %d Data: x%x x%x x%x\n",
 				 "residual %d Data: x%x x%x x%x\n",
 				 fcpDl,
 				 fcpDl,
 				 scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
 				 scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
 				 cmnd->underflow);
 				 cmnd->underflow);
 
 
 		/*
 		/*
-		 * If there is an under run check if under run reported by
+		 * If there is an under run, check if under run reported by
 		 * storage array is same as the under run reported by HBA.
 		 * storage array is same as the under run reported by HBA.
 		 * If this is not same, there is a dropped frame.
 		 * If this is not same, there is a dropped frame.
 		 */
 		 */
-		if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
-			fcpi_parm &&
-			(scsi_get_resid(cmnd) != fcpi_parm)) {
+		if (fcpi_parm && (scsi_get_resid(cmnd) != fcpi_parm)) {
 			lpfc_printf_vlog(vport, KERN_WARNING,
 			lpfc_printf_vlog(vport, KERN_WARNING,
 					 LOG_FCP | LOG_FCP_ERROR,
 					 LOG_FCP | LOG_FCP_ERROR,
 					 "9026 FCP Read Check Error "
 					 "9026 FCP Read Check Error "
@@ -3926,7 +3933,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 	struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
 	struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
 	struct lpfc_nodelist *pnode = rdata->pnode;
 	struct lpfc_nodelist *pnode = rdata->pnode;
 	struct scsi_cmnd *cmd;
 	struct scsi_cmnd *cmd;
-	int depth;
 	unsigned long flags;
 	unsigned long flags;
 	struct lpfc_fast_path_event *fast_path_evt;
 	struct lpfc_fast_path_event *fast_path_evt;
 	struct Scsi_Host *shost;
 	struct Scsi_Host *shost;
@@ -4132,16 +4138,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		}
 		}
 		spin_unlock_irqrestore(shost->host_lock, flags);
 		spin_unlock_irqrestore(shost->host_lock, flags);
 	} else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
 	} else if (pnode && NLP_CHK_NODE_ACT(pnode)) {
-		if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) &&
-		   time_after(jiffies, pnode->last_change_time +
+		if ((pnode->cmd_qdepth != vport->cfg_tgt_queue_depth) &&
+		    time_after(jiffies, pnode->last_change_time +
 			      msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
 			      msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
 			spin_lock_irqsave(shost->host_lock, flags);
 			spin_lock_irqsave(shost->host_lock, flags);
-			depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT
-				/ 100;
-			depth = depth ? depth : 1;
-			pnode->cmd_qdepth += depth;
-			if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth)
-				pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
+			pnode->cmd_qdepth = vport->cfg_tgt_queue_depth;
 			pnode->last_change_time = jiffies;
 			pnode->last_change_time = jiffies;
 			spin_unlock_irqrestore(shost->host_lock, flags);
 			spin_unlock_irqrestore(shost->host_lock, flags);
 		}
 		}
@@ -4564,9 +4565,32 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
 	 */
 	 */
 	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
 	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
 		goto out_tgt_busy;
 		goto out_tgt_busy;
-	if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
+	if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) {
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_ERROR,
+				 "3377 Target Queue Full, scsi Id:%d Qdepth:%d"
+				 " Pending command:%d"
+				 " WWNN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, "
+				 " WWPN:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+				 ndlp->nlp_sid, ndlp->cmd_qdepth,
+				 atomic_read(&ndlp->cmd_pending),
+				 ndlp->nlp_nodename.u.wwn[0],
+				 ndlp->nlp_nodename.u.wwn[1],
+				 ndlp->nlp_nodename.u.wwn[2],
+				 ndlp->nlp_nodename.u.wwn[3],
+				 ndlp->nlp_nodename.u.wwn[4],
+				 ndlp->nlp_nodename.u.wwn[5],
+				 ndlp->nlp_nodename.u.wwn[6],
+				 ndlp->nlp_nodename.u.wwn[7],
+				 ndlp->nlp_portname.u.wwn[0],
+				 ndlp->nlp_portname.u.wwn[1],
+				 ndlp->nlp_portname.u.wwn[2],
+				 ndlp->nlp_portname.u.wwn[3],
+				 ndlp->nlp_portname.u.wwn[4],
+				 ndlp->nlp_portname.u.wwn[5],
+				 ndlp->nlp_portname.u.wwn[6],
+				 ndlp->nlp_portname.u.wwn[7]);
 		goto out_tgt_busy;
 		goto out_tgt_busy;
-
+	}
 	lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp);
 	lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp);
 	if (lpfc_cmd == NULL) {
 	if (lpfc_cmd == NULL) {
 		lpfc_rampdown_queue_depth(phba);
 		lpfc_rampdown_queue_depth(phba);

+ 1 - 1
drivers/scsi/lpfc/lpfc_scsi.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *

+ 484 - 208
drivers/scsi/lpfc/lpfc_sli.c

@@ -1,8 +1,7 @@
-
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -36,6 +35,9 @@
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/fc/fc_fs.h>
 #include <scsi/fc/fc_fs.h>
 #include <linux/aer.h>
 #include <linux/aer.h>
+#ifdef CONFIG_X86
+#include <asm/set_memory.h>
+#endif
 
 
 #include <linux/nvme-fc-driver.h>
 #include <linux/nvme-fc-driver.h>
 
 
@@ -107,12 +109,14 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
  * The caller is expected to hold the hbalock when calling this routine.
  * The caller is expected to hold the hbalock when calling this routine.
  **/
  **/
 static int
 static int
-lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
+lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe128 *wqe)
 {
 {
 	union lpfc_wqe *temp_wqe;
 	union lpfc_wqe *temp_wqe;
 	struct lpfc_register doorbell;
 	struct lpfc_register doorbell;
 	uint32_t host_index;
 	uint32_t host_index;
 	uint32_t idx;
 	uint32_t idx;
+	uint32_t i = 0;
+	uint8_t *tmp;
 
 
 	/* sanity check on queue memory */
 	/* sanity check on queue memory */
 	if (unlikely(!q))
 	if (unlikely(!q))
@@ -129,10 +133,25 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
 	/* set consumption flag every once in a while */
 	/* set consumption flag every once in a while */
 	if (!((q->host_index + 1) % q->entry_repost))
 	if (!((q->host_index + 1) % q->entry_repost))
 		bf_set(wqe_wqec, &wqe->generic.wqe_com, 1);
 		bf_set(wqe_wqec, &wqe->generic.wqe_com, 1);
+	else
+		bf_set(wqe_wqec, &wqe->generic.wqe_com, 0);
 	if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED)
 	if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED)
 		bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id);
 		bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id);
 	lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
 	lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
-	/* ensure WQE bcopy flushed before doorbell write */
+	if (q->dpp_enable && q->phba->cfg_enable_dpp) {
+		/* write to DPP aperture taking advatage of Combined Writes */
+		tmp = (uint8_t *)temp_wqe;
+#ifdef __raw_writeq
+		for (i = 0; i < q->entry_size; i += sizeof(uint64_t))
+			__raw_writeq(*((uint64_t *)(tmp + i)),
+					q->dpp_regaddr + i);
+#else
+		for (i = 0; i < q->entry_size; i += sizeof(uint32_t))
+			__raw_writel(*((uint32_t *)(tmp + i)),
+					q->dpp_regaddr + i);
+#endif
+	}
+	/* ensure WQE bcopy and DPP flushed before doorbell write */
 	wmb();
 	wmb();
 
 
 	/* Update the host index before invoking device */
 	/* Update the host index before invoking device */
@@ -143,9 +162,18 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
 	/* Ring Doorbell */
 	/* Ring Doorbell */
 	doorbell.word0 = 0;
 	doorbell.word0 = 0;
 	if (q->db_format == LPFC_DB_LIST_FORMAT) {
 	if (q->db_format == LPFC_DB_LIST_FORMAT) {
-		bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1);
-		bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index);
-		bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id);
+		if (q->dpp_enable && q->phba->cfg_enable_dpp) {
+			bf_set(lpfc_if6_wq_db_list_fm_num_posted, &doorbell, 1);
+			bf_set(lpfc_if6_wq_db_list_fm_dpp, &doorbell, 1);
+			bf_set(lpfc_if6_wq_db_list_fm_dpp_id, &doorbell,
+			    q->dpp_id);
+			bf_set(lpfc_if6_wq_db_list_fm_id, &doorbell,
+			    q->queue_id);
+		} else {
+			bf_set(lpfc_wq_db_list_fm_num_posted, &doorbell, 1);
+			bf_set(lpfc_wq_db_list_fm_index, &doorbell, host_index);
+			bf_set(lpfc_wq_db_list_fm_id, &doorbell, q->queue_id);
+		}
 	} else if (q->db_format == LPFC_DB_RING_FORMAT) {
 	} else if (q->db_format == LPFC_DB_RING_FORMAT) {
 		bf_set(lpfc_wq_db_ring_fm_num_posted, &doorbell, 1);
 		bf_set(lpfc_wq_db_ring_fm_num_posted, &doorbell, 1);
 		bf_set(lpfc_wq_db_ring_fm_id, &doorbell, q->queue_id);
 		bf_set(lpfc_wq_db_ring_fm_id, &doorbell, q->queue_id);
@@ -262,16 +290,18 @@ lpfc_sli4_mq_release(struct lpfc_queue *q)
 static struct lpfc_eqe *
 static struct lpfc_eqe *
 lpfc_sli4_eq_get(struct lpfc_queue *q)
 lpfc_sli4_eq_get(struct lpfc_queue *q)
 {
 {
+	struct lpfc_hba *phba;
 	struct lpfc_eqe *eqe;
 	struct lpfc_eqe *eqe;
 	uint32_t idx;
 	uint32_t idx;
 
 
 	/* sanity check on queue memory */
 	/* sanity check on queue memory */
 	if (unlikely(!q))
 	if (unlikely(!q))
 		return NULL;
 		return NULL;
+	phba = q->phba;
 	eqe = q->qe[q->hba_index].eqe;
 	eqe = q->qe[q->hba_index].eqe;
 
 
 	/* If the next EQE is not valid then we are done */
 	/* If the next EQE is not valid then we are done */
-	if (!bf_get_le32(lpfc_eqe_valid, eqe))
+	if (bf_get_le32(lpfc_eqe_valid, eqe) != q->qe_valid)
 		return NULL;
 		return NULL;
 	/* If the host has not yet processed the next entry then we are done */
 	/* If the host has not yet processed the next entry then we are done */
 	idx = ((q->hba_index + 1) % q->entry_count);
 	idx = ((q->hba_index + 1) % q->entry_count);
@@ -279,6 +309,10 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
 		return NULL;
 		return NULL;
 
 
 	q->hba_index = idx;
 	q->hba_index = idx;
+	/* if the index wrapped around, toggle the valid bit */
+	if (phba->sli4_hba.pc_sli4_params.eqav && !q->hba_index)
+		q->qe_valid = (q->qe_valid) ? 0 : 1;
+
 
 
 	/*
 	/*
 	 * insert barrier for instruction interlock : data from the hardware
 	 * insert barrier for instruction interlock : data from the hardware
@@ -298,7 +332,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
  * @q: The Event Queue to disable interrupts
  * @q: The Event Queue to disable interrupts
  *
  *
  **/
  **/
-static inline void
+inline void
 lpfc_sli4_eq_clr_intr(struct lpfc_queue *q)
 lpfc_sli4_eq_clr_intr(struct lpfc_queue *q)
 {
 {
 	struct lpfc_register doorbell;
 	struct lpfc_register doorbell;
@@ -309,7 +343,26 @@ lpfc_sli4_eq_clr_intr(struct lpfc_queue *q)
 	bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
 	bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
 		(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
 		(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
 	bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
 	bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
-	writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+	writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
+}
+
+/**
+ * lpfc_sli4_if6_eq_clr_intr - Turn off interrupts from this EQ
+ * @q: The Event Queue to disable interrupts
+ *
+ **/
+inline void
+lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q)
+{
+	struct lpfc_register doorbell;
+
+	doorbell.word0 = 0;
+	bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1);
+	bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
+	bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
+		(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
+	bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
+	writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
 }
 }
 
 
 /**
 /**
@@ -331,17 +384,21 @@ uint32_t
 lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
 lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
 {
 {
 	uint32_t released = 0;
 	uint32_t released = 0;
+	struct lpfc_hba *phba;
 	struct lpfc_eqe *temp_eqe;
 	struct lpfc_eqe *temp_eqe;
 	struct lpfc_register doorbell;
 	struct lpfc_register doorbell;
 
 
 	/* sanity check on queue memory */
 	/* sanity check on queue memory */
 	if (unlikely(!q))
 	if (unlikely(!q))
 		return 0;
 		return 0;
+	phba = q->phba;
 
 
 	/* while there are valid entries */
 	/* while there are valid entries */
 	while (q->hba_index != q->host_index) {
 	while (q->hba_index != q->host_index) {
-		temp_eqe = q->qe[q->host_index].eqe;
-		bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
+		if (!phba->sli4_hba.pc_sli4_params.eqav) {
+			temp_eqe = q->qe[q->host_index].eqe;
+			bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
+		}
 		released++;
 		released++;
 		q->host_index = ((q->host_index + 1) % q->entry_count);
 		q->host_index = ((q->host_index + 1) % q->entry_count);
 	}
 	}
@@ -359,10 +416,63 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
 	bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
 	bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
 			(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
 			(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
 	bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
 	bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
-	writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+	writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
 	/* PCI read to flush PCI pipeline on re-arming for INTx mode */
 	/* PCI read to flush PCI pipeline on re-arming for INTx mode */
 	if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
 	if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
-		readl(q->phba->sli4_hba.EQCQDBregaddr);
+		readl(q->phba->sli4_hba.EQDBregaddr);
+	return released;
+}
+
+/**
+ * lpfc_sli4_if6_eq_release - Indicates the host has finished processing an EQ
+ * @q: The Event Queue that the host has completed processing for.
+ * @arm: Indicates whether the host wants to arms this CQ.
+ *
+ * This routine will mark all Event Queue Entries on @q, from the last
+ * known completed entry to the last entry that was processed, as completed
+ * by clearing the valid bit for each completion queue entry. Then it will
+ * notify the HBA, by ringing the doorbell, that the EQEs have been processed.
+ * The internal host index in the @q will be updated by this routine to indicate
+ * that the host has finished processing the entries. The @arm parameter
+ * indicates that the queue should be rearmed when ringing the doorbell.
+ *
+ * This function will return the number of EQEs that were popped.
+ **/
+uint32_t
+lpfc_sli4_if6_eq_release(struct lpfc_queue *q, bool arm)
+{
+	uint32_t released = 0;
+	struct lpfc_hba *phba;
+	struct lpfc_eqe *temp_eqe;
+	struct lpfc_register doorbell;
+
+	/* sanity check on queue memory */
+	if (unlikely(!q))
+		return 0;
+	phba = q->phba;
+
+	/* while there are valid entries */
+	while (q->hba_index != q->host_index) {
+		if (!phba->sli4_hba.pc_sli4_params.eqav) {
+			temp_eqe = q->qe[q->host_index].eqe;
+			bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
+		}
+		released++;
+		q->host_index = ((q->host_index + 1) % q->entry_count);
+	}
+	if (unlikely(released == 0 && !arm))
+		return 0;
+
+	/* ring doorbell for number popped */
+	doorbell.word0 = 0;
+	if (arm)
+		bf_set(lpfc_if6_eq_doorbell_arm, &doorbell, 1);
+	bf_set(lpfc_if6_eq_doorbell_num_released, &doorbell, released);
+	bf_set(lpfc_if6_eq_doorbell_eqid, &doorbell, q->queue_id);
+	writel(doorbell.word0, q->phba->sli4_hba.EQDBregaddr);
+	/* PCI read to flush PCI pipeline on re-arming for INTx mode */
+	if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
+		readl(q->phba->sli4_hba.EQDBregaddr);
 	return released;
 	return released;
 }
 }
 
 
@@ -378,23 +488,28 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
 static struct lpfc_cqe *
 static struct lpfc_cqe *
 lpfc_sli4_cq_get(struct lpfc_queue *q)
 lpfc_sli4_cq_get(struct lpfc_queue *q)
 {
 {
+	struct lpfc_hba *phba;
 	struct lpfc_cqe *cqe;
 	struct lpfc_cqe *cqe;
 	uint32_t idx;
 	uint32_t idx;
 
 
 	/* sanity check on queue memory */
 	/* sanity check on queue memory */
 	if (unlikely(!q))
 	if (unlikely(!q))
 		return NULL;
 		return NULL;
+	phba = q->phba;
+	cqe = q->qe[q->hba_index].cqe;
 
 
 	/* If the next CQE is not valid then we are done */
 	/* If the next CQE is not valid then we are done */
-	if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
+	if (bf_get_le32(lpfc_cqe_valid, cqe) != q->qe_valid)
 		return NULL;
 		return NULL;
 	/* If the host has not yet processed the next entry then we are done */
 	/* If the host has not yet processed the next entry then we are done */
 	idx = ((q->hba_index + 1) % q->entry_count);
 	idx = ((q->hba_index + 1) % q->entry_count);
 	if (idx == q->host_index)
 	if (idx == q->host_index)
 		return NULL;
 		return NULL;
 
 
-	cqe = q->qe[q->hba_index].cqe;
 	q->hba_index = idx;
 	q->hba_index = idx;
+	/* if the index wrapped around, toggle the valid bit */
+	if (phba->sli4_hba.pc_sli4_params.cqav && !q->hba_index)
+		q->qe_valid = (q->qe_valid) ? 0 : 1;
 
 
 	/*
 	/*
 	 * insert barrier for instruction interlock : data from the hardware
 	 * insert barrier for instruction interlock : data from the hardware
@@ -427,16 +542,21 @@ uint32_t
 lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
 lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
 {
 {
 	uint32_t released = 0;
 	uint32_t released = 0;
+	struct lpfc_hba *phba;
 	struct lpfc_cqe *temp_qe;
 	struct lpfc_cqe *temp_qe;
 	struct lpfc_register doorbell;
 	struct lpfc_register doorbell;
 
 
 	/* sanity check on queue memory */
 	/* sanity check on queue memory */
 	if (unlikely(!q))
 	if (unlikely(!q))
 		return 0;
 		return 0;
+	phba = q->phba;
+
 	/* while there are valid entries */
 	/* while there are valid entries */
 	while (q->hba_index != q->host_index) {
 	while (q->hba_index != q->host_index) {
-		temp_qe = q->qe[q->host_index].cqe;
-		bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
+		if (!phba->sli4_hba.pc_sli4_params.cqav) {
+			temp_qe = q->qe[q->host_index].cqe;
+			bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
+		}
 		released++;
 		released++;
 		q->host_index = ((q->host_index + 1) % q->entry_count);
 		q->host_index = ((q->host_index + 1) % q->entry_count);
 	}
 	}
@@ -452,7 +572,57 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
 	bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell,
 	bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell,
 			(q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT));
 			(q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT));
 	bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id);
 	bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id);
-	writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
+	writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr);
+	return released;
+}
+
+/**
+ * lpfc_sli4_if6_cq_release - Indicates the host has finished processing a CQ
+ * @q: The Completion Queue that the host has completed processing for.
+ * @arm: Indicates whether the host wants to arms this CQ.
+ *
+ * This routine will mark all Completion queue entries on @q, from the last
+ * known completed entry to the last entry that was processed, as completed
+ * by clearing the valid bit for each completion queue entry. Then it will
+ * notify the HBA, by ringing the doorbell, that the CQEs have been processed.
+ * The internal host index in the @q will be updated by this routine to indicate
+ * that the host has finished processing the entries. The @arm parameter
+ * indicates that the queue should be rearmed when ringing the doorbell.
+ *
+ * This function will return the number of CQEs that were released.
+ **/
+uint32_t
+lpfc_sli4_if6_cq_release(struct lpfc_queue *q, bool arm)
+{
+	uint32_t released = 0;
+	struct lpfc_hba *phba;
+	struct lpfc_cqe *temp_qe;
+	struct lpfc_register doorbell;
+
+	/* sanity check on queue memory */
+	if (unlikely(!q))
+		return 0;
+	phba = q->phba;
+
+	/* while there are valid entries */
+	while (q->hba_index != q->host_index) {
+		if (!phba->sli4_hba.pc_sli4_params.cqav) {
+			temp_qe = q->qe[q->host_index].cqe;
+			bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
+		}
+		released++;
+		q->host_index = ((q->host_index + 1) % q->entry_count);
+	}
+	if (unlikely(released == 0 && !arm))
+		return 0;
+
+	/* ring doorbell for number popped */
+	doorbell.word0 = 0;
+	if (arm)
+		bf_set(lpfc_if6_cq_doorbell_arm, &doorbell, 1);
+	bf_set(lpfc_if6_cq_doorbell_num_released, &doorbell, released);
+	bf_set(lpfc_if6_cq_doorbell_cqid, &doorbell, q->queue_id);
+	writel(doorbell.word0, q->phba->sli4_hba.CQDBregaddr);
 	return released;
 	return released;
 }
 }
 
 
@@ -2218,18 +2388,18 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 void
 void
 lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
 {
-	wait_queue_head_t *pdone_q;
 	unsigned long drvr_flag;
 	unsigned long drvr_flag;
+	struct completion *pmbox_done;
 
 
 	/*
 	/*
-	 * If pdone_q is empty, the driver thread gave up waiting and
+	 * If pmbox_done is empty, the driver thread gave up waiting and
 	 * continued running.
 	 * continued running.
 	 */
 	 */
 	pmboxq->mbox_flag |= LPFC_MBX_WAKE;
 	pmboxq->mbox_flag |= LPFC_MBX_WAKE;
 	spin_lock_irqsave(&phba->hbalock, drvr_flag);
 	spin_lock_irqsave(&phba->hbalock, drvr_flag);
-	pdone_q = (wait_queue_head_t *) pmboxq->context1;
-	if (pdone_q)
-		wake_up_interruptible(pdone_q);
+	pmbox_done = (struct completion *)pmboxq->context3;
+	if (pmbox_done)
+		complete(pmbox_done);
 	spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 	spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 	return;
 	return;
 }
 }
@@ -2330,7 +2500,7 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) {
 	if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) {
 		if (phba->sli_rev == LPFC_SLI_REV4 &&
 		if (phba->sli_rev == LPFC_SLI_REV4 &&
 		    (bf_get(lpfc_sli_intf_if_type,
 		    (bf_get(lpfc_sli_intf_if_type,
-		     &phba->sli4_hba.sli_intf) ==
+		     &phba->sli4_hba.sli_intf) >=
 		     LPFC_SLI_INTF_IF_TYPE_2)) {
 		     LPFC_SLI_INTF_IF_TYPE_2)) {
 			if (ndlp) {
 			if (ndlp) {
 				lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
 				lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
@@ -3776,6 +3946,7 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring  *pring;
 	struct lpfc_sli_ring  *pring;
 	uint32_t i;
 	uint32_t i;
+	struct lpfc_iocbq *piocb, *next_iocb;
 
 
 	spin_lock_irq(&phba->hbalock);
 	spin_lock_irq(&phba->hbalock);
 	/* Indicate the I/O queues are flushed */
 	/* Indicate the I/O queues are flushed */
@@ -3790,6 +3961,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
 			spin_lock_irq(&pring->ring_lock);
 			spin_lock_irq(&pring->ring_lock);
 			/* Retrieve everything on txq */
 			/* Retrieve everything on txq */
 			list_splice_init(&pring->txq, &txq);
 			list_splice_init(&pring->txq, &txq);
+			list_for_each_entry_safe(piocb, next_iocb,
+						 &pring->txcmplq, list)
+				piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
 			/* Retrieve everything on the txcmplq */
 			/* Retrieve everything on the txcmplq */
 			list_splice_init(&pring->txcmplq, &txcmplq);
 			list_splice_init(&pring->txcmplq, &txcmplq);
 			pring->txq_cnt = 0;
 			pring->txq_cnt = 0;
@@ -3811,6 +3985,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
 		spin_lock_irq(&phba->hbalock);
 		spin_lock_irq(&phba->hbalock);
 		/* Retrieve everything on txq */
 		/* Retrieve everything on txq */
 		list_splice_init(&pring->txq, &txq);
 		list_splice_init(&pring->txq, &txq);
+		list_for_each_entry_safe(piocb, next_iocb,
+					 &pring->txcmplq, list)
+			piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
 		/* Retrieve everything on the txcmplq */
 		/* Retrieve everything on the txcmplq */
 		list_splice_init(&pring->txcmplq, &txcmplq);
 		list_splice_init(&pring->txcmplq, &txcmplq);
 		pring->txq_cnt = 0;
 		pring->txq_cnt = 0;
@@ -3842,6 +4019,7 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba)
 	LIST_HEAD(txcmplq);
 	LIST_HEAD(txcmplq);
 	struct lpfc_sli_ring  *pring;
 	struct lpfc_sli_ring  *pring;
 	uint32_t i;
 	uint32_t i;
+	struct lpfc_iocbq *piocb, *next_iocb;
 
 
 	if (phba->sli_rev < LPFC_SLI_REV4)
 	if (phba->sli_rev < LPFC_SLI_REV4)
 		return;
 		return;
@@ -3858,8 +4036,11 @@ lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba)
 	for (i = 0; i < phba->cfg_nvme_io_channel; i++) {
 	for (i = 0; i < phba->cfg_nvme_io_channel; i++) {
 		pring = phba->sli4_hba.nvme_wq[i]->pring;
 		pring = phba->sli4_hba.nvme_wq[i]->pring;
 
 
-		/* Retrieve everything on the txcmplq */
 		spin_lock_irq(&pring->ring_lock);
 		spin_lock_irq(&pring->ring_lock);
+		list_for_each_entry_safe(piocb, next_iocb,
+					 &pring->txcmplq, list)
+			piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
+		/* Retrieve everything on the txcmplq */
 		list_splice_init(&pring->txcmplq, &txcmplq);
 		list_splice_init(&pring->txcmplq, &txcmplq);
 		pring->txcmplq_cnt = 0;
 		pring->txcmplq_cnt = 0;
 		spin_unlock_irq(&pring->ring_lock);
 		spin_unlock_irq(&pring->ring_lock);
@@ -4812,13 +4993,14 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
 		phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
 		phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
 		phba->port_gp = phba->mbox->us.s3_pgp.port;
 		phba->port_gp = phba->mbox->us.s3_pgp.port;
 
 
-		if (phba->cfg_enable_bg) {
-			if (pmb->u.mb.un.varCfgPort.gbg)
-				phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
-			else
+		if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
+			if (pmb->u.mb.un.varCfgPort.gbg == 0) {
+				phba->cfg_enable_bg = 0;
+				phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
 				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 						"0443 Adapter did not grant "
 						"0443 Adapter did not grant "
 						"BlockGuard\n");
 						"BlockGuard\n");
+			}
 		}
 		}
 	} else {
 	} else {
 		phba->hbq_get = NULL;
 		phba->hbq_get = NULL;
@@ -5290,41 +5472,42 @@ static void
 lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
 lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
 {
 {
 	int qidx;
 	int qidx;
+	struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
 
 
-	lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM);
-	lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM);
-	if (phba->sli4_hba.nvmels_cq)
-		lpfc_sli4_cq_release(phba->sli4_hba.nvmels_cq,
+	sli4_hba->sli4_cq_release(sli4_hba->mbx_cq, LPFC_QUEUE_REARM);
+	sli4_hba->sli4_cq_release(sli4_hba->els_cq, LPFC_QUEUE_REARM);
+	if (sli4_hba->nvmels_cq)
+		sli4_hba->sli4_cq_release(sli4_hba->nvmels_cq,
 						LPFC_QUEUE_REARM);
 						LPFC_QUEUE_REARM);
 
 
-	if (phba->sli4_hba.fcp_cq)
+	if (sli4_hba->fcp_cq)
 		for (qidx = 0; qidx < phba->cfg_fcp_io_channel; qidx++)
 		for (qidx = 0; qidx < phba->cfg_fcp_io_channel; qidx++)
-			lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[qidx],
+			sli4_hba->sli4_cq_release(sli4_hba->fcp_cq[qidx],
 						LPFC_QUEUE_REARM);
 						LPFC_QUEUE_REARM);
 
 
-	if (phba->sli4_hba.nvme_cq)
+	if (sli4_hba->nvme_cq)
 		for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++)
 		for (qidx = 0; qidx < phba->cfg_nvme_io_channel; qidx++)
-			lpfc_sli4_cq_release(phba->sli4_hba.nvme_cq[qidx],
+			sli4_hba->sli4_cq_release(sli4_hba->nvme_cq[qidx],
 						LPFC_QUEUE_REARM);
 						LPFC_QUEUE_REARM);
 
 
 	if (phba->cfg_fof)
 	if (phba->cfg_fof)
-		lpfc_sli4_cq_release(phba->sli4_hba.oas_cq, LPFC_QUEUE_REARM);
+		sli4_hba->sli4_cq_release(sli4_hba->oas_cq, LPFC_QUEUE_REARM);
 
 
-	if (phba->sli4_hba.hba_eq)
+	if (sli4_hba->hba_eq)
 		for (qidx = 0; qidx < phba->io_channel_irqs; qidx++)
 		for (qidx = 0; qidx < phba->io_channel_irqs; qidx++)
-			lpfc_sli4_eq_release(phba->sli4_hba.hba_eq[qidx],
-						LPFC_QUEUE_REARM);
+			sli4_hba->sli4_eq_release(sli4_hba->hba_eq[qidx],
+							LPFC_QUEUE_REARM);
 
 
 	if (phba->nvmet_support) {
 	if (phba->nvmet_support) {
 		for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) {
 		for (qidx = 0; qidx < phba->cfg_nvmet_mrq; qidx++) {
-			lpfc_sli4_cq_release(
-				phba->sli4_hba.nvmet_cqset[qidx],
+			sli4_hba->sli4_cq_release(
+				sli4_hba->nvmet_cqset[qidx],
 				LPFC_QUEUE_REARM);
 				LPFC_QUEUE_REARM);
 		}
 		}
 	}
 	}
 
 
 	if (phba->cfg_fof)
 	if (phba->cfg_fof)
-		lpfc_sli4_eq_release(phba->sli4_hba.fof_eq, LPFC_QUEUE_REARM);
+		sli4_hba->sli4_eq_release(sli4_hba->fof_eq, LPFC_QUEUE_REARM);
 }
 }
 
 
 /**
 /**
@@ -6533,9 +6716,11 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 	struct lpfc_rqe hrqe;
 	struct lpfc_rqe hrqe;
 	struct lpfc_rqe drqe;
 	struct lpfc_rqe drqe;
 	struct lpfc_rqb *rqbp;
 	struct lpfc_rqb *rqbp;
+	unsigned long flags;
 	struct rqb_dmabuf *rqb_buffer;
 	struct rqb_dmabuf *rqb_buffer;
 	LIST_HEAD(rqb_buf_list);
 	LIST_HEAD(rqb_buf_list);
 
 
+	spin_lock_irqsave(&phba->hbalock, flags);
 	rqbp = hrq->rqbp;
 	rqbp = hrq->rqbp;
 	for (i = 0; i < count; i++) {
 	for (i = 0; i < count; i++) {
 		/* IF RQ is already full, don't bother */
 		/* IF RQ is already full, don't bother */
@@ -6559,6 +6744,15 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 		drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys);
 		drqe.address_hi = putPaddrHigh(rqb_buffer->dbuf.phys);
 		rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe);
 		rc = lpfc_sli4_rq_put(hrq, drq, &hrqe, &drqe);
 		if (rc < 0) {
 		if (rc < 0) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"6421 Cannot post to HRQ %d: %x %x %x "
+					"DRQ %x %x\n",
+					hrq->queue_id,
+					hrq->host_index,
+					hrq->hba_index,
+					hrq->entry_count,
+					drq->host_index,
+					drq->hba_index);
 			rqbp->rqb_free_buffer(phba, rqb_buffer);
 			rqbp->rqb_free_buffer(phba, rqb_buffer);
 		} else {
 		} else {
 			list_add_tail(&rqb_buffer->hbuf.list,
 			list_add_tail(&rqb_buffer->hbuf.list,
@@ -6566,6 +6760,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 			rqbp->buffer_count++;
 			rqbp->buffer_count++;
 		}
 		}
 	}
 	}
+	spin_unlock_irqrestore(&phba->hbalock, flags);
 	return 1;
 	return 1;
 }
 }
 
 
@@ -6693,6 +6888,18 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
 	/* Save information as VPD data */
 	/* Save information as VPD data */
 	phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
 	phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev;
 	phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev;
 	phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev;
+
+	/*
+	 * This is because first G7 ASIC doesn't support the standard
+	 * 0x5a NVME cmd descriptor type/subtype
+	 */
+	if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
+			LPFC_SLI_INTF_IF_TYPE_6) &&
+	    (phba->vpd.rev.biuRev == LPFC_G7_ASIC_1) &&
+	    (phba->vpd.rev.smRev == 0) &&
+	    (phba->cfg_nvme_embed_cmd == 1))
+		phba->cfg_nvme_embed_cmd = 0;
+
 	phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev;
 	phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev;
 	phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high,
 	phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high,
 					 &mqe->un.read_rev);
 					 &mqe->un.read_rev);
@@ -6771,21 +6978,26 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
 				"0378 No support for fcpi mode.\n");
 				"0378 No support for fcpi mode.\n");
 		ftr_rsp++;
 		ftr_rsp++;
 	}
 	}
-	if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs))
-		phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED;
-	else
-		phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED;
+
+	/* Performance Hints are ONLY for FCoE */
+	if (phba->hba_flag & HBA_FCOE_MODE) {
+		if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs))
+			phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED;
+		else
+			phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED;
+	}
+
 	/*
 	/*
 	 * If the port cannot support the host's requested features
 	 * If the port cannot support the host's requested features
 	 * then turn off the global config parameters to disable the
 	 * then turn off the global config parameters to disable the
 	 * feature in the driver.  This is not a fatal error.
 	 * feature in the driver.  This is not a fatal error.
 	 */
 	 */
-	phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
-	if (phba->cfg_enable_bg) {
-		if (bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))
-			phba->sli3_options |= LPFC_SLI3_BG_ENABLED;
-		else
+	if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) {
+		if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) {
+			phba->cfg_enable_bg = 0;
+			phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED;
 			ftr_rsp++;
 			ftr_rsp++;
+		}
 	}
 	}
 
 
 	if (phba->max_vpi && phba->cfg_enable_npiv &&
 	if (phba->max_vpi && phba->cfg_enable_npiv &&
@@ -7209,6 +7421,7 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
 	struct lpfc_queue *mcq;
 	struct lpfc_queue *mcq;
 	struct lpfc_mcqe *mcqe;
 	struct lpfc_mcqe *mcqe;
 	bool pending_completions = false;
 	bool pending_completions = false;
+	uint8_t	qe_valid;
 
 
 	if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
 	if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
 		return false;
 		return false;
@@ -7217,7 +7430,8 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
 
 
 	mcq = phba->sli4_hba.mbx_cq;
 	mcq = phba->sli4_hba.mbx_cq;
 	idx = mcq->hba_index;
 	idx = mcq->hba_index;
-	while (bf_get_le32(lpfc_cqe_valid, mcq->qe[idx].cqe)) {
+	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;
 		mcqe = (struct lpfc_mcqe *)mcq->qe[idx].cqe;
 		if (bf_get_le32(lpfc_trailer_completed, mcqe) &&
 		if (bf_get_le32(lpfc_trailer_completed, mcqe) &&
 		    (!bf_get_le32(lpfc_trailer_async, mcqe))) {
 		    (!bf_get_le32(lpfc_trailer_async, mcqe))) {
@@ -7227,6 +7441,10 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
 		idx = (idx + 1) % mcq->entry_count;
 		idx = (idx + 1) % mcq->entry_count;
 		if (mcq->hba_index == idx)
 		if (mcq->hba_index == idx)
 			break;
 			break;
+
+		/* if the index wrapped around, toggle the valid bit */
+		if (phba->sli4_hba.pc_sli4_params.cqav && !idx)
+			qe_valid = (qe_valid) ? 0 : 1;
 	}
 	}
 	return pending_completions;
 	return pending_completions;
 
 
@@ -7246,7 +7464,7 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
 bool
 bool
 lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
 lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
 {
 {
-
+	struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba;
 	uint32_t eqidx;
 	uint32_t eqidx;
 	struct lpfc_queue *fpeq = NULL;
 	struct lpfc_queue *fpeq = NULL;
 	struct lpfc_eqe *eqe;
 	struct lpfc_eqe *eqe;
@@ -7257,11 +7475,11 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
 
 
 	/* Find the eq associated with the mcq */
 	/* Find the eq associated with the mcq */
 
 
-	if (phba->sli4_hba.hba_eq)
+	if (sli4_hba->hba_eq)
 		for (eqidx = 0; eqidx < phba->io_channel_irqs; eqidx++)
 		for (eqidx = 0; eqidx < phba->io_channel_irqs; eqidx++)
-			if (phba->sli4_hba.hba_eq[eqidx]->queue_id ==
-			    phba->sli4_hba.mbx_cq->assoc_qid) {
-				fpeq = phba->sli4_hba.hba_eq[eqidx];
+			if (sli4_hba->hba_eq[eqidx]->queue_id ==
+			    sli4_hba->mbx_cq->assoc_qid) {
+				fpeq = sli4_hba->hba_eq[eqidx];
 				break;
 				break;
 			}
 			}
 	if (!fpeq)
 	if (!fpeq)
@@ -7269,7 +7487,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
 
 
 	/* Turn off interrupts from this EQ */
 	/* Turn off interrupts from this EQ */
 
 
-	lpfc_sli4_eq_clr_intr(fpeq);
+	sli4_hba->sli4_eq_clr_intr(fpeq);
 
 
 	/* Check to see if a mbox completion is pending */
 	/* Check to see if a mbox completion is pending */
 
 
@@ -7290,7 +7508,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
 
 
 	/* Always clear and re-arm the EQ */
 	/* Always clear and re-arm the EQ */
 
 
-	lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
+	sli4_hba->sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
 
 
 	return mbox_pending;
 	return mbox_pending;
 
 
@@ -8100,7 +8318,7 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
 	} else if (flag == MBX_POLL) {
 	} else if (flag == MBX_POLL) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
 		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
 				"(%d):2542 Try to issue mailbox command "
 				"(%d):2542 Try to issue mailbox command "
-				"x%x (x%x/x%x) synchronously ahead of async"
+				"x%x (x%x/x%x) synchronously ahead of async "
 				"mailbox command queue: x%x x%x\n",
 				"mailbox command queue: x%x x%x\n",
 				mboxq->vport ? mboxq->vport->vpi : 0,
 				mboxq->vport ? mboxq->vport->vpi : 0,
 				mboxq->u.mb.mbxCommand,
 				mboxq->u.mb.mbxCommand,
@@ -8664,7 +8882,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
  **/
  **/
 static int
 static int
 lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
-		union lpfc_wqe *wqe)
+		union lpfc_wqe128 *wqe)
 {
 {
 	uint32_t xmit_len = 0, total_len = 0;
 	uint32_t xmit_len = 0, total_len = 0;
 	uint8_t ct = 0;
 	uint8_t ct = 0;
@@ -8767,7 +8985,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 					iocbq->context2)->virt);
 					iocbq->context2)->virt);
 		if_type = bf_get(lpfc_sli_intf_if_type,
 		if_type = bf_get(lpfc_sli_intf_if_type,
 					&phba->sli4_hba.sli_intf);
 					&phba->sli4_hba.sli_intf);
-		if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+		if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
 			if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
 			if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
 				*pcmd == ELS_CMD_SCR ||
 				*pcmd == ELS_CMD_SCR ||
 				*pcmd == ELS_CMD_FDISC ||
 				*pcmd == ELS_CMD_FDISC ||
@@ -8870,31 +9088,36 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 		}
 		}
 		/* Note, word 10 is already initialized to 0 */
 		/* Note, word 10 is already initialized to 0 */
 
 
+		/* Don't set PBDE for Perf hints, just fcp_embed_pbde */
+		if (phba->fcp_embed_pbde)
+			bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 1);
+		else
+			bf_set(wqe_pbde, &wqe->fcp_iwrite.wqe_com, 0);
+
 		if (phba->fcp_embed_io) {
 		if (phba->fcp_embed_io) {
 			struct lpfc_scsi_buf *lpfc_cmd;
 			struct lpfc_scsi_buf *lpfc_cmd;
 			struct sli4_sge *sgl;
 			struct sli4_sge *sgl;
-			union lpfc_wqe128 *wqe128;
 			struct fcp_cmnd *fcp_cmnd;
 			struct fcp_cmnd *fcp_cmnd;
 			uint32_t *ptr;
 			uint32_t *ptr;
 
 
 			/* 128 byte wqe support here */
 			/* 128 byte wqe support here */
-			wqe128 = (union lpfc_wqe128 *)wqe;
 
 
 			lpfc_cmd = iocbq->context1;
 			lpfc_cmd = iocbq->context1;
 			sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
 			sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
 			fcp_cmnd = lpfc_cmd->fcp_cmnd;
 			fcp_cmnd = lpfc_cmd->fcp_cmnd;
 
 
 			/* Word 0-2 - FCP_CMND */
 			/* Word 0-2 - FCP_CMND */
-			wqe128->generic.bde.tus.f.bdeFlags =
+			wqe->generic.bde.tus.f.bdeFlags =
 				BUFF_TYPE_BDE_IMMED;
 				BUFF_TYPE_BDE_IMMED;
-			wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len;
-			wqe128->generic.bde.addrHigh = 0;
-			wqe128->generic.bde.addrLow =  88;  /* Word 22 */
+			wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
+			wqe->generic.bde.addrHigh = 0;
+			wqe->generic.bde.addrLow =  88;  /* Word 22 */
 
 
-			bf_set(wqe_wqes, &wqe128->fcp_iwrite.wqe_com, 1);
+			bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
+			bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 0);
 
 
 			/* Word 22-29  FCP CMND Payload */
 			/* Word 22-29  FCP CMND Payload */
-			ptr = &wqe128->words[22];
+			ptr = &wqe->words[22];
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 		}
 		}
 		break;
 		break;
@@ -8929,31 +9152,36 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 		}
 		}
 		/* Note, word 10 is already initialized to 0 */
 		/* Note, word 10 is already initialized to 0 */
 
 
+		/* Don't set PBDE for Perf hints, just fcp_embed_pbde */
+		if (phba->fcp_embed_pbde)
+			bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 1);
+		else
+			bf_set(wqe_pbde, &wqe->fcp_iread.wqe_com, 0);
+
 		if (phba->fcp_embed_io) {
 		if (phba->fcp_embed_io) {
 			struct lpfc_scsi_buf *lpfc_cmd;
 			struct lpfc_scsi_buf *lpfc_cmd;
 			struct sli4_sge *sgl;
 			struct sli4_sge *sgl;
-			union lpfc_wqe128 *wqe128;
 			struct fcp_cmnd *fcp_cmnd;
 			struct fcp_cmnd *fcp_cmnd;
 			uint32_t *ptr;
 			uint32_t *ptr;
 
 
 			/* 128 byte wqe support here */
 			/* 128 byte wqe support here */
-			wqe128 = (union lpfc_wqe128 *)wqe;
 
 
 			lpfc_cmd = iocbq->context1;
 			lpfc_cmd = iocbq->context1;
 			sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
 			sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
 			fcp_cmnd = lpfc_cmd->fcp_cmnd;
 			fcp_cmnd = lpfc_cmd->fcp_cmnd;
 
 
 			/* Word 0-2 - FCP_CMND */
 			/* Word 0-2 - FCP_CMND */
-			wqe128->generic.bde.tus.f.bdeFlags =
+			wqe->generic.bde.tus.f.bdeFlags =
 				BUFF_TYPE_BDE_IMMED;
 				BUFF_TYPE_BDE_IMMED;
-			wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len;
-			wqe128->generic.bde.addrHigh = 0;
-			wqe128->generic.bde.addrLow =  88;  /* Word 22 */
+			wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
+			wqe->generic.bde.addrHigh = 0;
+			wqe->generic.bde.addrLow =  88;  /* Word 22 */
 
 
-			bf_set(wqe_wqes, &wqe128->fcp_iread.wqe_com, 1);
+			bf_set(wqe_wqes, &wqe->fcp_iread.wqe_com, 1);
+			bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 0);
 
 
 			/* Word 22-29  FCP CMND Payload */
 			/* Word 22-29  FCP CMND Payload */
-			ptr = &wqe128->words[22];
+			ptr = &wqe->words[22];
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 		}
 		}
 		break;
 		break;
@@ -8990,28 +9218,27 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 		if (phba->fcp_embed_io) {
 		if (phba->fcp_embed_io) {
 			struct lpfc_scsi_buf *lpfc_cmd;
 			struct lpfc_scsi_buf *lpfc_cmd;
 			struct sli4_sge *sgl;
 			struct sli4_sge *sgl;
-			union lpfc_wqe128 *wqe128;
 			struct fcp_cmnd *fcp_cmnd;
 			struct fcp_cmnd *fcp_cmnd;
 			uint32_t *ptr;
 			uint32_t *ptr;
 
 
 			/* 128 byte wqe support here */
 			/* 128 byte wqe support here */
-			wqe128 = (union lpfc_wqe128 *)wqe;
 
 
 			lpfc_cmd = iocbq->context1;
 			lpfc_cmd = iocbq->context1;
 			sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
 			sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl;
 			fcp_cmnd = lpfc_cmd->fcp_cmnd;
 			fcp_cmnd = lpfc_cmd->fcp_cmnd;
 
 
 			/* Word 0-2 - FCP_CMND */
 			/* Word 0-2 - FCP_CMND */
-			wqe128->generic.bde.tus.f.bdeFlags =
+			wqe->generic.bde.tus.f.bdeFlags =
 				BUFF_TYPE_BDE_IMMED;
 				BUFF_TYPE_BDE_IMMED;
-			wqe128->generic.bde.tus.f.bdeSize = sgl->sge_len;
-			wqe128->generic.bde.addrHigh = 0;
-			wqe128->generic.bde.addrLow =  88;  /* Word 22 */
+			wqe->generic.bde.tus.f.bdeSize = sgl->sge_len;
+			wqe->generic.bde.addrHigh = 0;
+			wqe->generic.bde.addrLow =  88;  /* Word 22 */
 
 
-			bf_set(wqe_wqes, &wqe128->fcp_icmd.wqe_com, 1);
+			bf_set(wqe_wqes, &wqe->fcp_icmd.wqe_com, 1);
+			bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 0);
 
 
 			/* Word 22-29  FCP CMND Payload */
 			/* Word 22-29  FCP CMND Payload */
-			ptr = &wqe128->words[22];
+			ptr = &wqe->words[22];
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 			memcpy(ptr, fcp_cmnd, sizeof(struct fcp_cmnd));
 		}
 		}
 		break;
 		break;
@@ -9064,7 +9291,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
 
 
 		if_type = bf_get(lpfc_sli_intf_if_type,
 		if_type = bf_get(lpfc_sli_intf_if_type,
 					&phba->sli4_hba.sli_intf);
 					&phba->sli4_hba.sli_intf);
-		if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+		if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
 			if (iocbq->vport->fc_flag & FC_PT2PT) {
 			if (iocbq->vport->fc_flag & FC_PT2PT) {
 				bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
 				bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1);
 				bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
 				bf_set(els_rsp64_sid, &wqe->xmit_els_rsp,
@@ -9249,8 +9476,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
 			 struct lpfc_iocbq *piocb, uint32_t flag)
 			 struct lpfc_iocbq *piocb, uint32_t flag)
 {
 {
 	struct lpfc_sglq *sglq;
 	struct lpfc_sglq *sglq;
-	union lpfc_wqe *wqe;
-	union lpfc_wqe128 wqe128;
+	union lpfc_wqe128 wqe;
 	struct lpfc_queue *wq;
 	struct lpfc_queue *wq;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_sli_ring *pring;
 
 
@@ -9270,9 +9496,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
 
 
 	/*
 	/*
 	 * The WQE can be either 64 or 128 bytes,
 	 * The WQE can be either 64 or 128 bytes,
-	 * so allocate space on the stack assuming the largest.
 	 */
 	 */
-	wqe = (union lpfc_wqe *)&wqe128;
 
 
 	lockdep_assert_held(&phba->hbalock);
 	lockdep_assert_held(&phba->hbalock);
 
 
@@ -9322,10 +9546,10 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
 			return IOCB_ERROR;
 			return IOCB_ERROR;
 	}
 	}
 
 
-	if (lpfc_sli4_iocb2wqe(phba, piocb, wqe))
+	if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe))
 		return IOCB_ERROR;
 		return IOCB_ERROR;
 
 
-	if (lpfc_sli4_wq_put(wq, wqe))
+	if (lpfc_sli4_wq_put(wq, &wqe))
 		return IOCB_ERROR;
 		return IOCB_ERROR;
 	lpfc_sli_ringtxcmpl_put(phba, pring, piocb);
 	lpfc_sli_ringtxcmpl_put(phba, pring, piocb);
 
 
@@ -9470,7 +9694,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
 				fpeq = phba->sli4_hba.hba_eq[idx];
 				fpeq = phba->sli4_hba.hba_eq[idx];
 
 
 				/* Turn off interrupts from this EQ */
 				/* Turn off interrupts from this EQ */
-				lpfc_sli4_eq_clr_intr(fpeq);
+				phba->sli4_hba.sli4_eq_clr_intr(fpeq);
 
 
 				/*
 				/*
 				 * Process all the events on FCP EQ
 				 * Process all the events on FCP EQ
@@ -9482,7 +9706,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
 				}
 				}
 
 
 				/* Always clear and re-arm the EQ */
 				/* Always clear and re-arm the EQ */
-				lpfc_sli4_eq_release(fpeq,
+				phba->sli4_hba.sli4_eq_release(fpeq,
 					LPFC_QUEUE_REARM);
 					LPFC_QUEUE_REARM);
 			}
 			}
 			atomic_inc(&hba_eq_hdl->hba_eq_in_use);
 			atomic_inc(&hba_eq_hdl->hba_eq_in_use);
@@ -10695,7 +10919,7 @@ lpfc_sli4_abort_nvme_io(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 {
 {
 	struct lpfc_vport *vport = cmdiocb->vport;
 	struct lpfc_vport *vport = cmdiocb->vport;
 	struct lpfc_iocbq *abtsiocbp;
 	struct lpfc_iocbq *abtsiocbp;
-	union lpfc_wqe *abts_wqe;
+	union lpfc_wqe128 *abts_wqe;
 	int retval;
 	int retval;
 
 
 	/*
 	/*
@@ -11442,31 +11666,25 @@ int
 lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
 lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
 			 uint32_t timeout)
 			 uint32_t timeout)
 {
 {
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
-	MAILBOX_t *mb = NULL;
+	struct completion mbox_done;
 	int retval;
 	int retval;
 	unsigned long flag;
 	unsigned long flag;
 
 
-	/* The caller might set context1 for extended buffer */
-	if (pmboxq->context1)
-		mb = (MAILBOX_t *)pmboxq->context1;
-
 	pmboxq->mbox_flag &= ~LPFC_MBX_WAKE;
 	pmboxq->mbox_flag &= ~LPFC_MBX_WAKE;
 	/* setup wake call as IOCB callback */
 	/* setup wake call as IOCB callback */
 	pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait;
 	pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait;
-	/* setup context field to pass wait_queue pointer to wake function  */
-	pmboxq->context1 = &done_q;
 
 
+	/* setup context3 field to pass wait_queue pointer to wake function  */
+	init_completion(&mbox_done);
+	pmboxq->context3 = &mbox_done;
 	/* now issue the command */
 	/* now issue the command */
 	retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
 	retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
 	if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
 	if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
-		wait_event_interruptible_timeout(done_q,
-				pmboxq->mbox_flag & LPFC_MBX_WAKE,
-				msecs_to_jiffies(timeout * 1000));
+		wait_for_completion_timeout(&mbox_done,
+					    msecs_to_jiffies(timeout * 1000));
 
 
 		spin_lock_irqsave(&phba->hbalock, flag);
 		spin_lock_irqsave(&phba->hbalock, flag);
-		/* restore the possible extended buffer for free resource */
-		pmboxq->context1 = (uint8_t *)mb;
+		pmboxq->context3 = NULL;
 		/*
 		/*
 		 * if LPFC_MBX_WAKE flag is set the mailbox is completed
 		 * if LPFC_MBX_WAKE flag is set the mailbox is completed
 		 * else do not free the resources.
 		 * else do not free the resources.
@@ -11478,11 +11696,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
 			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		}
 		}
 		spin_unlock_irqrestore(&phba->hbalock, flag);
 		spin_unlock_irqrestore(&phba->hbalock, flag);
-	} else {
-		/* restore the possible extended buffer for free resource */
-		pmboxq->context1 = (uint8_t *)mb;
 	}
 	}
-
 	return retval;
 	return retval;
 }
 }
 
 
@@ -11648,6 +11862,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
 		}
 		}
 		break;
 		break;
 	case LPFC_SLI_INTF_IF_TYPE_2:
 	case LPFC_SLI_INTF_IF_TYPE_2:
+	case LPFC_SLI_INTF_IF_TYPE_6:
 		if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
 		if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
 			&portstat_reg.word0) ||
 			&portstat_reg.word0) ||
 			lpfc_readl(phba->sli4_hba.PSMPHRregaddr,
 			lpfc_readl(phba->sli4_hba.PSMPHRregaddr,
@@ -13112,7 +13327,7 @@ lpfc_sli4_sp_process_cq(struct work_struct *work)
 				"(x%x), type (%d)\n", cq->queue_id, cq->type);
 				"(x%x), type (%d)\n", cq->queue_id, cq->type);
 
 
 	/* In any case, flash and re-arm the RCQ */
 	/* In any case, flash and re-arm the RCQ */
-	lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+	phba->sli4_hba.sli4_cq_release(cq, LPFC_QUEUE_REARM);
 
 
 	/* wake up worker thread if there are works to be done */
 	/* wake up worker thread if there are works to be done */
 	if (workposted)
 	if (workposted)
@@ -13230,6 +13445,8 @@ lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
 		if (childwq->queue_id == hba_wqid) {
 		if (childwq->queue_id == hba_wqid) {
 			lpfc_sli4_wq_release(childwq,
 			lpfc_sli4_wq_release(childwq,
 					bf_get(lpfc_wcqe_r_wqe_index, wcqe));
 					bf_get(lpfc_wcqe_r_wqe_index, wcqe));
+			if (childwq->q_flag & HBA_NVMET_WQFULL)
+				lpfc_nvmet_wqfull_process(phba, childwq);
 			wqid_matched = true;
 			wqid_matched = true;
 			break;
 			break;
 		}
 		}
@@ -13542,7 +13759,7 @@ lpfc_sli4_hba_process_cq(struct work_struct *work)
 				"queue fcpcqid=%d\n", cq->queue_id);
 				"queue fcpcqid=%d\n", cq->queue_id);
 
 
 	/* In any case, flash and re-arm the CQ */
 	/* In any case, flash and re-arm the CQ */
-	lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM);
+	phba->sli4_hba.sli4_cq_release(cq, LPFC_QUEUE_REARM);
 
 
 	/* wake up worker thread if there are works to be done */
 	/* wake up worker thread if there are works to be done */
 	if (workposted)
 	if (workposted)
@@ -13559,7 +13776,7 @@ lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
 		;
 		;
 
 
 	/* Clear and re-arm the EQ */
 	/* Clear and re-arm the EQ */
-	lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
+	phba->sli4_hba.sli4_eq_release(eq, LPFC_QUEUE_REARM);
 }
 }
 
 
 
 
@@ -13707,7 +13924,7 @@ lpfc_sli4_fof_intr_handler(int irq, void *dev_id)
 		}
 		}
 	}
 	}
 	/* Always clear and re-arm the fast-path EQ */
 	/* Always clear and re-arm the fast-path EQ */
-	lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM);
+	phba->sli4_hba.sli4_eq_release(eq, LPFC_QUEUE_REARM);
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
@@ -13765,7 +13982,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
 
 
 	if (lpfc_fcp_look_ahead) {
 	if (lpfc_fcp_look_ahead) {
 		if (atomic_dec_and_test(&hba_eq_hdl->hba_eq_in_use))
 		if (atomic_dec_and_test(&hba_eq_hdl->hba_eq_in_use))
-			lpfc_sli4_eq_clr_intr(fpeq);
+			phba->sli4_hba.sli4_eq_clr_intr(fpeq);
 		else {
 		else {
 			atomic_inc(&hba_eq_hdl->hba_eq_in_use);
 			atomic_inc(&hba_eq_hdl->hba_eq_in_use);
 			return IRQ_NONE;
 			return IRQ_NONE;
@@ -13800,7 +14017,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
 		fpeq->EQ_max_eqe = ecount;
 		fpeq->EQ_max_eqe = ecount;
 
 
 	/* Always clear and re-arm the fast-path EQ */
 	/* Always clear and re-arm the fast-path EQ */
-	lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
+	phba->sli4_hba.sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
 
 
 	if (unlikely(ecount == 0)) {
 	if (unlikely(ecount == 0)) {
 		fpeq->EQ_no_entry++;
 		fpeq->EQ_no_entry++;
@@ -13948,6 +14165,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size,
 
 
 	INIT_LIST_HEAD(&queue->list);
 	INIT_LIST_HEAD(&queue->list);
 	INIT_LIST_HEAD(&queue->wq_list);
 	INIT_LIST_HEAD(&queue->wq_list);
+	INIT_LIST_HEAD(&queue->wqfull_list);
 	INIT_LIST_HEAD(&queue->page_list);
 	INIT_LIST_HEAD(&queue->page_list);
 	INIT_LIST_HEAD(&queue->child_list);
 	INIT_LIST_HEAD(&queue->child_list);
 
 
@@ -14173,11 +14391,21 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
 			 LPFC_MBOX_OPCODE_EQ_CREATE,
 			 LPFC_MBOX_OPCODE_EQ_CREATE,
 			 length, LPFC_SLI4_MBX_EMBED);
 			 length, LPFC_SLI4_MBX_EMBED);
 	eq_create = &mbox->u.mqe.un.eq_create;
 	eq_create = &mbox->u.mqe.un.eq_create;
+	shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr;
 	bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request,
 	bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request,
 	       eq->page_count);
 	       eq->page_count);
 	bf_set(lpfc_eq_context_size, &eq_create->u.request.context,
 	bf_set(lpfc_eq_context_size, &eq_create->u.request.context,
 	       LPFC_EQE_SIZE);
 	       LPFC_EQE_SIZE);
 	bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1);
 	bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1);
+
+	/* Use version 2 of CREATE_EQ if eqav is set */
+	if (phba->sli4_hba.pc_sli4_params.eqav) {
+		bf_set(lpfc_mbox_hdr_version, &shdr->request,
+		       LPFC_Q_CREATE_VERSION_2);
+		bf_set(lpfc_eq_context_autovalid, &eq_create->u.request.context,
+		       phba->sli4_hba.pc_sli4_params.eqav);
+	}
+
 	/* don't setup delay multiplier using EQ_CREATE */
 	/* don't setup delay multiplier using EQ_CREATE */
 	dmult = 0;
 	dmult = 0;
 	bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context,
 	bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context,
@@ -14222,7 +14450,6 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax)
 	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 	mbox->context1 = NULL;
 	mbox->context1 = NULL;
 	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
 	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
-	shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr;
 	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
 	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
 	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
 	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
 	if (shdr_status || shdr_add_status || rc) {
 	if (shdr_status || shdr_add_status || rc) {
@@ -14305,6 +14532,8 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
 		       (cq->page_size / SLI4_PAGE_SIZE));
 		       (cq->page_size / SLI4_PAGE_SIZE));
 		bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context,
 		bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context,
 		       eq->queue_id);
 		       eq->queue_id);
+		bf_set(lpfc_cq_context_autovalid, &cq_create->u.request.context,
+		       phba->sli4_hba.pc_sli4_params.cqav);
 	} else {
 	} else {
 		bf_set(lpfc_cq_eq_id, &cq_create->u.request.context,
 		bf_set(lpfc_cq_eq_id, &cq_create->u.request.context,
 		       eq->queue_id);
 		       eq->queue_id);
@@ -14476,6 +14705,9 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp,
 			       &cq_set->u.request, 0);
 			       &cq_set->u.request, 0);
 			bf_set(lpfc_mbx_cq_create_set_num_cq,
 			bf_set(lpfc_mbx_cq_create_set_num_cq,
 			       &cq_set->u.request, numcq);
 			       &cq_set->u.request, numcq);
+			bf_set(lpfc_mbx_cq_create_set_autovalid,
+			       &cq_set->u.request,
+			       phba->sli4_hba.pc_sli4_params.cqav);
 			switch (cq->entry_count) {
 			switch (cq->entry_count) {
 			case 2048:
 			case 2048:
 			case 4096:
 			case 4096:
@@ -14881,6 +15113,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 	void __iomem *bar_memmap_p;
 	void __iomem *bar_memmap_p;
 	uint32_t db_offset;
 	uint32_t db_offset;
 	uint16_t pci_barset;
 	uint16_t pci_barset;
+	uint8_t dpp_barset;
+	uint32_t dpp_offset;
+	unsigned long pg_addr;
 	uint8_t wq_create_version;
 	uint8_t wq_create_version;
 
 
 	/* sanity check on queue memory */
 	/* sanity check on queue memory */
@@ -14908,43 +15143,19 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 	bf_set(lpfc_mbox_hdr_version, &shdr->request,
 	bf_set(lpfc_mbox_hdr_version, &shdr->request,
 	       phba->sli4_hba.pc_sli4_params.wqv);
 	       phba->sli4_hba.pc_sli4_params.wqv);
 
 
+	if ((phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT) ||
+	    (wq->page_size > SLI4_PAGE_SIZE))
+		wq_create_version = LPFC_Q_CREATE_VERSION_1;
+	else
+		wq_create_version = LPFC_Q_CREATE_VERSION_0;
+
+
 	if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT)
 	if (phba->sli4_hba.pc_sli4_params.wqsize & LPFC_WQ_SZ128_SUPPORT)
 		wq_create_version = LPFC_Q_CREATE_VERSION_1;
 		wq_create_version = LPFC_Q_CREATE_VERSION_1;
 	else
 	else
 		wq_create_version = LPFC_Q_CREATE_VERSION_0;
 		wq_create_version = LPFC_Q_CREATE_VERSION_0;
 
 
 	switch (wq_create_version) {
 	switch (wq_create_version) {
-	case LPFC_Q_CREATE_VERSION_0:
-		switch (wq->entry_size) {
-		default:
-		case 64:
-			/* Nothing to do, version 0 ONLY supports 64 byte */
-			page = wq_create->u.request.page;
-			break;
-		case 128:
-			if (!(phba->sli4_hba.pc_sli4_params.wqsize &
-			    LPFC_WQ_SZ128_SUPPORT)) {
-				status = -ERANGE;
-				goto out;
-			}
-			/* If we get here the HBA MUST also support V1 and
-			 * we MUST use it
-			 */
-			bf_set(lpfc_mbox_hdr_version, &shdr->request,
-			       LPFC_Q_CREATE_VERSION_1);
-
-			bf_set(lpfc_mbx_wq_create_wqe_count,
-			       &wq_create->u.request_1, wq->entry_count);
-			bf_set(lpfc_mbx_wq_create_wqe_size,
-			       &wq_create->u.request_1,
-			       LPFC_WQ_WQE_SIZE_128);
-			bf_set(lpfc_mbx_wq_create_page_size,
-			       &wq_create->u.request_1,
-			       LPFC_WQ_PAGE_SIZE_4096);
-			page = wq_create->u.request_1.page;
-			break;
-		}
-		break;
 	case LPFC_Q_CREATE_VERSION_1:
 	case LPFC_Q_CREATE_VERSION_1:
 		bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
 		bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
 		       wq->entry_count);
 		       wq->entry_count);
@@ -14959,24 +15170,21 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 			       LPFC_WQ_WQE_SIZE_64);
 			       LPFC_WQ_WQE_SIZE_64);
 			break;
 			break;
 		case 128:
 		case 128:
-			if (!(phba->sli4_hba.pc_sli4_params.wqsize &
-				LPFC_WQ_SZ128_SUPPORT)) {
-				status = -ERANGE;
-				goto out;
-			}
 			bf_set(lpfc_mbx_wq_create_wqe_size,
 			bf_set(lpfc_mbx_wq_create_wqe_size,
 			       &wq_create->u.request_1,
 			       &wq_create->u.request_1,
 			       LPFC_WQ_WQE_SIZE_128);
 			       LPFC_WQ_WQE_SIZE_128);
 			break;
 			break;
 		}
 		}
+		/* Request DPP by default */
+		bf_set(lpfc_mbx_wq_create_dpp_req, &wq_create->u.request_1, 1);
 		bf_set(lpfc_mbx_wq_create_page_size,
 		bf_set(lpfc_mbx_wq_create_page_size,
 		       &wq_create->u.request_1,
 		       &wq_create->u.request_1,
 		       (wq->page_size / SLI4_PAGE_SIZE));
 		       (wq->page_size / SLI4_PAGE_SIZE));
 		page = wq_create->u.request_1.page;
 		page = wq_create->u.request_1.page;
 		break;
 		break;
 	default:
 	default:
-		status = -ERANGE;
-		goto out;
+		page = wq_create->u.request.page;
+		break;
 	}
 	}
 
 
 	list_for_each_entry(dmabuf, &wq->page_list, list) {
 	list_for_each_entry(dmabuf, &wq->page_list, list) {
@@ -15000,52 +15208,120 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 		status = -ENXIO;
 		status = -ENXIO;
 		goto out;
 		goto out;
 	}
 	}
-	wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id, &wq_create->u.response);
+
+	if (wq_create_version == LPFC_Q_CREATE_VERSION_0)
+		wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id,
+					&wq_create->u.response);
+	else
+		wq->queue_id = bf_get(lpfc_mbx_wq_create_v1_q_id,
+					&wq_create->u.response_1);
+
 	if (wq->queue_id == 0xFFFF) {
 	if (wq->queue_id == 0xFFFF) {
 		status = -ENXIO;
 		status = -ENXIO;
 		goto out;
 		goto out;
 	}
 	}
-	if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) {
-		wq->db_format = bf_get(lpfc_mbx_wq_create_db_format,
-				       &wq_create->u.response);
-		if ((wq->db_format != LPFC_DB_LIST_FORMAT) &&
-		    (wq->db_format != LPFC_DB_RING_FORMAT)) {
-			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"3265 WQ[%d] doorbell format not "
-					"supported: x%x\n", wq->queue_id,
-					wq->db_format);
-			status = -EINVAL;
-			goto out;
-		}
-		pci_barset = bf_get(lpfc_mbx_wq_create_bar_set,
-				    &wq_create->u.response);
-		bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba, pci_barset);
-		if (!bar_memmap_p) {
-			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"3263 WQ[%d] failed to memmap pci "
-					"barset:x%x\n", wq->queue_id,
-					pci_barset);
-			status = -ENOMEM;
-			goto out;
-		}
-		db_offset = wq_create->u.response.doorbell_offset;
-		if ((db_offset != LPFC_ULP0_WQ_DOORBELL) &&
-		    (db_offset != LPFC_ULP1_WQ_DOORBELL)) {
-			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"3252 WQ[%d] doorbell offset not "
-					"supported: x%x\n", wq->queue_id,
-					db_offset);
-			status = -EINVAL;
-			goto out;
-		}
-		wq->db_regaddr = bar_memmap_p + db_offset;
-		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-				"3264 WQ[%d]: barset:x%x, offset:x%x, "
-				"format:x%x\n", wq->queue_id, pci_barset,
-				db_offset, wq->db_format);
+
+	wq->db_format = LPFC_DB_LIST_FORMAT;
+	if (wq_create_version == LPFC_Q_CREATE_VERSION_0) {
+		if (phba->sli4_hba.fw_func_mode & LPFC_DUA_MODE) {
+			wq->db_format = bf_get(lpfc_mbx_wq_create_db_format,
+					       &wq_create->u.response);
+			if ((wq->db_format != LPFC_DB_LIST_FORMAT) &&
+			    (wq->db_format != LPFC_DB_RING_FORMAT)) {
+				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+						"3265 WQ[%d] doorbell format "
+						"not supported: x%x\n",
+						wq->queue_id, wq->db_format);
+				status = -EINVAL;
+				goto out;
+			}
+			pci_barset = bf_get(lpfc_mbx_wq_create_bar_set,
+					    &wq_create->u.response);
+			bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
+								   pci_barset);
+			if (!bar_memmap_p) {
+				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+						"3263 WQ[%d] failed to memmap "
+						"pci barset:x%x\n",
+						wq->queue_id, pci_barset);
+				status = -ENOMEM;
+				goto out;
+			}
+			db_offset = wq_create->u.response.doorbell_offset;
+			if ((db_offset != LPFC_ULP0_WQ_DOORBELL) &&
+			    (db_offset != LPFC_ULP1_WQ_DOORBELL)) {
+				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+						"3252 WQ[%d] doorbell offset "
+						"not supported: x%x\n",
+						wq->queue_id, db_offset);
+				status = -EINVAL;
+				goto out;
+			}
+			wq->db_regaddr = bar_memmap_p + db_offset;
+			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+					"3264 WQ[%d]: barset:x%x, offset:x%x, "
+					"format:x%x\n", wq->queue_id,
+					pci_barset, db_offset, wq->db_format);
+		} else
+			wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
 	} else {
 	} else {
-		wq->db_format = LPFC_DB_LIST_FORMAT;
-		wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
+		/* Check if DPP was honored by the firmware */
+		wq->dpp_enable = bf_get(lpfc_mbx_wq_create_dpp_rsp,
+				    &wq_create->u.response_1);
+		if (wq->dpp_enable) {
+			pci_barset = bf_get(lpfc_mbx_wq_create_v1_bar_set,
+					    &wq_create->u.response_1);
+			bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
+								   pci_barset);
+			if (!bar_memmap_p) {
+				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+						"3267 WQ[%d] failed to memmap "
+						"pci barset:x%x\n",
+						wq->queue_id, pci_barset);
+				status = -ENOMEM;
+				goto out;
+			}
+			db_offset = wq_create->u.response_1.doorbell_offset;
+			wq->db_regaddr = bar_memmap_p + db_offset;
+			wq->dpp_id = bf_get(lpfc_mbx_wq_create_dpp_id,
+					    &wq_create->u.response_1);
+			dpp_barset = bf_get(lpfc_mbx_wq_create_dpp_bar,
+					    &wq_create->u.response_1);
+			bar_memmap_p = lpfc_dual_chute_pci_bar_map(phba,
+								   dpp_barset);
+			if (!bar_memmap_p) {
+				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+						"3268 WQ[%d] failed to memmap "
+						"pci barset:x%x\n",
+						wq->queue_id, dpp_barset);
+				status = -ENOMEM;
+				goto out;
+			}
+			dpp_offset = wq_create->u.response_1.dpp_offset;
+			wq->dpp_regaddr = bar_memmap_p + dpp_offset;
+			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+					"3271 WQ[%d]: barset:x%x, offset:x%x, "
+					"dpp_id:x%x dpp_barset:x%x "
+					"dpp_offset:x%x\n",
+					wq->queue_id, pci_barset, db_offset,
+					wq->dpp_id, dpp_barset, dpp_offset);
+
+			/* Enable combined writes for DPP aperture */
+			pg_addr = (unsigned long)(wq->dpp_regaddr) & PAGE_MASK;
+#ifdef CONFIG_X86
+			rc = set_memory_wc(pg_addr, 1);
+			if (rc) {
+				lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"3272 Cannot setup Combined "
+					"Write on WQ[%d] - disable DPP\n",
+					wq->queue_id);
+				phba->cfg_enable_dpp = 0;
+			}
+#else
+			phba->cfg_enable_dpp = 0;
+#endif
+		} else
+			wq->db_regaddr = phba->sli4_hba.WQDBregaddr;
 	}
 	}
 	wq->pring = kzalloc(sizeof(struct lpfc_sli_ring), GFP_KERNEL);
 	wq->pring = kzalloc(sizeof(struct lpfc_sli_ring), GFP_KERNEL);
 	if (wq->pring == NULL) {
 	if (wq->pring == NULL) {
@@ -18616,6 +18892,7 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
 				"status x%x add_status x%x, mbx status x%x\n",
 				"status x%x add_status x%x, mbx status x%x\n",
 				shdr_status, shdr_add_status, rc);
 				shdr_status, shdr_add_status, rc);
 		rc = -ENXIO;
 		rc = -ENXIO;
+		*offset = shdr_add_status;
 	} else
 	} else
 		*offset += wr_object->u.response.actual_write_length;
 		*offset += wr_object->u.response.actual_write_length;
 	return rc;
 	return rc;
@@ -18753,8 +19030,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
 	unsigned long iflags = 0;
 	unsigned long iflags = 0;
 	char *fail_msg = NULL;
 	char *fail_msg = NULL;
 	struct lpfc_sglq *sglq;
 	struct lpfc_sglq *sglq;
-	union lpfc_wqe128 wqe128;
-	union lpfc_wqe *wqe = (union lpfc_wqe *) &wqe128;
+	union lpfc_wqe128 wqe;
 	uint32_t txq_cnt = 0;
 	uint32_t txq_cnt = 0;
 
 
 	pring = lpfc_phba_elsring(phba);
 	pring = lpfc_phba_elsring(phba);
@@ -18797,9 +19073,9 @@ lpfc_drain_txq(struct lpfc_hba *phba)
 		piocbq->sli4_xritag = sglq->sli4_xritag;
 		piocbq->sli4_xritag = sglq->sli4_xritag;
 		if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
 		if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
 			fail_msg = "to convert bpl to sgl";
 			fail_msg = "to convert bpl to sgl";
-		else if (lpfc_sli4_iocb2wqe(phba, piocbq, wqe))
+		else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe))
 			fail_msg = "to convert iocb to wqe";
 			fail_msg = "to convert iocb to wqe";
-		else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, wqe))
+		else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
 			fail_msg = " - Wq is full";
 			fail_msg = " - Wq is full";
 		else
 		else
 			lpfc_sli_ringtxcmpl_put(phba, pring, piocbq);
 			lpfc_sli_ringtxcmpl_put(phba, pring, piocbq);
@@ -18849,7 +19125,7 @@ lpfc_wqe_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeq,
 	struct ulp_bde64 bde;
 	struct ulp_bde64 bde;
 	struct sli4_sge *sgl  = NULL;
 	struct sli4_sge *sgl  = NULL;
 	struct lpfc_dmabuf *dmabuf;
 	struct lpfc_dmabuf *dmabuf;
-	union lpfc_wqe *wqe;
+	union lpfc_wqe128 *wqe;
 	int numBdes = 0;
 	int numBdes = 0;
 	int i = 0;
 	int i = 0;
 	uint32_t offset = 0; /* accumulated offset in the sg request list */
 	uint32_t offset = 0; /* accumulated offset in the sg request list */
@@ -18958,7 +19234,7 @@ int
 lpfc_sli4_issue_wqe(struct lpfc_hba *phba, uint32_t ring_number,
 lpfc_sli4_issue_wqe(struct lpfc_hba *phba, uint32_t ring_number,
 		    struct lpfc_iocbq *pwqe)
 		    struct lpfc_iocbq *pwqe)
 {
 {
-	union lpfc_wqe *wqe = &pwqe->wqe;
+	union lpfc_wqe128 *wqe = &pwqe->wqe;
 	struct lpfc_nvmet_rcv_ctx *ctxp;
 	struct lpfc_nvmet_rcv_ctx *ctxp;
 	struct lpfc_queue *wq;
 	struct lpfc_queue *wq;
 	struct lpfc_sglq *sglq;
 	struct lpfc_sglq *sglq;

+ 3 - 3
drivers/scsi/lpfc/lpfc_sli.h

@@ -61,9 +61,8 @@ struct lpfc_iocbq {
 	struct lpfc_wcqe_complete wcqe_cmpl;	/* WQE cmpl */
 	struct lpfc_wcqe_complete wcqe_cmpl;	/* WQE cmpl */
 	uint64_t isr_timestamp;
 	uint64_t isr_timestamp;
 
 
-	/* Be careful here */
-	union lpfc_wqe wqe;	/* WQE cmd */
-	IOCB_t iocb;		/* For IOCB cmd or if we want 128 byte WQE */
+	union lpfc_wqe128 wqe;	/* SLI-4 */
+	IOCB_t iocb;		/* SLI-3 */
 
 
 	uint8_t rsvd2;
 	uint8_t rsvd2;
 	uint8_t priority;	/* OAS priority */
 	uint8_t priority;	/* OAS priority */
@@ -148,6 +147,7 @@ typedef struct lpfcMboxq {
 	struct lpfc_vport *vport;/* virtual port pointer */
 	struct lpfc_vport *vport;/* virtual port pointer */
 	void *context1;		/* caller context information */
 	void *context1;		/* caller context information */
 	void *context2;		/* caller context information */
 	void *context2;		/* caller context information */
+	void *context3;
 
 
 	void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
 	void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
 	uint8_t mbox_flag;
 	uint8_t mbox_flag;

+ 36 - 6
drivers/scsi/lpfc/lpfc_sli4.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2009-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2009-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -145,6 +145,7 @@ struct lpfc_rqb {
 struct lpfc_queue {
 struct lpfc_queue {
 	struct list_head list;
 	struct list_head list;
 	struct list_head wq_list;
 	struct list_head wq_list;
+	struct list_head wqfull_list;
 	enum lpfc_sli4_queue_type type;
 	enum lpfc_sli4_queue_type type;
 	enum lpfc_sli4_queue_subtype subtype;
 	enum lpfc_sli4_queue_subtype subtype;
 	struct lpfc_hba *phba;
 	struct lpfc_hba *phba;
@@ -173,10 +174,16 @@ struct lpfc_queue {
 #define LPFC_EXPANDED_PAGE_SIZE	16384
 #define LPFC_EXPANDED_PAGE_SIZE	16384
 #define LPFC_DEFAULT_PAGE_SIZE	4096
 #define LPFC_DEFAULT_PAGE_SIZE	4096
 	uint16_t chann;		/* IO channel this queue is associated with */
 	uint16_t chann;		/* IO channel this queue is associated with */
-	uint16_t db_format;
+	uint8_t db_format;
 #define LPFC_DB_RING_FORMAT	0x01
 #define LPFC_DB_RING_FORMAT	0x01
 #define LPFC_DB_LIST_FORMAT	0x02
 #define LPFC_DB_LIST_FORMAT	0x02
+	uint8_t q_flag;
+#define HBA_NVMET_WQFULL	0x1 /* We hit WQ Full condition for NVMET */
 	void __iomem *db_regaddr;
 	void __iomem *db_regaddr;
+	uint16_t dpp_enable;
+	uint16_t dpp_id;
+	void __iomem *dpp_regaddr;
+
 	/* For q stats */
 	/* For q stats */
 	uint32_t q_cnt_1;
 	uint32_t q_cnt_1;
 	uint32_t q_cnt_2;
 	uint32_t q_cnt_2;
@@ -209,6 +216,7 @@ struct lpfc_queue {
 	struct work_struct spwork;
 	struct work_struct spwork;
 
 
 	uint64_t isr_timestamp;
 	uint64_t isr_timestamp;
+	uint8_t	qe_valid;
 	struct lpfc_queue *assoc_qp;
 	struct lpfc_queue *assoc_qp;
 	union sli4_qe qe[1];	/* array to index entries (must be last) */
 	union sli4_qe qe[1];	/* array to index entries (must be last) */
 };
 };
@@ -479,12 +487,19 @@ struct lpfc_pc_sli4_params {
 	uint8_t mqv;
 	uint8_t mqv;
 	uint8_t wqv;
 	uint8_t wqv;
 	uint8_t rqv;
 	uint8_t rqv;
+	uint8_t eqav;
+	uint8_t cqav;
 	uint8_t wqsize;
 	uint8_t wqsize;
 #define LPFC_WQ_SZ64_SUPPORT	1
 #define LPFC_WQ_SZ64_SUPPORT	1
 #define LPFC_WQ_SZ128_SUPPORT	2
 #define LPFC_WQ_SZ128_SUPPORT	2
 	uint8_t wqpcnt;
 	uint8_t wqpcnt;
 };
 };
 
 
+#define LPFC_CQ_4K_PAGE_SZ	0x1
+#define LPFC_CQ_16K_PAGE_SZ	0x4
+#define LPFC_WQ_4K_PAGE_SZ	0x1
+#define LPFC_WQ_16K_PAGE_SZ	0x4
+
 struct lpfc_iov {
 struct lpfc_iov {
 	uint32_t pf_number;
 	uint32_t pf_number;
 	uint32_t vf_number;
 	uint32_t vf_number;
@@ -516,11 +531,17 @@ struct lpfc_vector_map_info {
 /* SLI4 HBA data structure entries */
 /* SLI4 HBA data structure entries */
 struct lpfc_sli4_hba {
 struct lpfc_sli4_hba {
 	void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
 	void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for
-					     PCI BAR0, config space registers */
+					   * config space registers
+					   */
 	void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for
 	void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for
-					     PCI BAR1, control registers */
+					   * control registers
+					   */
 	void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for
 	void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for
-					     PCI BAR2, doorbell registers */
+					   * doorbell registers
+					   */
+	void __iomem *dpp_regs_memmap_p;  /* Kernel memory mapped address for
+					   * dpp registers
+					   */
 	union {
 	union {
 		struct {
 		struct {
 			/* IF Type 0, BAR 0 PCI cfg space reg mem map */
 			/* IF Type 0, BAR 0 PCI cfg space reg mem map */
@@ -561,7 +582,8 @@ struct lpfc_sli4_hba {
 	/* IF type 0, BAR 0 and if type 2, BAR 0 doorbell register memory map */
 	/* IF type 0, BAR 0 and if type 2, BAR 0 doorbell register memory map */
 	void __iomem *RQDBregaddr;	/* RQ_DOORBELL register */
 	void __iomem *RQDBregaddr;	/* RQ_DOORBELL register */
 	void __iomem *WQDBregaddr;	/* WQ_DOORBELL register */
 	void __iomem *WQDBregaddr;	/* WQ_DOORBELL register */
-	void __iomem *EQCQDBregaddr;	/* EQCQ_DOORBELL register */
+	void __iomem *CQDBregaddr;	/* CQ_DOORBELL register */
+	void __iomem *EQDBregaddr;	/* EQ_DOORBELL register */
 	void __iomem *MQDBregaddr;	/* MQ_DOORBELL register */
 	void __iomem *MQDBregaddr;	/* MQ_DOORBELL register */
 	void __iomem *BMBXregaddr;	/* BootStrap MBX register */
 	void __iomem *BMBXregaddr;	/* BootStrap MBX register */
 
 
@@ -574,6 +596,10 @@ struct lpfc_sli4_hba {
 	struct lpfc_bbscn_params bbscn_params;
 	struct lpfc_bbscn_params bbscn_params;
 	struct lpfc_hba_eq_hdl *hba_eq_hdl; /* HBA per-WQ handle */
 	struct lpfc_hba_eq_hdl *hba_eq_hdl; /* HBA per-WQ handle */
 
 
+	void (*sli4_eq_clr_intr)(struct lpfc_queue *q);
+	uint32_t (*sli4_eq_release)(struct lpfc_queue *q, bool arm);
+	uint32_t (*sli4_cq_release)(struct lpfc_queue *q, bool arm);
+
 	/* Pointers to the constructed SLI4 queues */
 	/* Pointers to the constructed SLI4 queues */
 	struct lpfc_queue **hba_eq;  /* Event queues for HBA */
 	struct lpfc_queue **hba_eq;  /* Event queues for HBA */
 	struct lpfc_queue **fcp_cq;  /* Fast-path FCP compl queue */
 	struct lpfc_queue **fcp_cq;  /* Fast-path FCP compl queue */
@@ -840,8 +866,12 @@ void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *);
 int lpfc_sli4_get_els_iocb_cnt(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_get_iocb_cnt(struct lpfc_hba *phba);
 int lpfc_sli4_init_vpi(struct lpfc_vport *);
 int lpfc_sli4_init_vpi(struct lpfc_vport *);
+inline void lpfc_sli4_eq_clr_intr(struct lpfc_queue *);
 uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool);
 uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool);
 uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool);
 uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool);
+inline void lpfc_sli4_if6_eq_clr_intr(struct lpfc_queue *q);
+uint32_t lpfc_sli4_if6_cq_release(struct lpfc_queue *q, bool arm);
+uint32_t lpfc_sli4_if6_eq_release(struct lpfc_queue *q, bool arm);
 void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t);
 void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t);
 int lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *, uint16_t);
 int lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *, uint16_t);
 int lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *, uint16_t);
 int lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *, uint16_t);

+ 4 - 4
drivers/scsi/lpfc/lpfc_version.h

@@ -1,7 +1,7 @@
 /*******************************************************************
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2017 Broadcom. All Rights Reserved. The term      *
+ * Copyright (C) 2017-2018 Broadcom. All Rights Reserved. The term *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * “Broadcom” refers to Broadcom Limited and/or its subsidiaries.  *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * EMULEX and SLI are trademarks of Emulex.                        *
@@ -20,7 +20,7 @@
  * included with this package.                                     *
  * included with this package.                                     *
  *******************************************************************/
  *******************************************************************/
 
 
-#define LPFC_DRIVER_VERSION "11.4.0.6"
+#define LPFC_DRIVER_VERSION "12.0.0.1"
 #define LPFC_DRIVER_NAME		"lpfc"
 #define LPFC_DRIVER_NAME		"lpfc"
 
 
 /* Used for SLI 2/3 */
 /* Used for SLI 2/3 */
@@ -32,6 +32,6 @@
 
 
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
 		LPFC_DRIVER_VERSION
 		LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright (C) 2017 Broadcom. All Rights Reserved. " \
-		"The term \"Broadcom\" refers to Broadcom Limited " \
+#define LPFC_COPYRIGHT "Copyright (C) 2017-2018 Broadcom. All Rights " \
+		"Reserved. The term \"Broadcom\" refers to Broadcom Limited " \
 		"and/or its subsidiaries."
 		"and/or its subsidiaries."

+ 1 - 2
drivers/scsi/megaraid/megaraid_sas_base.c

@@ -4022,7 +4022,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
 
 
 		cmd = instance->cmd_list[i];
 		cmd = instance->cmd_list[i];
 
 
-		cmd->frame = dma_pool_alloc(instance->frame_dma_pool,
+		cmd->frame = dma_pool_zalloc(instance->frame_dma_pool,
 					    GFP_KERNEL, &cmd->frame_phys_addr);
 					    GFP_KERNEL, &cmd->frame_phys_addr);
 
 
 		cmd->sense = dma_pool_alloc(instance->sense_dma_pool,
 		cmd->sense = dma_pool_alloc(instance->sense_dma_pool,
@@ -4038,7 +4038,6 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
 			return -ENOMEM;
 			return -ENOMEM;
 		}
 		}
 
 
-		memset(cmd->frame, 0, instance->mfi_frame_size);
 		cmd->frame->io.context = cpu_to_le32(cmd->index);
 		cmd->frame->io.context = cpu_to_le32(cmd->index);
 		cmd->frame->io.pad_0 = 0;
 		cmd->frame->io.pad_0 = 0;
 		if ((instance->adapter_type == MFI_SERIES) && reset_devices)
 		if ((instance->adapter_type == MFI_SERIES) && reset_devices)

+ 1 - 0
drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h

@@ -524,6 +524,7 @@ typedef struct _MPI2_CONFIG_REPLY {
 #define MPI2_MFGPAGE_DEVID_SAS2308_1                (0x0086)
 #define MPI2_MFGPAGE_DEVID_SAS2308_1                (0x0086)
 #define MPI2_MFGPAGE_DEVID_SAS2308_2                (0x0087)
 #define MPI2_MFGPAGE_DEVID_SAS2308_2                (0x0087)
 #define MPI2_MFGPAGE_DEVID_SAS2308_3                (0x006E)
 #define MPI2_MFGPAGE_DEVID_SAS2308_3                (0x006E)
+#define MPI2_MFGPAGE_DEVID_SAS2308_MPI_EP           (0x02B0)
 
 
 /*MPI v2.5 SAS products */
 /*MPI v2.5 SAS products */
 #define MPI25_MFGPAGE_DEVID_SAS3004                 (0x0096)
 #define MPI25_MFGPAGE_DEVID_SAS3004                 (0x0096)

+ 521 - 178
drivers/scsi/mpt3sas/mpt3sas_base.c

@@ -125,6 +125,362 @@ _scsih_set_fwfault_debug(const char *val, const struct kernel_param *kp)
 module_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug,
 module_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug,
 	param_get_int, &mpt3sas_fwfault_debug, 0644);
 	param_get_int, &mpt3sas_fwfault_debug, 0644);
 
 
+/**
+ * _base_clone_reply_to_sys_mem - copies reply to reply free iomem
+ *				  in BAR0 space.
+ *
+ * @ioc: per adapter object
+ * @reply: reply message frame(lower 32bit addr)
+ * @index: System request message index.
+ *
+ * @Returns - Nothing
+ */
+static void
+_base_clone_reply_to_sys_mem(struct MPT3SAS_ADAPTER *ioc, u32 reply,
+		u32 index)
+{
+	/*
+	 * 256 is offset within sys register.
+	 * 256 offset MPI frame starts. Max MPI frame supported is 32.
+	 * 32 * 128 = 4K. From here, Clone of reply free for mcpu starts
+	 */
+	u16 cmd_credit = ioc->facts.RequestCredit + 1;
+	void __iomem *reply_free_iomem = (void __iomem *)ioc->chip +
+			MPI_FRAME_START_OFFSET +
+			(cmd_credit * ioc->request_sz) + (index * sizeof(u32));
+
+	writel(reply, reply_free_iomem);
+}
+
+/**
+ * _base_clone_mpi_to_sys_mem - Writes/copies MPI frames
+ *				to system/BAR0 region.
+ *
+ * @dst_iomem: Pointer to the destinaltion location in BAR0 space.
+ * @src: Pointer to the Source data.
+ * @size: Size of data to be copied.
+ */
+static void
+_base_clone_mpi_to_sys_mem(void *dst_iomem, void *src, u32 size)
+{
+	int i;
+	u32 *src_virt_mem = (u32 *)src;
+
+	for (i = 0; i < size/4; i++)
+		writel((u32)src_virt_mem[i],
+				(void __iomem *)dst_iomem + (i * 4));
+}
+
+/**
+ * _base_clone_to_sys_mem - Writes/copies data to system/BAR0 region
+ *
+ * @dst_iomem: Pointer to the destination location in BAR0 space.
+ * @src: Pointer to the Source data.
+ * @size: Size of data to be copied.
+ */
+static void
+_base_clone_to_sys_mem(void __iomem *dst_iomem, void *src, u32 size)
+{
+	int i;
+	u32 *src_virt_mem = (u32 *)(src);
+
+	for (i = 0; i < size/4; i++)
+		writel((u32)src_virt_mem[i],
+			(void __iomem *)dst_iomem + (i * 4));
+}
+
+/**
+ * _base_get_chain - Calculates and Returns virtual chain address
+ *			 for the provided smid in BAR0 space.
+ *
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @sge_chain_count: Scatter gather chain count.
+ *
+ * @Return: chain address.
+ */
+static inline void __iomem*
+_base_get_chain(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+		u8 sge_chain_count)
+{
+	void __iomem *base_chain, *chain_virt;
+	u16 cmd_credit = ioc->facts.RequestCredit + 1;
+
+	base_chain  = (void __iomem *)ioc->chip + MPI_FRAME_START_OFFSET +
+		(cmd_credit * ioc->request_sz) +
+		REPLY_FREE_POOL_SIZE;
+	chain_virt = base_chain + (smid * ioc->facts.MaxChainDepth *
+			ioc->request_sz) + (sge_chain_count * ioc->request_sz);
+	return chain_virt;
+}
+
+/**
+ * _base_get_chain_phys - Calculates and Returns physical address
+ *			in BAR0 for scatter gather chains, for
+ *			the provided smid.
+ *
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @sge_chain_count: Scatter gather chain count.
+ *
+ * @Return - Physical chain address.
+ */
+static inline phys_addr_t
+_base_get_chain_phys(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+		u8 sge_chain_count)
+{
+	phys_addr_t base_chain_phys, chain_phys;
+	u16 cmd_credit = ioc->facts.RequestCredit + 1;
+
+	base_chain_phys  = ioc->chip_phys + MPI_FRAME_START_OFFSET +
+		(cmd_credit * ioc->request_sz) +
+		REPLY_FREE_POOL_SIZE;
+	chain_phys = base_chain_phys + (smid * ioc->facts.MaxChainDepth *
+			ioc->request_sz) + (sge_chain_count * ioc->request_sz);
+	return chain_phys;
+}
+
+/**
+ * _base_get_buffer_bar0 - Calculates and Returns BAR0 mapped Host
+ *			buffer address for the provided smid.
+ *			(Each smid can have 64K starts from 17024)
+ *
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * @Returns - Pointer to buffer location in BAR0.
+ */
+
+static void __iomem *
+_base_get_buffer_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+	u16 cmd_credit = ioc->facts.RequestCredit + 1;
+	// Added extra 1 to reach end of chain.
+	void __iomem *chain_end = _base_get_chain(ioc,
+			cmd_credit + 1,
+			ioc->facts.MaxChainDepth);
+	return chain_end + (smid * 64 * 1024);
+}
+
+/**
+ * _base_get_buffer_phys_bar0 - Calculates and Returns BAR0 mapped
+ *		Host buffer Physical address for the provided smid.
+ *		(Each smid can have 64K starts from 17024)
+ *
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * @Returns - Pointer to buffer location in BAR0.
+ */
+static phys_addr_t
+_base_get_buffer_phys_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+	u16 cmd_credit = ioc->facts.RequestCredit + 1;
+	phys_addr_t chain_end_phys = _base_get_chain_phys(ioc,
+			cmd_credit + 1,
+			ioc->facts.MaxChainDepth);
+	return chain_end_phys + (smid * 64 * 1024);
+}
+
+/**
+ * _base_get_chain_buffer_dma_to_chain_buffer - Iterates chain
+ *			lookup list and Provides chain_buffer
+ *			address for the matching dma address.
+ *			(Each smid can have 64K starts from 17024)
+ *
+ * @ioc: per adapter object
+ * @chain_buffer_dma: Chain buffer dma address.
+ *
+ * @Returns - Pointer to chain buffer. Or Null on Failure.
+ */
+static void *
+_base_get_chain_buffer_dma_to_chain_buffer(struct MPT3SAS_ADAPTER *ioc,
+		dma_addr_t chain_buffer_dma)
+{
+	u16 index;
+
+	for (index = 0; index < ioc->chain_depth; index++) {
+		if (ioc->chain_lookup[index].chain_buffer_dma ==
+				chain_buffer_dma)
+			return ioc->chain_lookup[index].chain_buffer;
+	}
+	pr_info(MPT3SAS_FMT
+	    "Provided chain_buffer_dma address is not in the lookup list\n",
+	    ioc->name);
+	return NULL;
+}
+
+/**
+ * _clone_sg_entries -	MPI EP's scsiio and config requests
+ *			are handled here. Base function for
+ *			double buffering, before submitting
+ *			the requests.
+ *
+ * @ioc: per adapter object.
+ * @mpi_request: mf request pointer.
+ * @smid: system request message index.
+ *
+ * @Returns: Nothing.
+ */
+static void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc,
+		void *mpi_request, u16 smid)
+{
+	Mpi2SGESimple32_t *sgel, *sgel_next;
+	u32  sgl_flags, sge_chain_count = 0;
+	bool is_write = 0;
+	u16 i = 0;
+	void __iomem *buffer_iomem;
+	phys_addr_t buffer_iomem_phys;
+	void __iomem *buff_ptr;
+	phys_addr_t buff_ptr_phys;
+	void __iomem *dst_chain_addr[MCPU_MAX_CHAINS_PER_IO];
+	void *src_chain_addr[MCPU_MAX_CHAINS_PER_IO];
+	phys_addr_t dst_addr_phys;
+	MPI2RequestHeader_t *request_hdr;
+	struct scsi_cmnd *scmd;
+	struct scatterlist *sg_scmd = NULL;
+	int is_scsiio_req = 0;
+
+	request_hdr = (MPI2RequestHeader_t *) mpi_request;
+
+	if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) {
+		Mpi25SCSIIORequest_t *scsiio_request =
+			(Mpi25SCSIIORequest_t *)mpi_request;
+		sgel = (Mpi2SGESimple32_t *) &scsiio_request->SGL;
+		is_scsiio_req = 1;
+	} else if (request_hdr->Function == MPI2_FUNCTION_CONFIG) {
+		Mpi2ConfigRequest_t  *config_req =
+			(Mpi2ConfigRequest_t *)mpi_request;
+		sgel = (Mpi2SGESimple32_t *) &config_req->PageBufferSGE;
+	} else
+		return;
+
+	/* From smid we can get scsi_cmd, once we have sg_scmd,
+	 * we just need to get sg_virt and sg_next to get virual
+	 * address associated with sgel->Address.
+	 */
+
+	if (is_scsiio_req) {
+		/* Get scsi_cmd using smid */
+		scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid);
+		if (scmd == NULL) {
+			pr_err(MPT3SAS_FMT "scmd is NULL\n", ioc->name);
+			return;
+		}
+
+		/* Get sg_scmd from scmd provided */
+		sg_scmd = scsi_sglist(scmd);
+	}
+
+	/*
+	 * 0 - 255	System register
+	 * 256 - 4352	MPI Frame. (This is based on maxCredit 32)
+	 * 4352 - 4864	Reply_free pool (512 byte is reserved
+	 *		considering maxCredit 32. Reply need extra
+	 *		room, for mCPU case kept four times of
+	 *		maxCredit).
+	 * 4864 - 17152	SGE chain element. (32cmd * 3 chain of
+	 *		128 byte size = 12288)
+	 * 17152 - x	Host buffer mapped with smid.
+	 *		(Each smid can have 64K Max IO.)
+	 * BAR0+Last 1K MSIX Addr and Data
+	 * Total size in use 2113664 bytes of 4MB BAR0
+	 */
+
+	buffer_iomem = _base_get_buffer_bar0(ioc, smid);
+	buffer_iomem_phys = _base_get_buffer_phys_bar0(ioc, smid);
+
+	buff_ptr = buffer_iomem;
+	buff_ptr_phys = buffer_iomem_phys;
+	WARN_ON(buff_ptr_phys > U32_MAX);
+
+	if (sgel->FlagsLength &
+			(MPI2_SGE_FLAGS_HOST_TO_IOC << MPI2_SGE_FLAGS_SHIFT))
+		is_write = 1;
+
+	for (i = 0; i < MPT_MIN_PHYS_SEGMENTS + ioc->facts.MaxChainDepth; i++) {
+
+		sgl_flags = (sgel->FlagsLength >> MPI2_SGE_FLAGS_SHIFT);
+
+		switch (sgl_flags & MPI2_SGE_FLAGS_ELEMENT_MASK) {
+		case MPI2_SGE_FLAGS_CHAIN_ELEMENT:
+			/*
+			 * Helper function which on passing
+			 * chain_buffer_dma returns chain_buffer. Get
+			 * the virtual address for sgel->Address
+			 */
+			sgel_next =
+				_base_get_chain_buffer_dma_to_chain_buffer(ioc,
+						sgel->Address);
+			if (sgel_next == NULL)
+				return;
+			/*
+			 * This is coping 128 byte chain
+			 * frame (not a host buffer)
+			 */
+			dst_chain_addr[sge_chain_count] =
+				_base_get_chain(ioc,
+					smid, sge_chain_count);
+			src_chain_addr[sge_chain_count] =
+						(void *) sgel_next;
+			dst_addr_phys = _base_get_chain_phys(ioc,
+						smid, sge_chain_count);
+			WARN_ON(dst_addr_phys > U32_MAX);
+			sgel->Address = (u32)dst_addr_phys;
+			sgel = sgel_next;
+			sge_chain_count++;
+			break;
+		case MPI2_SGE_FLAGS_SIMPLE_ELEMENT:
+			if (is_write) {
+				if (is_scsiio_req) {
+					_base_clone_to_sys_mem(buff_ptr,
+					    sg_virt(sg_scmd),
+					    (sgel->FlagsLength & 0x00ffffff));
+					/*
+					 * FIXME: this relies on a a zero
+					 * PCI mem_offset.
+					 */
+					sgel->Address = (u32)buff_ptr_phys;
+				} else {
+					_base_clone_to_sys_mem(buff_ptr,
+					    ioc->config_vaddr,
+					    (sgel->FlagsLength & 0x00ffffff));
+					sgel->Address = (u32)buff_ptr_phys;
+				}
+			}
+			buff_ptr += (sgel->FlagsLength & 0x00ffffff);
+			buff_ptr_phys += (sgel->FlagsLength & 0x00ffffff);
+			if ((sgel->FlagsLength &
+			    (MPI2_SGE_FLAGS_END_OF_BUFFER
+					<< MPI2_SGE_FLAGS_SHIFT)))
+				goto eob_clone_chain;
+			else {
+				/*
+				 * Every single element in MPT will have
+				 * associated sg_next. Better to sanity that
+				 * sg_next is not NULL, but it will be a bug
+				 * if it is null.
+				 */
+				if (is_scsiio_req) {
+					sg_scmd = sg_next(sg_scmd);
+					if (sg_scmd)
+						sgel++;
+					else
+						goto eob_clone_chain;
+				}
+			}
+			break;
+		}
+	}
+
+eob_clone_chain:
+	for (i = 0; i < sge_chain_count; i++) {
+		if (is_scsiio_req)
+			_base_clone_to_sys_mem(dst_chain_addr[i],
+				src_chain_addr[i], ioc->request_sz);
+	}
+}
+
 /**
 /**
  *  mpt3sas_remove_dead_ioc_func - kthread context to remove dead ioc
  *  mpt3sas_remove_dead_ioc_func - kthread context to remove dead ioc
  * @arg: input argument, used to derive ioc
  * @arg: input argument, used to derive ioc
@@ -875,7 +1231,7 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
 	ack_request->EventContext = mpi_reply->EventContext;
 	ack_request->EventContext = mpi_reply->EventContext;
 	ack_request->VF_ID = 0;  /* TODO */
 	ack_request->VF_ID = 0;  /* TODO */
 	ack_request->VP_ID = 0;
 	ack_request->VP_ID = 0;
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 
 
  out:
  out:
 
 
@@ -1075,6 +1431,10 @@ _base_interrupt(int irq, void *bus_id)
 				    0 : ioc->reply_free_host_index + 1;
 				    0 : ioc->reply_free_host_index + 1;
 				ioc->reply_free[ioc->reply_free_host_index] =
 				ioc->reply_free[ioc->reply_free_host_index] =
 				    cpu_to_le32(reply);
 				    cpu_to_le32(reply);
+				if (ioc->is_mcpu_endpoint)
+					_base_clone_reply_to_sys_mem(ioc,
+						cpu_to_le32(reply),
+						ioc->reply_free_host_index);
 				writel(ioc->reply_free_host_index,
 				writel(ioc->reply_free_host_index,
 				    &ioc->chip->ReplyFreeHostIndex);
 				    &ioc->chip->ReplyFreeHostIndex);
 			}
 			}
@@ -2214,6 +2574,9 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
 	struct sysinfo s;
 	struct sysinfo s;
 	u64 consistent_dma_mask;
 	u64 consistent_dma_mask;
 
 
+	if (ioc->is_mcpu_endpoint)
+		goto try_32bit;
+
 	if (ioc->dma_mask)
 	if (ioc->dma_mask)
 		consistent_dma_mask = DMA_BIT_MASK(64);
 		consistent_dma_mask = DMA_BIT_MASK(64);
 	else
 	else
@@ -2232,6 +2595,7 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
 		}
 		}
 	}
 	}
 
 
+ try_32bit:
 	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
 	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
 	    && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
 	    && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
 		ioc->base_add_sg_single = &_base_add_sg_single_32;
 		ioc->base_add_sg_single = &_base_add_sg_single_32;
@@ -2581,7 +2945,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
 	u32 pio_sz;
 	u32 pio_sz;
 	int i, r = 0;
 	int i, r = 0;
 	u64 pio_chip = 0;
 	u64 pio_chip = 0;
-	u64 chip_phys = 0;
+	phys_addr_t chip_phys = 0;
 	struct adapter_reply_queue *reply_q;
 	struct adapter_reply_queue *reply_q;
 
 
 	dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n",
 	dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n",
@@ -2629,7 +2993,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
 			if (memap_sz)
 			if (memap_sz)
 				continue;
 				continue;
 			ioc->chip_phys = pci_resource_start(pdev, i);
 			ioc->chip_phys = pci_resource_start(pdev, i);
-			chip_phys = (u64)ioc->chip_phys;
+			chip_phys = ioc->chip_phys;
 			memap_sz = pci_resource_len(pdev, i);
 			memap_sz = pci_resource_len(pdev, i);
 			ioc->chip = ioremap(ioc->chip_phys, memap_sz);
 			ioc->chip = ioremap(ioc->chip_phys, memap_sz);
 		}
 		}
@@ -2704,8 +3068,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
 		    "IO-APIC enabled"),
 		    "IO-APIC enabled"),
 		    pci_irq_vector(ioc->pdev, reply_q->msix_index));
 		    pci_irq_vector(ioc->pdev, reply_q->msix_index));
 
 
-	pr_info(MPT3SAS_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
-	    ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz);
+	pr_info(MPT3SAS_FMT "iomem(%pap), mapped(0x%p), size(%d)\n",
+	    ioc->name, &chip_phys, ioc->chip, memap_sz);
 	pr_info(MPT3SAS_FMT "ioport(0x%016llx), size(%d)\n",
 	pr_info(MPT3SAS_FMT "ioport(0x%016llx), size(%d)\n",
 	    ioc->name, (unsigned long long)pio_chip, pio_sz);
 	    ioc->name, (unsigned long long)pio_chip, pio_sz);
 
 
@@ -2960,6 +3324,29 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid)
 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 }
 }
 
 
+/**
+ * _base_mpi_ep_writeq - 32 bit write to MMIO
+ * @b: data payload
+ * @addr: address in MMIO space
+ * @writeq_lock: spin lock
+ *
+ * This special handling for MPI EP to take care of 32 bit
+ * environment where its not quarenteed to send the entire word
+ * in one transfer.
+ */
+static inline void
+_base_mpi_ep_writeq(__u64 b, volatile void __iomem *addr,
+					spinlock_t *writeq_lock)
+{
+	unsigned long flags;
+	__u64 data_out = cpu_to_le64(b);
+
+	spin_lock_irqsave(writeq_lock, flags);
+	writel((u32)(data_out), addr);
+	writel((u32)(data_out >> 32), (addr + 4));
+	spin_unlock_irqrestore(writeq_lock, flags);
+}
+
 /**
 /**
  * _base_writeq - 64 bit write to MMIO
  * _base_writeq - 64 bit write to MMIO
  * @ioc: per adapter object
  * @ioc: per adapter object
@@ -2981,16 +3368,40 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
 static inline void
 static inline void
 _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
 _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock)
 {
 {
-	unsigned long flags;
-	__u64 data_out = cpu_to_le64(b);
-
-	spin_lock_irqsave(writeq_lock, flags);
-	writel((u32)(data_out), addr);
-	writel((u32)(data_out >> 32), (addr + 4));
-	spin_unlock_irqrestore(writeq_lock, flags);
+	_base_mpi_ep_writeq(b, addr, writeq_lock);
 }
 }
 #endif
 #endif
 
 
+/**
+ * _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
+ *
+ * Return nothing.
+ */
+static void
+_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
+{
+	Mpi2RequestDescriptorUnion_t descriptor;
+	u64 *request = (u64 *)&descriptor;
+	void *mpi_req_iomem;
+	__le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid);
+
+	_clone_sg_entries(ioc, (void *) mfp, smid);
+	mpi_req_iomem = (void *)ioc->chip +
+			MPI_FRAME_START_OFFSET + (smid * ioc->request_sz);
+	_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.SMID = cpu_to_le16(smid);
+	descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
+	descriptor.SCSIIO.LMID = 0;
+	_base_mpi_ep_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+	    &ioc->scsi_lookup_lock);
+}
+
 /**
 /**
  * _base_put_smid_scsi_io - send SCSI_IO request to firmware
  * _base_put_smid_scsi_io - send SCSI_IO request to firmware
  * @ioc: per adapter object
  * @ioc: per adapter object
@@ -3016,15 +3427,15 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle)
 }
 }
 
 
 /**
 /**
- * _base_put_smid_fast_path - send fast path request to firmware
+ * mpt3sas_base_put_smid_fast_path - send fast path request to firmware
  * @ioc: per adapter object
  * @ioc: per adapter object
  * @smid: system request message index
  * @smid: system request message index
  * @handle: device handle
  * @handle: device handle
  *
  *
  * Return nothing.
  * Return nothing.
  */
  */
-static void
-_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+void
+mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
 	u16 handle)
 	u16 handle)
 {
 {
 	Mpi2RequestDescriptorUnion_t descriptor;
 	Mpi2RequestDescriptorUnion_t descriptor;
@@ -3041,18 +3452,34 @@ _base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
 }
 }
 
 
 /**
 /**
- * _base_put_smid_hi_priority - send Task Management request to firmware
+ * mpt3sas_base_put_smid_hi_priority - send Task Management request to firmware
  * @ioc: per adapter object
  * @ioc: per adapter object
  * @smid: system request message index
  * @smid: system request message index
  * @msix_task: msix_task will be same as msix of IO incase of task abort else 0.
  * @msix_task: msix_task will be same as msix of IO incase of task abort else 0.
  * Return nothing.
  * Return nothing.
  */
  */
-static void
-_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+void
+mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
 	u16 msix_task)
 	u16 msix_task)
 {
 {
 	Mpi2RequestDescriptorUnion_t descriptor;
 	Mpi2RequestDescriptorUnion_t descriptor;
-	u64 *request = (u64 *)&descriptor;
+	void *mpi_req_iomem;
+	u64 *request;
+
+	if (ioc->is_mcpu_endpoint) {
+		MPI2RequestHeader_t *request_hdr;
+
+		__le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid);
+
+		request_hdr = (MPI2RequestHeader_t *)mfp;
+		/* TBD 256 is offset within sys register. */
+		mpi_req_iomem = (void *)ioc->chip + MPI_FRAME_START_OFFSET
+					+ (smid * ioc->request_sz);
+		_base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp,
+							ioc->request_sz);
+	}
+
+	request = (u64 *)&descriptor;
 
 
 	descriptor.HighPriority.RequestFlags =
 	descriptor.HighPriority.RequestFlags =
 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
 	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
@@ -3060,20 +3487,25 @@ _base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
 	descriptor.HighPriority.SMID = cpu_to_le16(smid);
 	descriptor.HighPriority.SMID = cpu_to_le16(smid);
 	descriptor.HighPriority.LMID = 0;
 	descriptor.HighPriority.LMID = 0;
 	descriptor.HighPriority.Reserved1 = 0;
 	descriptor.HighPriority.Reserved1 = 0;
-	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
-	    &ioc->scsi_lookup_lock);
+	if (ioc->is_mcpu_endpoint)
+		_base_mpi_ep_writeq(*request,
+				&ioc->chip->RequestDescriptorPostLow,
+				&ioc->scsi_lookup_lock);
+	else
+		_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+		    &ioc->scsi_lookup_lock);
 }
 }
 
 
 /**
 /**
- * _base_put_smid_nvme_encap - send NVMe encapsulated request to
+ * mpt3sas_base_put_smid_nvme_encap - send NVMe encapsulated request to
  *  firmware
  *  firmware
  * @ioc: per adapter object
  * @ioc: per adapter object
  * @smid: system request message index
  * @smid: system request message index
  *
  *
  * Return nothing.
  * Return nothing.
  */
  */
-static void
-_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+void
+mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
 {
 {
 	Mpi2RequestDescriptorUnion_t descriptor;
 	Mpi2RequestDescriptorUnion_t descriptor;
 	u64 *request = (u64 *)&descriptor;
 	u64 *request = (u64 *)&descriptor;
@@ -3089,135 +3521,45 @@ _base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid)
 }
 }
 
 
 /**
 /**
- * _base_put_smid_default - Default, primarily used for config pages
+ * mpt3sas_base_put_smid_default - Default, primarily used for config pages
  * @ioc: per adapter object
  * @ioc: per adapter object
  * @smid: system request message index
  * @smid: system request message index
  *
  *
  * Return nothing.
  * Return nothing.
  */
  */
-static void
-_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+void
+mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
 {
 {
 	Mpi2RequestDescriptorUnion_t descriptor;
 	Mpi2RequestDescriptorUnion_t descriptor;
-	u64 *request = (u64 *)&descriptor;
+	void *mpi_req_iomem;
+	u64 *request;
+	MPI2RequestHeader_t *request_hdr;
+
+	if (ioc->is_mcpu_endpoint) {
+		__le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid);
 
 
+		request_hdr = (MPI2RequestHeader_t *)mfp;
+
+		_clone_sg_entries(ioc, (void *) mfp, smid);
+		/* TBD 256 is offset within sys register */
+		mpi_req_iomem = (void *)ioc->chip +
+			MPI_FRAME_START_OFFSET + (smid * ioc->request_sz);
+		_base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp,
+							ioc->request_sz);
+	}
+	request = (u64 *)&descriptor;
 	descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	descriptor.Default.MSIxIndex =  _base_get_msix_index(ioc);
 	descriptor.Default.MSIxIndex =  _base_get_msix_index(ioc);
 	descriptor.Default.SMID = cpu_to_le16(smid);
 	descriptor.Default.SMID = cpu_to_le16(smid);
 	descriptor.Default.LMID = 0;
 	descriptor.Default.LMID = 0;
 	descriptor.Default.DescriptorTypeDependent = 0;
 	descriptor.Default.DescriptorTypeDependent = 0;
-	_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
-	    &ioc->scsi_lookup_lock);
-}
-
-/**
-* _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_get_msix_index(ioc);
-	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_get_msix_index(ioc);
-	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_nvme_encap_atomic - send NVMe encapsulated request to
- *   firmware using Atomic Request Descriptor
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Return nothing.
- */
-static void
-_base_put_smid_nvme_encap_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid)
-{
-	Mpi26AtomicRequestDescriptor_t descriptor;
-	u32 *request = (u32 *)&descriptor;
-
-	descriptor.RequestFlags = MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
-	descriptor.MSIxIndex = _base_get_msix_index(ioc);
-	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_get_msix_index(ioc);
-	descriptor.SMID = cpu_to_le16(smid);
-
-	writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+	if (ioc->is_mcpu_endpoint)
+		_base_mpi_ep_writeq(*request,
+				&ioc->chip->RequestDescriptorPostLow,
+				&ioc->scsi_lookup_lock);
+	else
+		_base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
+				&ioc->scsi_lookup_lock);
 }
 }
 
 
 /**
 /**
@@ -3890,17 +4232,21 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
 		sg_tablesize = min_t(unsigned short, sg_tablesize,
 		sg_tablesize = min_t(unsigned short, sg_tablesize,
 		   MPT_KDUMP_MIN_PHYS_SEGMENTS);
 		   MPT_KDUMP_MIN_PHYS_SEGMENTS);
 
 
-	if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS)
-		sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
-	else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) {
-		sg_tablesize = min_t(unsigned short, sg_tablesize,
-				      SG_MAX_SEGMENTS);
-		pr_warn(MPT3SAS_FMT
-		 "sg_tablesize(%u) is bigger than kernel"
-		 " defined SG_CHUNK_SIZE(%u)\n", ioc->name,
-		 sg_tablesize, MPT_MAX_PHYS_SEGMENTS);
+	if (ioc->is_mcpu_endpoint)
+		ioc->shost->sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
+	else {
+		if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS)
+			sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
+		else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) {
+			sg_tablesize = min_t(unsigned short, sg_tablesize,
+					SG_MAX_SEGMENTS);
+			pr_warn(MPT3SAS_FMT
+				"sg_tablesize(%u) is bigger than kernel "
+				"defined SG_CHUNK_SIZE(%u)\n", ioc->name,
+				sg_tablesize, MPT_MAX_PHYS_SEGMENTS);
+		}
+		ioc->shost->sg_tablesize = sg_tablesize;
 	}
 	}
-	ioc->shost->sg_tablesize = sg_tablesize;
 
 
 	ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)),
 	ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)),
 		(facts->RequestCredit / 4));
 		(facts->RequestCredit / 4));
@@ -3985,13 +4331,18 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
 	/* reply free queue sizing - taking into account for 64 FW events */
 	/* reply free queue sizing - taking into account for 64 FW events */
 	ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
 	ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
 
 
-	/* calculate reply descriptor post queue depth */
-	ioc->reply_post_queue_depth = ioc->hba_queue_depth +
-				ioc->reply_free_queue_depth +  1 ;
-	/* align the reply post queue on the next 16 count boundary */
-	if (ioc->reply_post_queue_depth % 16)
-		ioc->reply_post_queue_depth += 16 -
-		(ioc->reply_post_queue_depth % 16);
+	/* mCPU manage single counters for simplicity */
+	if (ioc->is_mcpu_endpoint)
+		ioc->reply_post_queue_depth = ioc->reply_free_queue_depth;
+	else {
+		/* calculate reply descriptor post queue depth */
+		ioc->reply_post_queue_depth = ioc->hba_queue_depth +
+			ioc->reply_free_queue_depth +  1;
+		/* align the reply post queue on the next 16 count boundary */
+		if (ioc->reply_post_queue_depth % 16)
+			ioc->reply_post_queue_depth += 16 -
+				(ioc->reply_post_queue_depth % 16);
+	}
 
 
 	if (ioc->reply_post_queue_depth >
 	if (ioc->reply_post_queue_depth >
 	    facts->MaxReplyDescriptorPostQueueDepth) {
 	    facts->MaxReplyDescriptorPostQueueDepth) {
@@ -4789,7 +5140,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
 	    mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
 	    mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
 		ioc->ioc_link_reset_in_progress = 1;
 		ioc->ioc_link_reset_in_progress = 1;
 	init_completion(&ioc->base_cmds.done);
 	init_completion(&ioc->base_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->base_cmds.done,
 	wait_for_completion_timeout(&ioc->base_cmds.done,
 	    msecs_to_jiffies(10000));
 	    msecs_to_jiffies(10000));
 	if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
 	if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
@@ -4889,7 +5240,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
 	ioc->base_cmds.smid = smid;
 	ioc->base_cmds.smid = smid;
 	memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
 	memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
 	init_completion(&ioc->base_cmds.done);
 	init_completion(&ioc->base_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->base_cmds.done,
 	wait_for_completion_timeout(&ioc->base_cmds.done,
 	    msecs_to_jiffies(10000));
 	    msecs_to_jiffies(10000));
 	if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -5074,8 +5425,6 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc)
 	if ((facts->IOCCapabilities &
 	if ((facts->IOCCapabilities &
 	      MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices))
 	      MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices))
 		ioc->rdpq_array_capable = 1;
 		ioc->rdpq_array_capable = 1;
-	if (facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
-		ioc->atomic_desc_capable = 1;
 	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
 	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
 	facts->IOCRequestFrameSize =
 	facts->IOCRequestFrameSize =
 	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
 	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
@@ -5317,7 +5666,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc)
 	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
 	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
 
 
 	init_completion(&ioc->port_enable_cmds.done);
 	init_completion(&ioc->port_enable_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ);
 	wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ);
 	if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) {
 		pr_err(MPT3SAS_FMT "%s: timeout\n",
 		pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -5380,7 +5729,7 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc)
 	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
 	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
 	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
 	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
 
 
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -5499,7 +5848,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc)
 		mpi_request->EventMasks[i] =
 		mpi_request->EventMasks[i] =
 		    cpu_to_le32(ioc->event_masks[i]);
 		    cpu_to_le32(ioc->event_masks[i]);
 	init_completion(&ioc->base_cmds.done);
 	init_completion(&ioc->base_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
 	wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
 	if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
 		pr_err(MPT3SAS_FMT "%s: timeout\n",
 		pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -5819,8 +6168,12 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
 	/* initialize Reply Free Queue */
 	/* initialize Reply Free Queue */
 	for (i = 0, reply_address = (u32)ioc->reply_dma ;
 	for (i = 0, reply_address = (u32)ioc->reply_dma ;
 	    i < ioc->reply_free_queue_depth ; i++, reply_address +=
 	    i < ioc->reply_free_queue_depth ; i++, reply_address +=
-	    ioc->reply_sz)
+	    ioc->reply_sz) {
 		ioc->reply_free[i] = cpu_to_le32(reply_address);
 		ioc->reply_free[i] = cpu_to_le32(reply_address);
+		if (ioc->is_mcpu_endpoint)
+			_base_clone_reply_to_sys_mem(ioc,
+					(__le32)reply_address, i);
+	}
 
 
 	/* initialize reply queues */
 	/* initialize reply queues */
 	if (ioc->is_driver_loading)
 	if (ioc->is_driver_loading)
@@ -6009,20 +6362,10 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
 		break;
 		break;
 	}
 	}
 
 
-	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;
-		ioc->put_smid_nvme_encap = &_base_put_smid_nvme_encap_atomic;
-	} else {
-		ioc->put_smid_default = &_base_put_smid_default;
+	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;
 		ioc->put_smid_scsi_io = &_base_put_smid_scsi_io;
-		ioc->put_smid_fast_path = &_base_put_smid_fast_path;
-		ioc->put_smid_hi_priority = &_base_put_smid_hi_priority;
-		ioc->put_smid_nvme_encap = &_base_put_smid_nvme_encap;
-	}
-
 
 
 	/*
 	/*
 	 * These function pointers for other requests that don't
 	 * These function pointers for other requests that don't

+ 13 - 6
drivers/scsi/mpt3sas/mpt3sas_base.h

@@ -95,6 +95,8 @@
 #define MPT_MIN_PHYS_SEGMENTS	16
 #define MPT_MIN_PHYS_SEGMENTS	16
 #define MPT_KDUMP_MIN_PHYS_SEGMENTS	32
 #define MPT_KDUMP_MIN_PHYS_SEGMENTS	32
 
 
+#define MCPU_MAX_CHAINS_PER_IO	3
+
 #ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE
 #ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE
 #define MPT3SAS_SG_DEPTH		CONFIG_SCSI_MPT3SAS_MAX_SGE
 #define MPT3SAS_SG_DEPTH		CONFIG_SCSI_MPT3SAS_MAX_SGE
 #else
 #else
@@ -120,6 +122,8 @@
 #define MPT3SAS_NVME_QUEUE_DEPTH	128
 #define MPT3SAS_NVME_QUEUE_DEPTH	128
 #define MPT_NAME_LENGTH			32	/* generic length of strings */
 #define MPT_NAME_LENGTH			32	/* generic length of strings */
 #define MPT_STRING_LENGTH		64
 #define MPT_STRING_LENGTH		64
+#define MPI_FRAME_START_OFFSET		256
+#define REPLY_FREE_POOL_SIZE		512 /*(32 maxcredix *4)*(4 times)*/
 
 
 #define MPT_MAX_CALLBACKS		32
 #define MPT_MAX_CALLBACKS		32
 
 
@@ -1099,7 +1103,7 @@ struct MPT3SAS_ADAPTER {
 	char		tmp_string[MPT_STRING_LENGTH];
 	char		tmp_string[MPT_STRING_LENGTH];
 	struct pci_dev	*pdev;
 	struct pci_dev	*pdev;
 	Mpi2SystemInterfaceRegs_t __iomem *chip;
 	Mpi2SystemInterfaceRegs_t __iomem *chip;
-	resource_size_t	chip_phys;
+	phys_addr_t	chip_phys;
 	int		logging_level;
 	int		logging_level;
 	int		fwfault_debug;
 	int		fwfault_debug;
 	u8		ir_firmware;
 	u8		ir_firmware;
@@ -1236,6 +1240,7 @@ struct MPT3SAS_ADAPTER {
 	u16		config_page_sz;
 	u16		config_page_sz;
 	void		*config_page;
 	void		*config_page;
 	dma_addr_t	config_page_dma;
 	dma_addr_t	config_page_dma;
+	void		*config_vaddr;
 
 
 	/* scsiio request */
 	/* scsiio request */
 	u16		hba_queue_depth;
 	u16		hba_queue_depth;
@@ -1336,6 +1341,7 @@ struct MPT3SAS_ADAPTER {
 	u32		ring_buffer_offset;
 	u32		ring_buffer_offset;
 	u32		ring_buffer_sz;
 	u32		ring_buffer_sz;
 	u8		is_warpdrive;
 	u8		is_warpdrive;
+	u8		is_mcpu_endpoint;
 	u8		hide_ir_msg;
 	u8		hide_ir_msg;
 	u8		mfg_pg10_hide_flag;
 	u8		mfg_pg10_hide_flag;
 	u8		hide_drives;
 	u8		hide_drives;
@@ -1348,12 +1354,7 @@ struct MPT3SAS_ADAPTER {
 	void		*device_remove_in_progress;
 	void		*device_remove_in_progress;
 	u16		device_remove_in_progress_sz;
 	u16		device_remove_in_progress_sz;
 	u8		is_gen35_ioc;
 	u8		is_gen35_ioc;
-	u8		atomic_desc_capable;
 	PUT_SMID_IO_FP_HIP put_smid_scsi_io;
 	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;
-	PUT_SMID_DEFAULT put_smid_nvme_encap;
 
 
 };
 };
 
 
@@ -1394,6 +1395,12 @@ void *mpt3sas_base_get_pcie_sgl(struct MPT3SAS_ADAPTER *ioc, u16 smid);
 dma_addr_t mpt3sas_base_get_pcie_sgl_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid);
 dma_addr_t mpt3sas_base_get_pcie_sgl_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid);
 void mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc);
 void mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc);
 
 
+void mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+	u16 handle);
+void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid,
+	u16 msix_task);
+void mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+void mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid);
 /* hi-priority queue */
 /* hi-priority queue */
 u16 mpt3sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx);
 u16 mpt3sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx);
 u16 mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,
 u16 mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx,

+ 2 - 1
drivers/scsi/mpt3sas/mpt3sas_config.c

@@ -219,6 +219,7 @@ _config_alloc_config_dma_memory(struct MPT3SAS_ADAPTER *ioc,
 		mem->page = ioc->config_page;
 		mem->page = ioc->config_page;
 		mem->page_dma = ioc->config_page_dma;
 		mem->page_dma = ioc->config_page_dma;
 	}
 	}
+	ioc->config_vaddr = mem->page;
 	return r;
 	return r;
 }
 }
 
 
@@ -402,7 +403,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
 	memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
 	memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
 	_config_display_some_debug(ioc, smid, "config_request", NULL);
 	_config_display_some_debug(ioc, smid, "config_request", NULL);
 	init_completion(&ioc->config_cmds.done);
 	init_completion(&ioc->config_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
 	wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
 	if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
 		pr_err(MPT3SAS_FMT "%s: timeout\n",
 		pr_err(MPT3SAS_FMT "%s: timeout\n",

+ 11 - 11
drivers/scsi/mpt3sas/mpt3sas_ctl.c

@@ -820,7 +820,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
 			ret = -EINVAL;
 			ret = -EINVAL;
 			goto out;
 			goto out;
 		}
 		}
-		ioc->put_smid_nvme_encap(ioc, smid);
+		mpt3sas_base_put_smid_nvme_encap(ioc, smid);
 		break;
 		break;
 	}
 	}
 	case MPI2_FUNCTION_SCSI_IO_REQUEST:
 	case MPI2_FUNCTION_SCSI_IO_REQUEST:
@@ -845,7 +845,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
 		if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
 		if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
 			ioc->put_smid_scsi_io(ioc, smid, device_handle);
 			ioc->put_smid_scsi_io(ioc, smid, device_handle);
 		else
 		else
-			ioc->put_smid_default(ioc, smid);
+			mpt3sas_base_put_smid_default(ioc, smid);
 		break;
 		break;
 	}
 	}
 	case MPI2_FUNCTION_SCSI_TASK_MGMT:
 	case MPI2_FUNCTION_SCSI_TASK_MGMT:
@@ -882,7 +882,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
 		    tm_request->DevHandle));
 		    tm_request->DevHandle));
 		ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
 		ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
 		    data_in_dma, data_in_sz);
 		    data_in_dma, data_in_sz);
-		ioc->put_smid_hi_priority(ioc, smid, 0);
+		mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
 		break;
 		break;
 	}
 	}
 	case MPI2_FUNCTION_SMP_PASSTHROUGH:
 	case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -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,
 		ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
 		    data_in_sz);
 		    data_in_sz);
-		ioc->put_smid_default(ioc, smid);
+		mpt3sas_base_put_smid_default(ioc, smid);
 		break;
 		break;
 	}
 	}
 	case MPI2_FUNCTION_SATA_PASSTHROUGH:
 	case MPI2_FUNCTION_SATA_PASSTHROUGH:
@@ -928,7 +928,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,
 		ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
 		    data_in_sz);
 		    data_in_sz);
-		ioc->put_smid_default(ioc, smid);
+		mpt3sas_base_put_smid_default(ioc, smid);
 		break;
 		break;
 	}
 	}
 	case MPI2_FUNCTION_FW_DOWNLOAD:
 	case MPI2_FUNCTION_FW_DOWNLOAD:
@@ -936,7 +936,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,
 		ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,
 		    data_in_sz);
 		    data_in_sz);
-		ioc->put_smid_default(ioc, smid);
+		mpt3sas_base_put_smid_default(ioc, smid);
 		break;
 		break;
 	}
 	}
 	case MPI2_FUNCTION_TOOLBOX:
 	case MPI2_FUNCTION_TOOLBOX:
@@ -951,7 +951,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,
 			ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
 				data_in_dma, data_in_sz);
 				data_in_dma, data_in_sz);
 		}
 		}
-		ioc->put_smid_default(ioc, smid);
+		mpt3sas_base_put_smid_default(ioc, smid);
 		break;
 		break;
 	}
 	}
 	case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
 	case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
@@ -970,7 +970,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
 	default:
 	default:
 		ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
 		ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
 		    data_in_dma, data_in_sz);
 		    data_in_dma, data_in_sz);
-		ioc->put_smid_default(ioc, smid);
+		mpt3sas_base_put_smid_default(ioc, smid);
 		break;
 		break;
 	}
 	}
 
 
@@ -1601,7 +1601,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
 			cpu_to_le32(ioc->product_specific[buffer_type][i]);
 			cpu_to_le32(ioc->product_specific[buffer_type][i]);
 
 
 	init_completion(&ioc->ctl_cmds.done);
 	init_completion(&ioc->ctl_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 
 
@@ -1948,7 +1948,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
 	mpi_request->VP_ID = 0;
 	mpi_request->VP_ID = 0;
 
 
 	init_completion(&ioc->ctl_cmds.done);
 	init_completion(&ioc->ctl_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 
 
@@ -2215,7 +2215,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
 	mpi_request->VP_ID = 0;
 	mpi_request->VP_ID = 0;
 
 
 	init_completion(&ioc->ctl_cmds.done);
 	init_completion(&ioc->ctl_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
 	wait_for_completion_timeout(&ioc->ctl_cmds.done,
 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 	    MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
 
 

+ 46 - 28
drivers/scsi/mpt3sas/mpt3sas_scsih.c

@@ -2679,7 +2679,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle,
 	int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
 	int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
 	mpt3sas_scsih_set_tm_flag(ioc, handle);
 	mpt3sas_scsih_set_tm_flag(ioc, handle);
 	init_completion(&ioc->tm_cmds.done);
 	init_completion(&ioc->tm_cmds.done);
-	ioc->put_smid_hi_priority(ioc, smid, msix_task);
+	mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task);
 	wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
 	wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
 	if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
 		pr_err(MPT3SAS_FMT "%s: timeout\n",
 		pr_err(MPT3SAS_FMT "%s: timeout\n",
@@ -3641,7 +3641,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
 	mpi_request->DevHandle = cpu_to_le16(handle);
 	mpi_request->DevHandle = cpu_to_le16(handle);
 	mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
 	mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
 	set_bit(handle, ioc->device_remove_in_progress);
 	set_bit(handle, ioc->device_remove_in_progress);
-	ioc->put_smid_hi_priority(ioc, smid, 0);
+	mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
 	mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
 	mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
 
 
 out:
 out:
@@ -3742,7 +3742,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->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
 	mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
 	mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
 	mpi_request->DevHandle = mpi_request_tm->DevHandle;
 	mpi_request->DevHandle = mpi_request_tm->DevHandle;
-	ioc->put_smid_default(ioc, smid_sas_ctrl);
+	mpt3sas_base_put_smid_default(ioc, smid_sas_ctrl);
 
 
 	return _scsih_check_for_pending_tm(ioc, smid);
 	return _scsih_check_for_pending_tm(ioc, smid);
 }
 }
@@ -3837,7 +3837,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
 	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
 	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
 	mpi_request->DevHandle = cpu_to_le16(handle);
 	mpi_request->DevHandle = cpu_to_le16(handle);
 	mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
 	mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-	ioc->put_smid_hi_priority(ioc, smid, 0);
+	mpt3sas_base_put_smid_hi_priority(ioc, smid, 0);
 }
 }
 
 
 /**
 /**
@@ -3929,7 +3929,7 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event,
 	ack_request->EventContext = event_context;
 	ack_request->EventContext = event_context;
 	ack_request->VF_ID = 0;  /* TODO */
 	ack_request->VF_ID = 0;  /* TODO */
 	ack_request->VP_ID = 0;
 	ack_request->VP_ID = 0;
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 }
 }
 
 
 /**
 /**
@@ -3986,7 +3986,7 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
 	mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
 	mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
 	mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
 	mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
 	mpi_request->DevHandle = handle;
 	mpi_request->DevHandle = handle;
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 }
 }
 
 
 /**
 /**
@@ -4715,12 +4715,12 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 		if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) {
 		if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) {
 			mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len |
 			mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len |
 			    MPI25_SCSIIO_IOFLAGS_FAST_PATH);
 			    MPI25_SCSIIO_IOFLAGS_FAST_PATH);
-			ioc->put_smid_fast_path(ioc, smid, handle);
+			mpt3sas_base_put_smid_fast_path(ioc, smid, handle);
 		} else
 		} else
 			ioc->put_smid_scsi_io(ioc, smid,
 			ioc->put_smid_scsi_io(ioc, smid,
 			    le16_to_cpu(mpi_request->DevHandle));
 			    le16_to_cpu(mpi_request->DevHandle));
 	} else
 	} else
-		ioc->put_smid_default(ioc, smid);
+		mpt3sas_base_put_smid_default(ioc, smid);
 	return 0;
 	return 0;
 
 
  out:
  out:
@@ -7609,7 +7609,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
 	    handle, phys_disk_num));
 	    handle, phys_disk_num));
 
 
 	init_completion(&ioc->scsih_cmds.done);
 	init_completion(&ioc->scsih_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
 	wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
 
 
 	if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -9700,7 +9700,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
 	if (!ioc->hide_ir_msg)
 	if (!ioc->hide_ir_msg)
 		pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name);
 		pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name);
 	init_completion(&ioc->scsih_cmds.done);
 	init_completion(&ioc->scsih_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
 	wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
 
 
 	if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -10346,6 +10346,7 @@ _scsih_determine_hba_mpi_version(struct pci_dev *pdev)
 	case MPI2_MFGPAGE_DEVID_SAS2308_1:
 	case MPI2_MFGPAGE_DEVID_SAS2308_1:
 	case MPI2_MFGPAGE_DEVID_SAS2308_2:
 	case MPI2_MFGPAGE_DEVID_SAS2308_2:
 	case MPI2_MFGPAGE_DEVID_SAS2308_3:
 	case MPI2_MFGPAGE_DEVID_SAS2308_3:
+	case MPI2_MFGPAGE_DEVID_SAS2308_MPI_EP:
 		return MPI2_VERSION;
 		return MPI2_VERSION;
 	case MPI25_MFGPAGE_DEVID_SAS3004:
 	case MPI25_MFGPAGE_DEVID_SAS3004:
 	case MPI25_MFGPAGE_DEVID_SAS3008:
 	case MPI25_MFGPAGE_DEVID_SAS3008:
@@ -10423,11 +10424,18 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		ioc->hba_mpi_version_belonged = hba_mpi_version;
 		ioc->hba_mpi_version_belonged = hba_mpi_version;
 		ioc->id = mpt2_ids++;
 		ioc->id = mpt2_ids++;
 		sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME);
 		sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME);
-		if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) {
+		switch (pdev->device) {
+		case MPI2_MFGPAGE_DEVID_SSS6200:
 			ioc->is_warpdrive = 1;
 			ioc->is_warpdrive = 1;
 			ioc->hide_ir_msg = 1;
 			ioc->hide_ir_msg = 1;
-		} else
+			break;
+		case MPI2_MFGPAGE_DEVID_SAS2308_MPI_EP:
+			ioc->is_mcpu_endpoint = 1;
+			break;
+		default:
 			ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
 			ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
+			break;
+		}
 		break;
 		break;
 	case MPI25_VERSION:
 	case MPI25_VERSION:
 	case MPI26_VERSION:
 	case MPI26_VERSION:
@@ -10524,26 +10532,34 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	shost->transportt = mpt3sas_transport_template;
 	shost->transportt = mpt3sas_transport_template;
 	shost->unique_id = ioc->id;
 	shost->unique_id = ioc->id;
 
 
-	if (max_sectors != 0xFFFF) {
-		if (max_sectors < 64) {
-			shost->max_sectors = 64;
-			pr_warn(MPT3SAS_FMT "Invalid value %d passed " \
-			    "for max_sectors, range is 64 to 32767. Assigning "
-			    "value of 64.\n", ioc->name, max_sectors);
-		} else if (max_sectors > 32767) {
-			shost->max_sectors = 32767;
-			pr_warn(MPT3SAS_FMT "Invalid value %d passed " \
-			    "for max_sectors, range is 64 to 32767. Assigning "
-			    "default value of 32767.\n", ioc->name,
-			    max_sectors);
-		} else {
-			shost->max_sectors = max_sectors & 0xFFFE;
-			pr_info(MPT3SAS_FMT
+	if (ioc->is_mcpu_endpoint) {
+		/* mCPU MPI support 64K max IO */
+		shost->max_sectors = 128;
+		pr_info(MPT3SAS_FMT
 				"The max_sectors value is set to %d\n",
 				"The max_sectors value is set to %d\n",
 				ioc->name, shost->max_sectors);
 				ioc->name, shost->max_sectors);
+	} else {
+		if (max_sectors != 0xFFFF) {
+			if (max_sectors < 64) {
+				shost->max_sectors = 64;
+				pr_warn(MPT3SAS_FMT "Invalid value %d passed " \
+				    "for max_sectors, range is 64 to 32767. " \
+				    "Assigning value of 64.\n", \
+				    ioc->name, max_sectors);
+			} else if (max_sectors > 32767) {
+				shost->max_sectors = 32767;
+				pr_warn(MPT3SAS_FMT "Invalid value %d passed " \
+				    "for max_sectors, range is 64 to 32767." \
+				    "Assigning default value of 32767.\n", \
+				    ioc->name, max_sectors);
+			} else {
+				shost->max_sectors = max_sectors & 0xFFFE;
+				pr_info(MPT3SAS_FMT
+					"The max_sectors value is set to %d\n",
+					ioc->name, shost->max_sectors);
+			}
 		}
 		}
 	}
 	}
-
 	/* register EEDP capabilities with SCSI layer */
 	/* register EEDP capabilities with SCSI layer */
 	if (prot_mask > 0)
 	if (prot_mask > 0)
 		scsi_host_set_prot(shost, prot_mask);
 		scsi_host_set_prot(shost, prot_mask);
@@ -10856,6 +10872,8 @@ static const struct pci_device_id mpt3sas_pci_table[] = {
 		PCI_ANY_ID, PCI_ANY_ID },
 		PCI_ANY_ID, PCI_ANY_ID },
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
 		PCI_ANY_ID, PCI_ANY_ID },
 		PCI_ANY_ID, PCI_ANY_ID },
+	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_MPI_EP,
+		PCI_ANY_ID, PCI_ANY_ID },
 	/* SSS6200 */
 	/* SSS6200 */
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
 	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
 		PCI_ANY_ID, PCI_ANY_ID },
 		PCI_ANY_ID, PCI_ANY_ID },

+ 4 - 4
drivers/scsi/mpt3sas/mpt3sas_transport.c

@@ -392,7 +392,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,
 		"report_manufacture - send to sas_addr(0x%016llx)\n",
 		"report_manufacture - send to sas_addr(0x%016llx)\n",
 		ioc->name, (unsigned long long)sas_address));
 		ioc->name, (unsigned long long)sas_address));
 	init_completion(&ioc->transport_cmds.done);
 	init_completion(&ioc->transport_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 
 
 	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1198,7 +1198,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,
 		ioc->name, (unsigned long long)phy->identify.sas_address,
 		ioc->name, (unsigned long long)phy->identify.sas_address,
 		phy->number));
 		phy->number));
 	init_completion(&ioc->transport_cmds.done);
 	init_completion(&ioc->transport_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 
 
 	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -1514,7 +1514,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,
 		ioc->name, (unsigned long long)phy->identify.sas_address,
 		ioc->name, (unsigned long long)phy->identify.sas_address,
 		phy->number, phy_operation));
 		phy->number, phy_operation));
 	init_completion(&ioc->transport_cmds.done);
 	init_completion(&ioc->transport_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 
 
 	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
@@ -2014,7 +2014,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
 		"%s - sending smp request\n", ioc->name, __func__));
 		"%s - sending smp request\n", ioc->name, __func__));
 
 
 	init_completion(&ioc->transport_cmds.done);
 	init_completion(&ioc->transport_cmds.done);
-	ioc->put_smid_default(ioc, smid);
+	mpt3sas_base_put_smid_default(ioc, smid);
 	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);
 
 
 	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {
 	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {

+ 57 - 50
drivers/scsi/mvme147.c

@@ -3,6 +3,9 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/blkdev.h>
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 
 
 #include <asm/page.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable.h>
@@ -14,9 +17,6 @@
 #include "wd33c93.h"
 #include "wd33c93.h"
 #include "mvme147.h"
 #include "mvme147.h"
 
 
-#include <linux/stat.h>
-
-
 static irqreturn_t mvme147_intr(int irq, void *data)
 static irqreturn_t mvme147_intr(int irq, void *data)
 {
 {
 	struct Scsi_Host *instance = data;
 	struct Scsi_Host *instance = data;
@@ -65,40 +65,57 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 	m147_pcc->dma_cntrl = 0;
 	m147_pcc->dma_cntrl = 0;
 }
 }
 
 
-int mvme147_detect(struct scsi_host_template *tpnt)
+static struct scsi_host_template mvme147_host_template = {
+	.module			= THIS_MODULE,
+	.proc_name		= "MVME147",
+	.name			= "MVME147 built-in SCSI",
+	.queuecommand		= wd33c93_queuecommand,
+	.eh_abort_handler	= wd33c93_abort,
+	.eh_host_reset_handler	= wd33c93_host_reset,
+	.show_info		= wd33c93_show_info,
+	.write_info		= wd33c93_write_info,
+	.can_queue		= CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= CMD_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+static struct Scsi_Host *mvme147_shost;
+
+static int __init mvme147_init(void)
 {
 {
-	static unsigned char called = 0;
-	struct Scsi_Host *instance;
 	wd33c93_regs regs;
 	wd33c93_regs regs;
 	struct WD33C93_hostdata *hdata;
 	struct WD33C93_hostdata *hdata;
+	int error = -ENOMEM;
 
 
-	if (!MACH_IS_MVME147 || called)
+	if (!MACH_IS_MVME147)
 		return 0;
 		return 0;
-	called++;
 
 
-	tpnt->proc_name = "MVME147";
-	tpnt->show_info = wd33c93_show_info,
-	tpnt->write_info = wd33c93_write_info,
-
-	instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-	if (!instance)
+	mvme147_shost = scsi_host_alloc(&mvme147_host_template,
+			sizeof(struct WD33C93_hostdata));
+	if (!mvme147_shost)
 		goto err_out;
 		goto err_out;
+	mvme147_shost->base = 0xfffe4000;
+	mvme147_shost->irq = MVME147_IRQ_SCSI_PORT;
 
 
-	instance->base = 0xfffe4000;
-	instance->irq = MVME147_IRQ_SCSI_PORT;
 	regs.SASR = (volatile unsigned char *)0xfffe4000;
 	regs.SASR = (volatile unsigned char *)0xfffe4000;
 	regs.SCMD = (volatile unsigned char *)0xfffe4001;
 	regs.SCMD = (volatile unsigned char *)0xfffe4001;
-	hdata = shost_priv(instance);
+
+	hdata = shost_priv(mvme147_shost);
 	hdata->no_sync = 0xff;
 	hdata->no_sync = 0xff;
 	hdata->fast = 0;
 	hdata->fast = 0;
 	hdata->dma_mode = CTRL_DMA;
 	hdata->dma_mode = CTRL_DMA;
-	wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
 
 
-	if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0,
-			"MVME147 SCSI PORT", instance))
+	wd33c93_init(mvme147_shost, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
+
+	error = request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0,
+			"MVME147 SCSI PORT", mvme147_shost);
+	if (error)
 		goto err_unregister;
 		goto err_unregister;
-	if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0,
-			"MVME147 SCSI DMA", instance))
+	error = request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0,
+			"MVME147 SCSI DMA", mvme147_shost);
+	if (error)
 		goto err_free_irq;
 		goto err_free_irq;
 #if 0	/* Disabled; causes problems booting */
 #if 0	/* Disabled; causes problems booting */
 	m147_pcc->scsi_interrupt = 0x10;	/* Assert SCSI bus reset */
 	m147_pcc->scsi_interrupt = 0x10;	/* Assert SCSI bus reset */
@@ -112,40 +129,30 @@ int mvme147_detect(struct scsi_host_template *tpnt)
 	m147_pcc->dma_cntrl = 0x00;	/* ensure DMA is stopped */
 	m147_pcc->dma_cntrl = 0x00;	/* ensure DMA is stopped */
 	m147_pcc->dma_intr = 0x89;	/* Ack and enable ints */
 	m147_pcc->dma_intr = 0x89;	/* Ack and enable ints */
 
 
-	return 1;
+	error = scsi_add_host(mvme147_shost, NULL);
+	if (error)
+		goto err_free_irq;
+	scsi_scan_host(mvme147_shost);
+	return 0;
 
 
 err_free_irq:
 err_free_irq:
-	free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
+	free_irq(MVME147_IRQ_SCSI_PORT, mvme147_shost);
 err_unregister:
 err_unregister:
-	scsi_unregister(instance);
+	scsi_host_put(mvme147_shost);
 err_out:
 err_out:
-	return 0;
+	return error;
 }
 }
 
 
-static struct scsi_host_template driver_template = {
-	.proc_name		= "MVME147",
-	.name			= "MVME147 built-in SCSI",
-	.detect			= mvme147_detect,
-	.release		= mvme147_release,
-	.queuecommand		= wd33c93_queuecommand,
-	.eh_abort_handler	= wd33c93_abort,
-	.eh_host_reset_handler	= wd33c93_host_reset,
-	.can_queue		= CAN_QUEUE,
-	.this_id		= 7,
-	.sg_tablesize		= SG_ALL,
-	.cmd_per_lun		= CMD_PER_LUN,
-	.use_clustering		= ENABLE_CLUSTERING
-};
-
-
-#include "scsi_module.c"
-
-int mvme147_release(struct Scsi_Host *instance)
+static void __exit mvme147_exit(void)
 {
 {
-#ifdef MODULE
+	scsi_remove_host(mvme147_shost);
+
 	/* XXX Make sure DMA is stopped! */
 	/* XXX Make sure DMA is stopped! */
-	free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
-	free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr);
-#endif
-	return 1;
+	free_irq(MVME147_IRQ_SCSI_PORT, mvme147_shost);
+	free_irq(MVME147_IRQ_SCSI_DMA, mvme147_shost);
+
+	scsi_host_put(mvme147_shost);
 }
 }
+
+module_init(mvme147_init);
+module_exit(mvme147_exit);

+ 12 - 11
drivers/scsi/mvsas/mv_94xx.c

@@ -1080,16 +1080,16 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
 			void __iomem *regs = mvi->regs_ex - 0x10200;
 			void __iomem *regs = mvi->regs_ex - 0x10200;
 
 
 			int drive = (i/3) & (4-1); /* drive number on host */
 			int drive = (i/3) & (4-1); /* drive number on host */
-			u32 block = mr32(MVS_SGPIO_DCTRL +
+			int driveshift = drive * 8; /* bit offset of drive */
+			u32 block = ioread32be(regs + MVS_SGPIO_DCTRL +
 				MVS_SGPIO_HOST_OFFSET * mvi->id);
 				MVS_SGPIO_HOST_OFFSET * mvi->id);
 
 
-
 			/*
 			/*
 			* if bit is set then create a mask with the first
 			* if bit is set then create a mask with the first
 			* bit of the drive set in the mask ...
 			* bit of the drive set in the mask ...
 			*/
 			*/
-			u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ?
-				1<<(24-drive*8) : 0;
+			u32 bit = get_unaligned_be32(write_data) & (1 << i) ?
+				1 << driveshift : 0;
 
 
 			/*
 			/*
 			* ... and then shift it to the right position based
 			* ... and then shift it to the right position based
@@ -1098,26 +1098,27 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
 			switch (i%3) {
 			switch (i%3) {
 			case 0: /* activity */
 			case 0: /* activity */
 				block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT)
 				block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT)
-					<< (24-drive*8));
+					<< driveshift);
 					/* hardwire activity bit to SOF */
 					/* hardwire activity bit to SOF */
 				block |= LED_BLINKA_SOF << (
 				block |= LED_BLINKA_SOF << (
 					MVS_SGPIO_DCTRL_ACT_SHIFT +
 					MVS_SGPIO_DCTRL_ACT_SHIFT +
-					(24-drive*8));
+					driveshift);
 				break;
 				break;
 			case 1: /* id */
 			case 1: /* id */
 				block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT)
 				block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT)
-					<< (24-drive*8));
+					<< driveshift);
 				block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT;
 				block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT;
 				break;
 				break;
 			case 2: /* fail */
 			case 2: /* fail */
 				block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT)
 				block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT)
-					<< (24-drive*8));
+					<< driveshift);
 				block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT;
 				block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT;
 				break;
 				break;
 			}
 			}
 
 
-			mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
-				block);
+			iowrite32be(block,
+				regs + MVS_SGPIO_DCTRL +
+				MVS_SGPIO_HOST_OFFSET * mvi->id);
 
 
 		}
 		}
 
 
@@ -1132,7 +1133,7 @@ static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
 			void __iomem *regs = mvi->regs_ex - 0x10200;
 			void __iomem *regs = mvi->regs_ex - 0x10200;
 
 
 			mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
 			mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
-				be32_to_cpu(((u32 *) write_data)[i]));
+				((u32 *) write_data)[i]);
 		}
 		}
 		return reg_count;
 		return reg_count;
 	}
 	}

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio