Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Dec 2020 21:34:31 +0000 (13:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Dec 2020 21:34:31 +0000 (13:34 -0800)
Pull SCSI updates from James Bottomley:
 "This consists of the usual driver updates (ufs, qla2xxx, smartpqi,
  target, zfcp, fnic, mpt3sas, ibmvfc) plus a load of cleanups, a major
  power management rework and a load of assorted minor updates.

  There are a few core updates (formatting fixes being the big one) but
  nothing major this cycle"

* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (279 commits)
  scsi: mpt3sas: Update driver version to 36.100.00.00
  scsi: mpt3sas: Handle trigger page after firmware update
  scsi: mpt3sas: Add persistent MPI trigger page
  scsi: mpt3sas: Add persistent SCSI sense trigger page
  scsi: mpt3sas: Add persistent Event trigger page
  scsi: mpt3sas: Add persistent Master trigger page
  scsi: mpt3sas: Add persistent trigger pages support
  scsi: mpt3sas: Sync time periodically between driver and firmware
  scsi: qla2xxx: Update version to 10.02.00.104-k
  scsi: qla2xxx: Fix device loss on 4G and older HBAs
  scsi: qla2xxx: If fcport is undergoing deletion complete I/O with retry
  scsi: qla2xxx: Fix the call trace for flush workqueue
  scsi: qla2xxx: Fix flash update in 28XX adapters on big endian machines
  scsi: qla2xxx: Handle aborts correctly for port undergoing deletion
  scsi: qla2xxx: Fix N2N and NVMe connect retry failure
  scsi: qla2xxx: Fix FW initialization error on big endian machines
  scsi: qla2xxx: Fix crash during driver load on big endian machines
  scsi: qla2xxx: Fix compilation issue in PPC systems
  scsi: qla2xxx: Don't check for fw_started while posting NVMe command
  scsi: qla2xxx: Tear down session if FW say it is down
  ...

22 files changed:
1  2 
MAINTAINERS
block/blk-mq.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/message/fusion/mptscsih.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
drivers/scsi/hpsa.c
drivers/scsi/libiscsi.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/qla2xxx/qla_tmpl.c
drivers/scsi/scsi_lib.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/target/target_core_user.c

diff --combined MAINTAINERS
@@@ -929,18 -929,12 +929,18 @@@ L:      linux-i2c@vger.kernel.or
  S:    Maintained
  F:    drivers/i2c/busses/i2c-amd-mp2*
  
 +AMD PMC DRIVER
 +M:    Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
 +L:    platform-driver-x86@vger.kernel.org
 +S:    Maintained
 +F:    drivers/platform/x86/amd-pmc.*
 +
  AMD POWERPLAY
  M:    Evan Quan <evan.quan@amd.com>
  L:    amd-gfx@lists.freedesktop.org
  S:    Supported
  T:    git git://people.freedesktop.org/~agd5f/linux
 -F:    drivers/gpu/drm/amd/powerplay/
 +F:    drivers/gpu/drm/amd/pm/powerplay/
  
  AMD SEATTLE DEVICE TREE SUPPORT
  M:    Brijesh Singh <brijeshkumar.singh@amd.com>
@@@ -984,7 -978,7 +984,7 @@@ M: Michael Hennerich <Michael.Hennerich
  L:    linux-iio@vger.kernel.org
  S:    Supported
  W:    http://ez.analog.com/community/linux-device-drivers
 -F:    Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt
 +F:    Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
  F:    drivers/iio/adc/ad7768-1.c
  
  ANALOG DEVICES INC AD7780 DRIVER
@@@ -1079,7 -1073,6 +1079,7 @@@ M:      Hans Verkuil <hverkuil-cisco@xs4all.
  L:    linux-media@vger.kernel.org
  S:    Maintained
  F:    drivers/media/i2c/adv7604*
 +F:    Documentation/devicetree/bindings/media/i2c/adv7604.yaml
  
  ANALOG DEVICES INC ADV7842 DRIVER
  M:    Hans Verkuil <hverkuil-cisco@xs4all.nl>
@@@ -1180,6 -1173,16 +1180,6 @@@ S:     Supporte
  F:    Documentation/devicetree/bindings/rtc/google,goldfish-rtc.txt
  F:    drivers/rtc/rtc-goldfish.c
  
 -ANDROID ION DRIVER
 -M:    Laura Abbott <labbott@redhat.com>
 -M:    Sumit Semwal <sumit.semwal@linaro.org>
 -L:    devel@driverdev.osuosl.org
 -L:    dri-devel@lists.freedesktop.org
 -L:    linaro-mm-sig@lists.linaro.org (moderated for non-subscribers)
 -S:    Supported
 -F:    drivers/staging/android/ion
 -F:    drivers/staging/android/uapi/ion.h
 -
  AOA (Apple Onboard Audio) ALSA DRIVER
  M:    Johannes Berg <johannes@sipsolutions.net>
  L:    linuxppc-dev@lists.ozlabs.org
@@@ -1276,7 -1279,7 +1276,7 @@@ M:      Igor Russkikh <irusskikh@marvell.com
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    https://www.marvell.com/
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  F:    Documentation/networking/device_drivers/ethernet/aquantia/atlantic.rst
  F:    drivers/net/ethernet/aquantia/atlantic/
  
@@@ -1483,20 -1486,10 +1483,20 @@@ F:   Documentation/devicetree/bindings/io
  F:    drivers/iommu/arm/
  F:    drivers/iommu/io-pgtable-arm*
  
 +ARM AND ARM64 SoC SUB-ARCHITECTURES (COMMON PARTS)
 +M:    Arnd Bergmann <arnd@arndb.de>
 +M:    Olof Johansson <olof@lixom.net>
 +M:    soc@kernel.org
 +L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 +S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git
 +F:    arch/arm/boot/dts/Makefile
 +F:    arch/arm64/boot/dts/Makefile
 +
  ARM SUB-ARCHITECTURES
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git
  F:    arch/arm/mach-*/
  F:    arch/arm/plat-*/
  
@@@ -1508,7 -1501,7 +1508,7 @@@ S:      Maintaine
  F:    Documentation/devicetree/bindings/arm/actions.yaml
  F:    Documentation/devicetree/bindings/clock/actions,owl-cmu.txt
  F:    Documentation/devicetree/bindings/dma/owl-dma.yaml
 -F:    Documentation/devicetree/bindings/i2c/i2c-owl.txt
 +F:    Documentation/devicetree/bindings/i2c/i2c-owl.yaml
  F:    Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
  F:    Documentation/devicetree/bindings/mmc/owl-mmc.yaml
  F:    Documentation/devicetree/bindings/pinctrl/actions,*
@@@ -1553,7 -1546,6 +1553,7 @@@ F:      drivers/clk/sunxi
  ARM/Allwinner sunXi SoC support
  M:    Maxime Ripard <mripard@kernel.org>
  M:    Chen-Yu Tsai <wens@csie.org>
 +R:    Jernej Skrabec <jernej.skrabec@siol.net>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux.git
@@@ -1731,13 -1723,11 +1731,13 @@@ F:   arch/arm/mach-ep93xx/micro9.
  
  ARM/CORESIGHT FRAMEWORK AND DRIVERS
  M:    Mathieu Poirier <mathieu.poirier@linaro.org>
 -R:    Suzuki K Poulose <suzuki.poulose@arm.com>
 +M:    Suzuki K Poulose <suzuki.poulose@arm.com>
  R:    Mike Leach <mike.leach@linaro.org>
 +R:    Leo Yan <leo.yan@linaro.org>
  L:    coresight@lists.linaro.org (moderated for non-subscribers)
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git
  F:    Documentation/ABI/testing/sysfs-bus-coresight-devices-*
  F:    Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt
  F:    Documentation/devicetree/bindings/arm/coresight-cti.yaml
@@@ -1799,6 -1789,14 +1799,6 @@@ F:     drivers/firmware/turris-mox-rwtm.
  F:    drivers/gpio/gpio-moxtet.c
  F:    include/linux/moxtet.h
  
 -ARM/EBSA110 MACHINE SUPPORT
 -M:    Russell King <linux@armlinux.org.uk>
 -L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 -S:    Maintained
 -W:    http://www.armlinux.org.uk/
 -F:    arch/arm/mach-ebsa110/
 -F:    drivers/net/ethernet/amd/am79c961a.*
 -
  ARM/ENERGY MICRO (SILICON LABS) EFM32 SUPPORT
  M:    Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
  R:    Pengutronix Kernel Team <kernel@pengutronix.de>
@@@ -1996,6 -1994,7 +1996,6 @@@ N:      lpc18x
  
  ARM/LPC32XX SOC SUPPORT
  M:    Vladimir Zapolskiy <vz@mleia.com>
 -M:    Sylvain Lemieux <slemieux.tyco@gmail.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
  T:    git git://github.com/vzapolskiy/linux-lpc32xx.git
@@@ -2013,6 -2012,7 +2013,6 @@@ M:      Philipp Zabel <philipp.zabel@gmail.c
  S:    Maintained
  
  ARM/Marvell Dove/MV78xx0/Orion SOC support
 -M:    Jason Cooper <jason@lakedaemon.net>
  M:    Andrew Lunn <andrew@lunn.ch>
  M:    Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  M:    Gregory Clement <gregory.clement@bootlin.com>
@@@ -2029,6 -2029,7 +2029,6 @@@ F:      arch/arm/plat-orion
  F:    drivers/soc/dove/
  
  ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K, CN9130 SOC support
 -M:    Jason Cooper <jason@lakedaemon.net>
  M:    Andrew Lunn <andrew@lunn.ch>
  M:    Gregory Clement <gregory.clement@bootlin.com>
  M:    Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
@@@ -2118,13 -2119,6 +2118,13 @@@ T:    git git://github.com/microchip-ung/l
  F:    arch/arm64/boot/dts/microchip/
  N:    sparx5
  
 +Microchip Timer Counter Block (TCB) Capture Driver
 +M:    Kamel Bouhara <kamel.bouhara@bootlin.com>
 +L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 +L:    linux-iio@vger.kernel.org
 +S:    Maintained
 +F:    drivers/counter/microchip-tcb-capture.c
 +
  ARM/MIOA701 MACHINE SUPPORT
  M:    Robert Jarzmik <robert.jarzmik@free.fr>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@@ -2380,7 -2374,8 +2380,7 @@@ F:      drivers/i2c/busses/i2c-rk3x.
  F:    sound/soc/rockchip/
  N:    rockchip
  
 -ARM/SAMSUNG EXYNOS ARM ARCHITECTURES
 -M:    Kukjin Kim <kgene@kernel.org>
 +ARM/SAMSUNG S3C, S5P AND EXYNOS ARM ARCHITECTURES
  M:    Krzysztof Kozlowski <krzk@kernel.org>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  L:    linux-samsung-soc@vger.kernel.org
@@@ -2409,7 -2404,15 +2409,7 @@@ N:     s3c241
  N:    s3c64xx
  N:    s5pv210
  
 -ARM/SAMSUNG MOBILE MACHINE SUPPORT
 -M:    Kyungmin Park <kyungmin.park@samsung.com>
 -L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 -S:    Maintained
 -F:    arch/arm/mach-s5pv210/
 -
  ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
 -M:    Kyungmin Park <kyungmin.park@samsung.com>
 -M:    Kamil Debski <kamil@wypas.org>
  M:    Andrzej Hajda <a.hajda@samsung.com>
  L:    linux-arm-kernel@lists.infradead.org
  L:    linux-media@vger.kernel.org
@@@ -2434,6 -2437,9 +2434,6 @@@ S:      Maintaine
  F:    drivers/media/platform/s5p-jpeg/
  
  ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
 -M:    Kyungmin Park <kyungmin.park@samsung.com>
 -M:    Kamil Debski <kamil@wypas.org>
 -M:    Jeongtae Park <jtp.park@samsung.com>
  M:    Andrzej Hajda <a.hajda@samsung.com>
  L:    linux-arm-kernel@lists.infradead.org
  L:    linux-media@vger.kernel.org
@@@ -2480,7 -2486,7 +2480,7 @@@ F:      drivers/clk/socfpga
  ARM/SOCFPGA EDAC SUPPORT
  M:    Dinh Nguyen <dinguyen@kernel.org>
  S:    Maintained
 -F:    drivers/edac/altera_edac.
 +F:    drivers/edac/altera_edac.[ch]
  
  ARM/SPREADTRUM SoC SUPPORT
  M:    Orson Zhai <orsonzhai@gmail.com>
@@@ -2636,8 -2642,10 +2636,8 @@@ F:     drivers/pinctrl/visconti
  N:    visconti
  
  ARM/UNIPHIER ARCHITECTURE
 -M:    Masahiro Yamada <yamada.masahiro@socionext.com>
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 -S:    Maintained
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier.git
 +S:    Orphan
  F:    Documentation/devicetree/bindings/arm/socionext/uniphier.yaml
  F:    Documentation/devicetree/bindings/gpio/socionext,uniphier-gpio.yaml
  F:    Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml
@@@ -2958,7 -2966,7 +2958,7 @@@ ATMEL MAXTOUCH DRIVE
  M:    Nick Dyer <nick@shmanahar.org>
  S:    Maintained
  T:    git git://github.com/ndyer/linux.git
 -F:    Documentation/devicetree/bindings/input/atmel,maxtouch.txt
 +F:    Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
  F:    drivers/input/touchscreen/atmel_mxt_ts.c
  
  ATMEL WIRELESS DRIVER
@@@ -2977,8 -2985,6 +2977,8 @@@ L:      linux-kernel@vger.kernel.or
  S:    Maintained
  F:    arch/*/include/asm/atomic*.h
  F:    include/*/atomic*.h
 +F:    include/linux/refcount.h
 +F:    Documentation/atomic_*.txt
  F:    scripts/atomic/
  
  ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
@@@ -3117,6 -3123,8 +3117,6 @@@ Q:      https://patchwork.open-mesh.org/proj
  B:    https://www.open-mesh.org/projects/batman-adv/issues
  C:    irc://chat.freenode.net/batman
  T:    git https://git.open-mesh.org/linux-merge.git
 -F:    Documentation/ABI/obsolete/sysfs-class-net-batman-adv
 -F:    Documentation/ABI/obsolete/sysfs-class-net-mesh
  F:    Documentation/networking/batman-adv.rst
  F:    include/uapi/linux/batadv_packet.h
  F:    include/uapi/linux/batman_adv.h
@@@ -3200,9 -3208,8 +3200,9 @@@ F:      drivers/mtd/devices/block2mtd.
  BLUETOOTH DRIVERS
  M:    Marcel Holtmann <marcel@holtmann.org>
  M:    Johan Hedberg <johan.hedberg@gmail.com>
 +M:    Luiz Augusto von Dentz <luiz.dentz@gmail.com>
  L:    linux-bluetooth@vger.kernel.org
 -S:    Maintained
 +S:    Supported
  W:    http://www.bluez.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
@@@ -3211,9 -3218,8 +3211,9 @@@ F:      drivers/bluetooth
  BLUETOOTH SUBSYSTEM
  M:    Marcel Holtmann <marcel@holtmann.org>
  M:    Johan Hedberg <johan.hedberg@gmail.com>
 +M:    Luiz Augusto von Dentz <luiz.dentz@gmail.com>
  L:    linux-bluetooth@vger.kernel.org
 -S:    Maintained
 +S:    Supported
  W:    http://www.bluez.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
@@@ -3240,12 -3246,12 +3240,12 @@@ F:   drivers/iio/accel/bma400
  BPF (Safe dynamic programs and tools)
  M:    Alexei Starovoitov <ast@kernel.org>
  M:    Daniel Borkmann <daniel@iogearbox.net>
 +M:    Andrii Nakryiko <andrii@kernel.org>
  R:    Martin KaFai Lau <kafai@fb.com>
  R:    Song Liu <songliubraving@fb.com>
  R:    Yonghong Song <yhs@fb.com>
 -R:    Andrii Nakryiko <andrii@kernel.org>
  R:    John Fastabend <john.fastabend@gmail.com>
 -R:    KP Singh <kpsingh@chromium.org>
 +R:    KP Singh <kpsingh@kernel.org>
  L:    netdev@vger.kernel.org
  L:    bpf@vger.kernel.org
  S:    Supported
@@@ -3363,17 -3369,6 +3363,17 @@@ S:    Supporte
  F:    arch/x86/net/
  X:    arch/x86/net/bpf_jit_comp32.c
  
 +BPF LSM (Security Audit and Enforcement using BPF)
 +M:    KP Singh <kpsingh@kernel.org>
 +R:    Florent Revest <revest@chromium.org>
 +R:    Brendan Jackman <jackmanb@chromium.org>
 +L:    bpf@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/bpf/bpf_lsm.rst
 +F:    include/linux/bpf_lsm.h
 +F:    kernel/bpf/bpf_lsm.c
 +F:    security/bpf/
 +
  BROADCOM B44 10/100 ETHERNET DRIVER
  M:    Michael Chan <michael.chan@broadcom.com>
  L:    netdev@vger.kernel.org
@@@ -3546,12 -3541,11 +3546,12 @@@ BROADCOM BRCM80211 IEEE802.11n WIRELES
  M:    Arend van Spriel <arend.vanspriel@broadcom.com>
  M:    Franky Lin <franky.lin@broadcom.com>
  M:    Hante Meuleman <hante.meuleman@broadcom.com>
 -M:    Chi-Hsien Lin <chi-hsien.lin@cypress.com>
 -M:    Wright Feng <wright.feng@cypress.com>
 +M:    Chi-hsien Lin <chi-hsien.lin@infineon.com>
 +M:    Wright Feng <wright.feng@infineon.com>
 +M:    Chung-hsien Hsu <chung-hsien.hsu@infineon.com>
  L:    linux-wireless@vger.kernel.org
  L:    brcm80211-dev-list.pdl@broadcom.com
 -L:    brcm80211-dev-list@cypress.com
 +L:    SHA-cyfmac-dev-list@infineon.com
  S:    Supported
  F:    drivers/net/wireless/broadcom/brcm80211/
  
@@@ -3578,14 -3572,6 +3578,14 @@@ S:    Maintaine
  F:    Documentation/devicetree/bindings/usb/brcm,bcm7445-ehci.yaml
  F:    drivers/usb/host/ehci-brcm.*
  
 +BROADCOM BRCMSTB USB PIN MAP DRIVER
 +M:    Al Cooper <alcooperx@gmail.com>
 +L:    linux-usb@vger.kernel.org
 +L:    bcm-kernel-feedback-list@broadcom.com
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/usb/brcm,usb-pinmap.yaml
 +F:    drivers/usb/misc/brcmstb-usb-pinmap.c
 +
  BROADCOM BRCMSTB USB2 and USB3 PHY DRIVER
  M:    Al Cooper <alcooperx@gmail.com>
  L:    linux-kernel@vger.kernel.org
@@@ -3871,11 -3857,10 +3871,11 @@@ CADENCE USB3 DRD IP DRIVE
  M:    Peter Chen <peter.chen@nxp.com>
  M:    Pawel Laszczak <pawell@cadence.com>
  M:    Roger Quadros <rogerq@ti.com>
 +R:    Aswath Govindraju <a-govindraju@ti.com>
  L:    linux-usb@vger.kernel.org
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
 -F:    Documentation/devicetree/bindings/usb/cdns-usb3.txt
 +F:    Documentation/devicetree/bindings/usb/cdns,usb3.yaml
  F:    drivers/usb/cdns3/
  
  CADET FM/AM RADIO RECEIVER DRIVER
@@@ -3887,8 -3872,9 +3887,8 @@@ T:      git git://linuxtv.org/media_tree.gi
  F:    drivers/media/radio/radio-cadet*
  
  CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER
 -M:    Jonathan Corbet <corbet@lwn.net>
  L:    linux-media@vger.kernel.org
 -S:    Maintained
 +S:    Orphan
  T:    git git://linuxtv.org/media_tree.git
  F:    Documentation/admin-guide/media/cafe_ccic*
  F:    drivers/media/platform/marvell-ccic/
@@@ -4301,7 -4287,6 +4301,7 @@@ B:      https://github.com/ClangBuiltLinux/l
  C:    irc://chat.freenode.net/clangbuiltlinux
  F:    Documentation/kbuild/llvm.rst
  F:    scripts/clang-tools/
 +F:    scripts/lld-version.sh
  K:    \b(?i:clang|llvm)\b
  
  CLEANCACHE API
@@@ -4369,7 -4354,7 +4369,7 @@@ CODA V4L2 MEM2MEM DRIVE
  M:    Philipp Zabel <p.zabel@pengutronix.de>
  L:    linux-media@vger.kernel.org
  S:    Maintained
 -F:    Documentation/devicetree/bindings/media/coda.txt
 +F:    Documentation/devicetree/bindings/media/coda.yaml
  F:    drivers/media/platform/coda/
  
  CODE OF CONDUCT
@@@ -4511,13 -4496,6 +4511,13 @@@ L:    linux-hwmon@vger.kernel.or
  S:    Maintained
  F:    drivers/hwmon/corsair-cpro.c
  
 +CORSAIR-PSU HARDWARE MONITOR DRIVER
 +M:    Wilken Gottwalt <wilken.gottwalt@posteo.net>
 +L:    linux-hwmon@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/hwmon/corsair-psu.rst
 +F:    drivers/hwmon/corsair-psu.c
 +
  COSA/SRP SYNC SERIAL DRIVER
  M:    Jan "Yenya" Kasprzak <kas@fi.muni.cz>
  S:    Maintained
@@@ -4735,7 -4713,7 +4735,7 @@@ T:      git git://linuxtv.org/anttip/media_t
  F:    drivers/media/dvb-frontends/cxd2820r*
  
  CXGB3 ETHERNET DRIVER (CXGB3)
 -M:    Vishal Kulkarni <vishal@chelsio.com>
 +M:    Raju Rangoju <rajur@chelsio.com>
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.chelsio.com
@@@ -4767,7 -4745,7 +4767,7 @@@ W:      http://www.chelsio.co
  F:    drivers/net/ethernet/chelsio/inline_crypto/
  
  CXGB4 ETHERNET DRIVER (CXGB4)
 -M:    Vishal Kulkarni <vishal@chelsio.com>
 +M:    Raju Rangoju <rajur@chelsio.com>
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.chelsio.com
@@@ -4789,7 -4767,7 +4789,7 @@@ F:      drivers/infiniband/hw/cxgb4
  F:    include/uapi/rdma/cxgb4-abi.h
  
  CXGB4VF ETHERNET DRIVER (CXGB4VF)
 -M:    Vishal Kulkarni <vishal@gmail.com>
 +M:    Raju Rangoju <rajur@chelsio.com>
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.chelsio.com
@@@ -5013,15 -4991,6 +5013,15 @@@ M:    Mario Limonciello <mario.limonciello
  S:    Maintained
  F:    drivers/platform/x86/dell-wmi-descriptor.c
  
 +DELL WMI SYSMAN DRIVER
 +M:    Divya Bharathi <divya.bharathi@dell.com>
 +M:    Mario Limonciello <mario.limonciello@dell.com>
 +M:    Prasanth Ksr <prasanth.ksr@dell.com>
 +L:    platform-driver-x86@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/ABI/testing/sysfs-class-firmware-attributes
 +F:    drivers/platform/x86/dell-wmi-sysman/
 +
  DELL WMI NOTIFICATIONS DRIVER
  M:    Matthew Garrett <mjg59@srcf.ucam.org>
  M:    Pali Rohár <pali@kernel.org>
@@@ -5037,8 -5006,9 +5037,8 @@@ T:      git git://linuxtv.org/media_tree.gi
  F:    drivers/media/platform/sti/delta
  
  DENALI NAND DRIVER
 -M:    Masahiro Yamada <yamada.masahiro@socionext.com>
  L:    linux-mtd@lists.infradead.org
 -S:    Supported
 +S:    Orphan
  F:    drivers/mtd/nand/raw/denali*
  
  DESIGNWARE EDMA CORE IP DRIVER
@@@ -5151,9 -5121,7 +5151,9 @@@ M:      Support Opensource <support.opensour
  S:    Supported
  W:    http://www.dialog-semiconductor.com/products
  F:    Documentation/devicetree/bindings/input/da90??-onkey.txt
 +F:    Documentation/devicetree/bindings/input/dlg,da72??.txt
  F:    Documentation/devicetree/bindings/mfd/da90*.txt
 +F:    Documentation/devicetree/bindings/regulator/dlg,da9*.yaml
  F:    Documentation/devicetree/bindings/regulator/da92*.txt
  F:    Documentation/devicetree/bindings/regulator/slg51000.txt
  F:    Documentation/devicetree/bindings/sound/da[79]*.txt
@@@ -5163,7 -5131,6 +5163,7 @@@ F:      Documentation/hwmon/da90??.rs
  F:    drivers/gpio/gpio-da90??.c
  F:    drivers/hwmon/da90??-hwmon.c
  F:    drivers/iio/adc/da91??-*.c
 +F:    drivers/input/misc/da72??.[ch]
  F:    drivers/input/misc/da90??_onkey.c
  F:    drivers/input/touchscreen/da9052_tsi.c
  F:    drivers/leds/leds-da90??.c
@@@ -5179,7 -5146,6 +5179,7 @@@ F:      drivers/rtc/rtc-da90??.
  F:    drivers/thermal/da90??-thermal.c
  F:    drivers/video/backlight/da90??_bl.c
  F:    drivers/watchdog/da90??_wdt.c
 +F:    include/dt-bindings/regulator/dlg,da9*-regulator.h
  F:    include/linux/mfd/da903x.h
  F:    include/linux/mfd/da9052/
  F:    include/linux/mfd/da9055/
@@@ -5614,13 -5580,6 +5614,13 @@@ T:    git git://anongit.freedesktop.org/dr
  F:    Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml
  F:    drivers/gpu/drm/panel/panel-novatek-nt35510.c
  
 +DRM DRIVER FOR NOVATEK NT36672A PANELS
 +M:    Sumit Semwal <sumit.semwal@linaro.org>
 +S:    Maintained
 +T:    git git://anongit.freedesktop.org/drm/drm-misc
 +F:    Documentation/devicetree/bindings/display/panel/novatek,nt36672a.yaml
 +F:    drivers/gpu/drm/panel/panel-novatek-nt36672a.c
 +
  DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS
  M:    Ben Skeggs <bskeggs@redhat.com>
  L:    dri-devel@lists.freedesktop.org
@@@ -5908,7 -5867,6 +5908,7 @@@ S:      Supporte
  F:    Documentation/devicetree/bindings/display/mediatek/
  F:    drivers/gpu/drm/mediatek/
  F:    drivers/phy/mediatek/phy-mtk-hdmi*
 +F:    drivers/phy/mediatek/phy-mtk-mipi*
  
  DRM DRIVERS FOR NVIDIA TEGRA
  M:    Thierry Reding <thierry.reding@gmail.com>
@@@ -6001,7 -5959,6 +6001,7 @@@ F:      include/uapi/drm/v3d_drm.
  
  DRM DRIVERS FOR VC4
  M:    Eric Anholt <eric@anholt.net>
 +M:    Maxime Ripard <mripard@kernel.org>
  S:    Supported
  T:    git git://github.com/anholt/linux
  T:    git git://anongit.freedesktop.org/drm/drm-misc
@@@ -6396,13 -6353,6 +6396,13 @@@ L:    linux-edac@vger.kernel.or
  S:    Maintained
  F:    drivers/edac/ie31200_edac.c
  
 +EDAC-IGEN6
 +M:    Tony Luck <tony.luck@intel.com>
 +R:    Qiuxu Zhuo <qiuxu.zhuo@intel.com>
 +L:    linux-edac@vger.kernel.org
 +S:    Maintained
 +F:    drivers/edac/igen6_edac.c
 +
  EDAC-MPC85XX
  M:    Johannes Thumshirn <morbidrsa@gmail.com>
  L:    linux-edac@vger.kernel.org
@@@ -6452,7 -6402,7 +6452,7 @@@ EDAC-SKYLAK
  M:    Tony Luck <tony.luck@intel.com>
  L:    linux-edac@vger.kernel.org
  S:    Maintained
 -F:    drivers/edac/skx_*.c
 +F:    drivers/edac/skx_*.[ch]
  
  EDAC-TI
  M:    Tero Kristo <t-kristo@ti.com>
@@@ -6668,7 -6618,6 +6668,7 @@@ Q:      http://patchwork.ozlabs.org/project/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git
  F:    Documentation/filesystems/ext4/
  F:    fs/ext4/
 +F:    include/trace/events/ext4.h
  
  Extended Verification Module (EVM)
  M:    Mimi Zohar <zohar@linux.ibm.com>
@@@ -6959,10 -6908,17 +6959,10 @@@ S:   Maintaine
  W:    http://floatingpoint.sourceforge.net/emulator/index.html
  F:    arch/x86/math-emu/
  
 -FRAME RELAY DLCI/FRAD (Sangoma drivers too)
 -L:    netdev@vger.kernel.org
 -S:    Orphan
 -F:    drivers/net/wan/dlci.c
 -F:    drivers/net/wan/sdla.c
 -
  FRAMEBUFFER LAYER
 -M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
  L:    dri-devel@lists.freedesktop.org
  L:    linux-fbdev@vger.kernel.org
 -S:    Maintained
 +S:    Orphan
  Q:    http://patchwork.kernel.org/project/linux-fbdev/list/
  T:    git git://anongit.freedesktop.org/drm/drm-misc
  F:    Documentation/fb/
@@@ -7339,6 -7295,7 +7339,6 @@@ F:      drivers/staging/gasket
  
  GCC PLUGINS
  M:    Kees Cook <keescook@chromium.org>
 -R:    Emese Revfy <re.emese@gmail.com>
  L:    linux-hardening@vger.kernel.org
  S:    Maintained
  F:    Documentation/kbuild/gcc-plugins.rst
@@@ -7380,17 -7337,6 +7380,17 @@@ S:    Maintaine
  F:    drivers/base/arch_topology.c
  F:    include/linux/arch_topology.h
  
 +GENERIC ENTRY CODE
 +M:    Thomas Gleixner <tglx@linutronix.de>
 +M:    Peter Zijlstra <peterz@infradead.org>
 +M:    Andy Lutomirski <luto@kernel.org>
 +L:    linux-kernel@vger.kernel.org
 +S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/entry
 +F:    include/linux/entry-common.h
 +F:    include/linux/entry-kvm.h
 +F:    kernel/entry/
 +
  GENERIC GPIO I2C DRIVER
  M:    Wolfram Sang <wsa+renesas@sang-engineering.com>
  S:    Supported
@@@ -7755,9 -7701,9 +7755,9 @@@ F:      drivers/clocksource/h8300_*.
  F:    drivers/irqchip/irq-renesas-h8*.c
  
  HABANALABS PCI DRIVER
 -M:    Oded Gabbay <oded.gabbay@gmail.com>
 +M:    Oded Gabbay <ogabbay@kernel.org>
  S:    Supported
 -T:    git https://github.com/HabanaAI/linux.git
 +T:    git https://git.kernel.org/pub/scm/linux/kernel/git/ogabbay/linux.git
  F:    Documentation/ABI/testing/debugfs-driver-habanalabs
  F:    Documentation/ABI/testing/sysfs-driver-habanalabs
  F:    drivers/misc/habanalabs/
@@@ -7955,15 -7901,6 +7955,15 @@@ F:    include/linux/hippidevice.
  F:    include/uapi/linux/if_hippi.h
  F:    net/802/hippi.c
  
 +HIRSCHMANN HELLCREEK ETHERNET SWITCH DRIVER
 +M:    Kurt Kanzenbach <kurt@linutronix.de>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/net/dsa/hirschmann,hellcreek.yaml
 +F:    drivers/net/dsa/hirschmann/*
 +F:    include/linux/platform_data/hirschmann-hellcreek.h
 +F:    net/dsa/tag_hellcreek.c
 +
  HISILICON DMA DRIVER
  M:    Zhou Wang <wangzhou1@hisilicon.com>
  L:    dmaengine@vger.kernel.org
@@@ -7983,7 -7920,7 +7983,7 @@@ HISILICON LPC BUS DRIVE
  M:    john.garry@huawei.com
  S:    Maintained
  W:    http://www.hisilicon.com
 -F:    Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 +F:    Documentation/devicetree/bindings/arm/hisilicon/low-pin-count.yaml
  F:    drivers/bus/hisi_lpc.c
  
  HISILICON NETWORK SUBSYSTEM 3 DRIVER (HNS3)
@@@ -8062,7 -7999,7 +8062,7 @@@ F:      drivers/staging/hikey9xx
  HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT
  M:    Zaibo Xu <xuzaibo@huawei.com>
  S:    Maintained
 -F:    drivers/char/hw_random/hisi-trng-v2.c
 +F:    drivers/crypto/hisilicon/trng/trng.c
  
  HISILICON V3XX SPI NOR FLASH Controller Driver
  M:    John Garry <john.garry@huawei.com>
@@@ -8690,7 -8627,7 +8690,7 @@@ INA209 HARDWARE MONITOR DRIVE
  M:    Guenter Roeck <linux@roeck-us.net>
  L:    linux-hwmon@vger.kernel.org
  S:    Maintained
 -F:    Documentation/devicetree/bindings/hwmon/ina2xx.txt
 +F:    Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
  F:    Documentation/hwmon/ina209.rst
  F:    drivers/hwmon/ina209.c
  
@@@ -8736,16 -8673,19 +8736,16 @@@ F:   include/uapi/rdma
  F:    samples/bpf/ibumad_kern.c
  F:    samples/bpf/ibumad_user.c
  
 -INGENIC JZ4780 DMA Driver
 -M:    Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
 -S:    Maintained
 -F:    drivers/dma/dma-jz4780.c
 -
  INGENIC JZ4780 NAND DRIVER
  M:    Harvey Hunt <harveyhuntnexus@gmail.com>
  L:    linux-mtd@lists.infradead.org
 +L:    linux-mips@vger.kernel.org
  S:    Maintained
  F:    drivers/mtd/nand/raw/ingenic/
  
  INGENIC JZ47xx SoCs
  M:    Paul Cercueil <paul@crapouillou.net>
 +L:    linux-mips@vger.kernel.org
  S:    Maintained
  F:    arch/mips/boot/dts/ingenic/
  F:    arch/mips/generic/board-ingenic.c
@@@ -8893,8 -8833,8 +8893,8 @@@ S:      Supporte
  W:    http://www.intel.com/support/feedback.htm
  W:    http://e1000.sourceforge.net/
  Q:    http://patchwork.ozlabs.org/project/intel-wired-lan/list/
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue.git
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git
  F:    Documentation/networking/device_drivers/ethernet/intel/
  F:    drivers/net/ethernet/intel/
  F:    drivers/net/ethernet/intel/*/
@@@ -9018,23 -8958,6 +9018,23 @@@ M:    Deepak Saxena <dsaxena@plexity.net
  S:    Maintained
  F:    drivers/char/hw_random/ixp4xx-rng.c
  
 +INTEL KEEM BAY DRM DRIVER
 +M:    Anitha Chrisanthus <anitha.chrisanthus@intel.com>
 +M:    Edmund Dea <edmund.j.dea@intel.com>
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/display/intel,kmb_display.yaml
 +F:    drivers/gpu/drm/kmb/
 +
 +INTEL KEEM BAY OCS AES/SM4 CRYPTO DRIVER
 +M:    Daniele Alessandrelli <daniele.alessandrelli@intel.com>
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/crypto/intel,keembay-ocs-aes.yaml
 +F:    drivers/crypto/keembay/Kconfig
 +F:    drivers/crypto/keembay/Makefile
 +F:    drivers/crypto/keembay/keembay-ocs-aes-core.c
 +F:    drivers/crypto/keembay/ocs-aes.c
 +F:    drivers/crypto/keembay/ocs-aes.h
 +
  INTEL MANAGEMENT ENGINE (mei)
  M:    Tomas Winkler <tomas.winkler@intel.com>
  L:    linux-kernel@vger.kernel.org
@@@ -9053,6 -8976,22 +9053,6 @@@ S:     Supporte
  W:    https://01.org/linux-acpi
  F:    drivers/platform/x86/intel_menlow.c
  
 -INTEL MIC DRIVERS (mic)
 -M:    Sudeep Dutt <sudeep.dutt@intel.com>
 -M:    Ashutosh Dixit <ashutosh.dixit@intel.com>
 -S:    Supported
 -W:    https://github.com/sudeepdutt/mic
 -W:    http://software.intel.com/en-us/mic-developer
 -F:    Documentation/misc-devices/mic/
 -F:    drivers/dma/mic_x100_dma.c
 -F:    drivers/dma/mic_x100_dma.h
 -F:    drivers/misc/mic/
 -F:    include/linux/mic_bus.h
 -F:    include/linux/scif.h
 -F:    include/uapi/linux/mic_common.h
 -F:    include/uapi/linux/mic_ioctl.h
 -F:    include/uapi/linux/scif_ioctl.h
 -
  INTEL P-Unit IPC DRIVER
  M:    Zha Qipeng <qipeng.zha@intel.com>
  L:    platform-driver-x86@vger.kernel.org
@@@ -9082,12 -9021,6 +9082,12 @@@ F:    drivers/mfd/intel_soc_pmic
  F:    include/linux/mfd/intel_msic.h
  F:    include/linux/mfd/intel_soc_pmic*
  
 +INTEL PMT DRIVER
 +M:    "David E. Box" <david.e.box@linux.intel.com>
 +S:    Maintained
 +F:    drivers/mfd/intel_pmt.c
 +F:    drivers/platform/x86/intel_pmt_*
 +
  INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
  M:    Stanislav Yakovlev <stas.yakovlev@gmail.com>
  L:    linux-wireless@vger.kernel.org
@@@ -9163,13 -9096,26 +9163,13 @@@ S:   Supporte
  F:    drivers/net/wireless/intel/iwlegacy/
  
  INTEL WIRELESS WIFI LINK (iwlwifi)
 -M:    Johannes Berg <johannes.berg@intel.com>
 -M:    Emmanuel Grumbach <emmanuel.grumbach@intel.com>
  M:    Luca Coelho <luciano.coelho@intel.com>
 -M:    Intel Linux Wireless <linuxwifi@intel.com>
  L:    linux-wireless@vger.kernel.org
  S:    Supported
  W:    https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
  F:    drivers/net/wireless/intel/iwlwifi/
  
 -INTEL WIRELESS WIMAX CONNECTION 2400
 -M:    Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
 -M:    linux-wimax@intel.com
 -L:    wimax@linuxwimax.org (subscribers-only)
 -S:    Supported
 -W:    http://linuxwimax.org
 -F:    Documentation/admin-guide/wimax/i2400m.rst
 -F:    drivers/net/wimax/i2400m/
 -F:    include/uapi/linux/wimax/i2400m.h
 -
  INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER
  M:    Jithu Joseph <jithu.joseph@intel.com>
  R:    Maurice Ma <maurice.ma@intel.com>
@@@ -9199,19 -9145,6 +9199,19 @@@ F:    Documentation/x86/intel_txt.rs
  F:    arch/x86/kernel/tboot.c
  F:    include/linux/tboot.h
  
 +INTEL SGX
 +M:    Jarkko Sakkinen <jarkko@kernel.org>
 +L:    linux-sgx@vger.kernel.org
 +S:    Supported
 +Q:    https://patchwork.kernel.org/project/intel-sgx/list/
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-sgx.git
 +F:    Documentation/x86/sgx.rst
 +F:    arch/x86/entry/vdso/vsgx.S
 +F:    arch/x86/include/uapi/asm/sgx.h
 +F:    arch/x86/kernel/cpu/sgx/*
 +F:    tools/testing/selftests/sgx/*
 +K:    \bSGX_
 +
  INTERCONNECT API
  M:    Georgi Djakov <georgi.djakov@linaro.org>
  L:    linux-pm@vger.kernel.org
@@@ -9227,7 -9160,7 +9227,7 @@@ INVENSENSE ICM-426xx IMU DRIVE
  M:    Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
  L:    linux-iio@vger.kernel.org
  S:    Maintained
 -W     https://invensense.tdk.com/
 +W:    https://invensense.tdk.com/
  F:    Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
  F:    drivers/iio/imu/inv_icm42600/
  
@@@ -9258,7 -9191,6 +9258,7 @@@ F:      include/linux/iomap.
  
  IOMMU DRIVERS
  M:    Joerg Roedel <joro@8bytes.org>
 +M:    Will Deacon <will@kernel.org>
  L:    iommu@lists.linux-foundation.org
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@@ -9342,6 -9274,7 +9342,6 @@@ F:      kernel/irq
  
  IRQCHIP DRIVERS
  M:    Thomas Gleixner <tglx@linutronix.de>
 -M:    Jason Cooper <jason@lakedaemon.net>
  M:    Marc Zyngier <maz@kernel.org>
  L:    linux-kernel@vger.kernel.org
  S:    Maintained
@@@ -9707,7 -9640,7 +9707,7 @@@ F:      arch/arm64/kvm
  F:    include/kvm/arm_*
  
  KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
 -M:    Huacai Chen <chenhc@lemote.com>
 +M:    Huacai Chen <chenhuacai@kernel.org>
  M:    Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
  L:    linux-mips@vger.kernel.org
  L:    kvm@vger.kernel.org
@@@ -9741,7 -9674,6 +9741,7 @@@ F:      Documentation/virt/kvm/s390
  F:    arch/s390/include/asm/gmap.h
  F:    arch/s390/include/asm/kvm*
  F:    arch/s390/include/uapi/asm/kvm*
 +F:    arch/s390/kernel/uv.c
  F:    arch/s390/kvm/
  F:    arch/s390/mm/gmap.c
  F:    tools/testing/selftests/kvm/*/s390x/
@@@ -9930,6 -9862,13 +9930,6 @@@ S:     Maintaine
  F:    arch/mips/lantiq
  F:    drivers/soc/lantiq
  
 -LAPB module
 -L:    linux-x25@vger.kernel.org
 -S:    Orphan
 -F:    Documentation/networking/lapb-module.rst
 -F:    include/*/lapb.h
 -F:    net/lapb/
 -
  LASI 53c700 driver for PARISC
  M:    "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
  L:    linux-scsi@vger.kernel.org
@@@ -10458,8 -10397,6 +10458,8 @@@ L:   linux-m68k@lists.linux-m68k.or
  S:    Maintained
  W:    http://www.mac.linux-m68k.org/
  F:    arch/m68k/mac/
 +F:    drivers/macintosh/adb-iop.c
 +F:    drivers/macintosh/via-macii.c
  
  M68K ON HP9000/300
  M:    Philip Blundell <philb@gnu.org>
@@@ -10559,7 -10496,6 +10559,7 @@@ M:   Srujana Challa <schalla@marvell.com
  L:    linux-crypto@vger.kernel.org
  S:    Maintained
  F:    drivers/crypto/marvell/
 +F:    include/linux/soc/marvell/octeontx2/
  
  MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
  M:    Mirko Lindner <mlindner@marvell.com>
@@@ -10603,14 -10539,6 +10603,14 @@@ L: netdev@vger.kernel.or
  S:    Maintained
  F:    drivers/net/ethernet/marvell/mvneta.*
  
 +MARVELL MVPP2 ETHERNET DRIVER
 +M:    Marcin Wojtas <mw@semihalf.com>
 +M:    Russell King <linux@armlinux.org.uk>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/net/marvell-pp2.txt
 +F:    drivers/net/ethernet/marvell/mvpp2/
 +
  MARVELL MWIFIEX WIRELESS DRIVER
  M:    Amitkumar Karwar <amitkarwar@gmail.com>
  M:    Ganapathi Bhat <ganapathi.bhat@nxp.com>
@@@ -10640,7 -10568,6 +10640,7 @@@ M:   hariprasad <hkelam@marvell.com
  L:    netdev@vger.kernel.org
  S:    Supported
  F:    drivers/net/ethernet/marvell/octeontx2/nic/
 +F:    include/linux/soc/marvell/octeontx2/
  
  MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER
  M:    Sunil Goutham <sgoutham@marvell.com>
@@@ -10652,13 -10579,6 +10652,13 @@@ S: Supporte
  F:    Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
  F:    drivers/net/ethernet/marvell/octeontx2/af/
  
 +MARVELL PRESTERA ETHERNET SWITCH DRIVER
 +M:    Vadym Kochan <vkochan@marvell.com>
 +M:    Taras Chornyi <tchornyi@marvell.com>
 +S:    Supported
 +W:    https://github.com/Marvell-switching/switchdev-prestera
 +F:    drivers/net/ethernet/marvell/prestera/
 +
  MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
  M:    Nicolas Pitre <nico@fluxnic.net>
  S:    Odd Fixes
@@@ -10928,8 -10848,8 +10928,8 @@@ L:   linux-media@vger.kernel.or
  S:    Maintained
  T:    git git://linuxtv.org/media_tree.git
  F:    Documentation/admin-guide/media/imx7.rst
 -F:    Documentation/devicetree/bindings/media/imx7-csi.txt
 -F:    Documentation/devicetree/bindings/media/imx7-mipi-csi2.txt
 +F:    Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
 +F:    Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml
  F:    drivers/staging/media/imx/imx7-media-csi.c
  F:    drivers/staging/media/imx/imx7-mipi-csis.c
  
@@@ -11188,12 -11108,6 +11188,12 @@@ S: Maintaine
  F:    Documentation/devicetree/bindings/i2c/i2c-mt7621.txt
  F:    drivers/i2c/busses/i2c-mt7621.c
  
 +MEDIATEK MT7621 PHY PCI DRIVER
 +M:    Sergio Paracuellos <sergio.paracuellos@gmail.com>
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml
 +F:    drivers/phy/ralink/phy-mt7621-pci.c
 +
  MEDIATEK NAND CONTROLLER DRIVER
  L:    linux-mtd@lists.infradead.org
  S:    Orphan
@@@ -11269,10 -11183,9 +11269,10 @@@ F: Documentation/devicetree/bindings/in
  F:    drivers/input/touchscreen/melfas_mip4.c
  
  MELLANOX BLUEFIELD I2C DRIVER
 -M:    Khalil Blaiech <kblaiech@mellanox.com>
 +M:    Khalil Blaiech <kblaiech@nvidia.com>
  L:    linux-i2c@vger.kernel.org
  S:    Supported
 +F:    Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml
  F:    drivers/i2c/busses/i2c-mlxbf.c
  
  MELLANOX ETHERNET DRIVER (mlx4_en)
@@@ -11280,7 -11193,7 +11280,7 @@@ M:   Tariq Toukan <tariqt@nvidia.com
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.mellanox.com
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  F:    drivers/net/ethernet/mellanox/mlx4/en_*
  
  MELLANOX ETHERNET DRIVER (mlx5e)
@@@ -11288,7 -11201,7 +11288,7 @@@ M:   Saeed Mahameed <saeedm@nvidia.com
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.mellanox.com
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  F:    drivers/net/ethernet/mellanox/mlx5/core/en_*
  
  MELLANOX ETHERNET INNOVA DRIVERS
@@@ -11296,7 -11209,7 +11296,7 @@@ R:   Boris Pismenny <borisp@nvidia.com
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.mellanox.com
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  F:    drivers/net/ethernet/mellanox/mlx5/core/accel/*
  F:    drivers/net/ethernet/mellanox/mlx5/core/en_accel/*
  F:    drivers/net/ethernet/mellanox/mlx5/core/fpga/*
@@@ -11308,7 -11221,7 +11308,7 @@@ M:   Ido Schimmel <idosch@nvidia.com
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.mellanox.com
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  F:    drivers/net/ethernet/mellanox/mlxsw/
  F:    tools/testing/selftests/drivers/net/mlxsw/
  
@@@ -11317,7 -11230,7 +11317,7 @@@ M:   mlxsw@nvidia.co
  L:    netdev@vger.kernel.org
  S:    Supported
  W:    http://www.mellanox.com
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  F:    drivers/net/ethernet/mellanox/mlxfw/
  
  MELLANOX HARDWARE PLATFORM SUPPORT
@@@ -11336,7 -11249,7 +11336,7 @@@ L:   netdev@vger.kernel.or
  L:    linux-rdma@vger.kernel.org
  S:    Supported
  W:    http://www.mellanox.com
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  F:    drivers/net/ethernet/mellanox/mlx4/
  F:    include/linux/mlx4/
  
@@@ -11357,7 -11270,7 +11357,7 @@@ L:   netdev@vger.kernel.or
  L:    linux-rdma@vger.kernel.org
  S:    Supported
  W:    http://www.mellanox.com
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  F:    Documentation/networking/device_drivers/ethernet/mellanox/
  F:    drivers/net/ethernet/mellanox/mlx5/core/
  F:    include/linux/mlx5/
@@@ -11426,6 -11339,7 +11426,6 @@@ L:   linux-pm@vger.kernel.or
  L:    linux-tegra@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
  S:    Maintained
 -F:    drivers/devfreq/tegra20-devfreq.c
  F:    drivers/devfreq/tegra30-devfreq.c
  
  MEMORY MANAGEMENT
@@@ -11498,15 -11412,6 +11498,15 @@@ F: Documentation/devicetree/bindings/me
  F:    drivers/media/cec/platform/meson/ao-cec-g12a.c
  F:    drivers/media/cec/platform/meson/ao-cec.c
  
 +MESON GE2D DRIVER FOR AMLOGIC SOCS
 +M:    Neil Armstrong <narmstrong@baylibre.com>
 +L:    linux-media@vger.kernel.org
 +L:    linux-amlogic@lists.infradead.org
 +S:    Supported
 +T:    git git://linuxtv.org/media_tree.git
 +F:    Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml
 +F:    drivers/media/meson/ge2d/
 +
  MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS
  M:    Liang Yang <liang.yang@amlogic.com>
  L:    linux-mtd@lists.infradead.org
@@@ -11623,7 -11528,7 +11623,7 @@@ M:   Woojung Huh <woojung.huh@microchip.c
  M:    Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
  L:    netdev@vger.kernel.org
  S:    Maintained
 -F:    Documentation/devicetree/bindings/net/dsa/ksz.txt
 +F:    Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
  F:    drivers/net/dsa/microchip/*
  F:    include/linux/platform_data/microchip-ksz.h
  F:    net/dsa/tag_ksz.c
@@@ -11745,43 -11650,17 +11745,43 @@@ F:        drivers/scsi/smartpqi/smartpqi*.[ch
  F:    include/linux/cciss*.h
  F:    include/uapi/linux/cciss*.h
  
 +MICROSOFT SURFACE GPE LID SUPPORT DRIVER
 +M:    Maximilian Luz <luzmaximilian@gmail.com>
 +L:    platform-driver-x86@vger.kernel.org
 +S:    Maintained
 +F:    drivers/platform/surface/surface_gpe.c
 +
 +MICROSOFT SURFACE HARDWARE PLATFORM SUPPORT
 +M:    Hans de Goede <hdegoede@redhat.com>
 +M:    Mark Gross <mgross@linux.intel.com>
 +M:    Maximilian Luz <luzmaximilian@gmail.com>
 +L:    platform-driver-x86@vger.kernel.org
 +S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
 +F:    drivers/platform/surface/
 +
  MICROSOFT SURFACE PRO 3 BUTTON DRIVER
  M:    Chen Yu <yu.c.chen@intel.com>
  L:    platform-driver-x86@vger.kernel.org
  S:    Supported
 -F:    drivers/platform/x86/surfacepro3_button.c
 +F:    drivers/platform/surface/surfacepro3_button.c
  
  MICROTEK X6 SCANNER
  M:    Oliver Neukum <oliver@neukum.org>
  S:    Maintained
  F:    drivers/usb/image/microtek.*
  
 +MIPI CCS, SMIA AND SMIA++ IMAGE SENSOR DRIVER
 +M:    Sakari Ailus <sakari.ailus@linux.intel.com>
 +L:    linux-media@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml
 +F:    Documentation/driver-api/media/drivers/ccs/
 +F:    drivers/media/i2c/ccs-pll.c
 +F:    drivers/media/i2c/ccs-pll.h
 +F:    drivers/media/i2c/ccs/
 +F:    include/uapi/linux/smiapp.h
 +
  MIPS
  M:    Thomas Bogendoerfer <tsbogend@alpha.franken.de>
  L:    linux-mips@vger.kernel.org
@@@ -11849,7 -11728,7 +11849,7 @@@ F:   drivers/*/*/*loongson2
  F:    drivers/*/*loongson2*
  
  MIPS/LOONGSON64 ARCHITECTURE
 -M:    Huacai Chen <chenhc@lemote.com>
 +M:    Huacai Chen <chenhuacai@kernel.org>
  M:    Jiaxun Yang <jiaxun.yang@flygoat.com>
  L:    linux-mips@vger.kernel.org
  S:    Maintained
@@@ -12052,7 -11931,7 +12052,7 @@@ M:   Jacopo Mondi <jacopo@jmondi.org
  L:    linux-media@vger.kernel.org
  S:    Maintained
  T:    git git://linuxtv.org/media_tree.git
 -F:    Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.txt
 +F:    Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml
  F:    drivers/media/i2c/mt9v111.c
  
  MULTIFUNCTION DEVICES (MFD)
@@@ -12271,7 -12150,7 +12271,7 @@@ M:   Jakub Kicinski <kuba@kernel.org
  L:    netdev@vger.kernel.org
  S:    Maintained
  W:    http://www.linuxfoundation.org/en/Net
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
  F:    Documentation/devicetree/bindings/net/
@@@ -12316,7 -12195,7 +12316,7 @@@ M:   Jakub Kicinski <kuba@kernel.org
  L:    netdev@vger.kernel.org
  S:    Maintained
  W:    http://www.linuxfoundation.org/en/Net
 -Q:    http://patchwork.ozlabs.org/project/netdev/list/
 +Q:    https://patchwork.kernel.org/project/netdevbpf/list/
  B:    mailto:netdev@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
@@@ -12396,7 -12275,6 +12396,7 @@@ L:   mptcp@lists.01.or
  S:    Maintained
  W:    https://github.com/multipath-tcp/mptcp_net-next/wiki
  B:    https://github.com/multipath-tcp/mptcp_net-next/issues
 +F:    Documentation/networking/mptcp-sysctl.rst
  F:    include/net/mptcp.h
  F:    include/uapi/linux/mptcp.h
  F:    net/mptcp/
@@@ -12687,7 -12565,7 +12687,7 @@@ NXP FXAS21002C DRIVE
  M:    Rui Miguel Silva <rmfrfs@gmail.com>
  L:    linux-iio@vger.kernel.org
  S:    Maintained
 -F:    Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.txt
 +F:    Documentation/devicetree/bindings/iio/gyroscope/nxp,fxas21002c.yaml
  F:    drivers/iio/gyro/fxas21002c.h
  F:    drivers/iio/gyro/fxas21002c_core.c
  F:    drivers/iio/gyro/fxas21002c_i2c.c
@@@ -12701,12 -12579,6 +12701,12 @@@ S: Maintaine
  F:    Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
  F:    drivers/gpu/drm/imx/dcss/
  
 +NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER
 +M:    Jagan Teki <jagan@amarulasolutions.com>
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/regulator/nxp,pf8x00-regulator.yaml
 +F:    drivers/regulator/pf8x00-regulator.c
 +
  NXP PTN5150A CC LOGIC AND EXTCON DRIVER
  M:    Krzysztof Kozlowski <krzk@kernel.org>
  L:    linux-kernel@vger.kernel.org
@@@ -13004,14 -12876,6 +13004,14 @@@ M: Harald Welte <laforge@gnumonks.org
  S:    Maintained
  F:    drivers/char/pcmcia/cm4040_cs.*
  
 +OMNIVISION OV02A10 SENSOR DRIVER
 +M:    Dongchun Zhu <dongchun.zhu@mediatek.com>
 +L:    linux-media@vger.kernel.org
 +S:    Maintained
 +T:    git git://linuxtv.org/media_tree.git
 +F:    Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml
 +F:    drivers/media/i2c/ov02a10.c
 +
  OMNIVISION OV13858 SENSOR DRIVER
  M:    Sakari Ailus <sakari.ailus@linux.intel.com>
  L:    linux-media@vger.kernel.org
@@@ -13024,7 -12888,7 +13024,7 @@@ M:   Rui Miguel Silva <rmfrfs@gmail.com
  L:    linux-media@vger.kernel.org
  S:    Maintained
  T:    git git://linuxtv.org/media_tree.git
 -F:    Documentation/devicetree/bindings/media/i2c/ov2680.txt
 +F:    Documentation/devicetree/bindings/media/i2c/ov2680.yaml
  F:    drivers/media/i2c/ov2680.c
  
  OMNIVISION OV2685 SENSOR DRIVER
@@@ -13082,8 -12946,9 +13082,8 @@@ T:   git git://linuxtv.org/media_tree.gi
  F:    drivers/media/i2c/ov5695.c
  
  OMNIVISION OV7670 SENSOR DRIVER
 -M:    Jonathan Corbet <corbet@lwn.net>
  L:    linux-media@vger.kernel.org
 -S:    Maintained
 +S:    Orphan
  T:    git git://linuxtv.org/media_tree.git
  F:    Documentation/devicetree/bindings/media/i2c/ov7670.txt
  F:    drivers/media/i2c/ov7670.c
@@@ -13093,7 -12958,7 +13093,7 @@@ M:   Jacopo Mondi <jacopo@jmondi.org
  L:    linux-media@vger.kernel.org
  S:    Odd fixes
  T:    git git://linuxtv.org/media_tree.git
 -F:    Documentation/devicetree/bindings/media/i2c/ov772x.txt
 +F:    Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml
  F:    drivers/media/i2c/ov772x.c
  F:    include/media/i2c/ov772x.h
  
@@@ -13129,14 -12994,6 +13129,14 @@@ T: git git://linuxtv.org/media_tree.gi
  F:    Documentation/devicetree/bindings/media/i2c/ov9650.txt
  F:    drivers/media/i2c/ov9650.c
  
 +OMNIVISION OV9734 SENSOR DRIVER
 +M:    Tianshu Qiu <tian.shu.qiu@intel.com>
 +R:    Bingbu Cao <bingbu.cao@intel.com>
 +L:    linux-media@vger.kernel.org
 +S:    Maintained
 +T:    git git://linuxtv.org/media_tree.git
 +F:    drivers/media/i2c/ov9734.c
 +
  ONENAND FLASH DRIVER
  M:    Kyungmin Park <kyungmin.park@samsung.com>
  L:    linux-mtd@lists.infradead.org
@@@ -13339,13 -13196,11 +13339,13 @@@ M:        Jesper Dangaard Brouer <hawk@kernel.
  M:    Ilias Apalodimas <ilias.apalodimas@linaro.org>
  L:    netdev@vger.kernel.org
  S:    Supported
 +F:    Documentation/networking/page_pool.rst
  F:    include/net/page_pool.h
 +F:    include/trace/events/page_pool.h
  F:    net/core/page_pool.c
  
  PANASONIC LAPTOP ACPI EXTRAS DRIVER
 -M:    Harald Welte <laforge@gnumonks.org>
 +M:    Kenneth Chan <kenneth.t.chan@gmail.com>
  L:    platform-driver-x86@vger.kernel.org
  S:    Maintained
  F:    drivers/platform/x86/panasonic-laptop.c
@@@ -13569,6 -13424,7 +13569,6 @@@ F:   drivers/pci/controller/mobiveil/pcie
  
  PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
  M:    Thomas Petazzoni <thomas.petazzoni@bootlin.com>
 -M:    Jason Cooper <jason@lakedaemon.net>
  L:    linux-pci@vger.kernel.org
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
  S:    Maintained
@@@ -13644,8 -13500,6 +13644,8 @@@ M:   Kishon Vijay Abraham I <kishon@ti.co
  M:    Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
  L:    linux-pci@vger.kernel.org
  S:    Supported
 +F:    Documentation/PCI/endpoint/*
 +F:    Documentation/misc-devices/pci-endpoint-test.rst
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
  F:    drivers/misc/pci_endpoint_test.c
  F:    drivers/pci/endpoint/
@@@ -14069,13 -13923,6 +14069,13 @@@ M: Logan Gunthorpe <logang@deltatee.com
  S:    Maintained
  F:    drivers/dma/plx_dma.c
  
 +PM6764TR DRIVER
 +M:    Charles Hsu     <hsu.yungteng@gmail.com>
 +L:    linux-hwmon@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/hwmon/pm6764tr.rst
 +F:    drivers/hwmon/pmbus/pm6764tr.c
 +
  PM-GRAPH UTILITY
  M:    "Todd E Brandt" <todd.e.brandt@linux.intel.com>
  L:    linux-pm@vger.kernel.org
@@@ -14383,6 -14230,7 +14383,6 @@@ F:   drivers/media/usb/pwc/
  F:    include/trace/events/pwc.h
  
  PWM FAN DRIVER
 -M:    Kamil Debski <kamil@wypas.org>
  M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
  L:    linux-hwmon@vger.kernel.org
  S:    Supported
@@@ -14618,7 -14466,6 +14618,7 @@@ W:   https://wireless.wiki.kernel.org/en/
  F:    drivers/net/wireless/ath/ath9k/
  
  QUALCOMM CAMERA SUBSYSTEM DRIVER
 +M:    Robert Foss <robert.foss@linaro.org>
  M:    Todor Tomov <todor.too@gmail.com>
  L:    linux-media@vger.kernel.org
  S:    Maintained
@@@ -14700,22 -14547,6 +14700,22 @@@ F: Documentation/devicetree/bindings/ma
  F:    drivers/mailbox/qcom-ipcc.c
  F:    include/dt-bindings/mailbox/qcom-ipcc.h
  
 +QUALCOMM IPQ4019 USB PHY DRIVER
 +M:    Robert Marko <robert.marko@sartura.hr>
 +M:    Luka Perkov <luka.perkov@sartura.hr>
 +L:    linux-arm-msm@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml
 +F:    drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c
 +
 +QUALCOMM IPQ4019 VQMMC REGULATOR DRIVER
 +M:    Robert Marko <robert.marko@sartura.hr>
 +M:    Luka Perkov <luka.perkov@sartura.hr>
 +L:    linux-arm-msm@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/regulator/vqmmc-ipq4019-regulator.yaml
 +F:    drivers/regulator/vqmmc-ipq4019-regulator.c
 +
  QUALCOMM RMNET DRIVER
  M:    Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
  M:    Sean Tranchetti <stranche@codeaurora.org>
@@@ -15000,7 -14831,7 +15000,7 @@@ T:   git git://git.kernel.org/pub/scm/lin
  F:    drivers/net/wireless/realtek/rtlwifi/
  
  REALTEK WIRELESS DRIVER (rtw88)
 -M:    Yan-Hsuan Chuang <yhchuang@realtek.com>
 +M:    Yan-Hsuan Chuang <tony0620emma@gmail.com>
  L:    linux-wireless@vger.kernel.org
  S:    Maintained
  F:    drivers/net/wireless/realtek/rtw88/
@@@ -15071,6 -14902,7 +15071,6 @@@ RENESAS ETHERNET DRIVER
  R:    Sergei Shtylyov <sergei.shtylyov@gmail.com>
  L:    netdev@vger.kernel.org
  L:    linux-renesas-soc@vger.kernel.org
 -F:    Documentation/devicetree/bindings/net/renesas,*.txt
  F:    Documentation/devicetree/bindings/net/renesas,*.yaml
  F:    drivers/net/ethernet/renesas/
  F:    include/linux/sh_eth.h
@@@ -15116,7 -14948,6 +15116,7 @@@ M:   Philipp Zabel <p.zabel@pengutronix.d
  S:    Maintained
  T:    git git://git.pengutronix.de/git/pza/linux
  F:    Documentation/devicetree/bindings/reset/
 +F:    Documentation/driver-api/reset.rst
  F:    drivers/reset/
  F:    include/dt-bindings/reset/
  F:    include/linux/reset-controller.h
@@@ -15201,13 -15032,10 +15201,13 @@@ ROCKCHIP ISP V1 DRIVE
  M:    Helen Koike <helen.koike@collabora.com>
  M:    Dafna Hirschfeld <dafna.hirschfeld@collabora.com>
  L:    linux-media@vger.kernel.org
 +L:    linux-rockchip@lists.infradead.org
  S:    Maintained
  F:    Documentation/admin-guide/media/rkisp1.rst
 +F:    Documentation/devicetree/bindings/media/rockchip-isp1.yaml
  F:    Documentation/userspace-api/media/v4l/pixfmt-meta-rkisp1.rst
 -F:    drivers/staging/media/rkisp1/
 +F:    drivers/media/platform/rockchip/rkisp1
 +F:    include/uapi/linux/rkisp1-config.h
  
  ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER
  M:    Jacob Chen <jacob-chen@iotwrt.com>
@@@ -15431,6 -15259,7 +15431,6 @@@ F:   drivers/iommu/s390-iommu.
  S390 IUCV NETWORK LAYER
  M:    Julian Wiedmann <jwi@linux.ibm.com>
  M:    Karsten Graul <kgraul@linux.ibm.com>
 -M:    Ursula Braun <ubraun@linux.ibm.com>
  L:    linux-s390@vger.kernel.org
  S:    Supported
  W:    http://www.ibm.com/developerworks/linux/linux390/
@@@ -15441,6 -15270,7 +15441,6 @@@ F:   net/iucv
  S390 NETWORK DRIVERS
  M:    Julian Wiedmann <jwi@linux.ibm.com>
  M:    Karsten Graul <kgraul@linux.ibm.com>
 -M:    Ursula Braun <ubraun@linux.ibm.com>
  L:    linux-s390@vger.kernel.org
  S:    Supported
  W:    http://www.ibm.com/developerworks/linux/linux390/
@@@ -15542,6 -15372,7 +15542,6 @@@ F:   security/safesetid
  
  SAMSUNG AUDIO (ASoC) DRIVERS
  M:    Krzysztof Kozlowski <krzk@kernel.org>
 -M:    Sangbeom Kim <sbkim73@samsung.com>
  M:    Sylwester Nawrocki <s.nawrocki@samsung.com>
  L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
  S:    Supported
@@@ -15569,14 -15400,6 +15569,14 @@@ L: linux-fbdev@vger.kernel.or
  S:    Maintained
  F:    drivers/video/fbdev/s3c-fb.c
  
 +SAMSUNG INTERCONNECT DRIVERS
 +M:    Sylwester Nawrocki <s.nawrocki@samsung.com>
 +M:    Artur Świgoń <a.swigon@samsung.com>
 +L:    linux-pm@vger.kernel.org
 +L:    linux-samsung-soc@vger.kernel.org
 +S:    Supported
 +F:    drivers/interconnect/samsung/
 +
  SAMSUNG LAPTOP DRIVER
  M:    Corentin Chary <corentin.chary@gmail.com>
  L:    platform-driver-x86@vger.kernel.org
@@@ -15584,6 -15407,7 +15584,6 @@@ S:   Maintaine
  F:    drivers/platform/x86/samsung-laptop.c
  
  SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS
 -M:    Sangbeom Kim <sbkim73@samsung.com>
  M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
  L:    linux-kernel@vger.kernel.org
@@@ -15617,12 -15441,14 +15617,12 @@@ F:        Documentation/devicetree/bindings/ne
  F:    drivers/nfc/s3fwrn5
  
  SAMSUNG S5C73M3 CAMERA DRIVER
 -M:    Kyungmin Park <kyungmin.park@samsung.com>
  M:    Andrzej Hajda <a.hajda@samsung.com>
  L:    linux-media@vger.kernel.org
  S:    Supported
  F:    drivers/media/i2c/s5c73m3/*
  
  SAMSUNG S5K5BAF CAMERA DRIVER
 -M:    Kyungmin Park <kyungmin.park@samsung.com>
  M:    Andrzej Hajda <a.hajda@samsung.com>
  L:    linux-media@vger.kernel.org
  S:    Supported
@@@ -15640,6 -15466,7 +15640,6 @@@ F:   Documentation/devicetree/bindings/cr
  F:    drivers/crypto/s5p-sss.c
  
  SAMSUNG S5P/EXYNOS4 SOC SERIES CAMERA SUBSYSTEM DRIVERS
 -M:    Kyungmin Park <kyungmin.park@samsung.com>
  M:    Sylwester Nawrocki <s.nawrocki@samsung.com>
  L:    linux-media@vger.kernel.org
  S:    Supported
@@@ -15662,6 -15489,7 +15662,6 @@@ F:   include/linux/clk/samsung.
  F:    include/linux/platform_data/clk-s3c2410.h
  
  SAMSUNG SPI DRIVERS
 -M:    Kukjin Kim <kgene@kernel.org>
  M:    Krzysztof Kozlowski <krzk@kernel.org>
  M:    Andi Shyti <andi@etezian.org>
  L:    linux-spi@vger.kernel.org
@@@ -15687,6 -15515,7 +15687,6 @@@ T:   git https://github.com/lmajewski/lin
  F:    drivers/thermal/samsung/
  
  SAMSUNG USB2 PHY DRIVER
 -M:    Kamil Debski <kamil@wypas.org>
  M:    Sylwester Nawrocki <s.nawrocki@samsung.com>
  L:    linux-kernel@vger.kernel.org
  S:    Supported
@@@ -15780,6 -15609,15 +15780,15 @@@ F: Documentation/scsi/st.rs
  F:    drivers/scsi/st.*
  F:    drivers/scsi/st_*.h
  
+ SCSI TARGET CORE USER DRIVER
+ M:    Bodo Stroesser <bostroesser@gmail.com>
+ L:    linux-scsi@vger.kernel.org
+ L:    target-devel@vger.kernel.org
+ S:    Supported
+ F:    Documentation/target/tcmu-design.rst
+ F:    drivers/target/target_core_user.c
+ F:    include/uapi/linux/target_core_user.h
  SCSI TARGET SUBSYSTEM
  M:    "Martin K. Petersen" <martin.petersen@oracle.com>
  L:    linux-scsi@vger.kernel.org
@@@ -15985,8 -15823,9 +15994,8 @@@ F:   drivers/slimbus
  F:    include/linux/slimbus.h
  
  SFC NETWORK DRIVER
 -M:    Solarflare linux maintainers <linux-net-drivers@solarflare.com>
 -M:    Edward Cree <ecree@solarflare.com>
 -M:    Martin Habets <mhabets@solarflare.com>
 +M:    Edward Cree <ecree.xilinx@gmail.com>
 +M:    Martin Habets <habetsm.xilinx@gmail.com>
  L:    netdev@vger.kernel.org
  S:    Supported
  F:    drivers/net/ethernet/sfc/
@@@ -16003,18 -15842,18 +16012,18 @@@ F:        include/linux/sfp.
  K:    phylink\.h|struct\s+phylink|\.phylink|>phylink_|phylink_(autoneg|clear|connect|create|destroy|disconnect|ethtool|helper|mac|mii|of|set|start|stop|test|validate)
  
  SGI GRU DRIVER
 -M:    Dimitri Sivanich <sivanich@sgi.com>
 +M:    Dimitri Sivanich <dimitri.sivanich@hpe.com>
  S:    Maintained
  F:    drivers/misc/sgi-gru/
  
  SGI XP/XPC/XPNET DRIVER
 -M:    Cliff Whickman <cpw@sgi.com>
  M:    Robin Holt <robinmholt@gmail.com>
 +M:    Steve Wahl <steve.wahl@hpe.com>
 +R:    Mike Travis <mike.travis@hpe.com>
  S:    Maintained
  F:    drivers/misc/sgi-xp/
  
  SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
 -M:    Ursula Braun <ubraun@linux.ibm.com>
  M:    Karsten Graul <kgraul@linux.ibm.com>
  L:    linux-s390@vger.kernel.org
  S:    Supported
@@@ -16295,6 -16134,16 +16304,6 @@@ S:  Maintaine
  F:    drivers/firmware/smccc/
  F:    include/linux/arm-smccc.h
  
 -SMIA AND SMIA++ IMAGE SENSOR DRIVER
 -M:    Sakari Ailus <sakari.ailus@linux.intel.com>
 -L:    linux-media@vger.kernel.org
 -S:    Maintained
 -F:    Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
 -F:    drivers/media/i2c/smiapp-pll.c
 -F:    drivers/media/i2c/smiapp-pll.h
 -F:    drivers/media/i2c/smiapp/
 -F:    include/uapi/linux/smiapp.h
 -
  SMM665 HARDWARE MONITOR DRIVER
  M:    Guenter Roeck <linux@roeck-us.net>
  L:    linux-hwmon@vger.kernel.org
@@@ -16457,7 -16306,7 +16466,7 @@@ M:   Ricardo Ribalda <ribalda@kernel.org
  L:    linux-media@vger.kernel.org
  S:    Maintained
  T:    git git://linuxtv.org/media_tree.git
 -F:    Documentation/devicetree/bindings/media/i2c/sony,imx214.txt
 +F:    Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml
  F:    drivers/media/i2c/imx214.c
  
  SONY IMX219 SENSOR DRIVER
@@@ -16693,10 -16542,8 +16702,10 @@@ F: Documentation/networking/device_driv
  F:    drivers/net/ethernet/toshiba/spider_net*
  
  SPMI SUBSYSTEM
 -R:    Stephen Boyd <sboyd@kernel.org>
 -L:    linux-arm-msm@vger.kernel.org
 +M:    Stephen Boyd <sboyd@kernel.org>
 +L:    linux-kernel@vger.kernel.org
 +S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/sboyd/spmi.git
  F:    Documentation/devicetree/bindings/spmi/
  F:    drivers/spmi/
  F:    include/dt-bindings/spmi/spmi.h
@@@ -17556,12 -17403,6 +17565,12 @@@ W: http://thinkwiki.org/wiki/Ibm-acp
  T:    git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
  F:    drivers/platform/x86/thinkpad_acpi.c
  
 +THUNDERBOLT DMA TRAFFIC TEST DRIVER
 +M:    Isaac Hazan <isaac.hazan@intel.com>
 +L:    linux-usb@vger.kernel.org
 +S:    Maintained
 +F:    drivers/thunderbolt/dma_test.c
 +
  THUNDERBOLT DRIVER
  M:    Andreas Noever <andreas.noever@gmail.com>
  M:    Michael Jamet <michael.jamet@intel.com>
@@@ -18274,7 -18115,7 +18283,7 @@@ M:   Yu Chen <chenyu56@huawei.com
  M:    Binghui Wang <wangbinghui@hisilicon.com>
  L:    linux-usb@vger.kernel.org
  S:    Maintained
 -F:    Documentation/devicetree/bindings/phy/phy-hi3660-usb3.txt
 +F:    Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml
  F:    drivers/phy/hisilicon/phy-hi3660-usb3.c
  
  USB ISP116X DRIVER
@@@ -18359,14 -18200,6 +18368,14 @@@ L: linux-usb@vger.kernel.or
  S:    Supported
  F:    drivers/usb/class/usblp.c
  
 +USB RAW GADGET DRIVER
 +R:    Andrey Konovalov <andreyknvl@gmail.com>
 +L:    linux-usb@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/usb/raw-gadget.rst
 +F:    drivers/usb/gadget/legacy/raw_gadget.c
 +F:    include/uapi/linux/usb/raw_gadget.h
 +
  USB QMI WWAN NETWORK DRIVER
  M:    Bjørn Mork <bjorn@mork.no>
  L:    netdev@vger.kernel.org
@@@ -18561,12 -18394,6 +18570,12 @@@ F: include/uapi/linux/uuid.
  F:    lib/test_uuid.c
  F:    lib/uuid.c
  
 +UV SYSFS DRIVER
 +M:    Justin Ernst <justin.ernst@hpe.com>
 +L:    platform-driver-x86@vger.kernel.org
 +S:    Maintained
 +F:    drivers/platform/x86/uv_sysfs.c
 +
  UVESAFB DRIVER
  M:    Michal Januszewski <spock@gentoo.org>
  L:    linux-fbdev@vger.kernel.org
@@@ -19089,6 -18916,18 +19098,6 @@@ S:  Supporte
  W:    https://wireless.wiki.kernel.org/en/users/Drivers/wil6210
  F:    drivers/net/wireless/ath/wil6210/
  
 -WIMAX STACK
 -M:    Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
 -M:    linux-wimax@intel.com
 -L:    wimax@linuxwimax.org (subscribers-only)
 -S:    Supported
 -W:    http://linuxwimax.org
 -F:    Documentation/admin-guide/wimax/wimax.rst
 -F:    include/linux/wimax/debug.h
 -F:    include/net/wimax.h
 -F:    include/uapi/linux/wimax.h
 -F:    net/wimax/
 -
  WINBOND CIR DRIVER
  M:    David Härdeman <david@hardeman.nu>
  S:    Maintained
@@@ -19186,18 -19025,12 +19195,18 @@@ L:        linux-kernel@vger.kernel.or
  S:    Maintained
  N:    axp[128]
  
 -X.25 NETWORK LAYER
 -M:    Andrew Hendry <andrew.hendry@gmail.com>
 +X.25 STACK
 +M:    Martin Schiller <ms@dev.tdt.de>
  L:    linux-x25@vger.kernel.org
 -S:    Odd Fixes
 +S:    Maintained
 +F:    Documentation/networking/lapb-module.rst
  F:    Documentation/networking/x25*
 +F:    drivers/net/wan/hdlc_x25.c
 +F:    drivers/net/wan/lapbether.c
 +F:    include/*/lapb.h
  F:    include/net/x25*
 +F:    include/uapi/linux/x25.h
 +F:    net/lapb/
  F:    net/x25/
  
  X86 ARCHITECTURE (32-BIT AND 64-BIT)
@@@ -19261,7 -19094,6 +19270,7 @@@ F:   arch/x86/platfor
  
  X86 PLATFORM UV HPE SUPERDOME FLEX
  M:    Steve Wahl <steve.wahl@hpe.com>
 +R:    Mike Travis <mike.travis@hpe.com>
  R:    Dimitri Sivanich <dimitri.sivanich@hpe.com>
  R:    Russ Anderson <russ.anderson@hpe.com>
  S:    Supported
@@@ -19312,17 -19144,12 +19321,17 @@@ L:        netdev@vger.kernel.or
  L:    bpf@vger.kernel.org
  S:    Supported
  F:    include/net/xdp.h
 +F:    include/net/xdp_priv.h
  F:    include/trace/events/xdp.h
  F:    kernel/bpf/cpumap.c
  F:    kernel/bpf/devmap.c
  F:    net/core/xdp.c
 -N:    xdp
 -K:    xdp
 +F:    samples/bpf/xdp*
 +F:    tools/testing/selftests/bpf/*xdp*
 +F:    tools/testing/selftests/bpf/*/*xdp*
 +F:    drivers/net/ethernet/*/*/*/*/*xdp*
 +F:    drivers/net/ethernet/*/*/*xdp*
 +K:    (?:\b|_)xdp(?:\b|_)
  
  XDP SOCKETS (AF_XDP)
  M:    Björn Töpel <bjorn.topel@intel.com>
@@@ -19331,12 -19158,9 +19340,12 @@@ R: Jonathan Lemon <jonathan.lemon@gmail
  L:    netdev@vger.kernel.org
  L:    bpf@vger.kernel.org
  S:    Maintained
 +F:    Documentation/networking/af_xdp.rst
  F:    include/net/xdp_sock*
  F:    include/net/xsk_buff_pool.h
  F:    include/uapi/linux/if_xdp.h
 +F:    include/uapi/linux/xdp_diag.h
 +F:    include/net/netns/xdp.h
  F:    net/xdp/
  F:    samples/bpf/xdpsock*
  F:    tools/lib/bpf/xsk*
@@@ -19604,13 -19428,6 +19613,13 @@@ T: git git://git.kernel.org/pub/scm/lin
  F:    Documentation/filesystems/zonefs.rst
  F:    fs/zonefs/
  
 +ZPOOL COMPRESSED PAGE STORAGE API
 +M:    Dan Streetman <ddstreet@ieee.org>
 +L:    linux-mm@kvack.org
 +S:    Maintained
 +F:    include/linux/zpool.h
 +F:    mm/zpool.c
 +
  ZR36067 VIDEO FOR LINUX DRIVER
  M:    Corentin Labbe <clabbe@baylibre.com>
  L:    mjpeg-users@lists.sourceforge.net
@@@ -19621,6 -19438,13 +19630,6 @@@ Q:  https://patchwork.linuxtv.org/projec
  F:    Documentation/driver-api/media/drivers/zoran.rst
  F:    drivers/staging/media/zoran/
  
 -ZPOOL COMPRESSED PAGE STORAGE API
 -M:    Dan Streetman <ddstreet@ieee.org>
 -L:    linux-mm@kvack.org
 -S:    Maintained
 -F:    include/linux/zpool.h
 -F:    mm/zpool.c
 -
  ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
  M:    Minchan Kim <minchan@kernel.org>
  M:    Nitin Gupta <ngupta@vflare.org>
diff --combined block/blk-mq.c
@@@ -95,7 -95,7 +95,7 @@@ static void blk_mq_hctx_clear_pending(s
  }
  
  struct mq_inflight {
 -      struct hd_struct *part;
 +      struct block_device *part;
        unsigned int inflight[2];
  };
  
@@@ -105,15 -105,13 +105,15 @@@ static bool blk_mq_check_inflight(struc
  {
        struct mq_inflight *mi = priv;
  
 -      if (rq->part == mi->part && blk_mq_rq_state(rq) == MQ_RQ_IN_FLIGHT)
 +      if ((!mi->part->bd_partno || rq->part == mi->part) &&
 +          blk_mq_rq_state(rq) == MQ_RQ_IN_FLIGHT)
                mi->inflight[rq_data_dir(rq)]++;
  
        return true;
  }
  
 -unsigned int blk_mq_in_flight(struct request_queue *q, struct hd_struct *part)
 +unsigned int blk_mq_in_flight(struct request_queue *q,
 +              struct block_device *part)
  {
        struct mq_inflight mi = { .part = part };
  
        return mi.inflight[0] + mi.inflight[1];
  }
  
 -void blk_mq_in_flight_rw(struct request_queue *q, struct hd_struct *part,
 -                       unsigned int inflight[2])
 +void blk_mq_in_flight_rw(struct request_queue *q, struct block_device *part,
 +              unsigned int inflight[2])
  {
        struct mq_inflight mi = { .part = part };
  
@@@ -673,7 -671,9 +673,7 @@@ bool blk_mq_complete_request_remote(str
                return false;
  
        if (blk_mq_complete_need_ipi(rq)) {
 -              rq->csd.func = __blk_mq_complete_request_remote;
 -              rq->csd.info = rq;
 -              rq->csd.flags = 0;
 +              INIT_CSD(&rq->csd, __blk_mq_complete_request_remote, rq);
                smp_call_function_single_async(rq->mq_ctx->cpu, &rq->csd);
        } else {
                if (rq->q->nr_hw_queues > 1)
@@@ -731,7 -731,7 +731,7 @@@ void blk_mq_start_request(struct reques
  {
        struct request_queue *q = rq->q;
  
 -      trace_block_rq_issue(q, rq);
 +      trace_block_rq_issue(rq);
  
        if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) {
                rq->io_start_time_ns = ktime_get_ns();
@@@ -758,7 -758,7 +758,7 @@@ static void __blk_mq_requeue_request(st
  
        blk_mq_put_driver_tag(rq);
  
 -      trace_block_rq_requeue(q, rq);
 +      trace_block_rq_requeue(rq);
        rq_qos_requeue(q, rq);
  
        if (blk_mq_request_started(rq)) {
@@@ -1404,7 -1404,7 +1404,7 @@@ bool blk_mq_dispatch_rq_list(struct blk
                        break;
                default:
                        errors++;
-                       blk_mq_end_request(rq, BLK_STS_IOERR);
+                       blk_mq_end_request(rq, ret);
                }
        } while (!list_empty(list));
  out:
@@@ -1592,7 -1592,7 +1592,7 @@@ select_cpu
   * __blk_mq_delay_run_hw_queue - Run (or schedule to run) a hardware queue.
   * @hctx: Pointer to the hardware queue to run.
   * @async: If we want to run the queue asynchronously.
 - * @msecs: Microseconds of delay to wait before running the queue.
 + * @msecs: Milliseconds of delay to wait before running the queue.
   *
   * If !@async, try to run the queue now. Else, run the queue asynchronously and
   * with a delay of @msecs.
@@@ -1621,7 -1621,7 +1621,7 @@@ static void __blk_mq_delay_run_hw_queue
  /**
   * blk_mq_delay_run_hw_queue - Run a hardware queue asynchronously.
   * @hctx: Pointer to the hardware queue to run.
 - * @msecs: Microseconds of delay to wait before running the queue.
 + * @msecs: Milliseconds of delay to wait before running the queue.
   *
   * Run a hardware queue asynchronously with a delay of @msecs.
   */
@@@ -1685,7 -1685,7 +1685,7 @@@ EXPORT_SYMBOL(blk_mq_run_hw_queues)
  /**
   * blk_mq_delay_run_hw_queues - Run all hardware queues asynchronously.
   * @q: Pointer to the request queue to run.
 - * @msecs: Microseconds of delay to wait before running the queues.
 + * @msecs: Milliseconds of delay to wait before running the queues.
   */
  void blk_mq_delay_run_hw_queues(struct request_queue *q, unsigned long msecs)
  {
@@@ -1819,7 -1819,7 +1819,7 @@@ static inline void __blk_mq_insert_req_
  
        lockdep_assert_held(&ctx->lock);
  
 -      trace_block_rq_insert(hctx->queue, rq);
 +      trace_block_rq_insert(rq);
  
        if (at_head)
                list_add(&rq->queuelist, &ctx->rq_lists[type]);
@@@ -1876,7 -1876,7 +1876,7 @@@ void blk_mq_insert_requests(struct blk_
         */
        list_for_each_entry(rq, list, queuelist) {
                BUG_ON(rq->mq_ctx != ctx);
 -              trace_block_rq_insert(hctx->queue, rq);
 +              trace_block_rq_insert(rq);
        }
  
        spin_lock(&ctx->lock);
@@@ -2157,7 -2157,6 +2157,7 @@@ blk_qc_t blk_mq_submit_bio(struct bio *
        unsigned int nr_segs;
        blk_qc_t cookie;
        blk_status_t ret;
 +      bool hipri;
  
        blk_queue_bounce(q, &bio);
        __blk_queue_split(&bio, &nr_segs);
  
        rq_qos_throttle(q, bio);
  
 +      hipri = bio->bi_opf & REQ_HIPRI;
 +
        data.cmd_flags = bio->bi_opf;
        rq = __blk_mq_alloc_request(&data);
        if (unlikely(!rq)) {
                goto queue_exit;
        }
  
 -      trace_block_getrq(q, bio, bio->bi_opf);
 +      trace_block_getrq(bio);
  
        rq_qos_track(q, rq, bio);
  
                blk_mq_sched_insert_request(rq, false, true, true);
        }
  
 +      if (!hipri)
 +              return BLK_QC_T_NONE;
        return cookie;
  queue_exit:
        blk_queue_exit(q);
@@@ -3380,12 -3375,6 +3380,12 @@@ static int blk_mq_realloc_tag_set_tags(
        return 0;
  }
  
 +static int blk_mq_alloc_tag_set_tags(struct blk_mq_tag_set *set,
 +                              int new_nr_hw_queues)
 +{
 +      return blk_mq_realloc_tag_set_tags(set, 0, new_nr_hw_queues);
 +}
 +
  /*
   * Alloc a tag set to be associated with one or more request queues.
   * May fail with EINVAL for various error conditions. May adjust the
@@@ -3439,7 -3428,7 +3439,7 @@@ int blk_mq_alloc_tag_set(struct blk_mq_
        if (set->nr_maps == 1 && set->nr_hw_queues > nr_cpu_ids)
                set->nr_hw_queues = nr_cpu_ids;
  
 -      if (blk_mq_realloc_tag_set_tags(set, 0, set->nr_hw_queues) < 0)
 +      if (blk_mq_alloc_tag_set_tags(set, set->nr_hw_queues) < 0)
                return -ENOMEM;
  
        ret = -ENOMEM;
@@@ -3874,10 -3863,9 +3874,10 @@@ int blk_poll(struct request_queue *q, b
         * the state. Like for the other success return cases, the
         * caller is responsible for checking if the IO completed. If
         * the IO isn't complete, we'll get called again and will go
 -       * straight to the busy poll loop.
 +       * straight to the busy poll loop. If specified not to spin,
 +       * we also should not sleep.
         */
 -      if (blk_mq_poll_hybrid(q, hctx, cookie))
 +      if (spin && blk_mq_poll_hybrid(q, hctx, cookie))
                return 1;
  
        hctx->poll_considered++;
@@@ -622,11 -622,10 +622,11 @@@ static int srpt_refresh_port(struct srp
  /**
   * srpt_unregister_mad_agent - unregister MAD callback functions
   * @sdev: SRPT HCA pointer.
 + * @port_cnt: number of ports with registered MAD
   *
   * Note: It is safe to call this function more than once for the same device.
   */
 -static void srpt_unregister_mad_agent(struct srpt_device *sdev)
 +static void srpt_unregister_mad_agent(struct srpt_device *sdev, int port_cnt)
  {
        struct ib_port_modify port_modify = {
                .clr_port_cap_mask = IB_PORT_DEVICE_MGMT_SUP,
        struct srpt_port *sport;
        int i;
  
 -      for (i = 1; i <= sdev->device->phys_port_cnt; i++) {
 +      for (i = 1; i <= port_cnt; i++) {
                sport = &sdev->port[i - 1];
                WARN_ON(sport->port != i);
                if (sport->mad_agent) {
@@@ -2085,7 -2084,7 +2085,7 @@@ static void srpt_release_channel_work(s
        se_sess = ch->sess;
        BUG_ON(!se_sess);
  
-       target_sess_cmd_list_set_waiting(se_sess);
+       target_stop_session(se_sess);
        target_wait_for_sess_cmds(se_sess);
  
        target_remove_session(se_sess);
@@@ -3186,8 -3185,7 +3186,8 @@@ static int srpt_add_one(struct ib_devic
                if (ret) {
                        pr_err("MAD registration failed for %s-%d.\n",
                               dev_name(&sdev->device->dev), i);
 -                      goto err_event;
 +                      i--;
 +                      goto err_port;
                }
        }
  
        pr_debug("added %s.\n", dev_name(&device->dev));
        return 0;
  
 -err_event:
 +err_port:
 +      srpt_unregister_mad_agent(sdev, i);
        ib_unregister_event_handler(&sdev->event_handler);
  err_cm:
        if (sdev->cm_id)
@@@ -3224,7 -3221,7 +3224,7 @@@ static void srpt_remove_one(struct ib_d
        struct srpt_device *sdev = client_data;
        int i;
  
 -      srpt_unregister_mad_agent(sdev);
 +      srpt_unregister_mad_agent(sdev, sdev->device->phys_port_cnt);
  
        ib_unregister_event_handler(&sdev->event_handler);
  
@@@ -52,7 -52,7 +52,7 @@@
  #include <linux/kdev_t.h>
  #include <linux/blkdev.h>
  #include <linux/delay.h>      /* for mdelay */
- #include <linux/interrupt.h>  /* needed for in_interrupt() proto */
+ #include <linux/interrupt.h>
  #include <linux/reboot.h>     /* notifier code */
  #include <linux/workqueue.h>
  
@@@ -1176,10 -1176,8 +1176,10 @@@ mptscsih_remove(struct pci_dev *pdev
        MPT_SCSI_HOST           *hd;
        int sz1;
  
 -      if((hd = shost_priv(host)) == NULL)
 -              return;
 +      if (host == NULL)
 +              hd = NULL;
 +      else
 +              hd = shost_priv(host);
  
        mptscsih_shutdown(pdev);
  
            "Free'd ScsiLookup (%d) memory\n",
            ioc->name, sz1));
  
 -      kfree(hd->info_kbuf);
 +      if (hd)
 +              kfree(hd->info_kbuf);
  
        /* NULL the Scsi_Host pointer
         */
        ioc->sh = NULL;
  
 -      scsi_host_put(host);
 -
 +      if (host)
 +              scsi_host_put(host);
        mpt_detach(pdev);
  
  }
@@@ -70,6 -70,7 +70,6 @@@
  #define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED      0x00000004
  #define ZFCP_STATUS_ADAPTER_XCONFIG_OK                0x00000008
  #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT     0x00000010
 -#define ZFCP_STATUS_ADAPTER_SUSPENDED         0x00000040
  #define ZFCP_STATUS_ADAPTER_ERP_PENDING               0x00000100
  #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED    0x00000200
  #define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED  0x00000400
@@@ -200,6 -201,7 +200,7 @@@ struct zfcp_adapter 
        struct zfcp_fc_events events;
        unsigned long           next_port_scan;
        struct zfcp_diag_adapter        *diagnostics;
+       struct work_struct      version_change_lost_work;
  };
  
  struct zfcp_port {
@@@ -20,8 -20,6 +20,6 @@@ extern struct zfcp_port *zfcp_get_port_
  extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *);
  extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, u64, u32,
                                           u32);
- extern void zfcp_sg_free_table(struct scatterlist *, int);
- extern int zfcp_sg_setup_table(struct scatterlist *, int);
  extern void zfcp_adapter_release(struct kref *);
  extern void zfcp_adapter_unregister(struct zfcp_adapter *);
  
@@@ -49,6 -47,7 +47,6 @@@ extern void zfcp_dbf_hba_fsf_fces(char 
                                  u32 fc_security_new);
  extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
  extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **);
 -extern void zfcp_dbf_hba_basic(char *, struct zfcp_adapter *);
  extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
  extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
  extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
@@@ -242,6 -242,19 +242,19 @@@ static void zfcp_fsf_status_read_link_d
        }
  }
  
+ static void
+ zfcp_fsf_status_read_version_change(struct zfcp_adapter *adapter,
+                                   struct fsf_status_read_buffer *sr_buf)
+ {
+       if (sr_buf->status_subtype == FSF_STATUS_READ_SUB_LIC_CHANGE) {
+               u32 version = sr_buf->payload.version_change.current_version;
+               WRITE_ONCE(adapter->fsf_lic_version, version);
+               snprintf(fc_host_firmware_version(adapter->scsi_host),
+                        FC_VERSION_STRING_SIZE, "%#08x", version);
+       }
+ }
  static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
  {
        struct zfcp_adapter *adapter = req->adapter;
        case FSF_STATUS_READ_NOTIFICATION_LOST:
                if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
                        zfcp_fc_conditional_port_scan(adapter);
+               if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_VERSION_CHANGE)
+                       queue_work(adapter->work_queue,
+                                  &adapter->version_change_lost_work);
                break;
        case FSF_STATUS_READ_FEATURE_UPDATE_ALERT:
                adapter->adapter_features = sr_buf->payload.word[0];
                break;
+       case FSF_STATUS_READ_VERSION_CHANGE:
+               zfcp_fsf_status_read_version_change(adapter, sr_buf);
+               break;
        }
  
        mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data);
@@@ -2359,7 -2378,8 +2378,7 @@@ static void zfcp_fsf_req_trace(struct z
                }
        }
  
 -      blk_add_driver_data(scsi->request->q, scsi->request, &blktrc,
 -                          sizeof(blktrc));
 +      blk_add_driver_data(scsi->request, &blktrc, sizeof(blktrc));
  }
  
  /**
@@@ -164,7 -164,7 +164,7 @@@ DEVICE_ATTR(beiscsi_active_session_coun
             beiscsi_active_session_disp, NULL);
  DEVICE_ATTR(beiscsi_free_session_count, S_IRUGO,
             beiscsi_free_session_disp, NULL);
- struct device_attribute *beiscsi_attrs[] = {
+ static struct device_attribute *beiscsi_attrs[] = {
        &dev_attr_beiscsi_log_enable,
        &dev_attr_beiscsi_drvr_ver,
        &dev_attr_beiscsi_adapter_family,
@@@ -3020,6 -3020,7 +3020,6 @@@ static int beiscsi_create_eqs(struct be
                        goto create_eq_error;
                }
  
 -              mem->dma = paddr;
                mem->va = eq_vaddress;
                ret = be_fill_queue(eq, phba->params.num_eq_entries,
                                    sizeof(struct be_eq_entry), eq_vaddress);
                        goto create_eq_error;
                }
  
 +              mem->dma = paddr;
                ret = beiscsi_cmd_eq_create(&phba->ctrl, eq,
                                            BEISCSI_EQ_DELAY_DEF);
                if (ret) {
@@@ -3086,6 -3086,7 +3086,6 @@@ static int beiscsi_create_cqs(struct be
                        goto create_cq_error;
                }
  
 -              mem->dma = paddr;
                ret = be_fill_queue(cq, phba->params.num_cq_entries,
                                    sizeof(struct sol_cqe), cq_vaddress);
                if (ret) {
                        goto create_cq_error;
                }
  
 +              mem->dma = paddr;
                ret = beiscsi_cmd_cq_create(&phba->ctrl, cq, eq, false,
                                            false, 0);
                if (ret) {
@@@ -16,8 -16,6 +16,8 @@@
  
  #include "bnx2fc.h"
  
 +#include <linux/ethtool.h>
 +
  static struct list_head adapter_list;
  static struct list_head if_list;
  static u32 adapter_count;
@@@ -2088,7 -2086,7 +2088,7 @@@ static int __bnx2fc_disable(struct fcoe
  {
        struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr);
  
-       if (interface->enabled == true) {
+       if (interface->enabled) {
                if (!ctlr->lp) {
                        pr_err(PFX "__bnx2fc_disable: lport not found\n");
                        return -ENODEV;
@@@ -2186,7 -2184,7 +2186,7 @@@ static int __bnx2fc_enable(struct fcoe_
        struct cnic_fc_npiv_tbl *npiv_tbl;
        struct fc_lport *lport;
  
-       if (interface->enabled == false) {
+       if (!interface->enabled) {
                if (!ctlr->lp) {
                        pr_err(PFX "__bnx2fc_enable: lport not found\n");
                        return -ENODEV;
@@@ -2277,7 -2275,7 +2277,7 @@@ static int bnx2fc_ctlr_enabled(struct f
        case FCOE_CTLR_UNUSED:
        default:
                return -ENOTSUPP;
-       };
+       }
  }
  
  enum bnx2fc_create_link_state {
@@@ -408,12 -408,20 +408,20 @@@ static char print_alua_state(unsigned c
  static int alua_check_sense(struct scsi_device *sdev,
                            struct scsi_sense_hdr *sense_hdr)
  {
+       struct alua_dh_data *h = sdev->handler_data;
+       struct alua_port_group *pg;
        switch (sense_hdr->sense_key) {
        case NOT_READY:
                if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
                        /*
                         * LUN Not Accessible - ALUA state transition
                         */
+                       rcu_read_lock();
+                       pg = rcu_dereference(h->pg);
+                       if (pg)
+                               pg->state = SCSI_ACCESS_STATE_TRANSITIONING;
+                       rcu_read_unlock();
                        alua_check(sdev, false);
                        return NEEDS_RETRY;
                }
@@@ -658,8 -666,8 +666,8 @@@ static int alua_rtpg(struct scsi_devic
                                        rcu_read_lock();
                                        list_for_each_entry_rcu(h,
                                                &tmp_pg->dh_list, node) {
 -                                              /* h->sdev should always be valid */
 -                                              BUG_ON(!h->sdev);
 +                                              if (!h->sdev)
 +                                                      continue;
                                                h->sdev->access_state = desc[0];
                                        }
                                        rcu_read_unlock();
                        pg->expiry = 0;
                        rcu_read_lock();
                        list_for_each_entry_rcu(h, &pg->dh_list, node) {
 -                              BUG_ON(!h->sdev);
 +                              if (!h->sdev)
 +                                      continue;
                                h->sdev->access_state =
                                        (pg->state & SCSI_ACCESS_STATE_MASK);
                                if (pg->pref)
@@@ -1092,7 -1099,7 +1100,7 @@@ static blk_status_t alua_prep_fn(struc
        case SCSI_ACCESS_STATE_LBA:
                return BLK_STS_OK;
        case SCSI_ACCESS_STATE_TRANSITIONING:
-               return BLK_STS_RESOURCE;
+               return BLK_STS_AGAIN;
        default:
                req->rq_flags |= RQF_QUIET;
                return BLK_STS_IOERR;
@@@ -1148,6 -1155,7 +1156,6 @@@ static void alua_bus_detach(struct scsi
        spin_lock(&h->pg_lock);
        pg = rcu_dereference_protected(h->pg, lockdep_is_held(&h->pg_lock));
        rcu_assign_pointer(h->pg, NULL);
 -      h->sdev = NULL;
        spin_unlock(&h->pg_lock);
        if (pg) {
                spin_lock_irq(&pg->lock);
                kref_put(&pg->kref, release_port_group);
        }
        sdev->handler_data = NULL;
 +      synchronize_rcu();
        kfree(h);
  }
  
@@@ -445,19 -445,13 +445,19 @@@ static int hisi_sas_task_prep(struct sa
                }
        }
  
 -      if (scmd) {
 +      if (scmd && hisi_hba->shost->nr_hw_queues) {
                unsigned int dq_index;
                u32 blk_tag;
  
                blk_tag = blk_mq_unique_tag(scmd->request);
                dq_index = blk_mq_unique_tag_to_hwq(blk_tag);
                *dq_pointer = dq = &hisi_hba->dq[dq_index];
 +      } else if (hisi_hba->shost->nr_hw_queues)  {
 +              struct Scsi_Host *shost = hisi_hba->shost;
 +              struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
 +              int queue = qmap->mq_map[raw_smp_processor_id()];
 +
 +              *dq_pointer = dq = &hisi_hba->dq[queue];
        } else {
                *dq_pointer = dq = sas_dev->dq;
        }
@@@ -591,13 -585,7 +591,7 @@@ static int hisi_sas_task_exec(struct sa
        dev = hisi_hba->dev;
  
        if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
-               /*
-                * For IOs from upper layer, it may already disable preempt
-                * in the IO path, if disable preempt again in down(),
-                * function schedule() will report schedule_bug(), so check
-                * preemptible() before goto down().
-                */
-               if (!preemptible())
+               if (!gfpflags_allow_blocking(gfp_flags))
                        return -EINVAL;
  
                down(&hisi_hba->sem);
@@@ -2696,1382 -2684,42 +2690,42 @@@ int hisi_sas_probe(struct platform_devi
  err_out_register_ha:
        scsi_remove_host(shost);
  err_out_ha:
-       hisi_sas_debugfs_exit(hisi_hba);
        hisi_sas_free(hisi_hba);
        scsi_host_put(shost);
        return rc;
  }
  EXPORT_SYMBOL_GPL(hisi_sas_probe);
  
- struct dentry *hisi_sas_debugfs_dir;
- static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba)
- {
-       int queue_entry_size = hisi_hba->hw->complete_hdr_size;
-       int dump_index = hisi_hba->debugfs_dump_index;
-       int i;
-       for (i = 0; i < hisi_hba->queue_count; i++)
-               memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr,
-                      hisi_hba->complete_hdr[i],
-                      HISI_SAS_QUEUE_SLOTS * queue_entry_size);
- }
- static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba)
- {
-       int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr);
-       int dump_index = hisi_hba->debugfs_dump_index;
-       int i;
-       for (i = 0; i < hisi_hba->queue_count; i++) {
-               struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr;
-               int j;
-               debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr;
-               cmd_hdr = hisi_hba->cmd_hdr[i];
-               for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++)
-                       memcpy(&debugfs_cmd_hdr[j], &cmd_hdr[j],
-                              queue_entry_size);
-       }
- }
- static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba)
- {
-       int dump_index = hisi_hba->debugfs_dump_index;
-       const struct hisi_sas_debugfs_reg *port =
-               hisi_hba->hw->debugfs_reg_port;
-       int i, phy_cnt;
-       u32 offset;
-       u32 *databuf;
-       for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) {
-               databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data;
-               for (i = 0; i < port->count; i++, databuf++) {
-                       offset = port->base_off + 4 * i;
-                       *databuf = port->read_port_reg(hisi_hba, phy_cnt,
-                                                      offset);
-               }
-       }
- }
- static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba)
- {
-       int dump_index = hisi_hba->debugfs_dump_index;
-       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data;
-       const struct hisi_sas_hw *hw = hisi_hba->hw;
-       const struct hisi_sas_debugfs_reg *global =
-                       hw->debugfs_reg_array[DEBUGFS_GLOBAL];
-       int i;
-       for (i = 0; i < global->count; i++, databuf++)
-               *databuf = global->read_global_reg(hisi_hba, 4 * i);
- }
- static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba)
- {
-       int dump_index = hisi_hba->debugfs_dump_index;
-       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data;
-       const struct hisi_sas_hw *hw = hisi_hba->hw;
-       const struct hisi_sas_debugfs_reg *axi =
-                       hw->debugfs_reg_array[DEBUGFS_AXI];
-       int i;
-       for (i = 0; i < axi->count; i++, databuf++)
-               *databuf = axi->read_global_reg(hisi_hba,
-                                               4 * i + axi->base_off);
- }
- static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba)
- {
-       int dump_index = hisi_hba->debugfs_dump_index;
-       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data;
-       const struct hisi_sas_hw *hw = hisi_hba->hw;
-       const struct hisi_sas_debugfs_reg *ras =
-                       hw->debugfs_reg_array[DEBUGFS_RAS];
-       int i;
-       for (i = 0; i < ras->count; i++, databuf++)
-               *databuf = ras->read_global_reg(hisi_hba,
-                                               4 * i + ras->base_off);
- }
- static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba)
- {
-       int dump_index = hisi_hba->debugfs_dump_index;
-       void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache;
-       void *databuf = hisi_hba->debugfs_itct[dump_index].itct;
-       struct hisi_sas_itct *itct;
-       int i;
-       hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_ITCT_CACHE,
-                                          cachebuf);
-       itct = hisi_hba->itct;
-       for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
-               memcpy(databuf, itct, sizeof(struct hisi_sas_itct));
-               databuf += sizeof(struct hisi_sas_itct);
-       }
- }
- static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba)
- {
-       int dump_index = hisi_hba->debugfs_dump_index;
-       int max_command_entries = HISI_SAS_MAX_COMMANDS;
-       void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache;
-       void *databuf = hisi_hba->debugfs_iost[dump_index].iost;
-       struct hisi_sas_iost *iost;
-       int i;
-       hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_IOST_CACHE,
-                                          cachebuf);
-       iost = hisi_hba->iost;
-       for (i = 0; i < max_command_entries; i++, iost++) {
-               memcpy(databuf, iost, sizeof(struct hisi_sas_iost));
-               databuf += sizeof(struct hisi_sas_iost);
-       }
- }
- static const char *
- hisi_sas_debugfs_to_reg_name(int off, int base_off,
-                            const struct hisi_sas_debugfs_reg_lu *lu)
- {
-       for (; lu->name; lu++) {
-               if (off == lu->off - base_off)
-                       return lu->name;
-       }
-       return NULL;
- }
- static void hisi_sas_debugfs_print_reg(u32 *regs_val, const void *ptr,
-                                      struct seq_file *s)
- {
-       const struct hisi_sas_debugfs_reg *reg = ptr;
-       int i;
-       for (i = 0; i < reg->count; i++) {
-               int off = i * 4;
-               const char *name;
-               name = hisi_sas_debugfs_to_reg_name(off, reg->base_off,
-                                                   reg->lu);
-               if (name)
-                       seq_printf(s, "0x%08x 0x%08x %s\n", off,
-                                  regs_val[i], name);
-               else
-                       seq_printf(s, "0x%08x 0x%08x\n", off,
-                                  regs_val[i]);
-       }
- }
- static int hisi_sas_debugfs_global_show(struct seq_file *s, void *p)
- {
-       struct hisi_sas_debugfs_regs *global = s->private;
-       struct hisi_hba *hisi_hba = global->hisi_hba;
-       const struct hisi_sas_hw *hw = hisi_hba->hw;
-       const void *reg_global = hw->debugfs_reg_array[DEBUGFS_GLOBAL];
-       hisi_sas_debugfs_print_reg(global->data,
-                                  reg_global, s);
-       return 0;
- }
- static int hisi_sas_debugfs_global_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_global_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_global_fops = {
-       .open = hisi_sas_debugfs_global_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static int hisi_sas_debugfs_axi_show(struct seq_file *s, void *p)
- {
-       struct hisi_sas_debugfs_regs *axi = s->private;
-       struct hisi_hba *hisi_hba = axi->hisi_hba;
-       const struct hisi_sas_hw *hw = hisi_hba->hw;
-       const void *reg_axi = hw->debugfs_reg_array[DEBUGFS_AXI];
-       hisi_sas_debugfs_print_reg(axi->data,
-                                  reg_axi, s);
-       return 0;
- }
- static int hisi_sas_debugfs_axi_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_axi_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_axi_fops = {
-       .open = hisi_sas_debugfs_axi_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static int hisi_sas_debugfs_ras_show(struct seq_file *s, void *p)
- {
-       struct hisi_sas_debugfs_regs *ras = s->private;
-       struct hisi_hba *hisi_hba = ras->hisi_hba;
-       const struct hisi_sas_hw *hw = hisi_hba->hw;
-       const void *reg_ras = hw->debugfs_reg_array[DEBUGFS_RAS];
-       hisi_sas_debugfs_print_reg(ras->data,
-                                  reg_ras, s);
-       return 0;
- }
- static int hisi_sas_debugfs_ras_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_ras_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_ras_fops = {
-       .open = hisi_sas_debugfs_ras_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static int hisi_sas_debugfs_port_show(struct seq_file *s, void *p)
- {
-       struct hisi_sas_debugfs_port *port = s->private;
-       struct hisi_sas_phy *phy = port->phy;
-       struct hisi_hba *hisi_hba = phy->hisi_hba;
-       const struct hisi_sas_hw *hw = hisi_hba->hw;
-       const struct hisi_sas_debugfs_reg *reg_port = hw->debugfs_reg_port;
-       hisi_sas_debugfs_print_reg(port->data, reg_port, s);
-       return 0;
- }
- static int hisi_sas_debugfs_port_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_port_show, inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_port_fops = {
-       .open = hisi_sas_debugfs_port_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static void hisi_sas_show_row_64(struct seq_file *s, int index,
-                                int sz, __le64 *ptr)
- {
-       int i;
-       /* completion header size not fixed per HW version */
-       seq_printf(s, "index %04d:\n\t", index);
-       for (i = 1; i <= sz / 8; i++, ptr++) {
-               seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr));
-               if (!(i % 2))
-                       seq_puts(s, "\n\t");
-       }
-       seq_puts(s, "\n");
- }
- static void hisi_sas_show_row_32(struct seq_file *s, int index,
-                                int sz, __le32 *ptr)
- {
-       int i;
-       /* completion header size not fixed per HW version */
-       seq_printf(s, "index %04d:\n\t", index);
-       for (i = 1; i <= sz / 4; i++, ptr++) {
-               seq_printf(s, " 0x%08x", le32_to_cpu(*ptr));
-               if (!(i % 4))
-                       seq_puts(s, "\n\t");
-       }
-       seq_puts(s, "\n");
- }
- static void hisi_sas_cq_show_slot(struct seq_file *s, int slot,
-                                 struct hisi_sas_debugfs_cq *debugfs_cq)
- {
-       struct hisi_sas_cq *cq = debugfs_cq->cq;
-       struct hisi_hba *hisi_hba = cq->hisi_hba;
-       __le32 *complete_hdr = debugfs_cq->complete_hdr +
-                              (hisi_hba->hw->complete_hdr_size * slot);
-       hisi_sas_show_row_32(s, slot,
-                            hisi_hba->hw->complete_hdr_size,
-                            complete_hdr);
- }
- static int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p)
- {
-       struct hisi_sas_debugfs_cq *debugfs_cq = s->private;
-       int slot;
-       for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) {
-               hisi_sas_cq_show_slot(s, slot, debugfs_cq);
-       }
-       return 0;
- }
- static int hisi_sas_debugfs_cq_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_cq_show, inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_cq_fops = {
-       .open = hisi_sas_debugfs_cq_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static void hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr)
- {
-       struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr;
-       void *cmd_queue = debugfs_dq->hdr;
-       __le32 *cmd_hdr = cmd_queue +
-               sizeof(struct hisi_sas_cmd_hdr) * slot;
-       hisi_sas_show_row_32(s, slot, sizeof(struct hisi_sas_cmd_hdr), cmd_hdr);
- }
- static int hisi_sas_debugfs_dq_show(struct seq_file *s, void *p)
- {
-       int slot;
-       for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) {
-               hisi_sas_dq_show_slot(s, slot, s->private);
-       }
-       return 0;
- }
- static int hisi_sas_debugfs_dq_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_dq_show, inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_dq_fops = {
-       .open = hisi_sas_debugfs_dq_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p)
- {
-       struct hisi_sas_debugfs_iost *debugfs_iost = s->private;
-       struct hisi_sas_iost *iost = debugfs_iost->iost;
-       int i, max_command_entries = HISI_SAS_MAX_COMMANDS;
-       for (i = 0; i < max_command_entries; i++, iost++) {
-               __le64 *data = &iost->qw0;
-               hisi_sas_show_row_64(s, i, sizeof(*iost), data);
-       }
-       return 0;
- }
- static int hisi_sas_debugfs_iost_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_iost_show, inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_iost_fops = {
-       .open = hisi_sas_debugfs_iost_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p)
- {
-       struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private;
-       struct hisi_sas_iost_itct_cache *iost_cache = debugfs_iost_cache->cache;
-       u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
-       int i, tab_idx;
-       __le64 *iost;
-       for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) {
-               /*
-                * Data struct of IOST cache:
-                * Data[1]: BIT0~15: Table index
-                *          Bit16:   Valid mask
-                * Data[2]~[9]: IOST table
-                */
-               tab_idx = (iost_cache->data[1] & 0xffff);
-               iost = (__le64 *)iost_cache;
-               hisi_sas_show_row_64(s, tab_idx, cache_size, iost);
-       }
-       return 0;
- }
- static int hisi_sas_debugfs_iost_cache_open(struct inode *inode,
-                                           struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_iost_cache_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_iost_cache_fops = {
-       .open = hisi_sas_debugfs_iost_cache_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static int hisi_sas_debugfs_itct_show(struct seq_file *s, void *p)
- {
-       int i;
-       struct hisi_sas_debugfs_itct *debugfs_itct = s->private;
-       struct hisi_sas_itct *itct = debugfs_itct->itct;
-       for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
-               __le64 *data = &itct->qw0;
-               hisi_sas_show_row_64(s, i, sizeof(*itct), data);
-       }
-       return 0;
- }
- static int hisi_sas_debugfs_itct_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_itct_show, inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_itct_fops = {
-       .open = hisi_sas_debugfs_itct_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p)
+ int hisi_sas_remove(struct platform_device *pdev)
  {
-       struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private;
-       struct hisi_sas_iost_itct_cache *itct_cache = debugfs_itct_cache->cache;
-       u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
-       int i, tab_idx;
-       __le64 *itct;
+       struct sas_ha_struct *sha = platform_get_drvdata(pdev);
+       struct hisi_hba *hisi_hba = sha->lldd_ha;
+       struct Scsi_Host *shost = sha->core.shost;
  
-       for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) {
-               /*
-                * Data struct of ITCT cache:
-                * Data[1]: BIT0~15: Table index
-                *          Bit16:   Valid mask
-                * Data[2]~[9]: ITCT table
-                */
-               tab_idx = itct_cache->data[1] & 0xffff;
-               itct = (__le64 *)itct_cache;
+       if (timer_pending(&hisi_hba->timer))
+               del_timer(&hisi_hba->timer);
  
-               hisi_sas_show_row_64(s, tab_idx, cache_size, itct);
-       }
+       sas_unregister_ha(sha);
+       sas_remove_host(sha->core.shost);
  
+       hisi_sas_free(hisi_hba);
+       scsi_host_put(shost);
        return 0;
  }
+ EXPORT_SYMBOL_GPL(hisi_sas_remove);
  
- static int hisi_sas_debugfs_itct_cache_open(struct inode *inode,
-                                           struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_itct_cache_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_itct_cache_fops = {
-       .open = hisi_sas_debugfs_itct_cache_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba)
- {
-       u64 *debugfs_timestamp;
-       int dump_index = hisi_hba->debugfs_dump_index;
-       struct dentry *dump_dentry;
-       struct dentry *dentry;
-       char name[256];
-       int p;
-       int c;
-       int d;
-       snprintf(name, 256, "%d", dump_index);
-       dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry);
-       debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index];
-       debugfs_create_u64("timestamp", 0400, dump_dentry,
-                          debugfs_timestamp);
-       debugfs_create_file("global", 0400, dump_dentry,
-                          &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL],
-                          &hisi_sas_debugfs_global_fops);
-       /* Create port dir and files */
-       dentry = debugfs_create_dir("port", dump_dentry);
-       for (p = 0; p < hisi_hba->n_phy; p++) {
-               snprintf(name, 256, "%d", p);
-               debugfs_create_file(name, 0400, dentry,
-                                   &hisi_hba->debugfs_port_reg[dump_index][p],
-                                   &hisi_sas_debugfs_port_fops);
-       }
-       /* Create CQ dir and files */
-       dentry = debugfs_create_dir("cq", dump_dentry);
-       for (c = 0; c < hisi_hba->queue_count; c++) {
-               snprintf(name, 256, "%d", c);
-               debugfs_create_file(name, 0400, dentry,
-                                   &hisi_hba->debugfs_cq[dump_index][c],
-                                   &hisi_sas_debugfs_cq_fops);
-       }
-       /* Create DQ dir and files */
-       dentry = debugfs_create_dir("dq", dump_dentry);
-       for (d = 0; d < hisi_hba->queue_count; d++) {
-               snprintf(name, 256, "%d", d);
-               debugfs_create_file(name, 0400, dentry,
-                                   &hisi_hba->debugfs_dq[dump_index][d],
-                                   &hisi_sas_debugfs_dq_fops);
-       }
-       debugfs_create_file("iost", 0400, dump_dentry,
-                           &hisi_hba->debugfs_iost[dump_index],
-                           &hisi_sas_debugfs_iost_fops);
-       debugfs_create_file("iost_cache", 0400, dump_dentry,
-                           &hisi_hba->debugfs_iost_cache[dump_index],
-                           &hisi_sas_debugfs_iost_cache_fops);
-       debugfs_create_file("itct", 0400, dump_dentry,
-                           &hisi_hba->debugfs_itct[dump_index],
-                           &hisi_sas_debugfs_itct_fops);
-       debugfs_create_file("itct_cache", 0400, dump_dentry,
-                           &hisi_hba->debugfs_itct_cache[dump_index],
-                           &hisi_sas_debugfs_itct_cache_fops);
-       debugfs_create_file("axi", 0400, dump_dentry,
-                           &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI],
-                           &hisi_sas_debugfs_axi_fops);
-       debugfs_create_file("ras", 0400, dump_dentry,
-                           &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS],
-                           &hisi_sas_debugfs_ras_fops);
-       return;
- }
- static void hisi_sas_debugfs_snapshot_regs(struct hisi_hba *hisi_hba)
- {
-       hisi_hba->hw->snapshot_prepare(hisi_hba);
-       hisi_sas_debugfs_snapshot_global_reg(hisi_hba);
-       hisi_sas_debugfs_snapshot_port_reg(hisi_hba);
-       hisi_sas_debugfs_snapshot_axi_reg(hisi_hba);
-       hisi_sas_debugfs_snapshot_ras_reg(hisi_hba);
-       hisi_sas_debugfs_snapshot_cq_reg(hisi_hba);
-       hisi_sas_debugfs_snapshot_dq_reg(hisi_hba);
-       hisi_sas_debugfs_snapshot_itct_reg(hisi_hba);
-       hisi_sas_debugfs_snapshot_iost_reg(hisi_hba);
-       hisi_sas_debugfs_create_files(hisi_hba);
-       hisi_hba->hw->snapshot_restore(hisi_hba);
- }
+ bool hisi_sas_debugfs_enable;
+ EXPORT_SYMBOL_GPL(hisi_sas_debugfs_enable);
+ module_param_named(debugfs_enable, hisi_sas_debugfs_enable, bool, 0444);
+ MODULE_PARM_DESC(hisi_sas_debugfs_enable, "Enable driver debugfs (default disabled)");
  
- static ssize_t hisi_sas_debugfs_trigger_dump_write(struct file *file,
-                                                  const char __user *user_buf,
-                                                  size_t count, loff_t *ppos)
- {
-       struct hisi_hba *hisi_hba = file->f_inode->i_private;
-       char buf[8];
+ u32 hisi_sas_debugfs_dump_count = 1;
+ EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dump_count);
+ module_param_named(debugfs_dump_count, hisi_sas_debugfs_dump_count, uint, 0444);
+ MODULE_PARM_DESC(hisi_sas_debugfs_dump_count, "Number of debugfs dumps to allow");
  
-       if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count)
-               return -EFAULT;
-       if (count > 8)
-               return -EFAULT;
-       if (copy_from_user(buf, user_buf, count))
-               return -EFAULT;
-       if (buf[0] != '1')
-               return -EFAULT;
-       queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
-       return count;
- }
- static const struct file_operations hisi_sas_debugfs_trigger_dump_fops = {
-       .write = &hisi_sas_debugfs_trigger_dump_write,
-       .owner = THIS_MODULE,
- };
- enum {
-       HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0,
-       HISI_SAS_BIST_LOOPBACK_MODE_SERDES,
-       HISI_SAS_BIST_LOOPBACK_MODE_REMOTE,
- };
- static const struct {
-       int             value;
-       char            *name;
- } hisi_sas_debugfs_loop_linkrate[] = {
-       { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
-       { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
-       { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
-       { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" },
- };
- static int hisi_sas_debugfs_bist_linkrate_show(struct seq_file *s, void *p)
- {
-       struct hisi_hba *hisi_hba = s->private;
-       int i;
-       for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) {
-               int match = (hisi_hba->debugfs_bist_linkrate ==
-                            hisi_sas_debugfs_loop_linkrate[i].value);
-               seq_printf(s, "%s%s%s ", match ? "[" : "",
-                          hisi_sas_debugfs_loop_linkrate[i].name,
-                          match ? "]" : "");
-       }
-       seq_puts(s, "\n");
-       return 0;
- }
- static ssize_t hisi_sas_debugfs_bist_linkrate_write(struct file *filp,
-                                                   const char __user *buf,
-                                                   size_t count, loff_t *ppos)
- {
-       struct seq_file *m = filp->private_data;
-       struct hisi_hba *hisi_hba = m->private;
-       char kbuf[16] = {}, *pkbuf;
-       bool found = false;
-       int i;
-       if (hisi_hba->debugfs_bist_enable)
-               return -EPERM;
-       if (count >= sizeof(kbuf))
-               return -EOVERFLOW;
-       if (copy_from_user(kbuf, buf, count))
-               return -EINVAL;
-       pkbuf = strstrip(kbuf);
-       for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) {
-               if (!strncmp(hisi_sas_debugfs_loop_linkrate[i].name,
-                            pkbuf, 16)) {
-                       hisi_hba->debugfs_bist_linkrate =
-                               hisi_sas_debugfs_loop_linkrate[i].value;
-                       found = true;
-                       break;
-               }
-       }
-       if (!found)
-               return -EINVAL;
-       return count;
- }
- static int hisi_sas_debugfs_bist_linkrate_open(struct inode *inode,
-                                              struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_bist_linkrate_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_bist_linkrate_ops = {
-       .open = hisi_sas_debugfs_bist_linkrate_open,
-       .read = seq_read,
-       .write = hisi_sas_debugfs_bist_linkrate_write,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static const struct {
-       int             value;
-       char            *name;
- } hisi_sas_debugfs_loop_code_mode[] = {
-       { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" },
-       { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" },
-       { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" },
-       { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" },
-       { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" },
-       { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" },
-       { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" },
-       { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" },
-       { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" },
-       { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" },
-       { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" },
-       { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" },
- };
- static int hisi_sas_debugfs_bist_code_mode_show(struct seq_file *s, void *p)
- {
-       struct hisi_hba *hisi_hba = s->private;
-       int i;
-       for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) {
-               int match = (hisi_hba->debugfs_bist_code_mode ==
-                            hisi_sas_debugfs_loop_code_mode[i].value);
-               seq_printf(s, "%s%s%s ", match ? "[" : "",
-                          hisi_sas_debugfs_loop_code_mode[i].name,
-                          match ? "]" : "");
-       }
-       seq_puts(s, "\n");
-       return 0;
- }
- static ssize_t hisi_sas_debugfs_bist_code_mode_write(struct file *filp,
-                                                    const char __user *buf,
-                                                    size_t count,
-                                                    loff_t *ppos)
- {
-       struct seq_file *m = filp->private_data;
-       struct hisi_hba *hisi_hba = m->private;
-       char kbuf[16] = {}, *pkbuf;
-       bool found = false;
-       int i;
-       if (hisi_hba->debugfs_bist_enable)
-               return -EPERM;
-       if (count >= sizeof(kbuf))
-               return -EINVAL;
-       if (copy_from_user(kbuf, buf, count))
-               return -EOVERFLOW;
-       pkbuf = strstrip(kbuf);
-       for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) {
-               if (!strncmp(hisi_sas_debugfs_loop_code_mode[i].name,
-                            pkbuf, 16)) {
-                       hisi_hba->debugfs_bist_code_mode =
-                               hisi_sas_debugfs_loop_code_mode[i].value;
-                       found = true;
-                       break;
-               }
-       }
-       if (!found)
-               return -EINVAL;
-       return count;
- }
- static int hisi_sas_debugfs_bist_code_mode_open(struct inode *inode,
-                                               struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_bist_code_mode_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_bist_code_mode_ops = {
-       .open = hisi_sas_debugfs_bist_code_mode_open,
-       .read = seq_read,
-       .write = hisi_sas_debugfs_bist_code_mode_write,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static ssize_t hisi_sas_debugfs_bist_phy_write(struct file *filp,
-                                              const char __user *buf,
-                                              size_t count, loff_t *ppos)
- {
-       struct seq_file *m = filp->private_data;
-       struct hisi_hba *hisi_hba = m->private;
-       unsigned int phy_no;
-       int val;
-       if (hisi_hba->debugfs_bist_enable)
-               return -EPERM;
-       val = kstrtouint_from_user(buf, count, 0, &phy_no);
-       if (val)
-               return val;
-       if (phy_no >= hisi_hba->n_phy)
-               return -EINVAL;
-       hisi_hba->debugfs_bist_phy_no = phy_no;
-       return count;
- }
- static int hisi_sas_debugfs_bist_phy_show(struct seq_file *s, void *p)
- {
-       struct hisi_hba *hisi_hba = s->private;
-       seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no);
-       return 0;
- }
- static int hisi_sas_debugfs_bist_phy_open(struct inode *inode,
-                                         struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_bist_phy_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_bist_phy_ops = {
-       .open = hisi_sas_debugfs_bist_phy_open,
-       .read = seq_read,
-       .write = hisi_sas_debugfs_bist_phy_write,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static const struct {
-       int             value;
-       char            *name;
- } hisi_sas_debugfs_loop_modes[] = {
-       { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" },
-       { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" },
-       { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" },
- };
- static int hisi_sas_debugfs_bist_mode_show(struct seq_file *s, void *p)
- {
-       struct hisi_hba *hisi_hba = s->private;
-       int i;
-       for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) {
-               int match = (hisi_hba->debugfs_bist_mode ==
-                            hisi_sas_debugfs_loop_modes[i].value);
-               seq_printf(s, "%s%s%s ", match ? "[" : "",
-                          hisi_sas_debugfs_loop_modes[i].name,
-                          match ? "]" : "");
-       }
-       seq_puts(s, "\n");
-       return 0;
- }
- static ssize_t hisi_sas_debugfs_bist_mode_write(struct file *filp,
-                                               const char __user *buf,
-                                               size_t count, loff_t *ppos)
- {
-       struct seq_file *m = filp->private_data;
-       struct hisi_hba *hisi_hba = m->private;
-       char kbuf[16] = {}, *pkbuf;
-       bool found = false;
-       int i;
-       if (hisi_hba->debugfs_bist_enable)
-               return -EPERM;
-       if (count >= sizeof(kbuf))
-               return -EINVAL;
-       if (copy_from_user(kbuf, buf, count))
-               return -EOVERFLOW;
-       pkbuf = strstrip(kbuf);
-       for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) {
-               if (!strncmp(hisi_sas_debugfs_loop_modes[i].name, pkbuf, 16)) {
-                       hisi_hba->debugfs_bist_mode =
-                               hisi_sas_debugfs_loop_modes[i].value;
-                       found = true;
-                       break;
-               }
-       }
-       if (!found)
-               return -EINVAL;
-       return count;
- }
- static int hisi_sas_debugfs_bist_mode_open(struct inode *inode,
-                                          struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_bist_mode_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_bist_mode_ops = {
-       .open = hisi_sas_debugfs_bist_mode_open,
-       .read = seq_read,
-       .write = hisi_sas_debugfs_bist_mode_write,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static ssize_t hisi_sas_debugfs_bist_enable_write(struct file *filp,
-                                                 const char __user *buf,
-                                                 size_t count, loff_t *ppos)
- {
-       struct seq_file *m = filp->private_data;
-       struct hisi_hba *hisi_hba = m->private;
-       unsigned int enable;
-       int val;
-       val = kstrtouint_from_user(buf, count, 0, &enable);
-       if (val)
-               return val;
-       if (enable > 1)
-               return -EINVAL;
-       if (enable == hisi_hba->debugfs_bist_enable)
-               return count;
-       if (!hisi_hba->hw->set_bist)
-               return -EPERM;
-       val = hisi_hba->hw->set_bist(hisi_hba, enable);
-       if (val < 0)
-               return val;
-       hisi_hba->debugfs_bist_enable = enable;
-       return count;
- }
- static int hisi_sas_debugfs_bist_enable_show(struct seq_file *s, void *p)
- {
-       struct hisi_hba *hisi_hba = s->private;
-       seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable);
-       return 0;
- }
- static int hisi_sas_debugfs_bist_enable_open(struct inode *inode,
-                                            struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_bist_enable_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_bist_enable_ops = {
-       .open = hisi_sas_debugfs_bist_enable_open,
-       .read = seq_read,
-       .write = hisi_sas_debugfs_bist_enable_write,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static const struct {
-       char *name;
- } hisi_sas_debugfs_ffe_name[FFE_CFG_MAX] = {
-       { "SAS_1_5_GBPS" },
-       { "SAS_3_0_GBPS" },
-       { "SAS_6_0_GBPS" },
-       { "SAS_12_0_GBPS" },
-       { "FFE_RESV" },
-       { "SATA_1_5_GBPS" },
-       { "SATA_3_0_GBPS" },
-       { "SATA_6_0_GBPS" },
- };
- static ssize_t hisi_sas_debugfs_write(struct file *filp,
-                                     const char __user *buf,
-                                     size_t count, loff_t *ppos)
- {
-       struct seq_file *m = filp->private_data;
-       u32 *val = m->private;
-       int res;
-       res = kstrtouint_from_user(buf, count, 0, val);
-       if (res)
-               return res;
-       return count;
- }
- static int hisi_sas_debugfs_show(struct seq_file *s, void *p)
- {
-       u32 *val = s->private;
-       seq_printf(s, "0x%x\n", *val);
-       return 0;
- }
- static int hisi_sas_debugfs_open(struct inode *inode, struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_ops = {
-       .open = hisi_sas_debugfs_open,
-       .read = seq_read,
-       .write = hisi_sas_debugfs_write,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- static ssize_t hisi_sas_debugfs_phy_down_cnt_write(struct file *filp,
-                                                  const char __user *buf,
-                                                  size_t count, loff_t *ppos)
- {
-       struct seq_file *s = filp->private_data;
-       struct hisi_sas_phy *phy = s->private;
-       unsigned int set_val;
-       int res;
-       res = kstrtouint_from_user(buf, count, 0, &set_val);
-       if (res)
-               return res;
-       if (set_val > 0)
-               return -EINVAL;
-       atomic_set(&phy->down_cnt, 0);
-       return count;
- }
- static int hisi_sas_debugfs_phy_down_cnt_show(struct seq_file *s, void *p)
- {
-       struct hisi_sas_phy *phy = s->private;
-       seq_printf(s, "%d\n", atomic_read(&phy->down_cnt));
-       return 0;
- }
- static int hisi_sas_debugfs_phy_down_cnt_open(struct inode *inode,
-                                             struct file *filp)
- {
-       return single_open(filp, hisi_sas_debugfs_phy_down_cnt_show,
-                          inode->i_private);
- }
- static const struct file_operations hisi_sas_debugfs_phy_down_cnt_ops = {
-       .open = hisi_sas_debugfs_phy_down_cnt_open,
-       .read = seq_read,
-       .write = hisi_sas_debugfs_phy_down_cnt_write,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
- };
- void hisi_sas_debugfs_work_handler(struct work_struct *work)
- {
-       struct hisi_hba *hisi_hba =
-               container_of(work, struct hisi_hba, debugfs_work);
-       int debugfs_dump_index = hisi_hba->debugfs_dump_index;
-       struct device *dev = hisi_hba->dev;
-       u64 timestamp = local_clock();
-       if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) {
-               dev_warn(dev, "dump count exceeded!\n");
-               return;
-       }
-       do_div(timestamp, NSEC_PER_MSEC);
-       hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp;
-       hisi_sas_debugfs_snapshot_regs(hisi_hba);
-       hisi_hba->debugfs_dump_index++;
- }
- EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler);
- static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba, int dump_index)
- {
-       struct device *dev = hisi_hba->dev;
-       int i;
-       devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache);
-       devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache);
-       devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost);
-       devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct);
-       for (i = 0; i < hisi_hba->queue_count; i++)
-               devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr);
-       for (i = 0; i < hisi_hba->queue_count; i++)
-               devm_kfree(dev,
-                          hisi_hba->debugfs_cq[dump_index][i].complete_hdr);
-       for (i = 0; i < DEBUGFS_REGS_NUM; i++)
-               devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data);
-       for (i = 0; i < hisi_hba->n_phy; i++)
-               devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data);
- }
- static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba, int dump_index)
- {
-       const struct hisi_sas_hw *hw = hisi_hba->hw;
-       struct device *dev = hisi_hba->dev;
-       int p, c, d, r, i;
-       size_t sz;
-       for (r = 0; r < DEBUGFS_REGS_NUM; r++) {
-               struct hisi_sas_debugfs_regs *regs =
-                               &hisi_hba->debugfs_regs[dump_index][r];
-               sz = hw->debugfs_reg_array[r]->count * 4;
-               regs->data = devm_kmalloc(dev, sz, GFP_KERNEL);
-               if (!regs->data)
-                       goto fail;
-               regs->hisi_hba = hisi_hba;
-       }
-       sz = hw->debugfs_reg_port->count * 4;
-       for (p = 0; p < hisi_hba->n_phy; p++) {
-               struct hisi_sas_debugfs_port *port =
-                               &hisi_hba->debugfs_port_reg[dump_index][p];
-               port->data = devm_kmalloc(dev, sz, GFP_KERNEL);
-               if (!port->data)
-                       goto fail;
-               port->phy = &hisi_hba->phy[p];
-       }
-       sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
-       for (c = 0; c < hisi_hba->queue_count; c++) {
-               struct hisi_sas_debugfs_cq *cq =
-                               &hisi_hba->debugfs_cq[dump_index][c];
-               cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
-               if (!cq->complete_hdr)
-                       goto fail;
-               cq->cq = &hisi_hba->cq[c];
-       }
-       sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
-       for (d = 0; d < hisi_hba->queue_count; d++) {
-               struct hisi_sas_debugfs_dq *dq =
-                               &hisi_hba->debugfs_dq[dump_index][d];
-               dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
-               if (!dq->hdr)
-                       goto fail;
-               dq->dq = &hisi_hba->dq[d];
-       }
-       sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost);
-       hisi_hba->debugfs_iost[dump_index].iost =
-                               devm_kmalloc(dev, sz, GFP_KERNEL);
-       if (!hisi_hba->debugfs_iost[dump_index].iost)
-               goto fail;
-       sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
-            sizeof(struct hisi_sas_iost_itct_cache);
-       hisi_hba->debugfs_iost_cache[dump_index].cache =
-                               devm_kmalloc(dev, sz, GFP_KERNEL);
-       if (!hisi_hba->debugfs_iost_cache[dump_index].cache)
-               goto fail;
-       sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
-            sizeof(struct hisi_sas_iost_itct_cache);
-       hisi_hba->debugfs_itct_cache[dump_index].cache =
-                               devm_kmalloc(dev, sz, GFP_KERNEL);
-       if (!hisi_hba->debugfs_itct_cache[dump_index].cache)
-               goto fail;
-       /* New memory allocation must be locate before itct */
-       sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
-       hisi_hba->debugfs_itct[dump_index].itct =
-                               devm_kmalloc(dev, sz, GFP_KERNEL);
-       if (!hisi_hba->debugfs_itct[dump_index].itct)
-               goto fail;
-       return 0;
- fail:
-       for (i = 0; i < hisi_sas_debugfs_dump_count; i++)
-               hisi_sas_debugfs_release(hisi_hba, i);
-       return -ENOMEM;
- }
- static void hisi_sas_debugfs_phy_down_cnt_init(struct hisi_hba *hisi_hba)
- {
-       struct dentry *dir = debugfs_create_dir("phy_down_cnt",
-                                               hisi_hba->debugfs_dir);
-       char name[16];
-       int phy_no;
-       for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
-               snprintf(name, 16, "%d", phy_no);
-               debugfs_create_file(name, 0600, dir,
-                                   &hisi_hba->phy[phy_no],
-                                   &hisi_sas_debugfs_phy_down_cnt_ops);
-       }
- }
- static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba)
- {
-       struct dentry *ports_dentry;
-       int phy_no;
-       hisi_hba->debugfs_bist_dentry =
-                       debugfs_create_dir("bist", hisi_hba->debugfs_dir);
-       debugfs_create_file("link_rate", 0600,
-                           hisi_hba->debugfs_bist_dentry, hisi_hba,
-                           &hisi_sas_debugfs_bist_linkrate_ops);
-       debugfs_create_file("code_mode", 0600,
-                           hisi_hba->debugfs_bist_dentry, hisi_hba,
-                           &hisi_sas_debugfs_bist_code_mode_ops);
-       debugfs_create_file("fixed_code", 0600,
-                           hisi_hba->debugfs_bist_dentry,
-                           &hisi_hba->debugfs_bist_fixed_code[0],
-                           &hisi_sas_debugfs_ops);
-       debugfs_create_file("fixed_code_1", 0600,
-                           hisi_hba->debugfs_bist_dentry,
-                           &hisi_hba->debugfs_bist_fixed_code[1],
-                           &hisi_sas_debugfs_ops);
-       debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry,
-                           hisi_hba, &hisi_sas_debugfs_bist_phy_ops);
-       debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry,
-                          &hisi_hba->debugfs_bist_cnt);
-       debugfs_create_file("loopback_mode", 0600,
-                           hisi_hba->debugfs_bist_dentry,
-                           hisi_hba, &hisi_sas_debugfs_bist_mode_ops);
-       debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry,
-                           hisi_hba, &hisi_sas_debugfs_bist_enable_ops);
-       ports_dentry = debugfs_create_dir("port", hisi_hba->debugfs_bist_dentry);
-       for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
-               struct dentry *port_dentry;
-               struct dentry *ffe_dentry;
-               char name[256];
-               int i;
-               snprintf(name, 256, "%d", phy_no);
-               port_dentry = debugfs_create_dir(name, ports_dentry);
-               ffe_dentry = debugfs_create_dir("ffe", port_dentry);
-               for (i = 0; i < FFE_CFG_MAX; i++) {
-                       if (i == FFE_RESV)
-                               continue;
-                       debugfs_create_file(hisi_sas_debugfs_ffe_name[i].name,
-                                           0600, ffe_dentry,
-                                           &hisi_hba->debugfs_bist_ffe[phy_no][i],
-                                           &hisi_sas_debugfs_ops);
-               }
-       }
-       hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS;
- }
- void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
- {
-       struct device *dev = hisi_hba->dev;
-       int i;
-       hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev),
-                                                  hisi_sas_debugfs_dir);
-       debugfs_create_file("trigger_dump", 0200,
-                           hisi_hba->debugfs_dir,
-                           hisi_hba,
-                           &hisi_sas_debugfs_trigger_dump_fops);
-       /* create bist structures */
-       hisi_sas_debugfs_bist_init(hisi_hba);
-       hisi_hba->debugfs_dump_dentry =
-                       debugfs_create_dir("dump", hisi_hba->debugfs_dir);
-       hisi_sas_debugfs_phy_down_cnt_init(hisi_hba);
-       for (i = 0; i < hisi_sas_debugfs_dump_count; i++) {
-               if (hisi_sas_debugfs_alloc(hisi_hba, i)) {
-                       debugfs_remove_recursive(hisi_hba->debugfs_dir);
-                       dev_dbg(dev, "failed to init debugfs!\n");
-                       break;
-               }
-       }
- }
- EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init);
- void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba)
- {
-       debugfs_remove_recursive(hisi_hba->debugfs_dir);
- }
- EXPORT_SYMBOL_GPL(hisi_sas_debugfs_exit);
- int hisi_sas_remove(struct platform_device *pdev)
- {
-       struct sas_ha_struct *sha = platform_get_drvdata(pdev);
-       struct hisi_hba *hisi_hba = sha->lldd_ha;
-       struct Scsi_Host *shost = sha->core.shost;
-       if (timer_pending(&hisi_hba->timer))
-               del_timer(&hisi_hba->timer);
-       sas_unregister_ha(sha);
-       sas_remove_host(sha->core.shost);
-       hisi_sas_free(hisi_hba);
-       scsi_host_put(shost);
-       return 0;
- }
- EXPORT_SYMBOL_GPL(hisi_sas_remove);
- bool hisi_sas_debugfs_enable;
- EXPORT_SYMBOL_GPL(hisi_sas_debugfs_enable);
- module_param_named(debugfs_enable, hisi_sas_debugfs_enable, bool, 0444);
- MODULE_PARM_DESC(hisi_sas_debugfs_enable, "Enable driver debugfs (default disabled)");
- u32 hisi_sas_debugfs_dump_count = 1;
- EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dump_count);
- module_param_named(debugfs_dump_count, hisi_sas_debugfs_dump_count, uint, 0444);
- MODULE_PARM_DESC(hisi_sas_debugfs_dump_count, "Number of debugfs dumps to allow");
+ struct dentry *hisi_sas_debugfs_dir;
+ EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dir);
  
  static __init int hisi_sas_init(void)
  {
@@@ -522,6 -522,8 +522,8 @@@ module_param(auto_affine_msi_experiment
  MODULE_PARM_DESC(auto_affine_msi_experimental, "Enable auto-affinity of MSI IRQs as experimental:\n"
                 "default is off");
  
+ static void debugfs_work_handler_v3_hw(struct work_struct *work);
  static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
  {
        void __iomem *regs = hisi_hba->regs + off;
@@@ -2409,8 -2411,7 +2411,7 @@@ static int interrupt_init_v3_hw(struct 
                              DRV_NAME " phy", hisi_hba);
        if (rc) {
                dev_err(dev, "could not request phy interrupt, rc=%d\n", rc);
-               rc = -ENOENT;
-               goto free_irq_vectors;
+               return -ENOENT;
        }
  
        rc = devm_request_irq(dev, pci_irq_vector(pdev, 2),
                              DRV_NAME " channel", hisi_hba);
        if (rc) {
                dev_err(dev, "could not request chnl interrupt, rc=%d\n", rc);
-               rc = -ENOENT;
-               goto free_irq_vectors;
+               return -ENOENT;
        }
  
        rc = devm_request_irq(dev, pci_irq_vector(pdev, 11),
                              DRV_NAME " fatal", hisi_hba);
        if (rc) {
                dev_err(dev, "could not request fatal interrupt, rc=%d\n", rc);
-               rc = -ENOENT;
-               goto free_irq_vectors;
+               return -ENOENT;
        }
  
        if (hisi_sas_intr_conv)
                if (rc) {
                        dev_err(dev, "could not request cq%d interrupt, rc=%d\n",
                                i, rc);
-                       rc = -ENOENT;
-                       goto free_irq_vectors;
+                       return -ENOENT;
                }
 +              cq->irq_mask = pci_irq_get_affinity(pdev, i + BASE_VECTORS_V3_HW);
 +              if (!cq->irq_mask) {
 +                      dev_err(dev, "could not get cq%d irq affinity!\n", i);
 +                      return -ENOENT;
 +              }
        }
  
        return 0;
- free_irq_vectors:
-       pci_free_irq_vectors(pdev);
-       return rc;
  }
  
  static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
@@@ -2766,6 -2755,19 +2760,19 @@@ static struct device_attribute *host_at
        NULL
  };
  
+ #define HISI_SAS_DEBUGFS_REG(x) {#x, x}
+ struct hisi_sas_debugfs_reg_lu {
+       char *name;
+       int off;
+ };
+ struct hisi_sas_debugfs_reg {
+       const struct hisi_sas_debugfs_reg_lu *lu;
+       int count;
+       int base_off;
+ };
  static const struct hisi_sas_debugfs_reg_lu debugfs_port_reg_lu[] = {
        HISI_SAS_DEBUGFS_REG(PHY_CFG),
        HISI_SAS_DEBUGFS_REG(HARD_PHY_LINKRATE),
@@@ -2821,7 -2823,6 +2828,6 @@@ static const struct hisi_sas_debugfs_re
        .lu = debugfs_port_reg_lu,
        .count = 0x100,
        .base_off = PORT_BASE,
-       .read_port_reg = hisi_sas_phy_read32,
  };
  
  static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = {
  static const struct hisi_sas_debugfs_reg debugfs_global_reg = {
        .lu = debugfs_global_reg_lu,
        .count = 0x800,
-       .read_global_reg = hisi_sas_read32,
  };
  
  static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = {
@@@ -2909,7 -2909,6 +2914,6 @@@ static const struct hisi_sas_debugfs_re
        .lu = debugfs_axi_reg_lu,
        .count = 0x61,
        .base_off = AXI_MASTER_CFG_BASE,
-       .read_global_reg = hisi_sas_read32,
  };
  
  static const struct hisi_sas_debugfs_reg_lu debugfs_ras_reg_lu[] = {
@@@ -2927,7 -2926,6 +2931,6 @@@ static const struct hisi_sas_debugfs_re
        .lu = debugfs_ras_reg_lu,
        .count = 0x10,
        .base_off = RAS_BASE,
-       .read_global_reg = hisi_sas_read32,
  };
  
  static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba)
@@@ -3147,7 -3145,6 +3150,6 @@@ static struct scsi_host_template sht_v3
  };
  
  static const struct hisi_sas_hw hisi_sas_v3_hw = {
-       .hw_init = hisi_sas_v3_init,
        .setup_itct = setup_itct_v3_hw,
        .get_wideport_bitmap = get_wideport_bitmap_v3_hw,
        .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
        .get_events = phy_get_events_v3_hw,
        .write_gpio = write_gpio_v3_hw,
        .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw,
-       .debugfs_reg_array[DEBUGFS_GLOBAL] = &debugfs_global_reg,
-       .debugfs_reg_array[DEBUGFS_AXI] = &debugfs_axi_reg,
-       .debugfs_reg_array[DEBUGFS_RAS] = &debugfs_ras_reg,
-       .debugfs_reg_port = &debugfs_port_reg,
-       .snapshot_prepare = debugfs_snapshot_prepare_v3_hw,
-       .snapshot_restore = debugfs_snapshot_restore_v3_hw,
-       .read_iost_itct_cache = read_iost_itct_cache_v3_hw,
-       .set_bist = debugfs_set_bist_v3_hw,
  };
  
  static struct Scsi_Host *
@@@ -3195,7 -3184,7 +3189,7 @@@ hisi_sas_shost_alloc_pci(struct pci_de
        hisi_hba = shost_priv(shost);
  
        INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
-       INIT_WORK(&hisi_hba->debugfs_work, hisi_sas_debugfs_work_handler);
+       INIT_WORK(&hisi_hba->debugfs_work, debugfs_work_handler_v3_hw);
        hisi_hba->hw = &hisi_sas_v3_hw;
        hisi_hba->pci_dev = pdev;
        hisi_hba->dev = dev;
@@@ -3223,6 -3212,1196 +3217,1196 @@@ err_out
        return NULL;
  }
  
+ static void debugfs_snapshot_cq_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       int queue_entry_size = hisi_hba->hw->complete_hdr_size;
+       int dump_index = hisi_hba->debugfs_dump_index;
+       int i;
+       for (i = 0; i < hisi_hba->queue_count; i++)
+               memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr,
+                      hisi_hba->complete_hdr[i],
+                      HISI_SAS_QUEUE_SLOTS * queue_entry_size);
+ }
+ static void debugfs_snapshot_dq_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr);
+       int dump_index = hisi_hba->debugfs_dump_index;
+       int i;
+       for (i = 0; i < hisi_hba->queue_count; i++) {
+               struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr;
+               int j;
+               debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr;
+               cmd_hdr = hisi_hba->cmd_hdr[i];
+               for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++)
+                       memcpy(&debugfs_cmd_hdr[j], &cmd_hdr[j],
+                              queue_entry_size);
+       }
+ }
+ static void debugfs_snapshot_port_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       int dump_index = hisi_hba->debugfs_dump_index;
+       const struct hisi_sas_debugfs_reg *port = &debugfs_port_reg;
+       int i, phy_cnt;
+       u32 offset;
+       u32 *databuf;
+       for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) {
+               databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data;
+               for (i = 0; i < port->count; i++, databuf++) {
+                       offset = port->base_off + 4 * i;
+                       *databuf = hisi_sas_phy_read32(hisi_hba, phy_cnt,
+                                                      offset);
+               }
+       }
+ }
+ static void debugfs_snapshot_global_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       int dump_index = hisi_hba->debugfs_dump_index;
+       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data;
+       int i;
+       for (i = 0; i < debugfs_axi_reg.count; i++, databuf++)
+               *databuf = hisi_sas_read32(hisi_hba, 4 * i);
+ }
+ static void debugfs_snapshot_axi_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       int dump_index = hisi_hba->debugfs_dump_index;
+       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data;
+       const struct hisi_sas_debugfs_reg *axi = &debugfs_axi_reg;
+       int i;
+       for (i = 0; i < axi->count; i++, databuf++)
+               *databuf = hisi_sas_read32(hisi_hba, 4 * i + axi->base_off);
+ }
+ static void debugfs_snapshot_ras_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       int dump_index = hisi_hba->debugfs_dump_index;
+       u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data;
+       const struct hisi_sas_debugfs_reg *ras = &debugfs_ras_reg;
+       int i;
+       for (i = 0; i < ras->count; i++, databuf++)
+               *databuf = hisi_sas_read32(hisi_hba, 4 * i + ras->base_off);
+ }
+ static void debugfs_snapshot_itct_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       int dump_index = hisi_hba->debugfs_dump_index;
+       void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache;
+       void *databuf = hisi_hba->debugfs_itct[dump_index].itct;
+       struct hisi_sas_itct *itct;
+       int i;
+       read_iost_itct_cache_v3_hw(hisi_hba, HISI_SAS_ITCT_CACHE, cachebuf);
+       itct = hisi_hba->itct;
+       for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
+               memcpy(databuf, itct, sizeof(struct hisi_sas_itct));
+               databuf += sizeof(struct hisi_sas_itct);
+       }
+ }
+ static void debugfs_snapshot_iost_reg_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       int dump_index = hisi_hba->debugfs_dump_index;
+       int max_command_entries = HISI_SAS_MAX_COMMANDS;
+       void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache;
+       void *databuf = hisi_hba->debugfs_iost[dump_index].iost;
+       struct hisi_sas_iost *iost;
+       int i;
+       read_iost_itct_cache_v3_hw(hisi_hba, HISI_SAS_IOST_CACHE, cachebuf);
+       iost = hisi_hba->iost;
+       for (i = 0; i < max_command_entries; i++, iost++) {
+               memcpy(databuf, iost, sizeof(struct hisi_sas_iost));
+               databuf += sizeof(struct hisi_sas_iost);
+       }
+ }
+ static const char *
+ debugfs_to_reg_name_v3_hw(int off, int base_off,
+                         const struct hisi_sas_debugfs_reg_lu *lu)
+ {
+       for (; lu->name; lu++) {
+               if (off == lu->off - base_off)
+                       return lu->name;
+       }
+       return NULL;
+ }
+ static void debugfs_print_reg_v3_hw(u32 *regs_val, struct seq_file *s,
+                                   const struct hisi_sas_debugfs_reg *reg)
+ {
+       int i;
+       for (i = 0; i < reg->count; i++) {
+               int off = i * 4;
+               const char *name;
+               name = debugfs_to_reg_name_v3_hw(off, reg->base_off,
+                                                reg->lu);
+               if (name)
+                       seq_printf(s, "0x%08x 0x%08x %s\n", off,
+                                  regs_val[i], name);
+               else
+                       seq_printf(s, "0x%08x 0x%08x\n", off,
+                                  regs_val[i]);
+       }
+ }
+ static int debugfs_global_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_debugfs_regs *global = s->private;
+       debugfs_print_reg_v3_hw(global->data, s,
+                               &debugfs_global_reg);
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_global_v3_hw);
+ static int debugfs_axi_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_debugfs_regs *axi = s->private;
+       debugfs_print_reg_v3_hw(axi->data, s,
+                               &debugfs_axi_reg);
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_axi_v3_hw);
+ static int debugfs_ras_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_debugfs_regs *ras = s->private;
+       debugfs_print_reg_v3_hw(ras->data, s,
+                               &debugfs_ras_reg);
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_ras_v3_hw);
+ static int debugfs_port_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_debugfs_port *port = s->private;
+       const struct hisi_sas_debugfs_reg *reg_port = &debugfs_port_reg;
+       debugfs_print_reg_v3_hw(port->data, s, reg_port);
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_port_v3_hw);
+ static void debugfs_show_row_64_v3_hw(struct seq_file *s, int index,
+                                     int sz, __le64 *ptr)
+ {
+       int i;
+       /* completion header size not fixed per HW version */
+       seq_printf(s, "index %04d:\n\t", index);
+       for (i = 1; i <= sz / 8; i++, ptr++) {
+               seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr));
+               if (!(i % 2))
+                       seq_puts(s, "\n\t");
+       }
+       seq_puts(s, "\n");
+ }
+ static void debugfs_show_row_32_v3_hw(struct seq_file *s, int index,
+                                     int sz, __le32 *ptr)
+ {
+       int i;
+       /* completion header size not fixed per HW version */
+       seq_printf(s, "index %04d:\n\t", index);
+       for (i = 1; i <= sz / 4; i++, ptr++) {
+               seq_printf(s, " 0x%08x", le32_to_cpu(*ptr));
+               if (!(i % 4))
+                       seq_puts(s, "\n\t");
+       }
+       seq_puts(s, "\n");
+ }
+ static void debugfs_cq_show_slot_v3_hw(struct seq_file *s, int slot,
+                                      struct hisi_sas_debugfs_cq *debugfs_cq)
+ {
+       struct hisi_sas_cq *cq = debugfs_cq->cq;
+       struct hisi_hba *hisi_hba = cq->hisi_hba;
+       __le32 *complete_hdr = debugfs_cq->complete_hdr +
+                              (hisi_hba->hw->complete_hdr_size * slot);
+       debugfs_show_row_32_v3_hw(s, slot,
+                                 hisi_hba->hw->complete_hdr_size,
+                                 complete_hdr);
+ }
+ static int debugfs_cq_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_debugfs_cq *debugfs_cq = s->private;
+       int slot;
+       for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++)
+               debugfs_cq_show_slot_v3_hw(s, slot, debugfs_cq);
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_cq_v3_hw);
+ static void debugfs_dq_show_slot_v3_hw(struct seq_file *s, int slot,
+                                      void *dq_ptr)
+ {
+       struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr;
+       void *cmd_queue = debugfs_dq->hdr;
+       __le32 *cmd_hdr = cmd_queue +
+               sizeof(struct hisi_sas_cmd_hdr) * slot;
+       debugfs_show_row_32_v3_hw(s, slot, sizeof(struct hisi_sas_cmd_hdr),
+                                 cmd_hdr);
+ }
+ static int debugfs_dq_v3_hw_show(struct seq_file *s, void *p)
+ {
+       int slot;
+       for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++)
+               debugfs_dq_show_slot_v3_hw(s, slot, s->private);
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_dq_v3_hw);
+ static int debugfs_iost_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_debugfs_iost *debugfs_iost = s->private;
+       struct hisi_sas_iost *iost = debugfs_iost->iost;
+       int i, max_command_entries = HISI_SAS_MAX_COMMANDS;
+       for (i = 0; i < max_command_entries; i++, iost++) {
+               __le64 *data = &iost->qw0;
+               debugfs_show_row_64_v3_hw(s, i, sizeof(*iost), data);
+       }
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_iost_v3_hw);
+ static int debugfs_iost_cache_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private;
+       struct hisi_sas_iost_itct_cache *iost_cache =
+                                               debugfs_iost_cache->cache;
+       u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
+       int i, tab_idx;
+       __le64 *iost;
+       for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) {
+               /*
+                * Data struct of IOST cache:
+                * Data[1]: BIT0~15: Table index
+                *          Bit16:   Valid mask
+                * Data[2]~[9]: IOST table
+                */
+               tab_idx = (iost_cache->data[1] & 0xffff);
+               iost = (__le64 *)iost_cache;
+               debugfs_show_row_64_v3_hw(s, tab_idx, cache_size, iost);
+       }
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_iost_cache_v3_hw);
+ static int debugfs_itct_v3_hw_show(struct seq_file *s, void *p)
+ {
+       int i;
+       struct hisi_sas_debugfs_itct *debugfs_itct = s->private;
+       struct hisi_sas_itct *itct = debugfs_itct->itct;
+       for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
+               __le64 *data = &itct->qw0;
+               debugfs_show_row_64_v3_hw(s, i, sizeof(*itct), data);
+       }
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_itct_v3_hw);
+ static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private;
+       struct hisi_sas_iost_itct_cache *itct_cache =
+                                               debugfs_itct_cache->cache;
+       u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
+       int i, tab_idx;
+       __le64 *itct;
+       for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) {
+               /*
+                * Data struct of ITCT cache:
+                * Data[1]: BIT0~15: Table index
+                *          Bit16:   Valid mask
+                * Data[2]~[9]: ITCT table
+                */
+               tab_idx = itct_cache->data[1] & 0xffff;
+               itct = (__le64 *)itct_cache;
+               debugfs_show_row_64_v3_hw(s, tab_idx, cache_size, itct);
+       }
+       return 0;
+ }
+ DEFINE_SHOW_ATTRIBUTE(debugfs_itct_cache_v3_hw);
+ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       u64 *debugfs_timestamp;
+       int dump_index = hisi_hba->debugfs_dump_index;
+       struct dentry *dump_dentry;
+       struct dentry *dentry;
+       char name[256];
+       int p;
+       int c;
+       int d;
+       snprintf(name, 256, "%d", dump_index);
+       dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry);
+       debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index];
+       debugfs_create_u64("timestamp", 0400, dump_dentry,
+                          debugfs_timestamp);
+       debugfs_create_file("global", 0400, dump_dentry,
+                           &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL],
+                           &debugfs_global_v3_hw_fops);
+       /* Create port dir and files */
+       dentry = debugfs_create_dir("port", dump_dentry);
+       for (p = 0; p < hisi_hba->n_phy; p++) {
+               snprintf(name, 256, "%d", p);
+               debugfs_create_file(name, 0400, dentry,
+                                   &hisi_hba->debugfs_port_reg[dump_index][p],
+                                   &debugfs_port_v3_hw_fops);
+       }
+       /* Create CQ dir and files */
+       dentry = debugfs_create_dir("cq", dump_dentry);
+       for (c = 0; c < hisi_hba->queue_count; c++) {
+               snprintf(name, 256, "%d", c);
+               debugfs_create_file(name, 0400, dentry,
+                                   &hisi_hba->debugfs_cq[dump_index][c],
+                                   &debugfs_cq_v3_hw_fops);
+       }
+       /* Create DQ dir and files */
+       dentry = debugfs_create_dir("dq", dump_dentry);
+       for (d = 0; d < hisi_hba->queue_count; d++) {
+               snprintf(name, 256, "%d", d);
+               debugfs_create_file(name, 0400, dentry,
+                                   &hisi_hba->debugfs_dq[dump_index][d],
+                                   &debugfs_dq_v3_hw_fops);
+       }
+       debugfs_create_file("iost", 0400, dump_dentry,
+                           &hisi_hba->debugfs_iost[dump_index],
+                           &debugfs_iost_v3_hw_fops);
+       debugfs_create_file("iost_cache", 0400, dump_dentry,
+                           &hisi_hba->debugfs_iost_cache[dump_index],
+                           &debugfs_iost_cache_v3_hw_fops);
+       debugfs_create_file("itct", 0400, dump_dentry,
+                           &hisi_hba->debugfs_itct[dump_index],
+                           &debugfs_itct_v3_hw_fops);
+       debugfs_create_file("itct_cache", 0400, dump_dentry,
+                           &hisi_hba->debugfs_itct_cache[dump_index],
+                           &debugfs_itct_cache_v3_hw_fops);
+       debugfs_create_file("axi", 0400, dump_dentry,
+                           &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI],
+                           &debugfs_axi_v3_hw_fops);
+       debugfs_create_file("ras", 0400, dump_dentry,
+                           &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS],
+                           &debugfs_ras_v3_hw_fops);
+ }
+ static void debugfs_snapshot_regs_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       debugfs_snapshot_prepare_v3_hw(hisi_hba);
+       debugfs_snapshot_global_reg_v3_hw(hisi_hba);
+       debugfs_snapshot_port_reg_v3_hw(hisi_hba);
+       debugfs_snapshot_axi_reg_v3_hw(hisi_hba);
+       debugfs_snapshot_ras_reg_v3_hw(hisi_hba);
+       debugfs_snapshot_cq_reg_v3_hw(hisi_hba);
+       debugfs_snapshot_dq_reg_v3_hw(hisi_hba);
+       debugfs_snapshot_itct_reg_v3_hw(hisi_hba);
+       debugfs_snapshot_iost_reg_v3_hw(hisi_hba);
+       debugfs_create_files_v3_hw(hisi_hba);
+       debugfs_snapshot_restore_v3_hw(hisi_hba);
+ }
+ static ssize_t debugfs_trigger_dump_v3_hw_write(struct file *file,
+                                               const char __user *user_buf,
+                                               size_t count, loff_t *ppos)
+ {
+       struct hisi_hba *hisi_hba = file->f_inode->i_private;
+       char buf[8];
+       if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count)
+               return -EFAULT;
+       if (count > 8)
+               return -EFAULT;
+       if (copy_from_user(buf, user_buf, count))
+               return -EFAULT;
+       if (buf[0] != '1')
+               return -EFAULT;
+       queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
+       return count;
+ }
+ static const struct file_operations debugfs_trigger_dump_v3_hw_fops = {
+       .write = &debugfs_trigger_dump_v3_hw_write,
+       .owner = THIS_MODULE,
+ };
+ enum {
+       HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0,
+       HISI_SAS_BIST_LOOPBACK_MODE_SERDES,
+       HISI_SAS_BIST_LOOPBACK_MODE_REMOTE,
+ };
+ static const struct {
+       int             value;
+       char            *name;
+ } debugfs_loop_linkrate_v3_hw[] = {
+       { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
+       { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
+       { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
+       { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" },
+ };
+ static int debugfs_bist_linkrate_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_hba *hisi_hba = s->private;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) {
+               int match = (hisi_hba->debugfs_bist_linkrate ==
+                            debugfs_loop_linkrate_v3_hw[i].value);
+               seq_printf(s, "%s%s%s ", match ? "[" : "",
+                          debugfs_loop_linkrate_v3_hw[i].name,
+                          match ? "]" : "");
+       }
+       seq_puts(s, "\n");
+       return 0;
+ }
+ static ssize_t debugfs_bist_linkrate_v3_hw_write(struct file *filp,
+                                                const char __user *buf,
+                                                size_t count, loff_t *ppos)
+ {
+       struct seq_file *m = filp->private_data;
+       struct hisi_hba *hisi_hba = m->private;
+       char kbuf[16] = {}, *pkbuf;
+       bool found = false;
+       int i;
+       if (hisi_hba->debugfs_bist_enable)
+               return -EPERM;
+       if (count >= sizeof(kbuf))
+               return -EOVERFLOW;
+       if (copy_from_user(kbuf, buf, count))
+               return -EINVAL;
+       pkbuf = strstrip(kbuf);
+       for (i = 0; i < ARRAY_SIZE(debugfs_loop_linkrate_v3_hw); i++) {
+               if (!strncmp(debugfs_loop_linkrate_v3_hw[i].name,
+                            pkbuf, 16)) {
+                       hisi_hba->debugfs_bist_linkrate =
+                               debugfs_loop_linkrate_v3_hw[i].value;
+                       found = true;
+                       break;
+               }
+       }
+       if (!found)
+               return -EINVAL;
+       return count;
+ }
+ static int debugfs_bist_linkrate_v3_hw_open(struct inode *inode,
+                                           struct file *filp)
+ {
+       return single_open(filp, debugfs_bist_linkrate_v3_hw_show,
+                          inode->i_private);
+ }
+ static const struct file_operations debugfs_bist_linkrate_v3_hw_fops = {
+       .open = debugfs_bist_linkrate_v3_hw_open,
+       .read = seq_read,
+       .write = debugfs_bist_linkrate_v3_hw_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+ };
+ static const struct {
+       int             value;
+       char            *name;
+ } debugfs_loop_code_mode_v3_hw[] = {
+       { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" },
+       { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" },
+       { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" },
+       { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" },
+       { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" },
+       { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" },
+       { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" },
+       { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" },
+       { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" },
+       { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" },
+       { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" },
+       { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" },
+ };
+ static int debugfs_bist_code_mode_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_hba *hisi_hba = s->private;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) {
+               int match = (hisi_hba->debugfs_bist_code_mode ==
+                            debugfs_loop_code_mode_v3_hw[i].value);
+               seq_printf(s, "%s%s%s ", match ? "[" : "",
+                          debugfs_loop_code_mode_v3_hw[i].name,
+                          match ? "]" : "");
+       }
+       seq_puts(s, "\n");
+       return 0;
+ }
+ static ssize_t debugfs_bist_code_mode_v3_hw_write(struct file *filp,
+                                                 const char __user *buf,
+                                                 size_t count,
+                                                 loff_t *ppos)
+ {
+       struct seq_file *m = filp->private_data;
+       struct hisi_hba *hisi_hba = m->private;
+       char kbuf[16] = {}, *pkbuf;
+       bool found = false;
+       int i;
+       if (hisi_hba->debugfs_bist_enable)
+               return -EPERM;
+       if (count >= sizeof(kbuf))
+               return -EINVAL;
+       if (copy_from_user(kbuf, buf, count))
+               return -EOVERFLOW;
+       pkbuf = strstrip(kbuf);
+       for (i = 0; i < ARRAY_SIZE(debugfs_loop_code_mode_v3_hw); i++) {
+               if (!strncmp(debugfs_loop_code_mode_v3_hw[i].name,
+                            pkbuf, 16)) {
+                       hisi_hba->debugfs_bist_code_mode =
+                               debugfs_loop_code_mode_v3_hw[i].value;
+                       found = true;
+                       break;
+               }
+       }
+       if (!found)
+               return -EINVAL;
+       return count;
+ }
+ static int debugfs_bist_code_mode_v3_hw_open(struct inode *inode,
+                                            struct file *filp)
+ {
+       return single_open(filp, debugfs_bist_code_mode_v3_hw_show,
+                          inode->i_private);
+ }
+ static const struct file_operations debugfs_bist_code_mode_v3_hw_fops = {
+       .open = debugfs_bist_code_mode_v3_hw_open,
+       .read = seq_read,
+       .write = debugfs_bist_code_mode_v3_hw_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+ };
+ static ssize_t debugfs_bist_phy_v3_hw_write(struct file *filp,
+                                           const char __user *buf,
+                                           size_t count, loff_t *ppos)
+ {
+       struct seq_file *m = filp->private_data;
+       struct hisi_hba *hisi_hba = m->private;
+       unsigned int phy_no;
+       int val;
+       if (hisi_hba->debugfs_bist_enable)
+               return -EPERM;
+       val = kstrtouint_from_user(buf, count, 0, &phy_no);
+       if (val)
+               return val;
+       if (phy_no >= hisi_hba->n_phy)
+               return -EINVAL;
+       hisi_hba->debugfs_bist_phy_no = phy_no;
+       return count;
+ }
+ static int debugfs_bist_phy_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_hba *hisi_hba = s->private;
+       seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no);
+       return 0;
+ }
+ static int debugfs_bist_phy_v3_hw_open(struct inode *inode,
+                                      struct file *filp)
+ {
+       return single_open(filp, debugfs_bist_phy_v3_hw_show,
+                          inode->i_private);
+ }
+ static const struct file_operations debugfs_bist_phy_v3_hw_fops = {
+       .open = debugfs_bist_phy_v3_hw_open,
+       .read = seq_read,
+       .write = debugfs_bist_phy_v3_hw_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+ };
+ static const struct {
+       int             value;
+       char            *name;
+ } debugfs_loop_modes_v3_hw[] = {
+       { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" },
+       { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" },
+       { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" },
+ };
+ static int debugfs_bist_mode_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_hba *hisi_hba = s->private;
+       int i;
+       for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) {
+               int match = (hisi_hba->debugfs_bist_mode ==
+                            debugfs_loop_modes_v3_hw[i].value);
+               seq_printf(s, "%s%s%s ", match ? "[" : "",
+                          debugfs_loop_modes_v3_hw[i].name,
+                          match ? "]" : "");
+       }
+       seq_puts(s, "\n");
+       return 0;
+ }
+ static ssize_t debugfs_bist_mode_v3_hw_write(struct file *filp,
+                                            const char __user *buf,
+                                            size_t count, loff_t *ppos)
+ {
+       struct seq_file *m = filp->private_data;
+       struct hisi_hba *hisi_hba = m->private;
+       char kbuf[16] = {}, *pkbuf;
+       bool found = false;
+       int i;
+       if (hisi_hba->debugfs_bist_enable)
+               return -EPERM;
+       if (count >= sizeof(kbuf))
+               return -EINVAL;
+       if (copy_from_user(kbuf, buf, count))
+               return -EOVERFLOW;
+       pkbuf = strstrip(kbuf);
+       for (i = 0; i < ARRAY_SIZE(debugfs_loop_modes_v3_hw); i++) {
+               if (!strncmp(debugfs_loop_modes_v3_hw[i].name, pkbuf, 16)) {
+                       hisi_hba->debugfs_bist_mode =
+                               debugfs_loop_modes_v3_hw[i].value;
+                       found = true;
+                       break;
+               }
+       }
+       if (!found)
+               return -EINVAL;
+       return count;
+ }
+ static int debugfs_bist_mode_v3_hw_open(struct inode *inode,
+                                       struct file *filp)
+ {
+       return single_open(filp, debugfs_bist_mode_v3_hw_show,
+                          inode->i_private);
+ }
+ static const struct file_operations debugfs_bist_mode_v3_hw_fops = {
+       .open = debugfs_bist_mode_v3_hw_open,
+       .read = seq_read,
+       .write = debugfs_bist_mode_v3_hw_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+ };
+ static ssize_t debugfs_bist_enable_v3_hw_write(struct file *filp,
+                                              const char __user *buf,
+                                              size_t count, loff_t *ppos)
+ {
+       struct seq_file *m = filp->private_data;
+       struct hisi_hba *hisi_hba = m->private;
+       unsigned int enable;
+       int val;
+       val = kstrtouint_from_user(buf, count, 0, &enable);
+       if (val)
+               return val;
+       if (enable > 1)
+               return -EINVAL;
+       if (enable == hisi_hba->debugfs_bist_enable)
+               return count;
+       val = debugfs_set_bist_v3_hw(hisi_hba, enable);
+       if (val < 0)
+               return val;
+       hisi_hba->debugfs_bist_enable = enable;
+       return count;
+ }
+ static int debugfs_bist_enable_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_hba *hisi_hba = s->private;
+       seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable);
+       return 0;
+ }
+ static int debugfs_bist_enable_v3_hw_open(struct inode *inode,
+                                         struct file *filp)
+ {
+       return single_open(filp, debugfs_bist_enable_v3_hw_show,
+                          inode->i_private);
+ }
+ static const struct file_operations debugfs_bist_enable_v3_hw_fops = {
+       .open = debugfs_bist_enable_v3_hw_open,
+       .read = seq_read,
+       .write = debugfs_bist_enable_v3_hw_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+ };
+ static const struct {
+       char *name;
+ } debugfs_ffe_name_v3_hw[FFE_CFG_MAX] = {
+       { "SAS_1_5_GBPS" },
+       { "SAS_3_0_GBPS" },
+       { "SAS_6_0_GBPS" },
+       { "SAS_12_0_GBPS" },
+       { "FFE_RESV" },
+       { "SATA_1_5_GBPS" },
+       { "SATA_3_0_GBPS" },
+       { "SATA_6_0_GBPS" },
+ };
+ static ssize_t debugfs_v3_hw_write(struct file *filp,
+                                  const char __user *buf,
+                                  size_t count, loff_t *ppos)
+ {
+       struct seq_file *m = filp->private_data;
+       u32 *val = m->private;
+       int res;
+       res = kstrtouint_from_user(buf, count, 0, val);
+       if (res)
+               return res;
+       return count;
+ }
+ static int debugfs_v3_hw_show(struct seq_file *s, void *p)
+ {
+       u32 *val = s->private;
+       seq_printf(s, "0x%x\n", *val);
+       return 0;
+ }
+ static int debugfs_v3_hw_open(struct inode *inode, struct file *filp)
+ {
+       return single_open(filp, debugfs_v3_hw_show,
+                          inode->i_private);
+ }
+ static const struct file_operations debugfs_v3_hw_fops = {
+       .open = debugfs_v3_hw_open,
+       .read = seq_read,
+       .write = debugfs_v3_hw_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+ };
+ static ssize_t debugfs_phy_down_cnt_v3_hw_write(struct file *filp,
+                                               const char __user *buf,
+                                               size_t count, loff_t *ppos)
+ {
+       struct seq_file *s = filp->private_data;
+       struct hisi_sas_phy *phy = s->private;
+       unsigned int set_val;
+       int res;
+       res = kstrtouint_from_user(buf, count, 0, &set_val);
+       if (res)
+               return res;
+       if (set_val > 0)
+               return -EINVAL;
+       atomic_set(&phy->down_cnt, 0);
+       return count;
+ }
+ static int debugfs_phy_down_cnt_v3_hw_show(struct seq_file *s, void *p)
+ {
+       struct hisi_sas_phy *phy = s->private;
+       seq_printf(s, "%d\n", atomic_read(&phy->down_cnt));
+       return 0;
+ }
+ static int debugfs_phy_down_cnt_v3_hw_open(struct inode *inode,
+                                          struct file *filp)
+ {
+       return single_open(filp, debugfs_phy_down_cnt_v3_hw_show,
+                          inode->i_private);
+ }
+ static const struct file_operations debugfs_phy_down_cnt_v3_hw_fops = {
+       .open = debugfs_phy_down_cnt_v3_hw_open,
+       .read = seq_read,
+       .write = debugfs_phy_down_cnt_v3_hw_write,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .owner = THIS_MODULE,
+ };
+ static void debugfs_work_handler_v3_hw(struct work_struct *work)
+ {
+       struct hisi_hba *hisi_hba =
+               container_of(work, struct hisi_hba, debugfs_work);
+       int debugfs_dump_index = hisi_hba->debugfs_dump_index;
+       struct device *dev = hisi_hba->dev;
+       u64 timestamp = local_clock();
+       if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) {
+               dev_warn(dev, "dump count exceeded!\n");
+               return;
+       }
+       do_div(timestamp, NSEC_PER_MSEC);
+       hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp;
+       debugfs_snapshot_regs_v3_hw(hisi_hba);
+       hisi_hba->debugfs_dump_index++;
+ }
+ static void debugfs_release_v3_hw(struct hisi_hba *hisi_hba, int dump_index)
+ {
+       struct device *dev = hisi_hba->dev;
+       int i;
+       devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache);
+       devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache);
+       devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost);
+       devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct);
+       for (i = 0; i < hisi_hba->queue_count; i++)
+               devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr);
+       for (i = 0; i < hisi_hba->queue_count; i++)
+               devm_kfree(dev,
+                          hisi_hba->debugfs_cq[dump_index][i].complete_hdr);
+       for (i = 0; i < DEBUGFS_REGS_NUM; i++)
+               devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data);
+       for (i = 0; i < hisi_hba->n_phy; i++)
+               devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data);
+ }
+ static const struct hisi_sas_debugfs_reg *debugfs_reg_array_v3_hw[DEBUGFS_REGS_NUM] = {
+       [DEBUGFS_GLOBAL] = &debugfs_global_reg,
+       [DEBUGFS_AXI] = &debugfs_axi_reg,
+       [DEBUGFS_RAS] = &debugfs_ras_reg,
+ };
+ static int debugfs_alloc_v3_hw(struct hisi_hba *hisi_hba, int dump_index)
+ {
+       const struct hisi_sas_hw *hw = hisi_hba->hw;
+       struct device *dev = hisi_hba->dev;
+       int p, c, d, r, i;
+       size_t sz;
+       for (r = 0; r < DEBUGFS_REGS_NUM; r++) {
+               struct hisi_sas_debugfs_regs *regs =
+                               &hisi_hba->debugfs_regs[dump_index][r];
+               sz = debugfs_reg_array_v3_hw[r]->count * 4;
+               regs->data = devm_kmalloc(dev, sz, GFP_KERNEL);
+               if (!regs->data)
+                       goto fail;
+               regs->hisi_hba = hisi_hba;
+       }
+       sz = debugfs_port_reg.count * 4;
+       for (p = 0; p < hisi_hba->n_phy; p++) {
+               struct hisi_sas_debugfs_port *port =
+                               &hisi_hba->debugfs_port_reg[dump_index][p];
+               port->data = devm_kmalloc(dev, sz, GFP_KERNEL);
+               if (!port->data)
+                       goto fail;
+               port->phy = &hisi_hba->phy[p];
+       }
+       sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+       for (c = 0; c < hisi_hba->queue_count; c++) {
+               struct hisi_sas_debugfs_cq *cq =
+                               &hisi_hba->debugfs_cq[dump_index][c];
+               cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
+               if (!cq->complete_hdr)
+                       goto fail;
+               cq->cq = &hisi_hba->cq[c];
+       }
+       sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+       for (d = 0; d < hisi_hba->queue_count; d++) {
+               struct hisi_sas_debugfs_dq *dq =
+                               &hisi_hba->debugfs_dq[dump_index][d];
+               dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
+               if (!dq->hdr)
+                       goto fail;
+               dq->dq = &hisi_hba->dq[d];
+       }
+       sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost);
+       hisi_hba->debugfs_iost[dump_index].iost =
+                               devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_iost[dump_index].iost)
+               goto fail;
+       sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
+            sizeof(struct hisi_sas_iost_itct_cache);
+       hisi_hba->debugfs_iost_cache[dump_index].cache =
+                               devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_iost_cache[dump_index].cache)
+               goto fail;
+       sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
+            sizeof(struct hisi_sas_iost_itct_cache);
+       hisi_hba->debugfs_itct_cache[dump_index].cache =
+                               devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_itct_cache[dump_index].cache)
+               goto fail;
+       /* New memory allocation must be locate before itct */
+       sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+       hisi_hba->debugfs_itct[dump_index].itct =
+                               devm_kmalloc(dev, sz, GFP_KERNEL);
+       if (!hisi_hba->debugfs_itct[dump_index].itct)
+               goto fail;
+       return 0;
+ fail:
+       for (i = 0; i < hisi_sas_debugfs_dump_count; i++)
+               debugfs_release_v3_hw(hisi_hba, i);
+       return -ENOMEM;
+ }
+ static void debugfs_phy_down_cnt_init_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       struct dentry *dir = debugfs_create_dir("phy_down_cnt",
+                                               hisi_hba->debugfs_dir);
+       char name[16];
+       int phy_no;
+       for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+               snprintf(name, 16, "%d", phy_no);
+               debugfs_create_file(name, 0600, dir,
+                                   &hisi_hba->phy[phy_no],
+                                   &debugfs_phy_down_cnt_v3_hw_fops);
+       }
+ }
+ static void debugfs_bist_init_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       struct dentry *ports_dentry;
+       int phy_no;
+       hisi_hba->debugfs_bist_dentry =
+                       debugfs_create_dir("bist", hisi_hba->debugfs_dir);
+       debugfs_create_file("link_rate", 0600,
+                           hisi_hba->debugfs_bist_dentry, hisi_hba,
+                           &debugfs_bist_linkrate_v3_hw_fops);
+       debugfs_create_file("code_mode", 0600,
+                           hisi_hba->debugfs_bist_dentry, hisi_hba,
+                           &debugfs_bist_code_mode_v3_hw_fops);
+       debugfs_create_file("fixed_code", 0600,
+                           hisi_hba->debugfs_bist_dentry,
+                           &hisi_hba->debugfs_bist_fixed_code[0],
+                           &debugfs_v3_hw_fops);
+       debugfs_create_file("fixed_code_1", 0600,
+                           hisi_hba->debugfs_bist_dentry,
+                           &hisi_hba->debugfs_bist_fixed_code[1],
+                           &debugfs_v3_hw_fops);
+       debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry,
+                           hisi_hba, &debugfs_bist_phy_v3_hw_fops);
+       debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry,
+                          &hisi_hba->debugfs_bist_cnt);
+       debugfs_create_file("loopback_mode", 0600,
+                           hisi_hba->debugfs_bist_dentry,
+                           hisi_hba, &debugfs_bist_mode_v3_hw_fops);
+       debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry,
+                           hisi_hba, &debugfs_bist_enable_v3_hw_fops);
+       ports_dentry = debugfs_create_dir("port", hisi_hba->debugfs_bist_dentry);
+       for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
+               struct dentry *port_dentry;
+               struct dentry *ffe_dentry;
+               char name[256];
+               int i;
+               snprintf(name, 256, "%d", phy_no);
+               port_dentry = debugfs_create_dir(name, ports_dentry);
+               ffe_dentry = debugfs_create_dir("ffe", port_dentry);
+               for (i = 0; i < FFE_CFG_MAX; i++) {
+                       if (i == FFE_RESV)
+                               continue;
+                       debugfs_create_file(debugfs_ffe_name_v3_hw[i].name,
+                                           0600, ffe_dentry,
+                                           &hisi_hba->debugfs_bist_ffe[phy_no][i],
+                                           &debugfs_v3_hw_fops);
+               }
+       }
+       hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS;
+ }
+ static void debugfs_init_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       struct device *dev = hisi_hba->dev;
+       int i;
+       hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev),
+                                                  hisi_sas_debugfs_dir);
+       debugfs_create_file("trigger_dump", 0200,
+                           hisi_hba->debugfs_dir,
+                           hisi_hba,
+                           &debugfs_trigger_dump_v3_hw_fops);
+       /* create bist structures */
+       debugfs_bist_init_v3_hw(hisi_hba);
+       hisi_hba->debugfs_dump_dentry =
+                       debugfs_create_dir("dump", hisi_hba->debugfs_dir);
+       debugfs_phy_down_cnt_init_v3_hw(hisi_hba);
+       for (i = 0; i < hisi_sas_debugfs_dump_count; i++) {
+               if (debugfs_alloc_v3_hw(hisi_hba, i)) {
+                       debugfs_remove_recursive(hisi_hba->debugfs_dir);
+                       dev_dbg(dev, "failed to init debugfs!\n");
+                       break;
+               }
+       }
+ }
+ static void debugfs_exit_v3_hw(struct hisi_hba *hisi_hba)
+ {
+       debugfs_remove_recursive(hisi_hba->debugfs_dir);
+ }
  static int
  hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
  {
        }
  
        if (hisi_sas_debugfs_enable)
-               hisi_sas_debugfs_init(hisi_hba);
+               debugfs_init_v3_hw(hisi_hba);
  
        rc = interrupt_preinit_v3_hw(hisi_hba);
        if (rc)
-               goto err_out_ha;
+               goto err_out_debugfs;
        dev_err(dev, "%d hw queues\n", shost->nr_hw_queues);
        rc = scsi_add_host(shost, dev);
        if (rc)
-               goto err_out_ha;
+               goto err_out_free_irq_vectors;
  
        rc = sas_register_ha(sha);
        if (rc)
                goto err_out_register_ha;
  
-       rc = hisi_hba->hw->hw_init(hisi_hba);
+       rc = hisi_sas_v3_init(hisi_hba);
        if (rc)
                goto err_out_register_ha;
  
  
  err_out_register_ha:
        scsi_remove_host(shost);
+ err_out_free_irq_vectors:
+       pci_free_irq_vectors(pdev);
+ err_out_debugfs:
+       debugfs_exit_v3_hw(hisi_hba);
  err_out_ha:
-       hisi_sas_debugfs_exit(hisi_hba);
+       hisi_sas_free(hisi_hba);
        scsi_host_put(shost);
  err_out_regions:
        pci_release_regions(pdev);
@@@ -3394,7 -4577,7 +4582,7 @@@ static void hisi_sas_v3_remove(struct p
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        hisi_sas_free(hisi_hba);
-       hisi_sas_debugfs_exit(hisi_hba);
+       debugfs_exit_v3_hw(hisi_hba);
        scsi_host_put(shost);
  }
  
@@@ -3445,7 -4628,6 +4633,6 @@@ static int _suspend_v3_hw(struct devic
        struct hisi_hba *hisi_hba = sha->lldd_ha;
        struct device *dev = hisi_hba->dev;
        struct Scsi_Host *shost = hisi_hba->shost;
-       pci_power_t device_state;
        int rc;
  
        if (!pdev->pm_cap) {
  
        hisi_sas_init_mem(hisi_hba);
  
-       device_state = pci_choose_state(pdev, PMSG_SUSPEND);
-       dev_warn(dev, "entering operating state [D%d]\n",
-                       device_state);
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, device_state);
+       dev_warn(dev, "entering suspend state\n");
  
        hisi_sas_release_tasks(hisi_hba);
  
@@@ -3496,16 -4673,7 +4678,7 @@@ static int _resume_v3_hw(struct device 
  
        dev_warn(dev, "resuming from operating state [D%d]\n",
                 device_state);
-       pci_set_power_state(pdev, PCI_D0);
-       pci_enable_wake(pdev, PCI_D0, 0);
-       pci_restore_state(pdev);
-       rc = pci_enable_device(pdev);
-       if (rc) {
-               dev_err(dev, "enable device failed during resume (%d)\n", rc);
-               return rc;
-       }
  
-       pci_set_master(pdev);
        scsi_unblock_requests(shost);
        clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
  
        rc = hw_init_v3_hw(hisi_hba);
        if (rc) {
                scsi_remove_host(shost);
-               pci_disable_device(pdev);
                return rc;
        }
-       hisi_hba->hw->phys_init(hisi_hba);
+       phys_init_v3_hw(hisi_hba);
        sas_resume_ha(sha);
        clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
  
        return 0;
  }
  
- static int suspend_v3_hw(struct device *device)
+ static int __maybe_unused suspend_v3_hw(struct device *device)
  {
        struct pci_dev *pdev = to_pci_dev(device);
        struct sas_ha_struct *sha = pci_get_drvdata(pdev);
        return rc;
  }
  
- static int resume_v3_hw(struct device *device)
+ static int __maybe_unused resume_v3_hw(struct device *device)
  {
        struct pci_dev *pdev = to_pci_dev(device);
        struct sas_ha_struct *sha = pci_get_drvdata(pdev);
@@@ -3562,21 -4729,10 +4734,10 @@@ static const struct pci_error_handlers 
        .reset_done     = hisi_sas_reset_done_v3_hw,
  };
  
- static int runtime_suspend_v3_hw(struct device *dev)
- {
-       return suspend_v3_hw(dev);
- }
- static int runtime_resume_v3_hw(struct device *dev)
- {
-       return resume_v3_hw(dev);
- }
- static const struct dev_pm_ops hisi_sas_v3_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(suspend_v3_hw, resume_v3_hw)
-       SET_RUNTIME_PM_OPS(runtime_suspend_v3_hw,
-                          runtime_resume_v3_hw, NULL)
- };
+ static UNIVERSAL_DEV_PM_OPS(hisi_sas_v3_pm_ops,
+                           suspend_v3_hw,
+                           resume_v3_hw,
+                           NULL);
  
  static struct pci_driver sas_v3_pci_driver = {
        .name           = DRV_NAME,
diff --combined drivers/scsi/hpsa.c
@@@ -3881,8 -3881,6 +3881,6 @@@ static unsigned char hpsa_volume_offlin
        u8 sense_key, asc, ascq;
        int sense_len;
        int rc, ldstat = 0;
-       u16 cmd_status;
-       u8 scsi_status;
  #define ASC_LUN_NOT_READY 0x04
  #define ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS 0x04
  #define ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ 0x02
        else
                sense_len = c->err_info->SenseLen;
        decode_sense_data(sense, sense_len, &sense_key, &asc, &ascq);
-       cmd_status = c->err_info->CommandStatus;
-       scsi_status = c->err_info->ScsiStatus;
        cmd_free(h, c);
  
        /* Determine the reason for not ready state */
@@@ -4351,7 -4347,7 +4347,7 @@@ static void hpsa_update_scsi_devices(st
        u32 ndev_allocated = 0;
        struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
        int ncurrent = 0;
-       int i, n_ext_target_devs, ndevs_to_allocate;
+       int i, ndevs_to_allocate;
        int raid_ctlr_position;
        bool physical_device;
        DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
                raid_ctlr_position = nphysicals + nlogicals;
  
        /* adjust our table of devices */
-       n_ext_target_devs = 0;
        for (i = 0; i < nphysicals + nlogicals + 1; i++) {
                u8 *lunaddrbytes, is_OBDR = 0;
                int rc = 0;
@@@ -4580,7 -4575,7 +4575,7 @@@ static int hpsa_scatter_gather(struct c
                struct scsi_cmnd *cmd)
  {
        struct scatterlist *sg;
-       int use_sg, i, sg_limit, chained, last_sg;
+       int use_sg, i, sg_limit, chained;
        struct SGDescriptor *curr_sg;
  
        BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
        curr_sg = cp->SG;
        chained = use_sg > h->max_cmd_sg_entries;
        sg_limit = chained ? h->max_cmd_sg_entries - 1 : use_sg;
-       last_sg = scsi_sg_count(cmd) - 1;
        scsi_for_each_sg(cmd, sg, sg_limit, i) {
                hpsa_set_sg_descriptor(curr_sg, sg);
                curr_sg++;
@@@ -7442,7 -7436,6 +7436,6 @@@ static int find_PCI_BAR_index(struct pc
                                dev_warn(&pdev->dev,
                                       "base address is invalid\n");
                                return -1;
-                               break;
                        }
                }
                if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
@@@ -8636,7 -8629,7 +8629,7 @@@ static struct ctlr_info *hpda_alloc_ctl
  
  static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  {
-       int dac, rc;
+       int rc;
        struct ctlr_info *h;
        int try_soft_reset = 0;
        unsigned long flags;
@@@ -8712,13 -8705,9 +8705,9 @@@ reinit_after_soft_reset
  
        /* configure PCI DMA stuff */
        rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
-       if (rc == 0) {
-               dac = 1;
-       } else {
+       if (rc != 0) {
                rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
-               if (rc == 0) {
-                       dac = 0;
-               } else {
+               if (rc != 0) {
                        dev_err(&pdev->dev, "no suitable DMA available\n");
                        goto clean3;    /* shost, pci, lu, aer/h */
                }
        /* hook into SCSI subsystem */
        rc = hpsa_scsi_add_host(h);
        if (rc)
 -              goto clean7; /* perf, sg, cmd, irq, shost, pci, lu, aer/h */
 +              goto clean8; /* lastlogicals, perf, sg, cmd, irq, shost, pci, lu, aer/h */
  
        /* Monitor the controller for firmware lockups */
        h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
                                HPSA_EVENT_MONITOR_INTERVAL);
        return 0;
  
 +clean8: /* lastlogicals, perf, sg, cmd, irq, shost, pci, lu, aer/h */
 +      kfree(h->lastlogicals);
  clean7: /* perf, sg, cmd, irq, shost, pci, lu, aer/h */
        hpsa_free_performant_mode(h);
        h->access.set_intr_mask(h, HPSA_INTR_OFF);
@@@ -9092,25 -9079,27 +9081,27 @@@ static void hpsa_remove_one(struct pci_
        hpda_free_ctlr_info(h);                         /* init_one 1 */
  }
  
- static int hpsa_suspend(__attribute__((unused)) struct pci_dev *pdev,
-       __attribute__((unused)) pm_message_t state)
+ static int __maybe_unused hpsa_suspend(
+       __attribute__((unused)) struct device *dev)
  {
        return -ENOSYS;
  }
  
- static int hpsa_resume(__attribute__((unused)) struct pci_dev *pdev)
+ static int __maybe_unused hpsa_resume
+       (__attribute__((unused)) struct device *dev)
  {
        return -ENOSYS;
  }
  
+ static SIMPLE_DEV_PM_OPS(hpsa_pm_ops, hpsa_suspend, hpsa_resume);
  static struct pci_driver hpsa_pci_driver = {
        .name = HPSA,
        .probe = hpsa_init_one,
        .remove = hpsa_remove_one,
        .id_table = hpsa_pci_device_id, /* id_table */
        .shutdown = hpsa_shutdown,
-       .suspend = hpsa_suspend,
-       .resume = hpsa_resume,
+       .driver.pm = &hpsa_pm_ops,
  };
  
  /* Fill in bucket_map[], given nsgs (the max number of
@@@ -9299,10 -9288,9 +9290,9 @@@ static int hpsa_enter_performant_mode(s
        } else if (trans_support & CFGTBL_Trans_io_accel2) {
                u64 cfg_offset, cfg_base_addr_index;
                u32 bft2_offset, cfg_base_addr;
-               int rc;
  
-               rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
-                       &cfg_base_addr_index, &cfg_offset);
+               hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+                                   &cfg_base_addr_index, &cfg_offset);
                BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) != 64);
                bft2[15] = h->ioaccel_maxsg + HPSA_IOACCEL2_HEADER_SZ;
                calc_bucket_map(bft2, ARRAY_SIZE(bft2), h->ioaccel_maxsg,
diff --combined drivers/scsi/libiscsi.c
@@@ -533,8 -533,8 +533,8 @@@ static void iscsi_complete_task(struct 
        if (conn->task == task)
                conn->task = NULL;
  
 -      if (conn->ping_task == task)
 -              conn->ping_task = NULL;
 +      if (READ_ONCE(conn->ping_task) == task)
 +              WRITE_ONCE(conn->ping_task, NULL);
  
        /* release get from queueing */
        __iscsi_put_task(task);
@@@ -738,9 -738,6 +738,9 @@@ __iscsi_conn_send_pdu(struct iscsi_con
                                                   task->conn->session->age);
        }
  
 +      if (unlikely(READ_ONCE(conn->ping_task) == INVALID_SCSI_TASK))
 +              WRITE_ONCE(conn->ping_task, task);
 +
        if (!ihost->workq) {
                if (iscsi_prep_mgmt_task(conn, task))
                        goto free_task;
@@@ -780,7 -777,7 +780,7 @@@ int iscsi_conn_send_pdu(struct iscsi_cl
  EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
  
  /**
-  * iscsi_cmd_rsp - SCSI Command Response processing
+  * iscsi_scsi_cmd_rsp - SCSI Command Response processing
   * @conn: iscsi connection
   * @hdr: iscsi header
   * @task: scsi command task
@@@ -944,11 -941,8 +944,11 @@@ static int iscsi_send_nopout(struct isc
          struct iscsi_nopout hdr;
        struct iscsi_task *task;
  
 -      if (!rhdr && conn->ping_task)
 -              return -EINVAL;
 +      if (!rhdr) {
 +              if (READ_ONCE(conn->ping_task))
 +                      return -EINVAL;
 +              WRITE_ONCE(conn->ping_task, INVALID_SCSI_TASK);
 +      }
  
        memset(&hdr, 0, sizeof(struct iscsi_nopout));
        hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
  
        task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
        if (!task) {
 +              if (!rhdr)
 +                      WRITE_ONCE(conn->ping_task, NULL);
                iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
                return -EIO;
        } else if (!rhdr) {
                /* only track our nops */
 -              conn->ping_task = task;
                conn->last_ping = jiffies;
        }
  
@@@ -991,7 -984,7 +991,7 @@@ static int iscsi_nop_out_rsp(struct isc
        struct iscsi_conn *conn = task->conn;
        int rc = 0;
  
 -      if (conn->ping_task != task) {
 +      if (READ_ONCE(conn->ping_task) != task) {
                /*
                 * If this is not in response to one of our
                 * nops then it must be from userspace.
@@@ -1930,7 -1923,7 +1930,7 @@@ static void iscsi_start_tx(struct iscsi
   */
  static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
  {
 -      if (conn->ping_task &&
 +      if (READ_ONCE(conn->ping_task) &&
            time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
                           (conn->ping_timeout * HZ), jiffies))
                return 1;
@@@ -2065,7 -2058,7 +2065,7 @@@ enum blk_eh_timer_return iscsi_eh_cmd_t
         * Checking the transport already or nop from a cmd timeout still
         * running
         */
 -      if (conn->ping_task) {
 +      if (READ_ONCE(conn->ping_task)) {
                task->have_checked_conn = true;
                rc = BLK_EH_RESET_TIMER;
                goto done;
@@@ -37,6 -37,7 +37,6 @@@
  #include <linux/poll.h>
  #include <linux/vmalloc.h>
  #include <linux/irq_poll.h>
 -#include <linux/blk-mq-pci.h>
  
  #include <scsi/scsi.h>
  #include <scsi/scsi_cmnd.h>
@@@ -113,6 -114,10 +113,6 @@@ unsigned int enable_sdev_max_qd
  module_param(enable_sdev_max_qd, int, 0444);
  MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0");
  
 -int host_tagset_enable = 1;
 -module_param(host_tagset_enable, int, 0444);
 -MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)");
 -
  MODULE_LICENSE("GPL");
  MODULE_VERSION(MEGASAS_VERSION);
  MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com");
@@@ -3119,6 -3124,19 +3119,6 @@@ megasas_bios_param(struct scsi_device *
        return 0;
  }
  
 -static int megasas_map_queues(struct Scsi_Host *shost)
 -{
 -      struct megasas_instance *instance;
 -
 -      instance = (struct megasas_instance *)shost->hostdata;
 -
 -      if (shost->nr_hw_queues == 1)
 -              return 0;
 -
 -      return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
 -                      instance->pdev, instance->low_latency_index_start);
 -}
 -
  static void megasas_aen_polling(struct work_struct *work);
  
  /**
@@@ -3427,6 -3445,7 +3427,6 @@@ static struct scsi_host_template megasa
        .eh_timed_out = megasas_reset_timer,
        .shost_attrs = megaraid_host_attrs,
        .bios_param = megasas_bios_param,
 -      .map_queues = megasas_map_queues,
        .change_queue_depth = scsi_change_queue_depth,
        .max_segment_size = 0xffffffff,
  };
@@@ -6808,6 -6827,26 +6808,6 @@@ static int megasas_io_attach(struct meg
        host->max_lun = MEGASAS_MAX_LUN;
        host->max_cmd_len = 16;
  
 -      /* Use shared host tagset only for fusion adaptors
 -       * if there are managed interrupts (smp affinity enabled case).
 -       * Single msix_vectors in kdump, so shared host tag is also disabled.
 -       */
 -
 -      host->host_tagset = 0;
 -      host->nr_hw_queues = 1;
 -
 -      if ((instance->adapter_type != MFI_SERIES) &&
 -              (instance->msix_vectors > instance->low_latency_index_start) &&
 -              host_tagset_enable &&
 -              instance->smp_affinity_enable) {
 -              host->host_tagset = 1;
 -              host->nr_hw_queues = instance->msix_vectors -
 -                      instance->low_latency_index_start;
 -      }
 -
 -      dev_info(&instance->pdev->dev,
 -              "Max firmware commands: %d shared with nr_hw_queues = %d\n",
 -              instance->max_fw_cmds, host->nr_hw_queues);
        /*
         * Notify the mid-layer about the new controller
         */
@@@ -7554,25 -7593,23 +7554,23 @@@ static void megasas_shutdown_controller
        megasas_return_cmd(instance, cmd);
  }
  
- #ifdef CONFIG_PM
  /**
   * megasas_suspend -  driver suspend entry point
-  * @pdev:             PCI device structure
-  * @state:            PCI power state to suspend routine
+  * @dev:              Device structure
   */
- static int
- megasas_suspend(struct pci_dev *pdev, pm_message_t state)
+ static int __maybe_unused
+ megasas_suspend(struct device *dev)
  {
        struct megasas_instance *instance;
  
-       instance = pci_get_drvdata(pdev);
+       instance = dev_get_drvdata(dev);
  
        if (!instance)
                return 0;
  
        instance->unload = 1;
  
-       dev_info(&pdev->dev, "%s is called\n", __func__);
+       dev_info(dev, "%s is called\n", __func__);
  
        /* Shutdown SR-IOV heartbeat timer */
        if (instance->requestorId && !instance->skip_heartbeat_timer_del)
        if (instance->msix_vectors)
                pci_free_irq_vectors(instance->pdev);
  
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
        return 0;
  }
  
  /**
   * megasas_resume-      driver resume entry point
-  * @pdev:               PCI device structure
+  * @dev:              Device structure
   */
- static int
- megasas_resume(struct pci_dev *pdev)
+ static int __maybe_unused
+ megasas_resume(struct device *dev)
  {
        int rval;
        struct Scsi_Host *host;
        struct megasas_instance *instance;
        u32 status_reg;
  
-       instance = pci_get_drvdata(pdev);
+       instance = dev_get_drvdata(dev);
  
        if (!instance)
                return 0;
  
        host = instance->host;
-       pci_set_power_state(pdev, PCI_D0);
-       pci_enable_wake(pdev, PCI_D0, 0);
-       pci_restore_state(pdev);
-       dev_info(&pdev->dev, "%s is called\n", __func__);
-       /*
-        * PCI prepping: enable device set bus mastering and dma mask
-        */
-       rval = pci_enable_device_mem(pdev);
  
-       if (rval) {
-               dev_err(&pdev->dev, "Enable device failed\n");
-               return rval;
-       }
-       pci_set_master(pdev);
+       dev_info(dev, "%s is called\n", __func__);
  
        /*
         * We expect the FW state to be READY
@@@ -7769,14 -7787,8 +7748,8 @@@ fail_reenable_msix
  fail_set_dma_mask:
  fail_ready_state:
  
-       pci_disable_device(pdev);
        return -ENODEV;
  }
- #else
- #define megasas_suspend       NULL
- #define megasas_resume        NULL
- #endif
  
  static inline int
  megasas_wait_for_adapter_operational(struct megasas_instance *instance)
@@@ -7946,7 -7958,7 +7919,7 @@@ skip_firing_dcmds
  
  /**
   * megasas_shutdown - Shutdown entry point
-  * @pdev:             Generic device structure
+  * @pdev:             PCI device structure
   */
  static void megasas_shutdown(struct pci_dev *pdev)
  {
@@@ -8095,7 -8107,7 +8068,7 @@@ megasas_mgmt_fw_ioctl(struct megasas_in
        int error = 0, i;
        void *sense = NULL;
        dma_addr_t sense_handle;
-       unsigned long *sense_ptr;
+       void *sense_ptr;
        u32 opcode = 0;
        int ret = DCMD_SUCCESS;
  
        }
  
        if (ioc->sense_len) {
+               /* make sure the pointer is part of the frame */
+               if (ioc->sense_off >
+                   (sizeof(union megasas_frame) - sizeof(__le64))) {
+                       error = -EINVAL;
+                       goto out;
+               }
                sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
                                             &sense_handle, GFP_KERNEL);
                if (!sense) {
                        goto out;
                }
  
-               sense_ptr =
-               (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off);
+               sense_ptr = (void *)cmd->frame + ioc->sense_off;
                if (instance->consistent_mask_64bit)
-                       *sense_ptr = cpu_to_le64(sense_handle);
+                       put_unaligned_le64(sense_handle, sense_ptr);
                else
-                       *sense_ptr = cpu_to_le32(sense_handle);
+                       put_unaligned_le32(sense_handle, sense_ptr);
        }
  
        /*
         * copy out the sense
         */
        if (ioc->sense_len) {
+               void __user *uptr;
                /*
                 * sense_ptr points to the location that has the user
                 * sense buffer address
                 */
-               sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
-                               ioc->sense_off);
+               sense_ptr = (void *)ioc->frame.raw + ioc->sense_off;
+               if (in_compat_syscall())
+                       uptr = compat_ptr(get_unaligned((compat_uptr_t *)
+                                                       sense_ptr));
+               else
+                       uptr = get_unaligned((void __user **)sense_ptr);
  
-               if (copy_to_user((void __user *)((unsigned long)
-                                get_unaligned((unsigned long *)sense_ptr)),
-                                sense, ioc->sense_len)) {
+               if (copy_to_user(uptr, sense, ioc->sense_len)) {
                        dev_err(&instance->pdev->dev, "Failed to copy out to user "
                                        "sense data\n");
                        error = -EFAULT;
        return error;
  }
  
+ static struct megasas_iocpacket *
+ megasas_compat_iocpacket_get_user(void __user *arg)
+ {
+       struct megasas_iocpacket *ioc;
+       struct compat_megasas_iocpacket __user *cioc = arg;
+       size_t size;
+       int err = -EFAULT;
+       int i;
+       ioc = kzalloc(sizeof(*ioc), GFP_KERNEL);
+       if (!ioc)
+               return ERR_PTR(-ENOMEM);
+       size = offsetof(struct megasas_iocpacket, frame) + sizeof(ioc->frame);
+       if (copy_from_user(ioc, arg, size))
+               goto out;
+       for (i = 0; i < MAX_IOCTL_SGE; i++) {
+               compat_uptr_t iov_base;
+               if (get_user(iov_base, &cioc->sgl[i].iov_base) ||
+                   get_user(ioc->sgl[i].iov_len, &cioc->sgl[i].iov_len))
+                       goto out;
+               ioc->sgl[i].iov_base = compat_ptr(iov_base);
+       }
+       return ioc;
+ out:
+       kfree(ioc);
+       return ERR_PTR(err);
+ }
  static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
  {
        struct megasas_iocpacket __user *user_ioc =
        struct megasas_instance *instance;
        int error;
  
-       ioc = memdup_user(user_ioc, sizeof(*ioc));
+       if (in_compat_syscall())
+               ioc = megasas_compat_iocpacket_get_user(user_ioc);
+       else
+               ioc = memdup_user(user_ioc, sizeof(struct megasas_iocpacket));
        if (IS_ERR(ioc))
                return PTR_ERR(ioc);
  
@@@ -8439,78 -8496,13 +8457,13 @@@ megasas_mgmt_ioctl(struct file *file, u
  }
  
  #ifdef CONFIG_COMPAT
- static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
- {
-       struct compat_megasas_iocpacket __user *cioc =
-           (struct compat_megasas_iocpacket __user *)arg;
-       struct megasas_iocpacket __user *ioc =
-           compat_alloc_user_space(sizeof(struct megasas_iocpacket));
-       int i;
-       int error = 0;
-       compat_uptr_t ptr;
-       u32 local_sense_off;
-       u32 local_sense_len;
-       u32 user_sense_off;
-       if (clear_user(ioc, sizeof(*ioc)))
-               return -EFAULT;
-       if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
-           copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
-           copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) ||
-           copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) ||
-           copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) ||
-           copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32)))
-               return -EFAULT;
-       /*
-        * The sense_ptr is used in megasas_mgmt_fw_ioctl only when
-        * sense_len is not null, so prepare the 64bit value under
-        * the same condition.
-        */
-       if (get_user(local_sense_off, &ioc->sense_off) ||
-               get_user(local_sense_len, &ioc->sense_len) ||
-               get_user(user_sense_off, &cioc->sense_off))
-               return -EFAULT;
-       if (local_sense_off != user_sense_off)
-               return -EINVAL;
-       if (local_sense_len) {
-               void __user **sense_ioc_ptr =
-                       (void __user **)((u8 *)((unsigned long)&ioc->frame.raw) + local_sense_off);
-               compat_uptr_t *sense_cioc_ptr =
-                       (compat_uptr_t *)(((unsigned long)&cioc->frame.raw) + user_sense_off);
-               if (get_user(ptr, sense_cioc_ptr) ||
-                   put_user(compat_ptr(ptr), sense_ioc_ptr))
-                       return -EFAULT;
-       }
-       for (i = 0; i < MAX_IOCTL_SGE; i++) {
-               if (get_user(ptr, &cioc->sgl[i].iov_base) ||
-                   put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) ||
-                   copy_in_user(&ioc->sgl[i].iov_len,
-                                &cioc->sgl[i].iov_len, sizeof(compat_size_t)))
-                       return -EFAULT;
-       }
-       error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc);
-       if (copy_in_user(&cioc->frame.hdr.cmd_status,
-                        &ioc->frame.hdr.cmd_status, sizeof(u8))) {
-               printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n");
-               return -EFAULT;
-       }
-       return error;
- }
  static long
  megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
                          unsigned long arg)
  {
        switch (cmd) {
        case MEGASAS_IOC_FIRMWARE32:
-               return megasas_mgmt_compat_ioctl_fw(file, arg);
+               return megasas_mgmt_ioctl_fw(file, arg);
        case MEGASAS_IOC_GET_AEN:
                return megasas_mgmt_ioctl_aen(file, arg);
        }
@@@ -8534,6 -8526,8 +8487,8 @@@ static const struct file_operations meg
        .llseek = noop_llseek,
  };
  
+ static SIMPLE_DEV_PM_OPS(megasas_pm_ops, megasas_suspend, megasas_resume);
  /*
   * PCI hotplug support registration structure
   */
@@@ -8543,8 -8537,7 +8498,7 @@@ static struct pci_driver megasas_pci_dr
        .id_table = megasas_pci_table,
        .probe = megasas_probe_one,
        .remove = megasas_detach_one,
-       .suspend = megasas_suspend,
-       .resume = megasas_resume,
+       .driver.pm = &megasas_pm_ops,
        .shutdown = megasas_shutdown,
  };
  
@@@ -597,6 -597,71 +597,71 @@@ static int mpt3sas_remove_dead_ioc_func
  }
  
  /**
+  * _base_sync_drv_fw_timestamp - Sync Drive-Fw TimeStamp.
+  * @ioc: Per Adapter Object
+  *
+  * Return nothing.
+  */
+ static void _base_sync_drv_fw_timestamp(struct MPT3SAS_ADAPTER *ioc)
+ {
+       Mpi26IoUnitControlRequest_t *mpi_request;
+       Mpi26IoUnitControlReply_t *mpi_reply;
+       u16 smid;
+       ktime_t current_time;
+       u64 TimeStamp = 0;
+       u8 issue_reset = 0;
+       mutex_lock(&ioc->scsih_cmds.mutex);
+       if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) {
+               ioc_err(ioc, "scsih_cmd in use %s\n", __func__);
+               goto out;
+       }
+       ioc->scsih_cmds.status = MPT3_CMD_PENDING;
+       smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx);
+       if (!smid) {
+               ioc_err(ioc, "Failed obtaining a smid %s\n", __func__);
+               ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
+               goto out;
+       }
+       mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
+       ioc->scsih_cmds.smid = smid;
+       memset(mpi_request, 0, sizeof(Mpi26IoUnitControlRequest_t));
+       mpi_request->Function = MPI2_FUNCTION_IO_UNIT_CONTROL;
+       mpi_request->Operation = MPI26_CTRL_OP_SET_IOC_PARAMETER;
+       mpi_request->IOCParameter = MPI26_SET_IOC_PARAMETER_SYNC_TIMESTAMP;
+       current_time = ktime_get_real();
+       TimeStamp = ktime_to_ms(current_time);
+       mpi_request->Reserved7 = cpu_to_le32(TimeStamp & 0xFFFFFFFF);
+       mpi_request->IOCParameterValue = cpu_to_le32(TimeStamp >> 32);
+       init_completion(&ioc->scsih_cmds.done);
+       ioc->put_smid_default(ioc, smid);
+       dinitprintk(ioc, ioc_info(ioc,
+           "Io Unit Control Sync TimeStamp (sending), @time %lld ms\n",
+           TimeStamp));
+       wait_for_completion_timeout(&ioc->scsih_cmds.done,
+               MPT3SAS_TIMESYNC_TIMEOUT_SECONDS*HZ);
+       if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
+               mpt3sas_check_cmd_timeout(ioc,
+                   ioc->scsih_cmds.status, mpi_request,
+                   sizeof(Mpi2SasIoUnitControlRequest_t)/4, issue_reset);
+               goto issue_host_reset;
+       }
+       if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) {
+               mpi_reply = ioc->scsih_cmds.reply;
+               dinitprintk(ioc, ioc_info(ioc,
+                   "Io Unit Control sync timestamp (complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
+                   le16_to_cpu(mpi_reply->IOCStatus),
+                   le32_to_cpu(mpi_reply->IOCLogInfo)));
+       }
+ issue_host_reset:
+       if (issue_reset)
+               mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
+       ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
+ out:
+       mutex_unlock(&ioc->scsih_cmds.mutex);
+ }
+ /**
   * _base_fault_reset_work - workq handling ioc fault conditions
   * @work: input argument, used to derive ioc
   *
@@@ -720,7 -785,11 +785,11 @@@ _base_fault_reset_work(struct work_stru
                        return; /* don't rearm timer */
        }
        ioc->ioc_coredump_loop = 0;
+       if (ioc->time_sync_interval &&
+           ++ioc->timestamp_update_count >= ioc->time_sync_interval) {
+               ioc->timestamp_update_count = 0;
+               _base_sync_drv_fw_timestamp(ioc);
+       }
        spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
   rearm_timer:
        if (ioc->fault_reset_work_q)
@@@ -744,6 -813,7 +813,7 @@@ mpt3sas_base_start_watchdog(struct MPT3
        if (ioc->fault_reset_work_q)
                return;
  
+       ioc->timestamp_update_count = 0;
        /* initialize fault polling */
  
        INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
@@@ -905,6 -975,20 +975,20 @@@ _base_sas_ioc_info(struct MPT3SAS_ADAPT
  
        if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
                return;
+       /*
+        * Older Firmware version doesn't support driver trigger pages.
+        * So, skip displaying 'config invalid type' type
+        * of error message.
+        */
+       if (request_hdr->Function == MPI2_FUNCTION_CONFIG) {
+               Mpi2ConfigRequest_t *rqst = (Mpi2ConfigRequest_t *)request_hdr;
+               if ((rqst->ExtPageType ==
+                   MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER) &&
+                   !(ioc->logging_level & MPT_DEBUG_CONFIG)) {
+                       return;
+               }
+       }
  
        switch (ioc_status) {
  
@@@ -1740,13 -1824,6 +1824,13 @@@ _base_irqpoll(struct irq_poll *irqpoll
                reply_q->irq_poll_scheduled = false;
                reply_q->irq_line_enable = true;
                enable_irq(reply_q->os_irq);
 +              /*
 +               * Go for one more round of processing the
 +               * reply descriptor post queue incase if HBA
 +               * Firmware has posted some reply descriptors
 +               * while reenabling the IRQ.
 +               */
 +              _base_process_reply_queue(reply_q);
        }
  
        return num_entries;
@@@ -4721,6 -4798,311 +4805,311 @@@ _base_update_ioc_page1_inlinewith_perf_
  }
  
  /**
+  * _base_get_event_diag_triggers - get event diag trigger values from
+  *                            persistent pages
+  * @ioc : per adapter object
+  *
+  * Return nothing.
+  */
+ static void
+ _base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
+ {
+       Mpi26DriverTriggerPage2_t trigger_pg2;
+       struct SL_WH_EVENT_TRIGGER_T *event_tg;
+       MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY *mpi_event_tg;
+       Mpi2ConfigReply_t mpi_reply;
+       int r = 0, i = 0;
+       u16 count = 0;
+       u16 ioc_status;
+       r = mpt3sas_config_get_driver_trigger_pg2(ioc, &mpi_reply,
+           &trigger_pg2);
+       if (r)
+               return;
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               dinitprintk(ioc,
+                   ioc_err(ioc,
+                   "%s: Failed to get trigger pg2, ioc_status(0x%04x)\n",
+                  __func__, ioc_status));
+               return;
+       }
+       if (le16_to_cpu(trigger_pg2.NumMPIEventTrigger)) {
+               count = le16_to_cpu(trigger_pg2.NumMPIEventTrigger);
+               count = min_t(u16, NUM_VALID_ENTRIES, count);
+               ioc->diag_trigger_event.ValidEntries = count;
+               event_tg = &ioc->diag_trigger_event.EventTriggerEntry[0];
+               mpi_event_tg = &trigger_pg2.MPIEventTriggers[0];
+               for (i = 0; i < count; i++) {
+                       event_tg->EventValue = le16_to_cpu(
+                           mpi_event_tg->MPIEventCode);
+                       event_tg->LogEntryQualifier = le16_to_cpu(
+                           mpi_event_tg->MPIEventCodeSpecific);
+                       event_tg++;
+                       mpi_event_tg++;
+               }
+       }
+ }
+ /**
+  * _base_get_scsi_diag_triggers - get scsi diag trigger values from
+  *                            persistent pages
+  * @ioc : per adapter object
+  *
+  * Return nothing.
+  */
+ static void
+ _base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
+ {
+       Mpi26DriverTriggerPage3_t trigger_pg3;
+       struct SL_WH_SCSI_TRIGGER_T *scsi_tg;
+       MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY *mpi_scsi_tg;
+       Mpi2ConfigReply_t mpi_reply;
+       int r = 0, i = 0;
+       u16 count = 0;
+       u16 ioc_status;
+       r = mpt3sas_config_get_driver_trigger_pg3(ioc, &mpi_reply,
+           &trigger_pg3);
+       if (r)
+               return;
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               dinitprintk(ioc,
+                   ioc_err(ioc,
+                   "%s: Failed to get trigger pg3, ioc_status(0x%04x)\n",
+                   __func__, ioc_status));
+               return;
+       }
+       if (le16_to_cpu(trigger_pg3.NumSCSISenseTrigger)) {
+               count = le16_to_cpu(trigger_pg3.NumSCSISenseTrigger);
+               count = min_t(u16, NUM_VALID_ENTRIES, count);
+               ioc->diag_trigger_scsi.ValidEntries = count;
+               scsi_tg = &ioc->diag_trigger_scsi.SCSITriggerEntry[0];
+               mpi_scsi_tg = &trigger_pg3.SCSISenseTriggers[0];
+               for (i = 0; i < count; i++) {
+                       scsi_tg->ASCQ = mpi_scsi_tg->ASCQ;
+                       scsi_tg->ASC = mpi_scsi_tg->ASC;
+                       scsi_tg->SenseKey = mpi_scsi_tg->SenseKey;
+                       scsi_tg++;
+                       mpi_scsi_tg++;
+               }
+       }
+ }
+ /**
+  * _base_get_mpi_diag_triggers - get mpi diag trigger values from
+  *                            persistent pages
+  * @ioc : per adapter object
+  *
+  * Return nothing.
+  */
+ static void
+ _base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
+ {
+       Mpi26DriverTriggerPage4_t trigger_pg4;
+       struct SL_WH_MPI_TRIGGER_T *status_tg;
+       MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY *mpi_status_tg;
+       Mpi2ConfigReply_t mpi_reply;
+       int r = 0, i = 0;
+       u16 count = 0;
+       u16 ioc_status;
+       r = mpt3sas_config_get_driver_trigger_pg4(ioc, &mpi_reply,
+           &trigger_pg4);
+       if (r)
+               return;
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               dinitprintk(ioc,
+                   ioc_err(ioc,
+                   "%s: Failed to get trigger pg4, ioc_status(0x%04x)\n",
+                   __func__, ioc_status));
+               return;
+       }
+       if (le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger)) {
+               count = le16_to_cpu(trigger_pg4.NumIOCStatusLogInfoTrigger);
+               count = min_t(u16, NUM_VALID_ENTRIES, count);
+               ioc->diag_trigger_mpi.ValidEntries = count;
+               status_tg = &ioc->diag_trigger_mpi.MPITriggerEntry[0];
+               mpi_status_tg = &trigger_pg4.IOCStatusLoginfoTriggers[0];
+               for (i = 0; i < count; i++) {
+                       status_tg->IOCStatus = le16_to_cpu(
+                           mpi_status_tg->IOCStatus);
+                       status_tg->IocLogInfo = le32_to_cpu(
+                           mpi_status_tg->LogInfo);
+                       status_tg++;
+                       mpi_status_tg++;
+               }
+       }
+ }
+ /**
+  * _base_get_master_diag_triggers - get master diag trigger values from
+  *                            persistent pages
+  * @ioc : per adapter object
+  *
+  * Return nothing.
+  */
+ static void
+ _base_get_master_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
+ {
+       Mpi26DriverTriggerPage1_t trigger_pg1;
+       Mpi2ConfigReply_t mpi_reply;
+       int r;
+       u16 ioc_status;
+       r = mpt3sas_config_get_driver_trigger_pg1(ioc, &mpi_reply,
+           &trigger_pg1);
+       if (r)
+               return;
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               dinitprintk(ioc,
+                   ioc_err(ioc,
+                   "%s: Failed to get trigger pg1, ioc_status(0x%04x)\n",
+                  __func__, ioc_status));
+               return;
+       }
+       if (le16_to_cpu(trigger_pg1.NumMasterTrigger))
+               ioc->diag_trigger_master.MasterData |=
+                   le32_to_cpu(
+                   trigger_pg1.MasterTriggers[0].MasterTriggerFlags);
+ }
+ /**
+  * _base_check_for_trigger_pages_support - checks whether HBA FW supports
+  *                                    driver trigger pages or not
+  * @ioc : per adapter object
+  *
+  * Returns trigger flags mask if HBA FW supports driver trigger pages,
+  * otherwise returns EFAULT.
+  */
+ static int
+ _base_check_for_trigger_pages_support(struct MPT3SAS_ADAPTER *ioc)
+ {
+       Mpi26DriverTriggerPage0_t trigger_pg0;
+       int r = 0;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 ioc_status;
+       r = mpt3sas_config_get_driver_trigger_pg0(ioc, &mpi_reply,
+           &trigger_pg0);
+       if (r)
+               return -EFAULT;
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+           MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
+               return -EFAULT;
+       return le16_to_cpu(trigger_pg0.TriggerFlags);
+ }
+ /**
+  * _base_get_diag_triggers - Retrieve diag trigger values from
+  *                            persistent pages.
+  * @ioc : per adapter object
+  *
+  * Return nothing.
+  */
+ static void
+ _base_get_diag_triggers(struct MPT3SAS_ADAPTER *ioc)
+ {
+       u16 trigger_flags;
+       /*
+        * Default setting of master trigger.
+        */
+       ioc->diag_trigger_master.MasterData =
+           (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET);
+       trigger_flags = _base_check_for_trigger_pages_support(ioc);
+       if (trigger_flags < 0)
+               return;
+       ioc->supports_trigger_pages = 1;
+       /*
+        * Retrieve master diag trigger values from driver trigger pg1
+        * if master trigger bit enabled in TriggerFlags.
+        */
+       if ((u16)trigger_flags &
+           MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID)
+               _base_get_master_diag_triggers(ioc);
+       /*
+        * Retrieve event diag trigger values from driver trigger pg2
+        * if event trigger bit enabled in TriggerFlags.
+        */
+       if ((u16)trigger_flags &
+           MPI26_DRIVER_TRIGGER0_FLAG_MPI_EVENT_TRIGGER_VALID)
+               _base_get_event_diag_triggers(ioc);
+       /*
+        * Retrieve scsi diag trigger values from driver trigger pg3
+        * if scsi trigger bit enabled in TriggerFlags.
+        */
+       if ((u16)trigger_flags &
+           MPI26_DRIVER_TRIGGER0_FLAG_SCSI_SENSE_TRIGGER_VALID)
+               _base_get_scsi_diag_triggers(ioc);
+       /*
+        * Retrieve mpi error diag trigger values from driver trigger pg4
+        * if loginfo trigger bit enabled in TriggerFlags.
+        */
+       if ((u16)trigger_flags &
+           MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID)
+               _base_get_mpi_diag_triggers(ioc);
+ }
+ /**
+  * _base_update_diag_trigger_pages - Update the driver trigger pages after
+  *                    online FW update, incase updated FW supports driver
+  *                    trigger pages.
+  * @ioc : per adapter object
+  *
+  * Return nothing.
+  */
+ static void
+ _base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc)
+ {
+       if (ioc->diag_trigger_master.MasterData)
+               mpt3sas_config_update_driver_trigger_pg1(ioc,
+                   &ioc->diag_trigger_master, 1);
+       if (ioc->diag_trigger_event.ValidEntries)
+               mpt3sas_config_update_driver_trigger_pg2(ioc,
+                   &ioc->diag_trigger_event, 1);
+       if (ioc->diag_trigger_scsi.ValidEntries)
+               mpt3sas_config_update_driver_trigger_pg3(ioc,
+                   &ioc->diag_trigger_scsi, 1);
+       if (ioc->diag_trigger_mpi.ValidEntries)
+               mpt3sas_config_update_driver_trigger_pg4(ioc,
+                   &ioc->diag_trigger_mpi, 1);
+ }
+ /**
   * _base_static_config_pages - static start of day config pages
   * @ioc: per adapter object
   */
@@@ -4729,7 -5111,7 +5118,7 @@@ _base_static_config_pages(struct MPT3SA
  {
        Mpi2ConfigReply_t mpi_reply;
        u32 iounit_pg1_flags;
+       int tg_flags = 0;
        ioc->nvme_abort_timeout = 30;
        mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
        if (ioc->ir_firmware)
                else
                        ioc->nvme_abort_timeout = ioc->manu_pg11.NVMeAbortTO;
        }
+       ioc->time_sync_interval =
+           ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_MASK;
+       if (ioc->time_sync_interval) {
+               if (ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_UNIT_MASK)
+                       ioc->time_sync_interval =
+                           ioc->time_sync_interval * SECONDS_PER_HOUR;
+               else
+                       ioc->time_sync_interval =
+                           ioc->time_sync_interval * SECONDS_PER_MIN;
+               dinitprintk(ioc, ioc_info(ioc,
+                   "Driver-FW TimeSync interval is %d seconds. ManuPg11 TimeSync Unit is in %s\n",
+                   ioc->time_sync_interval, (ioc->manu_pg11.TimeSyncInterval &
+                   MPT3SAS_TIMESYNC_UNIT_MASK) ? "Hour" : "Minute"));
+       } else {
+               if (ioc->is_gen35_ioc)
+                       ioc_warn(ioc,
+                           "TimeSync Interval in Manuf page-11 is not enabled. Periodic Time-Sync will be disabled\n");
+       }
        mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
        mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
        mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
                ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
        if (ioc->is_aero_ioc)
                _base_update_ioc_page1_inlinewith_perf_mode(ioc);
+       if (ioc->is_gen35_ioc) {
+               if (ioc->is_driver_loading)
+                       _base_get_diag_triggers(ioc);
+               else {
+                       /*
+                        * In case of online HBA FW update operation,
+                        * check whether updated FW supports the driver trigger
+                        * pages or not.
+                        * - If previous FW has not supported driver trigger
+                        *   pages and newer FW supports them then update these
+                        *   pages with current diag trigger values.
+                        * - If previous FW has supported driver trigger pages
+                        *   and new FW doesn't support them then disable
+                        *   support_trigger_pages flag.
+                        */
+                       tg_flags = _base_check_for_trigger_pages_support(ioc);
+                       if (!ioc->supports_trigger_pages && tg_flags != -EFAULT)
+                               _base_update_diag_trigger_pages(ioc);
+                       else if (ioc->supports_trigger_pages &&
+                           tg_flags == -EFAULT)
+                               ioc->supports_trigger_pages = 0;
+               }
+       }
  }
  
  /**
@@@ -6459,7 -6881,7 +6888,7 @@@ _base_send_ioc_init(struct MPT3SAS_ADAP
  
        r = _base_handshake_req_reply_wait(ioc,
            sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request,
 -          sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10);
 +          sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 30);
  
        if (r != 0) {
                ioc_err(ioc, "%s: handshake failed (r=%d)\n", __func__, r);
                r = -EIO;
        }
  
+       /* Reset TimeSync Counter*/
+       ioc->timestamp_update_count = 0;
        return r;
  }
  
@@@ -664,7 -664,7 +664,7 @@@ _ctl_do_mpt_command(struct MPT3SAS_ADAP
        Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request = NULL;
        struct _pcie_device *pcie_device = NULL;
        u16 smid;
 -      u8 timeout;
 +      unsigned long timeout;
        u8 issue_reset;
        u32 sz, sz_arg;
        void *psge;
                    (Mpi2SmpPassthroughRequest_t *)mpi_request;
                u8 *data;
  
-               /* ioc determines which port to use */
-               smp_request->PhysicalPort = 0xFF;
+               if (!ioc->multipath_on_hba) {
+                       /* ioc determines which port to use */
+                       smp_request->PhysicalPort = 0xFF;
+               }
                if (smp_request->PassthroughFlags &
                    MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE)
                        data = (u8 *)&smp_request->SGL;
@@@ -928,7 -928,8 +928,8 @@@ qla27xx_template_checksum(void *p, ulon
  static inline int
  qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp)
  {
-       return qla27xx_template_checksum(tmp, tmp->template_size) == 0;
+       return qla27xx_template_checksum(tmp,
+               le32_to_cpu(tmp->template_size)) == 0;
  }
  
  static inline int
@@@ -944,7 -945,7 +945,7 @@@ qla27xx_execute_fwdt_template(struct sc
        ulong len = 0;
  
        if (qla27xx_fwdt_template_valid(tmp)) {
-               len = tmp->template_size;
+               len = le32_to_cpu(tmp->template_size);
                tmp = memcpy(buf, tmp, len);
                ql27xx_edit_template(vha, tmp);
                qla27xx_walk_template(vha, tmp, buf, &len);
@@@ -960,7 -961,7 +961,7 @@@ qla27xx_fwdt_calculate_dump_size(struc
        ulong len = 0;
  
        if (qla27xx_fwdt_template_valid(tmp)) {
-               len = tmp->template_size;
+               len = le32_to_cpu(tmp->template_size);
                qla27xx_walk_template(vha, tmp, NULL, &len);
        }
  
@@@ -972,7 -973,7 +973,7 @@@ qla27xx_fwdt_template_size(void *p
  {
        struct qla27xx_fwdt_template *tmp = p;
  
-       return tmp->template_size;
+       return le32_to_cpu(tmp->template_size);
  }
  
  int
@@@ -1001,8 -1002,10 +1002,8 @@@ qla27xx_mpi_fwdump(scsi_qla_host_t *vha
  {
        ulong flags = 0;
  
 -#ifndef __CHECKER__
        if (!hardware_locked)
                spin_lock_irqsave(&vha->hw->hardware_lock, flags);
 -#endif
        if (!vha->hw->mpi_fw_dump) {
                ql_log(ql_log_warn, vha, 0x02f3, "-> mpi_fwdump no buffer\n");
        } else {
        }
  
  bailout:
 -#ifndef __CHECKER__
        if (!hardware_locked)
                spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
 -#endif
  }
  
  void
diff --combined drivers/scsi/scsi_lib.c
@@@ -766,6 -766,9 +766,9 @@@ static void scsi_io_completion_action(s
                                case 0x24: /* depopulation in progress */
                                        action = ACTION_DELAYED_RETRY;
                                        break;
+                               case 0x0a: /* ALUA state transition */
+                                       blk_stat = BLK_STS_AGAIN;
+                                       fallthrough;
                                default:
                                        action = ACTION_FAIL;
                                        break;
@@@ -1455,7 -1458,7 +1458,7 @@@ static void scsi_softirq_done(struct re
  }
  
  /**
-  * scsi_dispatch_command - Dispatch a command to the low-level driver.
+  * scsi_dispatch_cmd - Dispatch a command to the low-level driver.
   * @cmd: command block we are dispatching.
   *
   * Return: nonzero return request was rejected and device's queue needs to be
@@@ -1703,9 -1706,15 +1706,14 @@@ out_put_budget
                break;
        case BLK_STS_RESOURCE:
        case BLK_STS_ZONE_RESOURCE:
 -              if (atomic_read(&sdev->device_busy) ||
 -                  scsi_device_blocked(sdev))
 +              if (scsi_device_blocked(sdev))
                        ret = BLK_STS_DEV_RESOURCE;
                break;
+       case BLK_STS_AGAIN:
+               scsi_req(req)->result = DID_BUS_BUSY << 16;
+               if (req->rq_flags & RQF_DONTPREP)
+                       scsi_mq_uninit_cmd(cmd);
+               break;
        default:
                if (unlikely(!scsi_device_online(sdev)))
                        scsi_req(req)->result = DID_NO_CONNECT << 16;
@@@ -2334,7 -2343,7 +2342,7 @@@ scsi_device_set_state(struct scsi_devic
  EXPORT_SYMBOL(scsi_device_set_state);
  
  /**
-  *    sdev_evt_emit - emit a single SCSI device uevent
+  *    scsi_evt_emit - emit a single SCSI device uevent
   *    @sdev: associated SCSI device
   *    @evt: event to emit
   *
@@@ -2382,7 -2391,7 +2390,7 @@@ static void scsi_evt_emit(struct scsi_d
  }
  
  /**
-  *    sdev_evt_thread - send a uevent for each scsi event
+  *    scsi_evt_thread - send a uevent for each scsi event
   *    @work: work struct for scsi_device
   *
   *    Dispatch queued events to their associated scsi_device kobjects
@@@ -2948,6 -2957,78 +2956,78 @@@ void sdev_enable_disk_events(struct scs
  }
  EXPORT_SYMBOL(sdev_enable_disk_events);
  
+ static unsigned char designator_prio(const unsigned char *d)
+ {
+       if (d[1] & 0x30)
+               /* not associated with LUN */
+               return 0;
+       if (d[3] == 0)
+               /* invalid length */
+               return 0;
+       /*
+        * Order of preference for lun descriptor:
+        * - SCSI name string
+        * - NAA IEEE Registered Extended
+        * - EUI-64 based 16-byte
+        * - EUI-64 based 12-byte
+        * - NAA IEEE Registered
+        * - NAA IEEE Extended
+        * - EUI-64 based 8-byte
+        * - SCSI name string (truncated)
+        * - T10 Vendor ID
+        * as longer descriptors reduce the likelyhood
+        * of identification clashes.
+        */
+       switch (d[1] & 0xf) {
+       case 8:
+               /* SCSI name string, variable-length UTF-8 */
+               return 9;
+       case 3:
+               switch (d[4] >> 4) {
+               case 6:
+                       /* NAA registered extended */
+                       return 8;
+               case 5:
+                       /* NAA registered */
+                       return 5;
+               case 4:
+                       /* NAA extended */
+                       return 4;
+               case 3:
+                       /* NAA locally assigned */
+                       return 1;
+               default:
+                       break;
+               }
+               break;
+       case 2:
+               switch (d[3]) {
+               case 16:
+                       /* EUI64-based, 16 byte */
+                       return 7;
+               case 12:
+                       /* EUI64-based, 12 byte */
+                       return 6;
+               case 8:
+                       /* EUI64-based, 8 byte */
+                       return 3;
+               default:
+                       break;
+               }
+               break;
+       case 1:
+               /* T10 vendor ID */
+               return 1;
+       default:
+               break;
+       }
+       return 0;
+ }
  /**
   * scsi_vpd_lun_id - return a unique device identification
   * @sdev: SCSI device
   */
  int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
  {
-       u8 cur_id_type = 0xff;
+       u8 cur_id_prio = 0;
        u8 cur_id_size = 0;
        const unsigned char *d, *cur_id_str;
        const struct scsi_vpd *vpd_pg83;
                return -ENXIO;
        }
  
-       /*
-        * Look for the correct descriptor.
-        * Order of preference for lun descriptor:
-        * - SCSI name string
-        * - NAA IEEE Registered Extended
-        * - EUI-64 based 16-byte
-        * - EUI-64 based 12-byte
-        * - NAA IEEE Registered
-        * - NAA IEEE Extended
-        * - T10 Vendor ID
-        * as longer descriptors reduce the likelyhood
-        * of identification clashes.
-        */
        /* The id string must be at least 20 bytes + terminating NULL byte */
        if (id_len < 21) {
                rcu_read_unlock();
        }
  
        memset(id, 0, id_len);
-       d = vpd_pg83->data + 4;
-       while (d < vpd_pg83->data + vpd_pg83->len) {
-               /* Skip designators not referring to the LUN */
-               if ((d[1] & 0x30) != 0x00)
-                       goto next_desig;
+       for (d = vpd_pg83->data + 4;
+            d < vpd_pg83->data + vpd_pg83->len;
+            d += d[3] + 4) {
+               u8 prio = designator_prio(d);
+               if (prio == 0 || cur_id_prio > prio)
+                       continue;
  
                switch (d[1] & 0xf) {
                case 0x1:
                        /* T10 Vendor ID */
                        if (cur_id_size > d[3])
                                break;
-                       /* Prefer anything */
-                       if (cur_id_type > 0x01 && cur_id_type != 0xff)
-                               break;
+                       cur_id_prio = prio;
                        cur_id_size = d[3];
                        if (cur_id_size + 4 > id_len)
                                cur_id_size = id_len - 4;
                        cur_id_str = d + 4;
-                       cur_id_type = d[1] & 0xf;
                        id_size = snprintf(id, id_len, "t10.%*pE",
                                           cur_id_size, cur_id_str);
                        break;
                case 0x2:
                        /* EUI-64 */
-                       if (cur_id_size > d[3])
-                               break;
-                       /* Prefer NAA IEEE Registered Extended */
-                       if (cur_id_type == 0x3 &&
-                           cur_id_size == d[3])
-                               break;
+                       cur_id_prio = prio;
                        cur_id_size = d[3];
                        cur_id_str = d + 4;
-                       cur_id_type = d[1] & 0xf;
                        switch (cur_id_size) {
                        case 8:
                                id_size = snprintf(id, id_len,
                                                   cur_id_str);
                                break;
                        default:
-                               cur_id_size = 0;
                                break;
                        }
                        break;
                case 0x3:
                        /* NAA */
-                       if (cur_id_size > d[3])
-                               break;
+                       cur_id_prio = prio;
                        cur_id_size = d[3];
                        cur_id_str = d + 4;
-                       cur_id_type = d[1] & 0xf;
                        switch (cur_id_size) {
                        case 8:
                                id_size = snprintf(id, id_len,
                                                   cur_id_str);
                                break;
                        default:
-                               cur_id_size = 0;
                                break;
                        }
                        break;
                case 0x8:
                        /* SCSI name string */
-                       if (cur_id_size + 4 > d[3])
+                       if (cur_id_size > d[3])
                                break;
                        /* Prefer others for truncated descriptor */
-                       if (cur_id_size && d[3] > id_len)
-                               break;
+                       if (d[3] > id_len) {
+                               prio = 2;
+                               if (cur_id_prio > prio)
+                                       break;
+                       }
+                       cur_id_prio = prio;
                        cur_id_size = id_size = d[3];
                        cur_id_str = d + 4;
-                       cur_id_type = d[1] & 0xf;
                        if (cur_id_size >= id_len)
                                cur_id_size = id_len - 1;
                        memcpy(id, cur_id_str, cur_id_size);
-                       /* Decrease priority for truncated descriptor */
-                       if (cur_id_size != id_size)
-                               cur_id_size = 6;
                        break;
                default:
                        break;
                }
- next_desig:
-               d += d[3] + 4;
        }
        rcu_read_unlock();
  
@@@ -163,6 -163,11 +163,11 @@@ struct ufs_pm_lvl_states ufs_pm_lvl_sta
        {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE},
        {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE},
        {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE},
+       /*
+        * For DeepSleep, the link is first put in hibern8 and then off.
+        * Leaving the link in hibern8 is not supported.
+        */
+       {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE},
  };
  
  static inline enum ufs_dev_pwr_mode
@@@ -221,8 -226,6 +226,6 @@@ static int ufshcd_eh_host_reset_handler
  static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
  static void ufshcd_hba_exit(struct ufs_hba *hba);
  static int ufshcd_probe_hba(struct ufs_hba *hba, bool async);
- static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
-                                bool skip_ref_clk);
  static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
  static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
  static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
@@@ -245,6 -248,8 +248,8 @@@ static int ufshcd_wb_buf_flush_disable(
  static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable);
  static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set);
  static inline void ufshcd_wb_toggle_flush(struct ufs_hba *hba, bool enable);
+ static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
+ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
  
  static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
  {
@@@ -348,7 -353,7 +353,7 @@@ static void ufshcd_add_command_trace(st
                unsigned int tag, const char *str)
  {
        sector_t lba = -1;
-       u8 opcode = 0;
+       u8 opcode = 0, group_id = 0;
        u32 intr, doorbell;
        struct ufshcd_lrb *lrbp = &hba->lrb[tag];
        struct scsi_cmnd *cmd = lrbp->cmd;
                                lba = cmd->request->bio->bi_iter.bi_sector;
                        transfer_len = be32_to_cpu(
                                lrbp->ucd_req_ptr->sc.exp_data_transfer_len);
+                       if (opcode == WRITE_10)
+                               group_id = lrbp->cmd->cmnd[6];
+               } else if (opcode == UNMAP) {
+                       if (cmd->request) {
+                               lba = scsi_get_lba(cmd);
+                               transfer_len = blk_rq_bytes(cmd->request);
+                       }
                }
        }
  
        intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
        doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
        trace_ufshcd_command(dev_name(hba->dev), str, tag,
-                               doorbell, transfer_len, intr, lba, opcode);
+                       doorbell, transfer_len, intr, lba, opcode, group_id);
  }
  
  static void ufshcd_print_clk_freqs(struct ufs_hba *hba)
        }
  }
  
- static void ufshcd_print_err_hist(struct ufs_hba *hba,
-                                 struct ufs_err_reg_hist *err_hist,
-                                 char *err_name)
+ static void ufshcd_print_evt(struct ufs_hba *hba, u32 id,
+                            char *err_name)
  {
        int i;
        bool found = false;
+       struct ufs_event_hist *e;
  
-       for (i = 0; i < UFS_ERR_REG_HIST_LENGTH; i++) {
-               int p = (i + err_hist->pos) % UFS_ERR_REG_HIST_LENGTH;
+       if (id >= UFS_EVT_CNT)
+               return;
  
-               if (err_hist->tstamp[p] == 0)
+       e = &hba->ufs_stats.event[id];
+       for (i = 0; i < UFS_EVENT_HIST_LENGTH; i++) {
+               int p = (i + e->pos) % UFS_EVENT_HIST_LENGTH;
+               if (e->tstamp[p] == 0)
                        continue;
                dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, p,
-                       err_hist->reg[p], ktime_to_us(err_hist->tstamp[p]));
+                       e->val[p], ktime_to_us(e->tstamp[p]));
                found = true;
        }
  
                dev_err(hba->dev, "No record of %s\n", err_name);
  }
  
- static void ufshcd_print_host_regs(struct ufs_hba *hba)
+ static void ufshcd_print_evt_hist(struct ufs_hba *hba)
  {
        ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: ");
  
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.pa_err, "pa_err");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.dl_err, "dl_err");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.nl_err, "nl_err");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.tl_err, "tl_err");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.dme_err, "dme_err");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.auto_hibern8_err,
-                             "auto_hibern8_err");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.fatal_err, "fatal_err");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.link_startup_err,
-                             "link_startup_fail");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.resume_err, "resume_fail");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.suspend_err,
-                             "suspend_fail");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.dev_reset, "dev_reset");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.host_reset, "host_reset");
-       ufshcd_print_err_hist(hba, &hba->ufs_stats.task_abort, "task_abort");
+       ufshcd_print_evt(hba, UFS_EVT_PA_ERR, "pa_err");
+       ufshcd_print_evt(hba, UFS_EVT_DL_ERR, "dl_err");
+       ufshcd_print_evt(hba, UFS_EVT_NL_ERR, "nl_err");
+       ufshcd_print_evt(hba, UFS_EVT_TL_ERR, "tl_err");
+       ufshcd_print_evt(hba, UFS_EVT_DME_ERR, "dme_err");
+       ufshcd_print_evt(hba, UFS_EVT_AUTO_HIBERN8_ERR,
+                        "auto_hibern8_err");
+       ufshcd_print_evt(hba, UFS_EVT_FATAL_ERR, "fatal_err");
+       ufshcd_print_evt(hba, UFS_EVT_LINK_STARTUP_FAIL,
+                        "link_startup_fail");
+       ufshcd_print_evt(hba, UFS_EVT_RESUME_ERR, "resume_fail");
+       ufshcd_print_evt(hba, UFS_EVT_SUSPEND_ERR,
+                        "suspend_fail");
+       ufshcd_print_evt(hba, UFS_EVT_DEV_RESET, "dev_reset");
+       ufshcd_print_evt(hba, UFS_EVT_HOST_RESET, "host_reset");
+       ufshcd_print_evt(hba, UFS_EVT_ABORT, "task_abort");
  
        ufshcd_vops_dbg_register_dump(hba);
  }
@@@ -1102,7 -1119,6 +1119,6 @@@ out
   */
  static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
  {
-       #define UFS_MIN_GEAR_TO_SCALE_DOWN      UFS_HS_G1
        int ret = 0;
        struct ufs_pa_layer_attr new_pwr_info;
  
                memcpy(&new_pwr_info, &hba->pwr_info,
                       sizeof(struct ufs_pa_layer_attr));
  
-               if (hba->pwr_info.gear_tx > UFS_MIN_GEAR_TO_SCALE_DOWN
-                   || hba->pwr_info.gear_rx > UFS_MIN_GEAR_TO_SCALE_DOWN) {
+               if (hba->pwr_info.gear_tx > hba->clk_scaling.min_gear ||
+                   hba->pwr_info.gear_rx > hba->clk_scaling.min_gear) {
                        /* save the current power mode */
                        memcpy(&hba->clk_scaling.saved_pwr_info.info,
                                &hba->pwr_info,
                                sizeof(struct ufs_pa_layer_attr));
  
                        /* scale down gear */
-                       new_pwr_info.gear_tx = UFS_MIN_GEAR_TO_SCALE_DOWN;
-                       new_pwr_info.gear_rx = UFS_MIN_GEAR_TO_SCALE_DOWN;
+                       new_pwr_info.gear_tx = hba->clk_scaling.min_gear;
+                       new_pwr_info.gear_rx = hba->clk_scaling.min_gear;
                }
        }
  
@@@ -1294,15 -1310,8 +1310,15 @@@ static int ufshcd_devfreq_target(struc
        }
        spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
  
 +      pm_runtime_get_noresume(hba->dev);
 +      if (!pm_runtime_active(hba->dev)) {
 +              pm_runtime_put_noidle(hba->dev);
 +              ret = -EAGAIN;
 +              goto out;
 +      }
        start = ktime_get();
        ret = ufshcd_devfreq_scale(hba, scale_up);
 +      pm_runtime_put(hba->dev);
  
        trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
                (scale_up ? "up" : "down"),
@@@ -1555,6 -1564,7 +1571,7 @@@ static void ufshcd_ungate_work(struct w
        }
  
        spin_unlock_irqrestore(hba->host->host_lock, flags);
+       ufshcd_hba_vreg_set_hpm(hba);
        ufshcd_setup_clocks(hba, true);
  
        ufshcd_enable_irq(hba);
@@@ -1634,12 -1644,12 +1651,12 @@@ start
                 */
                fallthrough;
        case CLKS_OFF:
 -              ufshcd_scsi_block_requests(hba);
                hba->clk_gating.state = REQ_CLKS_ON;
                trace_ufshcd_clk_gating(dev_name(hba->dev),
                                        hba->clk_gating.state);
 -              queue_work(hba->clk_gating.clk_gating_workq,
 -                         &hba->clk_gating.ungate_work);
 +              if (queue_work(hba->clk_gating.clk_gating_workq,
 +                             &hba->clk_gating.ungate_work))
 +                      ufshcd_scsi_block_requests(hba);
                /*
                 * fall through to check if we should wait for this
                 * work to be done or not.
@@@ -1714,12 -1724,10 +1731,10 @@@ static void ufshcd_gate_work(struct wor
  
        ufshcd_disable_irq(hba);
  
-       if (!ufshcd_is_link_active(hba))
-               ufshcd_setup_clocks(hba, false);
-       else
-               /* If link is active, device ref_clk can't be switched off */
-               __ufshcd_setup_clocks(hba, false, true);
+       ufshcd_setup_clocks(hba, false);
  
+       /* Put the host controller in low power mode if possible */
+       ufshcd_hba_vreg_set_lpm(hba);
        /*
         * In case you are here to cancel this work the gating state
         * would be marked as REQ_CLKS_ON. In this case keep the state
@@@ -1751,8 -1759,9 +1766,9 @@@ static void __ufshcd_release(struct ufs
  
        if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended ||
            hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL ||
-           ufshcd_any_tag_in_use(hba) || hba->outstanding_tasks ||
-           hba->active_uic_cmd || hba->uic_async_done)
+           hba->outstanding_tasks ||
+           hba->active_uic_cmd || hba->uic_async_done ||
+           hba->clk_gating.state == CLKS_OFF)
                return;
  
        hba->clk_gating.state = REQ_CLKS_OFF;
@@@ -1814,19 -1823,19 +1830,19 @@@ static ssize_t ufshcd_clkgate_enable_st
                return -EINVAL;
  
        value = !!value;
+       spin_lock_irqsave(hba->host->host_lock, flags);
        if (value == hba->clk_gating.is_enabled)
                goto out;
  
-       if (value) {
-               ufshcd_release(hba);
-       } else {
-               spin_lock_irqsave(hba->host->host_lock, flags);
+       if (value)
+               __ufshcd_release(hba);
+       else
                hba->clk_gating.active_reqs++;
-               spin_unlock_irqrestore(hba->host->host_lock, flags);
-       }
  
        hba->clk_gating.is_enabled = value;
  out:
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
        return count;
  }
  
@@@ -1837,6 -1846,9 +1853,9 @@@ static void ufshcd_init_clk_scaling(str
        if (!ufshcd_is_clkscaling_supported(hba))
                return;
  
+       if (!hba->clk_scaling.min_gear)
+               hba->clk_scaling.min_gear = UFS_HS_G1;
        INIT_WORK(&hba->clk_scaling.suspend_work,
                  ufshcd_clk_scaling_suspend_work);
        INIT_WORK(&hba->clk_scaling.resume_work,
@@@ -1874,7 -1886,7 +1893,7 @@@ static void ufshcd_init_clk_gating(stru
        snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d",
                 hba->host->host_no);
        hba->clk_gating.clk_gating_workq = alloc_ordered_workqueue(wq_name,
-                                                          WQ_MEM_RECLAIM);
+                                       WQ_MEM_RECLAIM | WQ_HIGHPRI);
  
        hba->clk_gating.is_enabled = true;
  
@@@ -2122,20 -2134,10 +2141,20 @@@ ufshcd_wait_for_uic_cmd(struct ufs_hba 
        unsigned long flags;
  
        if (wait_for_completion_timeout(&uic_cmd->done,
 -                                      msecs_to_jiffies(UIC_CMD_TIMEOUT)))
 +                                      msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
                ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
 -      else
 +      } else {
                ret = -ETIMEDOUT;
 +              dev_err(hba->dev,
 +                      "uic cmd 0x%x with arg3 0x%x completion timeout\n",
 +                      uic_cmd->command, uic_cmd->argument3);
 +
 +              if (!uic_cmd->cmd_active) {
 +                      dev_err(hba->dev, "%s: UIC cmd has been completed, return the result\n",
 +                              __func__);
 +                      ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
 +              }
 +      }
  
        spin_lock_irqsave(hba->host->host_lock, flags);
        hba->active_uic_cmd = NULL;
@@@ -2167,7 -2169,6 +2186,7 @@@ __ufshcd_send_uic_cmd(struct ufs_hba *h
        if (completion)
                init_completion(&uic_cmd->done);
  
 +      uic_cmd->cmd_active = 1;
        ufshcd_dispatch_uic_cmd(hba, uic_cmd);
  
        return 0;
@@@ -2557,6 -2558,14 +2576,14 @@@ static int ufshcd_queuecommand(struct S
                (hba->clk_gating.state != CLKS_ON));
  
        lrbp = &hba->lrb[tag];
+       if (unlikely(lrbp->in_use)) {
+               if (hba->pm_op_in_progress)
+                       set_host_byte(cmd, DID_BAD_TARGET);
+               else
+                       err = SCSI_MLQUEUE_HOST_BUSY;
+               ufshcd_release(hba);
+               goto out;
+       }
  
        WARN_ON(lrbp->cmd);
        lrbp->cmd = cmd;
@@@ -2799,6 -2808,11 +2826,11 @@@ static int ufshcd_exec_dev_cmd(struct u
  
        init_completion(&wait);
        lrbp = &hba->lrb[tag];
+       if (unlikely(lrbp->in_use)) {
+               err = -EBUSY;
+               goto out;
+       }
        WARN_ON(lrbp->cmd);
        err = ufshcd_compose_dev_cmd(hba, lrbp, cmd_type, tag);
        if (unlikely(err))
  
        err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
  
+ out:
        ufshcd_add_query_upiu_trace(hba, tag,
                        err ? "query_complete_err" : "query_complete");
  
@@@ -2960,14 -2975,14 +2993,14 @@@ int ufshcd_query_attr(struct ufs_hba *h
  
        BUG_ON(!hba);
  
-       ufshcd_hold(hba, false);
        if (!attr_val) {
                dev_err(hba->dev, "%s: attribute value required for opcode 0x%x\n",
                                __func__, opcode);
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
  
+       ufshcd_hold(hba, false);
        mutex_lock(&hba->dev_cmd.lock);
        ufshcd_init_query(hba, &request, &response, opcode, idn, index,
                        selector);
  
  out_unlock:
        mutex_unlock(&hba->dev_cmd.lock);
- out:
        ufshcd_release(hba);
        return err;
  }
@@@ -3051,21 -3065,20 +3083,20 @@@ static int __ufshcd_query_descriptor(st
  
        BUG_ON(!hba);
  
-       ufshcd_hold(hba, false);
        if (!desc_buf) {
                dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n",
                                __func__, opcode);
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
  
        if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) {
                dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n",
                                __func__, *buf_len);
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
  
+       ufshcd_hold(hba, false);
        mutex_lock(&hba->dev_cmd.lock);
        ufshcd_init_query(hba, &request, &response, opcode, idn, index,
                        selector);
  out_unlock:
        hba->dev_cmd.query.descriptor = NULL;
        mutex_unlock(&hba->dev_cmd.lock);
- out:
        ufshcd_release(hba);
        return err;
  }
@@@ -3199,19 -3211,13 +3229,19 @@@ int ufshcd_read_desc_param(struct ufs_h
        /* Get the length of descriptor */
        ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);
        if (!buff_len) {
 -              dev_err(hba->dev, "%s: Failed to get desc length", __func__);
 +              dev_err(hba->dev, "%s: Failed to get desc length\n", __func__);
 +              return -EINVAL;
 +      }
 +
 +      if (param_offset >= buff_len) {
 +              dev_err(hba->dev, "%s: Invalid offset 0x%x in descriptor IDN 0x%x, length 0x%x\n",
 +                      __func__, param_offset, desc_id, buff_len);
                return -EINVAL;
        }
  
        /* Check whether we need temp memory */
        if (param_offset != 0 || param_size < buff_len) {
 -              desc_buf = kmalloc(buff_len, GFP_KERNEL);
 +              desc_buf = kzalloc(buff_len, GFP_KERNEL);
                if (!desc_buf)
                        return -ENOMEM;
        } else {
                                        desc_buf, &buff_len);
  
        if (ret) {
 -              dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d",
 +              dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n",
                        __func__, desc_id, desc_index, param_offset, ret);
                goto out;
        }
  
        /* Sanity check */
        if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) {
 -              dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header",
 +              dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n",
                        __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]);
                ret = -EINVAL;
                goto out;
        buff_len = desc_buf[QUERY_DESC_LENGTH_OFFSET];
        ufshcd_update_desc_length(hba, desc_id, desc_index, buff_len);
  
 -      /* Check wherher we will not copy more data, than available */
 -      if (is_kmalloc && (param_offset + param_size) > buff_len)
 -              param_size = buff_len - param_offset;
 -
 -      if (is_kmalloc)
 +      if (is_kmalloc) {
 +              /* Make sure we don't copy more data than available */
 +              if (param_offset + param_size > buff_len)
 +                      param_size = buff_len - param_offset;
                memcpy(param_read_buf, &desc_buf[param_offset], param_size);
 +      }
  out:
        if (is_kmalloc)
                kfree(desc_buf);
@@@ -3601,6 -3607,22 +3631,22 @@@ static int ufshcd_dme_reset(struct ufs_
        return ret;
  }
  
+ int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
+                              int agreed_gear,
+                              int adapt_val)
+ {
+       int ret;
+       if (agreed_gear != UFS_HS_G4)
+               adapt_val = PA_NO_ADAPT;
+       ret = ufshcd_dme_set(hba,
+                            UIC_ARG_MIB(PA_TXHSADAPTTYPE),
+                            adapt_val);
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(ufshcd_dme_configure_adapt);
  /**
   * ufshcd_dme_enable - UIC command for DME_ENABLE
   * @hba: per adapter instance
@@@ -3831,18 -3853,10 +3877,18 @@@ static int ufshcd_uic_pwr_ctrl(struct u
                dev_err(hba->dev,
                        "pwr ctrl cmd 0x%x with mode 0x%x completion timeout\n",
                        cmd->command, cmd->argument3);
 +
 +              if (!cmd->cmd_active) {
 +                      dev_err(hba->dev, "%s: Power Mode Change operation has been completed, go check UPMCRS\n",
 +                              __func__);
 +                      goto check_upmcrs;
 +              }
 +
                ret = -ETIMEDOUT;
                goto out;
        }
  
 +check_upmcrs:
        status = ufshcd_get_upmcrs(hba);
        if (status != PWR_LOCAL) {
                dev_err(hba->dev,
@@@ -3854,7 -3868,7 +3900,7 @@@ out
        if (ret) {
                ufshcd_print_host_state(hba);
                ufshcd_print_pwr_info(hba);
-               ufshcd_print_host_regs(hba);
+               ufshcd_print_evt_hist(hba);
        }
  
        spin_lock_irqsave(hba->host->host_lock, flags);
@@@ -4350,8 -4364,10 +4396,10 @@@ static inline void ufshcd_hba_stop(stru
   */
  static int ufshcd_hba_execute_hce(struct ufs_hba *hba)
  {
-       int retry;
+       int retry_outer = 3;
+       int retry_inner;
  
+ start:
        if (!ufshcd_is_hba_active(hba))
                /* change controller state to "reset state" */
                ufshcd_hba_stop(hba);
        ufshcd_delay_us(hba->vps->hba_enable_delay_us, 100);
  
        /* wait for the host controller to complete initialization */
-       retry = 50;
+       retry_inner = 50;
        while (ufshcd_is_hba_active(hba)) {
-               if (retry) {
-                       retry--;
+               if (retry_inner) {
+                       retry_inner--;
                } else {
                        dev_err(hba->dev,
                                "Controller enable failed\n");
+                       if (retry_outer) {
+                               retry_outer--;
+                               goto start;
+                       }
                        return -EIO;
                }
                usleep_range(1000, 1100);
@@@ -4460,14 -4480,21 +4512,21 @@@ static inline int ufshcd_disable_device
        return ufshcd_disable_tx_lcc(hba, true);
  }
  
- void ufshcd_update_reg_hist(struct ufs_err_reg_hist *reg_hist,
-                           u32 reg)
+ void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val)
  {
-       reg_hist->reg[reg_hist->pos] = reg;
-       reg_hist->tstamp[reg_hist->pos] = ktime_get();
-       reg_hist->pos = (reg_hist->pos + 1) % UFS_ERR_REG_HIST_LENGTH;
+       struct ufs_event_hist *e;
+       if (id >= UFS_EVT_CNT)
+               return;
+       e = &hba->ufs_stats.event[id];
+       e->val[e->pos] = val;
+       e->tstamp[e->pos] = ktime_get();
+       e->pos = (e->pos + 1) % UFS_EVENT_HIST_LENGTH;
+       ufshcd_vops_event_notify(hba, id, &val);
  }
- EXPORT_SYMBOL_GPL(ufshcd_update_reg_hist);
+ EXPORT_SYMBOL_GPL(ufshcd_update_evt_hist);
  
  /**
   * ufshcd_link_startup - Initialize unipro link startup
@@@ -4496,7 -4523,8 +4555,8 @@@ link_startup
  
                /* check if device is detected by inter-connect layer */
                if (!ret && !ufshcd_is_device_present(hba)) {
-                       ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err,
+                       ufshcd_update_evt_hist(hba,
+                                              UFS_EVT_LINK_STARTUP_FAIL,
                                               0);
                        dev_err(hba->dev, "%s: Device not present\n", __func__);
                        ret = -ENXIO;
                 * succeeds. So reset the local Uni-Pro and try again.
                 */
                if (ret && ufshcd_hba_enable(hba)) {
-                       ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err,
+                       ufshcd_update_evt_hist(hba,
+                                              UFS_EVT_LINK_STARTUP_FAIL,
                                               (u32)ret);
                        goto out;
                }
  
        if (ret) {
                /* failed to get the link up... retire */
-               ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err,
+               ufshcd_update_evt_hist(hba,
+                                      UFS_EVT_LINK_STARTUP_FAIL,
                                       (u32)ret);
                goto out;
        }
@@@ -4551,7 -4581,7 +4613,7 @@@ out
                dev_err(hba->dev, "link startup failed %d\n", ret);
                ufshcd_print_host_state(hba);
                ufshcd_print_pwr_info(hba);
-               ufshcd_print_host_regs(hba);
+               ufshcd_print_evt_hist(hba);
        }
        return ret;
  }
@@@ -4906,7 -4936,7 +4968,7 @@@ ufshcd_transfer_rsp_status(struct ufs_h
                dev_err(hba->dev,
                                "OCS error from controller = %x for tag %d\n",
                                ocs, lrbp->task_tag);
-               ufshcd_print_host_regs(hba);
+               ufshcd_print_evt_hist(hba);
                ufshcd_print_host_state(hba);
                break;
        } /* end of switch */
@@@ -4934,14 -4964,11 +4996,14 @@@ static irqreturn_t ufshcd_uic_cmd_compl
                        ufshcd_get_uic_cmd_result(hba);
                hba->active_uic_cmd->argument3 =
                        ufshcd_get_dme_attr_val(hba);
 +              if (!hba->uic_async_done)
 +                      hba->active_uic_cmd->cmd_active = 0;
                complete(&hba->active_uic_cmd->done);
                retval = IRQ_HANDLED;
        }
  
        if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) {
 +              hba->active_uic_cmd->cmd_active = 0;
                complete(hba->uic_async_done);
                retval = IRQ_HANDLED;
        }
@@@ -4964,9 -4991,11 +5026,11 @@@ static void __ufshcd_transfer_req_compl
        struct scsi_cmnd *cmd;
        int result;
        int index;
+       bool update_scaling = false;
  
        for_each_set_bit(index, &completed_reqs, hba->nutrs) {
                lrbp = &hba->lrb[index];
+               lrbp->in_use = false;
                lrbp->compl_time_stamp = ktime_get();
                cmd = lrbp->cmd;
                if (cmd) {
                        /* Do not touch lrbp after scsi done */
                        cmd->scsi_done(cmd);
                        __ufshcd_release(hba);
+                       update_scaling = true;
                } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
                        lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
                        if (hba->dev_cmd.complete) {
                                ufshcd_add_command_trace(hba, index,
                                                "dev_complete");
                                complete(hba->dev_cmd.complete);
+                               update_scaling = true;
                        }
                }
-               if (ufshcd_is_clkscaling_supported(hba))
+               if (ufshcd_is_clkscaling_supported(hba) && update_scaling)
                        hba->clk_scaling.active_reqs--;
        }
  
@@@ -5632,7 -5663,9 +5698,9 @@@ static inline void ufshcd_schedule_eh_w
  static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
  {
        pm_runtime_get_sync(hba->dev);
-       if (pm_runtime_suspended(hba->dev)) {
+       if (pm_runtime_status_suspended(hba->dev) || hba->is_sys_suspended) {
+               enum ufs_pm_op pm_op;
                /*
                 * Don't assume anything of pm_runtime_get_sync(), if
                 * resume fails, irq and clocks can be OFF, and powers
                if (!ufshcd_is_clkgating_allowed(hba))
                        ufshcd_setup_clocks(hba, true);
                ufshcd_release(hba);
-               ufshcd_vops_resume(hba, UFS_RUNTIME_PM);
+               pm_op = hba->is_sys_suspended ? UFS_SYSTEM_PM : UFS_RUNTIME_PM;
+               ufshcd_vops_resume(hba, pm_op);
        } else {
                ufshcd_hold(hba, false);
                if (hba->clk_scaling.is_allowed) {
@@@ -5668,7 -5702,7 +5737,7 @@@ static void ufshcd_err_handling_unprepa
  
  static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba)
  {
-       return (hba->ufshcd_state == UFSHCD_STATE_ERROR ||
+       return (!hba->is_powered || hba->ufshcd_state == UFSHCD_STATE_ERROR ||
                (!(hba->saved_err || hba->saved_uic_err || hba->force_reset ||
                        ufshcd_is_link_broken(hba))));
  }
@@@ -5681,6 -5715,7 +5750,7 @@@ static void ufshcd_recover_pm_error(str
        struct request_queue *q;
        int ret;
  
+       hba->is_sys_suspended = false;
        /*
         * Set RPM status of hba device to RPM_ACTIVE,
         * this also clears its runtime error.
@@@ -5739,11 -5774,13 +5809,13 @@@ static void ufshcd_err_handler(struct w
  
        hba = container_of(work, struct ufs_hba, eh_work);
  
+       down(&hba->eh_sem);
        spin_lock_irqsave(hba->host->host_lock, flags);
        if (ufshcd_err_handling_should_stop(hba)) {
                if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
                        hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
                spin_unlock_irqrestore(hba->host->host_lock, flags);
+               up(&hba->eh_sem);
                return;
        }
        ufshcd_set_eh_in_progress(hba);
        ufshcd_err_handling_prepare(hba);
        spin_lock_irqsave(hba->host->host_lock, flags);
        ufshcd_scsi_block_requests(hba);
-       /*
-        * A full reset and restore might have happened after preparation
-        * is finished, double check whether we should stop.
-        */
-       if (ufshcd_err_handling_should_stop(hba)) {
-               if (hba->ufshcd_state != UFSHCD_STATE_ERROR)
-                       hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
-               goto out;
-       }
        hba->ufshcd_state = UFSHCD_STATE_RESET;
  
        /* Complete requests that have door-bell cleared by h/w */
        ufshcd_complete_requests(hba);
  
+       /*
+        * A full reset and restore might have happened after preparation
+        * is finished, double check whether we should stop.
+        */
+       if (ufshcd_err_handling_should_stop(hba))
+               goto skip_err_handling;
        if (hba->dev_quirks & UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
                bool ret;
  
                /* release the lock as ufshcd_quirk_dl_nac_errors() may sleep */
                ret = ufshcd_quirk_dl_nac_errors(hba);
                spin_lock_irqsave(hba->host->host_lock, flags);
-               if (!ret && !hba->force_reset && ufshcd_is_link_active(hba))
+               if (!ret && ufshcd_err_handling_should_stop(hba))
                        goto skip_err_handling;
        }
  
-       if (hba->force_reset || ufshcd_is_link_broken(hba) ||
-           ufshcd_is_saved_err_fatal(hba) ||
-           ((hba->saved_err & UIC_ERROR) &&
-            (hba->saved_uic_err & (UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
-                                   UFSHCD_UIC_DL_TCx_REPLAY_ERROR))))
-               needs_reset = true;
        if ((hba->saved_err & (INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK)) ||
            (hba->saved_uic_err &&
             (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) {
                spin_unlock_irqrestore(hba->host->host_lock, flags);
                ufshcd_print_host_state(hba);
                ufshcd_print_pwr_info(hba);
-               ufshcd_print_host_regs(hba);
+               ufshcd_print_evt_hist(hba);
                ufshcd_print_tmrs(hba, hba->outstanding_tasks);
                ufshcd_print_trs(hba, hba->outstanding_reqs, pr_prdt);
                spin_lock_irqsave(hba->host->host_lock, flags);
         * transfers forcefully because they will get cleared during
         * host reset and restore
         */
-       if (needs_reset)
+       if (hba->force_reset || ufshcd_is_link_broken(hba) ||
+           ufshcd_is_saved_err_fatal(hba) ||
+           ((hba->saved_err & UIC_ERROR) &&
+            (hba->saved_uic_err & (UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
+                                   UFSHCD_UIC_DL_TCx_REPLAY_ERROR)))) {
+               needs_reset = true;
                goto do_reset;
+       }
  
        /*
         * If LINERESET was caught, UFS might have been put to PWM mode,
@@@ -5911,12 -5945,11 +5980,11 @@@ skip_err_handling
                        dev_err_ratelimited(hba->dev, "%s: exit: saved_err 0x%x saved_uic_err 0x%x",
                            __func__, hba->saved_err, hba->saved_uic_err);
        }
- out:
        ufshcd_clear_eh_in_progress(hba);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
        ufshcd_scsi_unblock_requests(hba);
        ufshcd_err_handling_unprepare(hba);
+       up(&hba->eh_sem);
  }
  
  /**
@@@ -5936,7 -5969,7 +6004,7 @@@ static irqreturn_t ufshcd_update_uic_er
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
        if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) &&
            (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) {
-               ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg);
+               ufshcd_update_evt_hist(hba, UFS_EVT_PA_ERR, reg);
                /*
                 * To know whether this error is fatal or not, DB timeout
                 * must be checked but this error is handled separately.
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
        if ((reg & UIC_DATA_LINK_LAYER_ERROR) &&
            (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) {
-               ufshcd_update_reg_hist(&hba->ufs_stats.dl_err, reg);
+               ufshcd_update_evt_hist(hba, UFS_EVT_DL_ERR, reg);
  
                if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
                        hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER);
        if ((reg & UIC_NETWORK_LAYER_ERROR) &&
            (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) {
-               ufshcd_update_reg_hist(&hba->ufs_stats.nl_err, reg);
+               ufshcd_update_evt_hist(hba, UFS_EVT_NL_ERR, reg);
                hba->uic_error |= UFSHCD_UIC_NL_ERROR;
                retval |= IRQ_HANDLED;
        }
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER);
        if ((reg & UIC_TRANSPORT_LAYER_ERROR) &&
            (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) {
-               ufshcd_update_reg_hist(&hba->ufs_stats.tl_err, reg);
+               ufshcd_update_evt_hist(hba, UFS_EVT_TL_ERR, reg);
                hba->uic_error |= UFSHCD_UIC_TL_ERROR;
                retval |= IRQ_HANDLED;
        }
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME);
        if ((reg & UIC_DME_ERROR) &&
            (reg & UIC_DME_ERROR_CODE_MASK)) {
-               ufshcd_update_reg_hist(&hba->ufs_stats.dme_err, reg);
+               ufshcd_update_evt_hist(hba, UFS_EVT_DME_ERR, reg);
                hba->uic_error |= UFSHCD_UIC_DME_ERROR;
                retval |= IRQ_HANDLED;
        }
@@@ -6043,7 -6076,8 +6111,8 @@@ static irqreturn_t ufshcd_check_errors(
        irqreturn_t retval = IRQ_NONE;
  
        if (hba->errors & INT_FATAL_ERRORS) {
-               ufshcd_update_reg_hist(&hba->ufs_stats.fatal_err, hba->errors);
+               ufshcd_update_evt_hist(hba, UFS_EVT_FATAL_ERR,
+                                      hba->errors);
                queue_eh_work = true;
        }
  
                        __func__, (hba->errors & UIC_HIBERNATE_ENTER) ?
                        "Enter" : "Exit",
                        hba->errors, ufshcd_get_upmcrs(hba));
-               ufshcd_update_reg_hist(&hba->ufs_stats.auto_hibern8_err,
+               ufshcd_update_evt_hist(hba, UFS_EVT_AUTO_HIBERN8_ERR,
                                       hba->errors);
                ufshcd_set_link_broken(hba);
                queue_eh_work = true;
                hba->saved_uic_err |= hba->uic_error;
  
                /* dump controller state before resetting */
-               if ((hba->saved_err & (INT_FATAL_ERRORS)) ||
+               if ((hba->saved_err &
+                    (INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK)) ||
                    (hba->saved_uic_err &&
                     (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) {
                        dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x\n",
@@@ -6407,8 -6442,12 +6477,12 @@@ static int ufshcd_issue_devman_upiu_cmd
  
        init_completion(&wait);
        lrbp = &hba->lrb[tag];
-       WARN_ON(lrbp->cmd);
+       if (unlikely(lrbp->in_use)) {
+               err = -EBUSY;
+               goto out;
+       }
  
+       WARN_ON(lrbp->cmd);
        lrbp->cmd = NULL;
        lrbp->sense_bufflen = 0;
        lrbp->sense_buffer = NULL;
                }
        }
  
+ out:
        blk_put_request(req);
  out_unlock:
        up_read(&hba->clk_scaling_lock);
@@@ -6601,7 -6641,7 +6676,7 @@@ static int ufshcd_eh_device_reset_handl
  
  out:
        hba->req_abort_count = 0;
-       ufshcd_update_reg_hist(&hba->ufs_stats.dev_reset, (u32)err);
+       ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, (u32)err);
        if (!err) {
                err = SUCCESS;
        } else {
@@@ -6624,7 -6664,8 +6699,8 @@@ static void ufshcd_set_req_abort_skip(s
  
  /**
   * ufshcd_try_to_abort_task - abort a specific task
-  * @cmd: SCSI command pointer
+  * @hba: Pointer to adapter instance
+  * @tag: Task tag/index to be aborted
   *
   * Abort the pending command in device by sending UFS_ABORT_TASK task management
   * command, and in host controller by clearing the door-bell register. There can
@@@ -6729,16 -6770,6 +6805,6 @@@ static int ufshcd_abort(struct scsi_cmn
                BUG();
        }
  
-       /*
-        * Task abort to the device W-LUN is illegal. When this command
-        * will fail, due to spec violation, scsi err handling next step
-        * will be to send LU reset which, again, is a spec violation.
-        * To avoid these unnecessary/illegal step we skip to the last error
-        * handling stage: reset and restore.
-        */
-       if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN)
-               return ufshcd_eh_host_reset_handler(cmd);
        ufshcd_hold(hba, false);
        reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
        /* If command is already aborted/completed, return SUCCESS */
         * to reduce repeated printouts. For other aborted requests only print
         * basic details.
         */
-       scsi_print_command(hba->lrb[tag].cmd);
+       scsi_print_command(cmd);
        if (!hba->req_abort_count) {
-               ufshcd_update_reg_hist(&hba->ufs_stats.task_abort, 0);
-               ufshcd_print_host_regs(hba);
+               ufshcd_update_evt_hist(hba, UFS_EVT_ABORT, tag);
+               ufshcd_print_evt_hist(hba);
                ufshcd_print_host_state(hba);
                ufshcd_print_pwr_info(hba);
                ufshcd_print_trs(hba, 1 << tag, true);
                goto cleanup;
        }
  
+       /*
+        * Task abort to the device W-LUN is illegal. When this command
+        * will fail, due to spec violation, scsi err handling next step
+        * will be to send LU reset which, again, is a spec violation.
+        * To avoid these unnecessary/illegal steps, first we clean up
+        * the lrb taken by this cmd and mark the lrb as in_use, then
+        * queue the eh_work and bail.
+        */
+       if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN) {
+               ufshcd_update_evt_hist(hba, UFS_EVT_ABORT, lrbp->lun);
+               spin_lock_irqsave(host->host_lock, flags);
+               if (lrbp->cmd) {
+                       __ufshcd_transfer_req_compl(hba, (1UL << tag));
+                       __set_bit(tag, &hba->outstanding_reqs);
+                       lrbp->in_use = true;
+                       hba->force_reset = true;
+                       ufshcd_schedule_eh_work(hba);
+               }
+               spin_unlock_irqrestore(host->host_lock, flags);
+               goto out;
+       }
        /* Skip task abort in case previous aborts failed and report failure */
        if (lrbp->req_abort_skip)
                err = -EIO;
@@@ -6845,7 -6899,7 +6934,7 @@@ static int ufshcd_host_reset_and_restor
  out:
        if (err)
                dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err);
-       ufshcd_update_reg_hist(&hba->ufs_stats.host_reset, (u32)err);
+       ufshcd_update_evt_hist(hba, UFS_EVT_HOST_RESET, (u32)err);
        return err;
  }
  
@@@ -6891,6 -6945,7 +6980,7 @@@ static int ufshcd_reset_and_restore(str
         */
        scsi_report_bus_reset(hba->host, 0);
        if (err) {
+               hba->ufshcd_state = UFSHCD_STATE_ERROR;
                hba->saved_err |= saved_err;
                hba->saved_uic_err |= saved_uic_err;
        }
@@@ -7092,7 -7147,6 +7182,6 @@@ static inline void ufshcd_blk_pm_runtim
  static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
  {
        int ret = 0;
-       struct scsi_device *sdev_rpmb;
        struct scsi_device *sdev_boot;
  
        hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0,
        ufshcd_blk_pm_runtime_init(hba->sdev_ufs_device);
        scsi_device_put(hba->sdev_ufs_device);
  
-       sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
+       hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
                ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
-       if (IS_ERR(sdev_rpmb)) {
-               ret = PTR_ERR(sdev_rpmb);
+       if (IS_ERR(hba->sdev_rpmb)) {
+               ret = PTR_ERR(hba->sdev_rpmb);
                goto remove_sdev_ufs_device;
        }
-       ufshcd_blk_pm_runtime_init(sdev_rpmb);
-       scsi_device_put(sdev_rpmb);
+       ufshcd_blk_pm_runtime_init(hba->sdev_rpmb);
+       scsi_device_put(hba->sdev_rpmb);
  
        sdev_boot = __scsi_add_device(hba->host, 0, 0,
                ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
        return ret;
  }
  
+ static int
+ ufshcd_send_request_sense(struct ufs_hba *hba, struct scsi_device *sdp);
+ static int ufshcd_clear_ua_wlun(struct ufs_hba *hba, u8 wlun)
+ {
+       struct scsi_device *sdp;
+       unsigned long flags;
+       int ret = 0;
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       if (wlun == UFS_UPIU_UFS_DEVICE_WLUN)
+               sdp = hba->sdev_ufs_device;
+       else if (wlun == UFS_UPIU_RPMB_WLUN)
+               sdp = hba->sdev_rpmb;
+       else
+               BUG();
+       if (sdp) {
+               ret = scsi_device_get(sdp);
+               if (!ret && !scsi_device_online(sdp)) {
+                       ret = -ENODEV;
+                       scsi_device_put(sdp);
+               }
+       } else {
+               ret = -ENODEV;
+       }
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+       if (ret)
+               goto out_err;
+       ret = ufshcd_send_request_sense(hba, sdp);
+       scsi_device_put(sdp);
+ out_err:
+       if (ret)
+               dev_err(hba->dev, "%s: UAC clear LU=%x ret = %d\n",
+                               __func__, wlun, ret);
+       return ret;
+ }
+ static int ufshcd_clear_ua_wluns(struct ufs_hba *hba)
+ {
+       int ret = 0;
+       if (!hba->wlun_dev_clr_ua)
+               goto out;
+       ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_UFS_DEVICE_WLUN);
+       if (!ret)
+               ret = ufshcd_clear_ua_wlun(hba, UFS_UPIU_RPMB_WLUN);
+       if (!ret)
+               hba->wlun_dev_clr_ua = false;
+ out:
+       if (ret)
+               dev_err(hba->dev, "%s: Failed to clear UAC WLUNS ret = %d\n",
+                               __func__, ret);
+       return ret;
+ }
  /**
   * ufshcd_probe_hba - probe hba to detect device and initialize
   * @hba: per-adapter instance
@@@ -7739,8 -7850,10 +7885,10 @@@ static void ufshcd_async_scan(void *dat
        struct ufs_hba *hba = (struct ufs_hba *)data;
        int ret;
  
+       down(&hba->eh_sem);
        /* Initialize hba, detect and initialize UFS device */
        ret = ufshcd_probe_hba(hba, true);
+       up(&hba->eh_sem);
        if (ret)
                goto out;
  
@@@ -7755,6 -7868,8 +7903,8 @@@ out
                pm_runtime_put_sync(hba->dev);
                ufshcd_exit_clk_scaling(hba);
                ufshcd_hba_exit(hba);
+       } else {
+               ufshcd_clear_ua_wluns(hba);
        }
  }
  
@@@ -7988,8 -8103,7 +8138,7 @@@ static int ufshcd_init_hba_vreg(struct 
        return 0;
  }
  
- static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
-                                       bool skip_ref_clk)
+ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
  {
        int ret = 0;
        struct ufs_clk_info *clki;
  
        list_for_each_entry(clki, head, list) {
                if (!IS_ERR_OR_NULL(clki->clk)) {
-                       if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
+                       /*
+                        * Don't disable clocks which are needed
+                        * to keep the link active.
+                        */
+                       if (ufshcd_is_link_active(hba) &&
+                           clki->keep_link_active)
                                continue;
  
                        clk_state_changed = on ^ clki->enabled;
@@@ -8052,11 -8171,6 +8206,6 @@@ out
        return ret;
  }
  
- static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
- {
-       return  __ufshcd_setup_clocks(hba, on, false);
- }
  static int ufshcd_init_clocks(struct ufs_hba *hba)
  {
        int ret = 0;
@@@ -8113,15 -8227,9 +8262,9 @@@ static int ufshcd_variant_hba_init(stru
  
        err = ufshcd_vops_init(hba);
        if (err)
-               goto out;
-       err = ufshcd_vops_setup_regulators(hba, true);
-       if (err)
-               ufshcd_vops_exit(hba);
- out:
-       if (err)
                dev_err(hba->dev, "%s: variant %s init failed err %d\n",
                        __func__, ufshcd_get_var_name(hba), err);
+ out:
        return err;
  }
  
@@@ -8130,8 -8238,6 +8273,6 @@@ static void ufshcd_variant_hba_exit(str
        if (!hba->vops)
                return;
  
-       ufshcd_vops_setup_regulators(hba, false);
        ufshcd_vops_exit(hba);
  }
  
@@@ -8327,7 -8433,8 +8468,8 @@@ static int ufshcd_link_state_transition
        }
        /*
         * If autobkops is enabled, link can't be turned off because
-        * turning off the link would also turn off the device.
+        * turning off the link would also turn off the device, except in the
+        * case of DeepSleep where the device is expected to remain powered.
         */
        else if ((req_link_state == UIC_LINK_OFF_STATE) &&
                 (!check_for_bkops || !hba->auto_bkops_enabled)) {
                 * put the link in low power mode is to send the DME end point
                 * to device and then send the DME reset command to local
                 * unipro. But putting the link in hibern8 is much faster.
+                *
+                * Note also that putting the link in Hibern8 is a requirement
+                * for entering DeepSleep.
                 */
                ret = ufshcd_uic_hibern8_enter(hba);
                if (ret) {
  
  static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba)
  {
-       if (ufshcd_is_link_off(hba))
+       if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba))
                ufshcd_setup_hba_vreg(hba, false);
  }
  
  static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)
  {
-       if (ufshcd_is_link_off(hba))
+       if (ufshcd_is_link_off(hba) || ufshcd_can_aggressive_pc(hba))
                ufshcd_setup_hba_vreg(hba, true);
  }
  
  static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
  {
        int ret = 0;
+       int check_for_bkops;
        enum ufs_pm_level pm_lvl;
        enum ufs_dev_pwr_mode req_dev_pwr_mode;
        enum uic_link_state req_link_state;
        }
  
        if (req_dev_pwr_mode != hba->curr_dev_pwr_mode) {
-               if ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
-                   !ufshcd_is_runtime_pm(pm_op)) {
+               if (!ufshcd_is_runtime_pm(pm_op))
                        /* ensure that bkops is disabled */
                        ufshcd_disable_auto_bkops(hba);
-               }
  
                if (!hba->dev_info.b_rpm_dev_flush_capable) {
                        ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
        }
  
        flush_work(&hba->eeh_work);
-       ret = ufshcd_link_state_transition(hba, req_link_state, 1);
+       /*
+        * In the case of DeepSleep, the device is expected to remain powered
+        * with the link off, so do not check for bkops.
+        */
+       check_for_bkops = !ufshcd_is_ufs_dev_deepsleep(hba);
+       ret = ufshcd_link_state_transition(hba, req_link_state, check_for_bkops);
        if (ret)
                goto set_dev_active;
  
@@@ -8575,11 -8690,7 +8725,7 @@@ disable_clks
         */
        ufshcd_disable_irq(hba);
  
-       if (!ufshcd_is_link_active(hba))
-               ufshcd_setup_clocks(hba, false);
-       else
-               /* If link is active, device ref_clk can't be switched off */
-               __ufshcd_setup_clocks(hba, false, true);
+       ufshcd_setup_clocks(hba, false);
  
        if (ufshcd_is_clkgating_allowed(hba)) {
                hba->clk_gating.state = CLKS_OFF;
@@@ -8595,11 -8706,25 +8741,25 @@@ set_link_active
        if (hba->clk_scaling.is_allowed)
                ufshcd_resume_clkscaling(hba);
        ufshcd_vreg_set_hpm(hba);
+       /*
+        * Device hardware reset is required to exit DeepSleep. Also, for
+        * DeepSleep, the link is off so host reset and restore will be done
+        * further below.
+        */
+       if (ufshcd_is_ufs_dev_deepsleep(hba)) {
+               ufshcd_vops_device_reset(hba);
+               WARN_ON(!ufshcd_is_link_off(hba));
+       }
        if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
                ufshcd_set_link_active(hba);
        else if (ufshcd_is_link_off(hba))
                ufshcd_host_reset_and_restore(hba);
  set_dev_active:
+       /* Can also get here needing to exit DeepSleep */
+       if (ufshcd_is_ufs_dev_deepsleep(hba)) {
+               ufshcd_vops_device_reset(hba);
+               ufshcd_host_reset_and_restore(hba);
+       }
        if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
                ufshcd_disable_auto_bkops(hba);
  enable_gating:
@@@ -8617,7 -8742,7 +8777,7 @@@ out
        hba->pm_op_in_progress = 0;
  
        if (ret)
-               ufshcd_update_reg_hist(&hba->ufs_stats.suspend_err, (u32)ret);
+               ufshcd_update_evt_hist(hba, UFS_EVT_SUSPEND_ERR, (u32)ret);
        return ret;
  }
  
@@@ -8661,6 -8786,9 +8821,9 @@@ static int ufshcd_resume(struct ufs_hb
        if (ret)
                goto disable_vreg;
  
+       /* For DeepSleep, the only supported option is to have the link off */
+       WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) && !ufshcd_is_link_off(hba));
        if (ufshcd_is_link_hibern8(hba)) {
                ret = ufshcd_uic_hibern8_exit(hba);
                if (!ret) {
                /*
                 * A full initialization of the host and the device is
                 * required since the link was put to off during suspend.
+                * Note, in the case of DeepSleep, the device will exit
+                * DeepSleep due to device reset.
                 */
                ret = ufshcd_reset_and_restore(hba);
                /*
@@@ -8736,7 -8866,7 +8901,7 @@@ disable_irq_and_vops_clks
  out:
        hba->pm_op_in_progress = 0;
        if (ret)
-               ufshcd_update_reg_hist(&hba->ufs_stats.resume_err, (u32)ret);
+               ufshcd_update_evt_hist(hba, UFS_EVT_RESUME_ERR, (u32)ret);
        return ret;
  }
  
@@@ -8753,6 -8883,7 +8918,7 @@@ int ufshcd_system_suspend(struct ufs_hb
        int ret = 0;
        ktime_t start = ktime_get();
  
+       down(&hba->eh_sem);
        if (!hba || !hba->is_powered)
                return 0;
  
@@@ -8783,6 -8914,8 +8949,8 @@@ out
                hba->curr_dev_pwr_mode, hba->uic_link_state);
        if (!ret)
                hba->is_sys_suspended = true;
+       else
+               up(&hba->eh_sem);
        return ret;
  }
  EXPORT_SYMBOL(ufshcd_system_suspend);
@@@ -8799,8 -8932,10 +8967,10 @@@ int ufshcd_system_resume(struct ufs_hb
        int ret = 0;
        ktime_t start = ktime_get();
  
-       if (!hba)
+       if (!hba) {
+               up(&hba->eh_sem);
                return -EINVAL;
+       }
  
        if (!hba->is_powered || pm_runtime_suspended(hba->dev))
                /*
@@@ -8816,6 -8951,7 +8986,7 @@@ out
                hba->curr_dev_pwr_mode, hba->uic_link_state);
        if (!ret)
                hba->is_sys_suspended = false;
+       up(&hba->eh_sem);
        return ret;
  }
  EXPORT_SYMBOL(ufshcd_system_resume);
@@@ -8907,18 -9043,25 +9078,21 @@@ int ufshcd_shutdown(struct ufs_hba *hba
  {
        int ret = 0;
  
+       down(&hba->eh_sem);
        if (!hba->is_powered)
                goto out;
  
        if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba))
                goto out;
  
 -      if (pm_runtime_suspended(hba->dev)) {
 -              ret = ufshcd_runtime_resume(hba);
 -              if (ret)
 -                      goto out;
 -      }
 +      pm_runtime_get_sync(hba->dev);
  
        ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM);
  out:
        if (ret)
                dev_err(hba->dev, "%s failed, err %d\n", __func__, ret);
+       hba->is_powered = false;
+       up(&hba->eh_sem);
        /* allow force shutdown even in case of errors */
        return 0;
  }
@@@ -8937,7 -9080,6 +9111,7 @@@ void ufshcd_remove(struct ufs_hba *hba
        blk_mq_free_tag_set(&hba->tmf_tag_set);
        blk_cleanup_queue(hba->cmd_queue);
        scsi_remove_host(hba->host);
 +      destroy_workqueue(hba->eh_wq);
        /* disable interrupts */
        ufshcd_disable_intr(hba, hba->intr_mask);
        ufshcd_hba_stop(hba);
@@@ -9114,6 -9256,8 +9288,8 @@@ int ufshcd_init(struct ufs_hba *hba, vo
        INIT_WORK(&hba->eh_work, ufshcd_err_handler);
        INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler);
  
+       sema_init(&hba->eh_sem, 1);
        /* Initialize UIC command mutex */
        mutex_init(&hba->uic_cmd_mutex);
  
        err = ufshcd_hba_enable(hba);
        if (err) {
                dev_err(hba->dev, "Host controller enable failed\n");
-               ufshcd_print_host_regs(hba);
+               ufshcd_print_evt_hist(hba);
                ufshcd_print_host_state(hba);
                goto free_tmf_queue;
        }
@@@ -9238,7 -9382,6 +9414,7 @@@ out_remove_scsi_host
  exit_gating:
        ufshcd_exit_clk_scaling(hba);
        ufshcd_exit_clk_gating(hba);
 +      destroy_workqueue(hba->eh_wq);
  out_disable:
        hba->is_irq_enabled = false;
        ufshcd_hba_exit(hba);
@@@ -58,13 -58,35 +58,36 @@@ enum dev_cmd_type 
        DEV_CMD_TYPE_QUERY              = 0x1,
  };
  
+ enum ufs_event_type {
+       /* uic specific errors */
+       UFS_EVT_PA_ERR = 0,
+       UFS_EVT_DL_ERR,
+       UFS_EVT_NL_ERR,
+       UFS_EVT_TL_ERR,
+       UFS_EVT_DME_ERR,
+       /* fatal errors */
+       UFS_EVT_AUTO_HIBERN8_ERR,
+       UFS_EVT_FATAL_ERR,
+       UFS_EVT_LINK_STARTUP_FAIL,
+       UFS_EVT_RESUME_ERR,
+       UFS_EVT_SUSPEND_ERR,
+       /* abnormal events */
+       UFS_EVT_DEV_RESET,
+       UFS_EVT_HOST_RESET,
+       UFS_EVT_ABORT,
+       UFS_EVT_CNT,
+ };
  /**
   * struct uic_command - UIC command structure
   * @command: UIC command
   * @argument1: UIC command argument 1
   * @argument2: UIC command argument 2
   * @argument3: UIC command argument 3
 + * @cmd_active: Indicate if UIC command is outstanding
   * @done: UIC command completion
   */
  struct uic_command {
@@@ -72,7 -94,6 +95,7 @@@
        u32 argument1;
        u32 argument2;
        u32 argument3;
 +      int cmd_active;
        struct completion done;
  };
  
@@@ -116,16 -137,22 +139,22 @@@ enum uic_link_state 
        ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)
  #define ufshcd_set_ufs_dev_poweroff(h) \
        ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE)
+ #define ufshcd_set_ufs_dev_deepsleep(h) \
+       ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE)
  #define ufshcd_is_ufs_dev_active(h) \
        ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)
  #define ufshcd_is_ufs_dev_sleep(h) \
        ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)
  #define ufshcd_is_ufs_dev_poweroff(h) \
        ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE)
+ #define ufshcd_is_ufs_dev_deepsleep(h) \
+       ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE)
  
  /*
   * UFS Power management levels.
-  * Each level is in increasing order of power savings.
+  * Each level is in increasing order of power savings, except DeepSleep
+  * which is lower than PowerDown with power on but not PowerDown with
+  * power off.
   */
  enum ufs_pm_level {
        UFS_PM_LVL_0, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */
        UFS_PM_LVL_3, /* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */
        UFS_PM_LVL_4, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */
        UFS_PM_LVL_5, /* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */
+       UFS_PM_LVL_6, /* UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE */
        UFS_PM_LVL_MAX
  };
  
@@@ -165,6 -193,7 +195,7 @@@ struct ufs_pm_lvl_states 
   * @crypto_key_slot: the key slot to use for inline crypto (-1 if none)
   * @data_unit_num: the data unit number for the first block for inline crypto
   * @req_abort_skip: skip request abort task flag
+  * @in_use: indicates that this lrb is still in use
   */
  struct ufshcd_lrb {
        struct utp_transfer_req_desc *utr_descriptor_ptr;
  #endif
  
        bool req_abort_skip;
+       bool in_use;
  };
  
  /**
@@@ -229,6 -259,8 +261,8 @@@ struct ufs_dev_cmd 
   * @max_freq: maximum frequency supported by the clock
   * @min_freq: min frequency that can be used for clock scaling
   * @curr_freq: indicates the current frequency that it is set to
+  * @keep_link_active: indicates that the clk should not be disabled if
+                     link is active
   * @enabled: variable to check against multiple enable/disable
   */
  struct ufs_clk_info {
        u32 max_freq;
        u32 min_freq;
        u32 curr_freq;
+       bool keep_link_active;
        bool enabled;
  };
  
@@@ -269,7 -302,6 +304,6 @@@ struct ufs_pwr_mode_info 
   * @get_ufs_hci_version: called to get UFS HCI version
   * @clk_scale_notify: notifies that clks are scaled up/down
   * @setup_clocks: called before touching any of the controller registers
-  * @setup_regulators: called before accessing the host controller
   * @hce_enable_notify: called before and after HCE enable bit is set to allow
   *                     variant specific Uni-Pro initialization.
   * @link_startup_notify: called before and after Link startup is carried out
   * @phy_initialization: used to initialize phys
   * @device_reset: called to issue a reset pulse on the UFS device
   * @program_key: program or evict an inline encryption key
+  * @event_notify: called to notify important events
   */
  struct ufs_hba_variant_ops {
        const char *name;
                                    enum ufs_notify_change_status);
        int     (*setup_clocks)(struct ufs_hba *, bool,
                                enum ufs_notify_change_status);
-       int     (*setup_regulators)(struct ufs_hba *, bool);
        int     (*hce_enable_notify)(struct ufs_hba *,
                                     enum ufs_notify_change_status);
        int     (*link_startup_notify)(struct ufs_hba *,
        int     (*resume)(struct ufs_hba *, enum ufs_pm_op);
        void    (*dbg_register_dump)(struct ufs_hba *hba);
        int     (*phy_initialization)(struct ufs_hba *);
-       void    (*device_reset)(struct ufs_hba *hba);
+       int     (*device_reset)(struct ufs_hba *hba);
        void    (*config_scaling_param)(struct ufs_hba *hba,
                                        struct devfreq_dev_profile *profile,
                                        void *data);
        int     (*program_key)(struct ufs_hba *hba,
                               const union ufs_crypto_cfg_entry *cfg, int slot);
+       void    (*event_notify)(struct ufs_hba *hba,
+                               enum ufs_event_type evt, void *data);
  };
  
  /* clock gating state  */
@@@ -382,6 -416,7 +418,7 @@@ struct ufs_saved_pwr_info 
   * @workq: workqueue to schedule devfreq suspend/resume work
   * @suspend_work: worker to suspend devfreq
   * @resume_work: worker to resume devfreq
+  * @min_gear: lowest HS gear to scale down to
   * @is_allowed: tracks if scaling is currently allowed or not
   * @is_busy_started: tracks if busy period has started or not
   * @is_suspended: tracks if devfreq is suspended or not
@@@ -396,22 -431,23 +433,23 @@@ struct ufs_clk_scaling 
        struct workqueue_struct *workq;
        struct work_struct suspend_work;
        struct work_struct resume_work;
+       u32 min_gear;
        bool is_allowed;
        bool is_busy_started;
        bool is_suspended;
  };
  
- #define UFS_ERR_REG_HIST_LENGTH 8
+ #define UFS_EVENT_HIST_LENGTH 8
  /**
-  * struct ufs_err_reg_hist - keeps history of errors
+  * struct ufs_event_hist - keeps history of errors
   * @pos: index to indicate cyclic buffer position
   * @reg: cyclic buffer for registers value
   * @tstamp: cyclic buffer for time stamp
   */
- struct ufs_err_reg_hist {
+ struct ufs_event_hist {
        int pos;
-       u32 reg[UFS_ERR_REG_HIST_LENGTH];
-       ktime_t tstamp[UFS_ERR_REG_HIST_LENGTH];
+       u32 val[UFS_EVENT_HIST_LENGTH];
+       ktime_t tstamp[UFS_EVENT_HIST_LENGTH];
  };
  
  /**
   *            reset this after link-startup.
   * @last_hibern8_exit_tstamp: Set time after the hibern8 exit.
   *            Clear after the first successful command completion.
-  * @pa_err: tracks pa-uic errors
-  * @dl_err: tracks dl-uic errors
-  * @nl_err: tracks nl-uic errors
-  * @tl_err: tracks tl-uic errors
-  * @dme_err: tracks dme errors
-  * @auto_hibern8_err: tracks auto-hibernate errors
-  * @fatal_err: tracks fatal errors
-  * @linkup_err: tracks link-startup errors
-  * @resume_err: tracks resume errors
-  * @suspend_err: tracks suspend errors
-  * @dev_reset: tracks device reset events
-  * @host_reset: tracks host reset events
-  * @tsk_abort: tracks task abort events
   */
  struct ufs_stats {
        u32 last_intr_status;
  
        u32 hibern8_exit_cnt;
        ktime_t last_hibern8_exit_tstamp;
-       /* uic specific errors */
-       struct ufs_err_reg_hist pa_err;
-       struct ufs_err_reg_hist dl_err;
-       struct ufs_err_reg_hist nl_err;
-       struct ufs_err_reg_hist tl_err;
-       struct ufs_err_reg_hist dme_err;
-       /* fatal errors */
-       struct ufs_err_reg_hist auto_hibern8_err;
-       struct ufs_err_reg_hist fatal_err;
-       struct ufs_err_reg_hist link_startup_err;
-       struct ufs_err_reg_hist resume_err;
-       struct ufs_err_reg_hist suspend_err;
-       /* abnormal events */
-       struct ufs_err_reg_hist dev_reset;
-       struct ufs_err_reg_hist host_reset;
-       struct ufs_err_reg_hist task_abort;
+       struct ufs_event_hist event[UFS_EVT_CNT];
  };
  
  enum ufshcd_quirks {
@@@ -594,6 -599,21 +601,21 @@@ enum ufshcd_caps 
         * inline crypto engine, if it is present
         */
        UFSHCD_CAP_CRYPTO                               = 1 << 8,
+       /*
+        * This capability allows the controller regulators to be put into
+        * lpm mode aggressively during clock gating.
+        * This would increase power savings.
+        */
+       UFSHCD_CAP_AGGR_POWER_COLLAPSE                  = 1 << 9,
+       /*
+        * This capability allows the host controller driver to use DeepSleep,
+        * if it is supported by the UFS device. The host controller driver must
+        * support device hardware reset via the hba->device_reset() callback,
+        * in order to exit DeepSleep state.
+        */
+       UFSHCD_CAP_DEEPSLEEP                            = 1 << 10,
  };
  
  struct ufs_hba_variant_params {
@@@ -683,6 -703,7 +705,7 @@@ struct ufs_hba 
         * "UFS device" W-LU.
         */
        struct scsi_device *sdev_ufs_device;
+       struct scsi_device *sdev_rpmb;
  
        enum ufs_dev_pwr_mode curr_dev_pwr_mode;
        enum uic_link_state uic_link_state;
        u32 intr_mask;
        u16 ee_ctrl_mask;
        bool is_powered;
+       struct semaphore eh_sem;
  
        /* Work Queues */
        struct workqueue_struct *eh_wq;
@@@ -831,6 -853,12 +855,12 @@@ return true
  #endif
  }
  
+ static inline bool ufshcd_can_aggressive_pc(struct ufs_hba *hba)
+ {
+       return !!(ufshcd_is_link_hibern8(hba) &&
+                 (hba->caps & UFSHCD_CAP_AGGR_POWER_COLLAPSE));
+ }
  static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
  {
        return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) &&
@@@ -882,8 -910,7 +912,7 @@@ int ufshcd_wait_for_register(struct ufs
                                u32 val, unsigned long interval_us,
                                unsigned long timeout_ms);
  void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk);
- void ufshcd_update_reg_hist(struct ufs_err_reg_hist *reg_hist,
-                           u32 reg);
+ void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val);
  
  static inline void check_upiu_size(void)
  {
@@@ -930,6 -957,9 +959,9 @@@ extern int ufshcd_runtime_idle(struct u
  extern int ufshcd_system_suspend(struct ufs_hba *hba);
  extern int ufshcd_system_resume(struct ufs_hba *hba);
  extern int ufshcd_shutdown(struct ufs_hba *hba);
+ extern int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
+                                     int agreed_gear,
+                                     int adapt_val);
  extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
                               u8 attr_set, u32 mib_val, u8 peer);
  extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
@@@ -1076,6 -1106,14 +1108,14 @@@ static inline int ufshcd_vops_clk_scale
        return 0;
  }
  
+ static inline void ufshcd_vops_event_notify(struct ufs_hba *hba,
+                                           enum ufs_event_type evt,
+                                           void *data)
+ {
+       if (hba->vops && hba->vops->event_notify)
+               hba->vops->event_notify(hba, evt, data);
+ }
  static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on,
                                        enum ufs_notify_change_status status)
  {
        return 0;
  }
  
- static inline int ufshcd_vops_setup_regulators(struct ufs_hba *hba, bool status)
- {
-       if (hba->vops && hba->vops->setup_regulators)
-               return hba->vops->setup_regulators(hba, status);
-       return 0;
- }
  static inline int ufshcd_vops_hce_enable_notify(struct ufs_hba *hba,
                                                bool status)
  {
@@@ -1109,6 -1139,14 +1141,14 @@@ static inline int ufshcd_vops_link_star
        return 0;
  }
  
+ static inline int ufshcd_vops_phy_initialization(struct ufs_hba *hba)
+ {
+       if (hba->vops && hba->vops->phy_initialization)
+               return hba->vops->phy_initialization(hba);
+       return 0;
+ }
  static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba,
                                  bool status,
                                  struct ufs_pa_layer_attr *dev_max_params,
@@@ -1181,9 -1219,12 +1221,12 @@@ static inline void ufshcd_vops_dbg_regi
  static inline void ufshcd_vops_device_reset(struct ufs_hba *hba)
  {
        if (hba->vops && hba->vops->device_reset) {
-               hba->vops->device_reset(hba);
-               ufshcd_set_ufs_dev_active(hba);
-               ufshcd_update_reg_hist(&hba->ufs_stats.dev_reset, 0);
+               int err = hba->vops->device_reset(hba);
+               if (!err)
+                       ufshcd_set_ufs_dev_active(hba);
+               if (err != -EOPNOTSUPP)
+                       ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err);
        }
  }
  
@@@ -194,7 -194,7 +194,7 @@@ struct tcmu_tmr 
  
        uint8_t tmr_type;
        uint32_t tmr_cmd_cnt;
 -      int16_t tmr_cmd_ids[0];
 +      int16_t tmr_cmd_ids[];
  };
  
  /*
@@@ -586,14 -586,15 +586,15 @@@ static inline void tcmu_cmd_set_block_c
  }
  
  static int new_block_to_iov(struct tcmu_dev *udev, struct tcmu_cmd *cmd,
-                           struct iovec **iov, int prev_dbi, int *remain)
+                           struct iovec **iov, int prev_dbi, int len)
  {
        /* Get the next dbi */
        int dbi = tcmu_cmd_get_dbi(cmd);
        /* Do not add more than DATA_BLOCK_SIZE to iov */
-       int len = min_t(int, DATA_BLOCK_SIZE, *remain);
+       if (len > DATA_BLOCK_SIZE)
+               len = DATA_BLOCK_SIZE;
  
-       *remain -= len;
        /*
         * The following code will gather and map the blocks to the same iovec
         * when the blocks are all next to each other.
@@@ -618,8 -619,8 +619,8 @@@ static void tcmu_setup_iovs(struct tcmu
        int dbi = -2;
  
        /* We prepare the IOVs for DMA_FROM_DEVICE transfer direction */
-       while (data_length > 0)
-               dbi = new_block_to_iov(udev, cmd, iov, dbi, &data_length);
+       for (; data_length > 0; data_length -= DATA_BLOCK_SIZE)
+               dbi = new_block_to_iov(udev, cmd, iov, dbi, data_length);
  }
  
  static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd)
@@@ -688,67 -689,83 +689,83 @@@ static inline size_t head_to_end(size_
  
  #define UPDATE_HEAD(head, used, size) smp_store_release(&head, ((head % size) + used) % size)
  
- static void scatter_data_area(struct tcmu_dev *udev, struct tcmu_cmd *tcmu_cmd,
-                             struct iovec **iov)
+ #define TCMU_SG_TO_DATA_AREA 1
+ #define TCMU_DATA_AREA_TO_SG 2
+ static inline void tcmu_copy_data(struct tcmu_dev *udev,
+                                 struct tcmu_cmd *tcmu_cmd, uint32_t direction,
+                                 struct scatterlist *sg, unsigned int sg_nents,
+                                 struct iovec **iov, size_t data_len)
  {
-       struct se_cmd *se_cmd = tcmu_cmd->se_cmd;
        /* start value of dbi + 1 must not be a valid dbi */
-       int i, dbi = -2;
-       int block_remaining = 0;
-       int data_len = se_cmd->data_length;
-       void *from, *to = NULL;
-       size_t copy_bytes, offset;
-       struct scatterlist *sg;
-       struct page *page = NULL;
-       for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, i) {
-               int sg_remaining = sg->length;
-               from = kmap_atomic(sg_page(sg)) + sg->offset;
-               while (sg_remaining > 0) {
-                       if (block_remaining == 0) {
-                               if (to) {
-                                       flush_dcache_page(page);
-                                       kunmap_atomic(to);
-                               }
-                               /* get next dbi and add to IOVs */
-                               dbi = new_block_to_iov(udev, tcmu_cmd, iov, dbi,
-                                                      &data_len);
-                               page = tcmu_get_block_page(udev, dbi);
-                               to = kmap_atomic(page);
-                               block_remaining = DATA_BLOCK_SIZE;
-                       }
-                       copy_bytes = min_t(size_t, sg_remaining,
-                                       block_remaining);
-                       offset = DATA_BLOCK_SIZE - block_remaining;
-                       memcpy(to + offset, from + sg->length - sg_remaining,
-                              copy_bytes);
+       int dbi = -2;
+       size_t block_remaining, cp_len;
+       struct sg_mapping_iter sg_iter;
+       unsigned int sg_flags;
+       struct page *page;
+       void *data_page_start, *data_addr;
  
-                       sg_remaining -= copy_bytes;
-                       block_remaining -= copy_bytes;
+       if (direction == TCMU_SG_TO_DATA_AREA)
+               sg_flags = SG_MITER_ATOMIC | SG_MITER_FROM_SG;
+       else
+               sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
+       sg_miter_start(&sg_iter, sg, sg_nents, sg_flags);
+       while (data_len) {
+               if (direction == TCMU_SG_TO_DATA_AREA)
+                       dbi = new_block_to_iov(udev, tcmu_cmd, iov, dbi,
+                                              data_len);
+               else
+                       dbi = tcmu_cmd_get_dbi(tcmu_cmd);
+               page = tcmu_get_block_page(udev, dbi);
+               if (direction == TCMU_DATA_AREA_TO_SG)
+                       flush_dcache_page(page);
+               data_page_start = kmap_atomic(page);
+               block_remaining = DATA_BLOCK_SIZE;
+               while (block_remaining && data_len) {
+                       if (!sg_miter_next(&sg_iter)) {
+                               /* set length to 0 to abort outer loop */
+                               data_len = 0;
+                               pr_debug("tcmu_move_data: aborting data copy due to exhausted sg_list\n");
+                               break;
+                       }
+                       cp_len = min3(sg_iter.length, block_remaining, data_len);
+                       data_addr = data_page_start +
+                                   DATA_BLOCK_SIZE - block_remaining;
+                       if (direction == TCMU_SG_TO_DATA_AREA)
+                               memcpy(data_addr, sg_iter.addr, cp_len);
+                       else
+                               memcpy(sg_iter.addr, data_addr, cp_len);
+                       data_len -= cp_len;
+                       block_remaining -= cp_len;
+                       sg_iter.consumed = cp_len;
                }
-               kunmap_atomic(from - sg->offset);
-       }
+               sg_miter_stop(&sg_iter);
  
-       if (to) {
-               flush_dcache_page(page);
-               kunmap_atomic(to);
+               kunmap_atomic(data_page_start);
+               if (direction == TCMU_SG_TO_DATA_AREA)
+                       flush_dcache_page(page);
        }
  }
  
- static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd,
+ static void scatter_data_area(struct tcmu_dev *udev, struct tcmu_cmd *tcmu_cmd,
+                             struct iovec **iov)
+ {
+       struct se_cmd *se_cmd = tcmu_cmd->se_cmd;
+       tcmu_copy_data(udev, tcmu_cmd, TCMU_SG_TO_DATA_AREA, se_cmd->t_data_sg,
+                      se_cmd->t_data_nents, iov, se_cmd->data_length);
+ }
+ static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *tcmu_cmd,
                             bool bidi, uint32_t read_len)
  {
-       struct se_cmd *se_cmd = cmd->se_cmd;
-       int i, dbi;
-       int block_remaining = 0;
-       void *from = NULL, *to;
-       size_t copy_bytes, offset;
-       struct scatterlist *sg, *data_sg;
-       struct page *page;
+       struct se_cmd *se_cmd = tcmu_cmd->se_cmd;
+       struct scatterlist *data_sg;
        unsigned int data_nents;
-       uint32_t count = 0;
  
        if (!bidi) {
                data_sg = se_cmd->t_data_sg;
                 * buffer blocks, and before gathering the Data-In buffer
                 * the Data-Out buffer blocks should be skipped.
                 */
-               count = cmd->dbi_cnt - cmd->dbi_bidi_cnt;
+               tcmu_cmd_set_dbi_cur(tcmu_cmd,
+                                    tcmu_cmd->dbi_cnt - tcmu_cmd->dbi_bidi_cnt);
  
                data_sg = se_cmd->t_bidi_data_sg;
                data_nents = se_cmd->t_bidi_data_nents;
        }
  
-       tcmu_cmd_set_dbi_cur(cmd, count);
-       for_each_sg(data_sg, sg, data_nents, i) {
-               int sg_remaining = sg->length;
-               to = kmap_atomic(sg_page(sg)) + sg->offset;
-               while (sg_remaining > 0 && read_len > 0) {
-                       if (block_remaining == 0) {
-                               if (from)
-                                       kunmap_atomic(from);
-                               block_remaining = DATA_BLOCK_SIZE;
-                               dbi = tcmu_cmd_get_dbi(cmd);
-                               page = tcmu_get_block_page(udev, dbi);
-                               from = kmap_atomic(page);
-                               flush_dcache_page(page);
-                       }
-                       copy_bytes = min_t(size_t, sg_remaining,
-                                       block_remaining);
-                       if (read_len < copy_bytes)
-                               copy_bytes = read_len;
-                       offset = DATA_BLOCK_SIZE - block_remaining;
-                       memcpy(to + sg->length - sg_remaining, from + offset,
-                                       copy_bytes);
-                       sg_remaining -= copy_bytes;
-                       block_remaining -= copy_bytes;
-                       read_len -= copy_bytes;
-               }
-               kunmap_atomic(to - sg->offset);
-               if (read_len == 0)
-                       break;
-       }
-       if (from)
-               kunmap_atomic(from);
+       tcmu_copy_data(udev, tcmu_cmd, TCMU_DATA_AREA_TO_SG, data_sg,
+                      data_nents, NULL, read_len);
  }
  
  static inline size_t spc_bitmap_free(unsigned long *bitmap, uint32_t thresh)