mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"Updates to the usual drivers (ufs, pm80xx, libata-scsi, smartpqi,
lpfc, qla2xxx).
We have a couple of major core changes impacting other systems:
- Command Duration Limits, which spills into block and ATA
- block level Persistent Reservation Operations, which touches block,
nvme, target and dm
Both of these are added with merge commits containing a cover letter
explaining what's going on"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (187 commits)
scsi: core: Improve warning message in scsi_device_block()
scsi: core: Replace scsi_target_block() with scsi_block_targets()
scsi: core: Don't wait for quiesce in scsi_device_block()
scsi: core: Don't wait for quiesce in scsi_stop_queue()
scsi: core: Merge scsi_internal_device_block() and device_block()
scsi: sg: Increase number of devices
scsi: bsg: Increase number of devices
scsi: qla2xxx: Remove unused nvme_ls_waitq wait queue
scsi: ufs: ufs-pci: Add support for Intel Arrow Lake
scsi: sd: sd_zbc: Use PAGE_SECTORS_SHIFT
scsi: ufs: wb: Add explicit flush_threshold sysfs attribute
scsi: ufs: ufs-qcom: Switch to the new ICE API
scsi: ufs: dt-bindings: qcom: Add ICE phandle
scsi: ufs: ufs-mediatek: Set UFSHCD_QUIRK_MCQ_BROKEN_RTC quirk
scsi: ufs: ufs-mediatek: Set UFSHCD_QUIRK_MCQ_BROKEN_INTR quirk
scsi: ufs: core: Add host quirk UFSHCD_QUIRK_MCQ_BROKEN_RTC
scsi: ufs: core: Add host quirk UFSHCD_QUIRK_MCQ_BROKEN_INTR
scsi: ufs: core: Remove dedicated hwq for dev command
scsi: ufs: core: mcq: Fix the incorrect OCS value for the device command
scsi: ufs: dt-bindings: samsung,exynos: Drop unneeded quotes
...
This commit is contained in:
@@ -95,3 +95,25 @@ Description:
|
|||||||
This file does not exist if the HBA driver does not implement
|
This file does not exist if the HBA driver does not implement
|
||||||
support for the SATA NCQ priority feature, regardless of the
|
support for the SATA NCQ priority feature, regardless of the
|
||||||
device support for this feature.
|
device support for this feature.
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/block/*/device/cdl_supported
|
||||||
|
Date: May, 2023
|
||||||
|
KernelVersion: v6.5
|
||||||
|
Contact: linux-scsi@vger.kernel.org
|
||||||
|
Description:
|
||||||
|
(RO) Indicates if the device supports the command duration
|
||||||
|
limits feature found in some ATA and SCSI devices.
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/block/*/device/cdl_enable
|
||||||
|
Date: May, 2023
|
||||||
|
KernelVersion: v6.5
|
||||||
|
Contact: linux-scsi@vger.kernel.org
|
||||||
|
Description:
|
||||||
|
(RW) For a device supporting the command duration limits
|
||||||
|
feature, write to the file to turn on or off the feature.
|
||||||
|
By default this feature is turned off.
|
||||||
|
Writing "1" to this file enables the use of command duration
|
||||||
|
limits for read and write commands in the kernel and turns on
|
||||||
|
the feature on the device. Writing "0" disables the feature.
|
||||||
|
|||||||
@@ -1426,6 +1426,17 @@ Description: This entry shows the status of WriteBooster buffer flushing
|
|||||||
If flushing is enabled, the device executes the flush
|
If flushing is enabled, the device executes the flush
|
||||||
operation when the command queue is empty.
|
operation when the command queue is empty.
|
||||||
|
|
||||||
|
What: /sys/bus/platform/drivers/ufshcd/*/wb_flush_threshold
|
||||||
|
What: /sys/bus/platform/devices/*.ufs/wb_flush_threshold
|
||||||
|
Date: June 2023
|
||||||
|
Contact: Lu Hongfei <luhongfei@vivo.com>
|
||||||
|
Description:
|
||||||
|
wb_flush_threshold represents the threshold for flushing WriteBooster buffer,
|
||||||
|
whose value expressed in unit of 10% granularity, such as '1' representing 10%,
|
||||||
|
'2' representing 20%, and so on.
|
||||||
|
If avail_wb_buff < wb_flush_threshold, it indicates that WriteBooster buffer needs to
|
||||||
|
be flushed, otherwise it is not necessary.
|
||||||
|
|
||||||
What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/hpb_version
|
What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/hpb_version
|
||||||
What: /sys/bus/platform/devices/*.ufs/device_descriptor/hpb_version
|
What: /sys/bus/platform/devices/*.ufs/device_descriptor/hpb_version
|
||||||
Date: June 2021
|
Date: June 2021
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ properties:
|
|||||||
- qcom,msm8994-ufshc
|
- qcom,msm8994-ufshc
|
||||||
- qcom,msm8996-ufshc
|
- qcom,msm8996-ufshc
|
||||||
- qcom,msm8998-ufshc
|
- qcom,msm8998-ufshc
|
||||||
|
- qcom,sa8775p-ufshc
|
||||||
- qcom,sc8280xp-ufshc
|
- qcom,sc8280xp-ufshc
|
||||||
- qcom,sdm845-ufshc
|
- qcom,sdm845-ufshc
|
||||||
- qcom,sm6350-ufshc
|
- qcom,sm6350-ufshc
|
||||||
@@ -70,6 +71,10 @@ properties:
|
|||||||
power-domains:
|
power-domains:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
qcom,ice:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description: phandle to the Inline Crypto Engine node
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
minItems: 1
|
minItems: 1
|
||||||
maxItems: 2
|
maxItems: 2
|
||||||
@@ -105,6 +110,7 @@ allOf:
|
|||||||
contains:
|
contains:
|
||||||
enum:
|
enum:
|
||||||
- qcom,msm8998-ufshc
|
- qcom,msm8998-ufshc
|
||||||
|
- qcom,sa8775p-ufshc
|
||||||
- qcom,sc8280xp-ufshc
|
- qcom,sc8280xp-ufshc
|
||||||
- qcom,sm8250-ufshc
|
- qcom,sm8250-ufshc
|
||||||
- qcom,sm8350-ufshc
|
- qcom,sm8350-ufshc
|
||||||
@@ -187,6 +193,26 @@ allOf:
|
|||||||
|
|
||||||
# TODO: define clock bindings for qcom,msm8994-ufshc
|
# TODO: define clock bindings for qcom,msm8994-ufshc
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
qcom,ice:
|
||||||
|
maxItems: 1
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
clocks:
|
||||||
|
minItems: 8
|
||||||
|
maxItems: 8
|
||||||
|
else:
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
minItems: 2
|
||||||
|
maxItems: 2
|
||||||
|
clocks:
|
||||||
|
minItems: 9
|
||||||
|
maxItems: 11
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ properties:
|
|||||||
const: ufs-phy
|
const: ufs-phy
|
||||||
|
|
||||||
samsung,sysreg:
|
samsung,sysreg:
|
||||||
$ref: '/schemas/types.yaml#/definitions/phandle-array'
|
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||||
description: Should be phandle/offset pair. The phandle to the syscon node
|
description: Should be phandle/offset pair. The phandle to the syscon node
|
||||||
which indicates the FSYSx sysreg interface and the offset of
|
which indicates the FSYSx sysreg interface and the offset of
|
||||||
the control register for UFS io coherency setting.
|
the control register for UFS io coherency setting.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
===================
|
||||||
ARECA FIRMWARE SPEC
|
ARECA FIRMWARE SPEC
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
======================================
|
==================
|
||||||
README file for the dc395x SCSI driver
|
dc395x SCSI driver
|
||||||
======================================
|
==================
|
||||||
|
|
||||||
Status
|
Status
|
||||||
------
|
------
|
||||||
@@ -11,13 +11,10 @@ be safe to use. Testing with hard disks has not been done to any
|
|||||||
great degree and caution should be exercised if you want to attempt
|
great degree and caution should be exercised if you want to attempt
|
||||||
to use this driver with hard disks.
|
to use this driver with hard disks.
|
||||||
|
|
||||||
This is a 2.5 only driver. For a 2.4 driver please see the original
|
This driver is evolved from `the original 2.4 driver
|
||||||
driver (which this driver started from) at
|
<https://web.archive.org/web/20140129181343/http://www.garloff.de/kurt/linux/dc395/>`_.
|
||||||
http://www.garloff.de/kurt/linux/dc395/
|
Problems, questions and patches should be submitted to the `Linux SCSI
|
||||||
|
mailing list <linux-scsi@vger.kernel.org>`_.
|
||||||
Problems, questions and patches should be submitted to the mailing
|
|
||||||
list. Details on the list, including archives, are available at
|
|
||||||
http://lists.twibble.org/mailman/listinfo/dc395x/
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
.. include:: <isonum.txt>
|
.. include:: <isonum.txt>
|
||||||
|
|
||||||
==========================================
|
================
|
||||||
README file for the Linux g_NCR5380 driver
|
g_NCR5380 driver
|
||||||
==========================================
|
================
|
||||||
|
|
||||||
Copyright |copy| 1993 Drew Eckhard
|
Copyright |copy| 1993 Drew Eckhard
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,38 @@
|
|||||||
SCSI Subsystem
|
SCSI Subsystem
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
scsi
|
||||||
|
|
||||||
|
SCSI driver APIs
|
||||||
|
================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
scsi_mid_low_api
|
||||||
|
scsi_eh
|
||||||
|
|
||||||
|
SCSI driver parameters
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
scsi-parameters
|
||||||
|
link_power_management_policy
|
||||||
|
|
||||||
|
SCSI host adapter drivers
|
||||||
|
=========================
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
@@ -25,7 +57,6 @@ SCSI Subsystem
|
|||||||
hpsa
|
hpsa
|
||||||
hptiop
|
hptiop
|
||||||
libsas
|
libsas
|
||||||
link_power_management_policy
|
|
||||||
lpfc
|
lpfc
|
||||||
megaraid
|
megaraid
|
||||||
ncr53c8xx
|
ncr53c8xx
|
||||||
@@ -33,12 +64,8 @@ SCSI Subsystem
|
|||||||
ppa
|
ppa
|
||||||
qlogicfas
|
qlogicfas
|
||||||
scsi-changer
|
scsi-changer
|
||||||
scsi_eh
|
|
||||||
scsi_fc_transport
|
scsi_fc_transport
|
||||||
scsi-generic
|
scsi-generic
|
||||||
scsi_mid_low_api
|
|
||||||
scsi-parameters
|
|
||||||
scsi
|
|
||||||
sd-parameters
|
sd-parameters
|
||||||
smartpqi
|
smartpqi
|
||||||
st
|
st
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
==========================
|
=================================
|
||||||
Notes on Management Module
|
Megaraid Common Management Module
|
||||||
==========================
|
=================================
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
=================================================
|
===========================
|
||||||
The Linux NCR53C8XX/SYM53C8XX drivers README file
|
NCR53C8XX/SYM53C8XX drivers
|
||||||
=================================================
|
===========================
|
||||||
|
|
||||||
Written by Gerard Roudier <groudier@free.fr>
|
Written by Gerard Roudier <groudier@free.fr>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
========================================
|
=========================
|
||||||
README for the SCSI media changer driver
|
SCSI media changer driver
|
||||||
========================================
|
=========================
|
||||||
|
|
||||||
This is a driver for SCSI Medium Changer devices, which are listed
|
This is a driver for SCSI Medium Changer devices, which are listed
|
||||||
with "Type: Medium Changer" in /proc/scsi/scsi.
|
with "Type: Medium Changer" in /proc/scsi/scsi.
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
=======================================
|
========================
|
||||||
Notes on Linux SCSI Generic (sg) driver
|
SCSI Generic (sg) driver
|
||||||
=======================================
|
========================
|
||||||
|
|
||||||
20020126
|
20020126
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
The SCSI Generic driver (sg) is one of the four "high level" SCSI device
|
The SCSI Generic driver (sg) is one of the four "high level" SCSI device
|
||||||
drivers along with sd, st and sr (disk, tape and CDROM respectively). Sg
|
drivers along with sd, st and sr (disk, tape and CD-ROM respectively). Sg
|
||||||
is more generalized (but lower level) than its siblings and tends to be
|
is more generalized (but lower level) than its siblings and tends to be
|
||||||
used on SCSI devices that don't fit into the already serviced categories.
|
used on SCSI devices that don't fit into the already serviced categories.
|
||||||
Thus sg is used for scanners, CD writers and reading audio CDs digitally
|
Thus sg is used for scanners, CD writers and reading audio CDs digitally
|
||||||
@@ -22,7 +22,7 @@ and examples.
|
|||||||
|
|
||||||
Major versions of the sg driver
|
Major versions of the sg driver
|
||||||
===============================
|
===============================
|
||||||
There are three major versions of sg found in the linux kernel (lk):
|
There are three major versions of sg found in the Linux kernel (lk):
|
||||||
- sg version 1 (original) from 1992 to early 1999 (lk 2.2.5) .
|
- sg version 1 (original) from 1992 to early 1999 (lk 2.2.5) .
|
||||||
It is based in the sg_header interface structure.
|
It is based in the sg_header interface structure.
|
||||||
- sg version 2 from lk 2.2.6 in the 2.2 series. It is based on
|
- sg version 2 from lk 2.2.6 in the 2.2 series. It is based on
|
||||||
@@ -33,34 +33,24 @@ There are three major versions of sg found in the linux kernel (lk):
|
|||||||
|
|
||||||
Sg driver documentation
|
Sg driver documentation
|
||||||
=======================
|
=======================
|
||||||
The most recent documentation of the sg driver is kept at the Linux
|
The most recent documentation of the sg driver is kept at
|
||||||
Documentation Project's (LDP) site:
|
|
||||||
|
|
||||||
- http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO
|
- https://sg.danny.cz/sg/
|
||||||
|
|
||||||
This describes the sg version 3 driver found in the lk 2.4 series.
|
This describes the sg version 3 driver found in the lk 2.4 series.
|
||||||
|
|
||||||
The LDP renders documents in single and multiple page HTML, postscript
|
Documentation (large version) for the version 2 sg driver found in the
|
||||||
and pdf. This document can also be found at:
|
lk 2.2 series can be found at
|
||||||
|
|
||||||
- http://sg.danny.cz/sg/p/sg_v3_ho.html
|
- https://sg.danny.cz/sg/p/scsi-generic_long.txt.
|
||||||
|
|
||||||
Documentation for the version 2 sg driver found in the lk 2.2 series can
|
|
||||||
be found at http://sg.danny.cz/sg/. A larger version
|
|
||||||
is at: http://sg.danny.cz/sg/p/scsi-generic_long.txt.
|
|
||||||
|
|
||||||
The original documentation for the sg driver (prior to lk 2.2.6) can be
|
The original documentation for the sg driver (prior to lk 2.2.6) can be
|
||||||
found at http://www.torque.net/sg/p/original/SCSI-Programming-HOWTO.txt
|
found in the LDP archives at
|
||||||
and in the LDP archives.
|
|
||||||
|
|
||||||
A changelog with brief notes can be found in the
|
- https://tldp.org/HOWTO/archived/SCSI-Programming-HOWTO/index.html
|
||||||
/usr/src/linux/include/scsi/sg.h file. Note that the glibc maintainers copy
|
|
||||||
and edit this file (removing its changelog for example) before placing it
|
|
||||||
in /usr/include/scsi/sg.h . Driver debugging information and other notes
|
|
||||||
can be found at the top of the /usr/src/linux/drivers/scsi/sg.c file.
|
|
||||||
|
|
||||||
A more general description of the Linux SCSI subsystem of which sg is a
|
A more general description of the Linux SCSI subsystem of which sg is a
|
||||||
part can be found at http://www.tldp.org/HOWTO/SCSI-2.4-HOWTO .
|
part can be found at https://www.tldp.org/HOWTO/SCSI-2.4-HOWTO .
|
||||||
|
|
||||||
|
|
||||||
Example code and utilities
|
Example code and utilities
|
||||||
@@ -73,8 +63,8 @@ There are two packages of sg utilities:
|
|||||||
and earlier
|
and earlier
|
||||||
========= ==========================================================
|
========= ==========================================================
|
||||||
|
|
||||||
Both packages will work in the lk 2.4 series however sg3_utils offers more
|
Both packages will work in the lk 2.4 series. However, sg3_utils offers more
|
||||||
capabilities. They can be found at: http://sg.danny.cz/sg/sg3_utils.html and
|
capabilities. They can be found at: https://sg.danny.cz/sg/sg3_utils.html and
|
||||||
freecode.com
|
freecode.com
|
||||||
|
|
||||||
Another approach is to look at the applications that use the sg driver.
|
Another approach is to look at the applications that use the sg driver.
|
||||||
@@ -83,7 +73,7 @@ These include cdrecord, cdparanoia, SANE and cdrdao.
|
|||||||
|
|
||||||
Mapping of Linux kernel versions to sg driver versions
|
Mapping of Linux kernel versions to sg driver versions
|
||||||
======================================================
|
======================================================
|
||||||
Here is a list of linux kernels in the 2.4 series that had new version
|
Here is a list of Linux kernels in the 2.4 series that had the new version
|
||||||
of the sg driver:
|
of the sg driver:
|
||||||
|
|
||||||
- lk 2.4.0 : sg version 3.1.17
|
- lk 2.4.0 : sg version 3.1.17
|
||||||
@@ -92,10 +82,10 @@ of the sg driver:
|
|||||||
- lk 2.4.17 : sg version 3.1.22
|
- lk 2.4.17 : sg version 3.1.22
|
||||||
|
|
||||||
.. [#] There were 3 changes to sg version 3.1.20 by third parties in the
|
.. [#] There were 3 changes to sg version 3.1.20 by third parties in the
|
||||||
next six linux kernel versions.
|
next six Linux kernel versions.
|
||||||
|
|
||||||
For reference here is a list of linux kernels in the 2.2 series that had
|
For reference here is a list of Linux kernels in the 2.2 series that had
|
||||||
new version of the sg driver:
|
the new version of the sg driver:
|
||||||
|
|
||||||
- lk 2.2.0 : original sg version [with no version number]
|
- lk 2.2.0 : original sg version [with no version number]
|
||||||
- lk 2.2.6 : sg version 2.1.31
|
- lk 2.2.6 : sg version 2.1.31
|
||||||
@@ -106,9 +96,8 @@ new version of the sg driver:
|
|||||||
- lk 2.2.17 : sg version 2.1.39
|
- lk 2.2.17 : sg version 2.1.39
|
||||||
- lk 2.2.20 : sg version 2.1.40
|
- lk 2.2.20 : sg version 2.1.40
|
||||||
|
|
||||||
The lk 2.5 development series has recently commenced and it currently
|
The lk 2.5 development series currently contains sg version 3.5.23
|
||||||
contains sg version 3.5.23 which is functionally equivalent to sg
|
which is functionally equivalent to sg version 3.1.22 found in lk 2.4.17.
|
||||||
version 3.1.22 found in lk 2.4.17.
|
|
||||||
|
|
||||||
|
|
||||||
Douglas Gilbert
|
Douglas Gilbert
|
||||||
|
|||||||
@@ -6,30 +6,28 @@ SCSI subsystem documentation
|
|||||||
|
|
||||||
The Linux Documentation Project (LDP) maintains a document describing
|
The Linux Documentation Project (LDP) maintains a document describing
|
||||||
the SCSI subsystem in the Linux kernel (lk) 2.4 series. See:
|
the SCSI subsystem in the Linux kernel (lk) 2.4 series. See:
|
||||||
http://www.tldp.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single
|
https://www.tldp.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single
|
||||||
and multiple page HTML renderings as well as postscript and pdf.
|
and multiple page HTML renderings as well as postscript and pdf.
|
||||||
It can also be found at:
|
|
||||||
http://web.archive.org/web/%2E/http://www.torque.net/scsi/SCSI-2.4-HOWTO
|
|
||||||
|
|
||||||
Notes on using modules in the SCSI subsystem
|
Notes on using modules in the SCSI subsystem
|
||||||
============================================
|
============================================
|
||||||
The scsi support in the linux kernel can be modularized in a number of
|
The SCSI support in the Linux kernel can be modularized in a number of
|
||||||
different ways depending upon the needs of the end user. To understand
|
different ways depending upon the needs of the end user. To understand
|
||||||
your options, we should first define a few terms.
|
your options, we should first define a few terms.
|
||||||
|
|
||||||
The scsi-core (also known as the "mid level") contains the core of scsi
|
The scsi-core (also known as the "mid level") contains the core of SCSI
|
||||||
support. Without it you can do nothing with any of the other scsi drivers.
|
support. Without it you can do nothing with any of the other SCSI drivers.
|
||||||
The scsi core support can be a module (scsi_mod.o), or it can be built into
|
The SCSI core support can be a module (scsi_mod.o), or it can be built into
|
||||||
the kernel. If the core is a module, it must be the first scsi module
|
the kernel. If the core is a module, it must be the first SCSI module
|
||||||
loaded, and if you unload the modules, it will have to be the last one
|
loaded, and if you unload the modules, it will have to be the last one
|
||||||
unloaded. In practice the modprobe and rmmod commands (and "autoclean")
|
unloaded. In practice the modprobe and rmmod commands
|
||||||
will enforce the correct ordering of loading and unloading modules in
|
will enforce the correct ordering of loading and unloading modules in
|
||||||
the SCSI subsystem.
|
the SCSI subsystem.
|
||||||
|
|
||||||
The individual upper and lower level drivers can be loaded in any order
|
The individual upper and lower level drivers can be loaded in any order
|
||||||
once the scsi core is present in the kernel (either compiled in or loaded
|
once the SCSI core is present in the kernel (either compiled in or loaded
|
||||||
as a module). The disk driver (sd_mod.o), cdrom driver (sr_mod.o),
|
as a module). The disk driver (sd_mod.o), CD-ROM driver (sr_mod.o),
|
||||||
tape driver [1]_ (st.o) and scsi generics driver (sg.o) represent the upper
|
tape driver [1]_ (st.o) and SCSI generics driver (sg.o) represent the upper
|
||||||
level drivers to support the various assorted devices which can be
|
level drivers to support the various assorted devices which can be
|
||||||
controlled. You can for example load the tape driver to use the tape drive,
|
controlled. You can for example load the tape driver to use the tape drive,
|
||||||
and then unload it once you have no further need for the driver (and release
|
and then unload it once you have no further need for the driver (and release
|
||||||
@@ -44,4 +42,3 @@ built into the kernel.
|
|||||||
|
|
||||||
.. [1] There is a variant of the st driver for controlling OnStream tape
|
.. [1] There is a variant of the st driver for controlling OnStream tape
|
||||||
devices. Its module name is osst.o .
|
devices. Its module name is osst.o .
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
================
|
=================
|
||||||
SCSI FC Tansport
|
SCSI FC Transport
|
||||||
================
|
=================
|
||||||
|
|
||||||
Date: 11/18/2008
|
Date: 11/18/2008
|
||||||
|
|
||||||
@@ -556,5 +556,5 @@ The following people have contributed to this document:
|
|||||||
|
|
||||||
|
|
||||||
James Smart
|
James Smart
|
||||||
james.smart@emulex.com
|
james.smart@broadcom.com
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
=========================================
|
============
|
||||||
The Linux SYM-2 driver documentation file
|
SYM-2 driver
|
||||||
=========================================
|
============
|
||||||
|
|
||||||
Written by Gerard Roudier <groudier@free.fr>
|
Written by Gerard Roudier <groudier@free.fr>
|
||||||
|
|
||||||
|
|||||||
13
MAINTAINERS
13
MAINTAINERS
@@ -5732,10 +5732,7 @@ DC395x SCSI driver
|
|||||||
M: Oliver Neukum <oliver@neukum.org>
|
M: Oliver Neukum <oliver@neukum.org>
|
||||||
M: Ali Akcaagac <aliakc@web.de>
|
M: Ali Akcaagac <aliakc@web.de>
|
||||||
M: Jamie Lenehan <lenehan@twibble.org>
|
M: Jamie Lenehan <lenehan@twibble.org>
|
||||||
L: dc395x@twibble.org
|
|
||||||
S: Maintained
|
S: Maintained
|
||||||
W: http://twibble.org/dist/dc395x/
|
|
||||||
W: http://lists.twibble.org/mailman/listinfo/dc395x/
|
|
||||||
F: Documentation/scsi/dc395x.rst
|
F: Documentation/scsi/dc395x.rst
|
||||||
F: drivers/scsi/dc395x.*
|
F: drivers/scsi/dc395x.*
|
||||||
|
|
||||||
@@ -18918,6 +18915,16 @@ F: include/linux/wait.h
|
|||||||
F: include/uapi/linux/sched.h
|
F: include/uapi/linux/sched.h
|
||||||
F: kernel/sched/
|
F: kernel/sched/
|
||||||
|
|
||||||
|
SCSI LIBSAS SUBSYSTEM
|
||||||
|
R: John Garry <john.g.garry@oracle.com>
|
||||||
|
R: Jason Yan <yanaijie@huawei.com>
|
||||||
|
L: linux-scsi@vger.kernel.org
|
||||||
|
S: Supported
|
||||||
|
F: drivers/scsi/libsas/
|
||||||
|
F: include/scsi/libsas.h
|
||||||
|
F: include/scsi/sas_ata.h
|
||||||
|
F: Documentation/scsi/libsas.rst
|
||||||
|
|
||||||
SCSI RDMA PROTOCOL (SRP) INITIATOR
|
SCSI RDMA PROTOCOL (SRP) INITIATOR
|
||||||
M: Bart Van Assche <bvanassche@acm.org>
|
M: Bart Van Assche <bvanassche@acm.org>
|
||||||
L: linux-rdma@vger.kernel.org
|
L: linux-rdma@vger.kernel.org
|
||||||
|
|||||||
@@ -5528,16 +5528,16 @@ bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
|
|||||||
bfqq->new_ioprio_class = task_nice_ioclass(tsk);
|
bfqq->new_ioprio_class = task_nice_ioclass(tsk);
|
||||||
break;
|
break;
|
||||||
case IOPRIO_CLASS_RT:
|
case IOPRIO_CLASS_RT:
|
||||||
bfqq->new_ioprio = IOPRIO_PRIO_DATA(bic->ioprio);
|
bfqq->new_ioprio = IOPRIO_PRIO_LEVEL(bic->ioprio);
|
||||||
bfqq->new_ioprio_class = IOPRIO_CLASS_RT;
|
bfqq->new_ioprio_class = IOPRIO_CLASS_RT;
|
||||||
break;
|
break;
|
||||||
case IOPRIO_CLASS_BE:
|
case IOPRIO_CLASS_BE:
|
||||||
bfqq->new_ioprio = IOPRIO_PRIO_DATA(bic->ioprio);
|
bfqq->new_ioprio = IOPRIO_PRIO_LEVEL(bic->ioprio);
|
||||||
bfqq->new_ioprio_class = IOPRIO_CLASS_BE;
|
bfqq->new_ioprio_class = IOPRIO_CLASS_BE;
|
||||||
break;
|
break;
|
||||||
case IOPRIO_CLASS_IDLE:
|
case IOPRIO_CLASS_IDLE:
|
||||||
bfqq->new_ioprio_class = IOPRIO_CLASS_IDLE;
|
bfqq->new_ioprio_class = IOPRIO_CLASS_IDLE;
|
||||||
bfqq->new_ioprio = 7;
|
bfqq->new_ioprio = IOPRIO_NR_LEVELS - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5834,7 +5834,7 @@ static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd,
|
|||||||
struct bfq_io_cq *bic,
|
struct bfq_io_cq *bic,
|
||||||
bool respawn)
|
bool respawn)
|
||||||
{
|
{
|
||||||
const int ioprio = IOPRIO_PRIO_DATA(bic->ioprio);
|
const int ioprio = IOPRIO_PRIO_LEVEL(bic->ioprio);
|
||||||
const int ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio);
|
const int ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio);
|
||||||
struct bfq_queue **async_bfqq = NULL;
|
struct bfq_queue **async_bfqq = NULL;
|
||||||
struct bfq_queue *bfqq;
|
struct bfq_queue *bfqq;
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ static const struct {
|
|||||||
[BLK_STS_NOSPC] = { -ENOSPC, "critical space allocation" },
|
[BLK_STS_NOSPC] = { -ENOSPC, "critical space allocation" },
|
||||||
[BLK_STS_TRANSPORT] = { -ENOLINK, "recoverable transport" },
|
[BLK_STS_TRANSPORT] = { -ENOLINK, "recoverable transport" },
|
||||||
[BLK_STS_TARGET] = { -EREMOTEIO, "critical target" },
|
[BLK_STS_TARGET] = { -EREMOTEIO, "critical target" },
|
||||||
[BLK_STS_NEXUS] = { -EBADE, "critical nexus" },
|
[BLK_STS_RESV_CONFLICT] = { -EBADE, "reservation conflict" },
|
||||||
[BLK_STS_MEDIUM] = { -ENODATA, "critical medium" },
|
[BLK_STS_MEDIUM] = { -ENODATA, "critical medium" },
|
||||||
[BLK_STS_PROTECTION] = { -EILSEQ, "protection" },
|
[BLK_STS_PROTECTION] = { -EILSEQ, "protection" },
|
||||||
[BLK_STS_RESOURCE] = { -ENOMEM, "kernel resource" },
|
[BLK_STS_RESOURCE] = { -ENOMEM, "kernel resource" },
|
||||||
@@ -170,6 +170,9 @@ static const struct {
|
|||||||
[BLK_STS_ZONE_OPEN_RESOURCE] = { -ETOOMANYREFS, "open zones exceeded" },
|
[BLK_STS_ZONE_OPEN_RESOURCE] = { -ETOOMANYREFS, "open zones exceeded" },
|
||||||
[BLK_STS_ZONE_ACTIVE_RESOURCE] = { -EOVERFLOW, "active zones exceeded" },
|
[BLK_STS_ZONE_ACTIVE_RESOURCE] = { -EOVERFLOW, "active zones exceeded" },
|
||||||
|
|
||||||
|
/* Command duration limit device-side timeout */
|
||||||
|
[BLK_STS_DURATION_LIMIT] = { -ETIME, "duration limit exceeded" },
|
||||||
|
|
||||||
/* everything else not covered above: */
|
/* everything else not covered above: */
|
||||||
[BLK_STS_IOERR] = { -EIO, "I/O" },
|
[BLK_STS_IOERR] = { -EIO, "I/O" },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ static inline struct bsg_device *to_bsg_device(struct inode *inode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define BSG_DEFAULT_CMDS 64
|
#define BSG_DEFAULT_CMDS 64
|
||||||
#define BSG_MAX_DEVS 32768
|
#define BSG_MAX_DEVS (1 << MINORBITS)
|
||||||
|
|
||||||
static DEFINE_IDA(bsg_minor_ida);
|
static DEFINE_IDA(bsg_minor_ida);
|
||||||
static const struct class bsg_class;
|
static const struct class bsg_class;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
int ioprio_check_cap(int ioprio)
|
int ioprio_check_cap(int ioprio)
|
||||||
{
|
{
|
||||||
int class = IOPRIO_PRIO_CLASS(ioprio);
|
int class = IOPRIO_PRIO_CLASS(ioprio);
|
||||||
int data = IOPRIO_PRIO_DATA(ioprio);
|
int level = IOPRIO_PRIO_LEVEL(ioprio);
|
||||||
|
|
||||||
switch (class) {
|
switch (class) {
|
||||||
case IOPRIO_CLASS_RT:
|
case IOPRIO_CLASS_RT:
|
||||||
@@ -49,15 +49,16 @@ int ioprio_check_cap(int ioprio)
|
|||||||
fallthrough;
|
fallthrough;
|
||||||
/* rt has prio field too */
|
/* rt has prio field too */
|
||||||
case IOPRIO_CLASS_BE:
|
case IOPRIO_CLASS_BE:
|
||||||
if (data >= IOPRIO_NR_LEVELS || data < 0)
|
if (level >= IOPRIO_NR_LEVELS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
case IOPRIO_CLASS_IDLE:
|
case IOPRIO_CLASS_IDLE:
|
||||||
break;
|
break;
|
||||||
case IOPRIO_CLASS_NONE:
|
case IOPRIO_CLASS_NONE:
|
||||||
if (data)
|
if (level)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
case IOPRIO_CLASS_INVALID:
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -665,12 +665,33 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set a taskfile command duration limit index.
|
||||||
|
*/
|
||||||
|
static inline void ata_set_tf_cdl(struct ata_queued_cmd *qc, int cdl)
|
||||||
|
{
|
||||||
|
struct ata_taskfile *tf = &qc->tf;
|
||||||
|
|
||||||
|
if (tf->protocol == ATA_PROT_NCQ)
|
||||||
|
tf->auxiliary |= cdl;
|
||||||
|
else
|
||||||
|
tf->feature |= cdl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark this command as having a CDL and request the result
|
||||||
|
* task file so that we can inspect the sense data available
|
||||||
|
* bit on completion.
|
||||||
|
*/
|
||||||
|
qc->flags |= ATA_QCFLAG_HAS_CDL | ATA_QCFLAG_RESULT_TF;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_build_rw_tf - Build ATA taskfile for given read/write request
|
* ata_build_rw_tf - Build ATA taskfile for given read/write request
|
||||||
* @qc: Metadata associated with the taskfile to build
|
* @qc: Metadata associated with the taskfile to build
|
||||||
* @block: Block address
|
* @block: Block address
|
||||||
* @n_block: Number of blocks
|
* @n_block: Number of blocks
|
||||||
* @tf_flags: RW/FUA etc...
|
* @tf_flags: RW/FUA etc...
|
||||||
|
* @cdl: Command duration limit index
|
||||||
* @class: IO priority class
|
* @class: IO priority class
|
||||||
*
|
*
|
||||||
* LOCKING:
|
* LOCKING:
|
||||||
@@ -685,7 +706,7 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
|
|||||||
* -EINVAL if the request is invalid.
|
* -EINVAL if the request is invalid.
|
||||||
*/
|
*/
|
||||||
int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
|
int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
|
||||||
unsigned int tf_flags, int class)
|
unsigned int tf_flags, int cdl, int class)
|
||||||
{
|
{
|
||||||
struct ata_taskfile *tf = &qc->tf;
|
struct ata_taskfile *tf = &qc->tf;
|
||||||
struct ata_device *dev = qc->dev;
|
struct ata_device *dev = qc->dev;
|
||||||
@@ -724,11 +745,20 @@ int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
|
|||||||
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED &&
|
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED &&
|
||||||
class == IOPRIO_CLASS_RT)
|
class == IOPRIO_CLASS_RT)
|
||||||
tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO;
|
tf->hob_nsect |= ATA_PRIO_HIGH << ATA_SHIFT_PRIO;
|
||||||
|
|
||||||
|
if ((dev->flags & ATA_DFLAG_CDL_ENABLED) && cdl)
|
||||||
|
ata_set_tf_cdl(qc, cdl);
|
||||||
|
|
||||||
} else if (dev->flags & ATA_DFLAG_LBA) {
|
} else if (dev->flags & ATA_DFLAG_LBA) {
|
||||||
tf->flags |= ATA_TFLAG_LBA;
|
tf->flags |= ATA_TFLAG_LBA;
|
||||||
|
|
||||||
/* We need LBA48 for FUA writes */
|
if ((dev->flags & ATA_DFLAG_CDL_ENABLED) && cdl)
|
||||||
if (!(tf->flags & ATA_TFLAG_FUA) && lba_28_ok(block, n_block)) {
|
ata_set_tf_cdl(qc, cdl);
|
||||||
|
|
||||||
|
/* Both FUA writes and a CDL index require 48-bit commands */
|
||||||
|
if (!(tf->flags & ATA_TFLAG_FUA) &&
|
||||||
|
!(qc->flags & ATA_QCFLAG_HAS_CDL) &&
|
||||||
|
lba_28_ok(block, n_block)) {
|
||||||
/* use LBA28 */
|
/* use LBA28 */
|
||||||
tf->device |= (block >> 24) & 0xf;
|
tf->device |= (block >> 24) & 0xf;
|
||||||
} else if (lba_48_ok(block, n_block)) {
|
} else if (lba_48_ok(block, n_block)) {
|
||||||
@@ -2367,6 +2397,139 @@ static void ata_dev_config_trusted(struct ata_device *dev)
|
|||||||
dev->flags |= ATA_DFLAG_TRUSTED;
|
dev->flags |= ATA_DFLAG_TRUSTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ata_dev_config_cdl(struct ata_device *dev)
|
||||||
|
{
|
||||||
|
struct ata_port *ap = dev->link->ap;
|
||||||
|
unsigned int err_mask;
|
||||||
|
bool cdl_enabled;
|
||||||
|
u64 val;
|
||||||
|
|
||||||
|
if (ata_id_major_version(dev->id) < 12)
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE) ||
|
||||||
|
!ata_identify_page_supported(dev, ATA_LOG_SUPPORTED_CAPABILITIES) ||
|
||||||
|
!ata_identify_page_supported(dev, ATA_LOG_CURRENT_SETTINGS))
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
|
||||||
|
ATA_LOG_SUPPORTED_CAPABILITIES,
|
||||||
|
ap->sector_buf, 1);
|
||||||
|
if (err_mask)
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
/* Check Command Duration Limit Supported bits */
|
||||||
|
val = get_unaligned_le64(&ap->sector_buf[168]);
|
||||||
|
if (!(val & BIT_ULL(63)) || !(val & BIT_ULL(0)))
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
/* Warn the user if command duration guideline is not supported */
|
||||||
|
if (!(val & BIT_ULL(1)))
|
||||||
|
ata_dev_warn(dev,
|
||||||
|
"Command duration guideline is not supported\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must have support for the sense data for successful NCQ commands
|
||||||
|
* log indicated by the successful NCQ command sense data supported bit.
|
||||||
|
*/
|
||||||
|
val = get_unaligned_le64(&ap->sector_buf[8]);
|
||||||
|
if (!(val & BIT_ULL(63)) || !(val & BIT_ULL(47))) {
|
||||||
|
ata_dev_warn(dev,
|
||||||
|
"CDL supported but Successful NCQ Command Sense Data is not supported\n");
|
||||||
|
goto not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Without NCQ autosense, the successful NCQ commands log is useless. */
|
||||||
|
if (!ata_id_has_ncq_autosense(dev->id)) {
|
||||||
|
ata_dev_warn(dev,
|
||||||
|
"CDL supported but NCQ autosense is not supported\n");
|
||||||
|
goto not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If CDL is marked as enabled, make sure the feature is enabled too.
|
||||||
|
* Conversely, if CDL is disabled, make sure the feature is turned off.
|
||||||
|
*/
|
||||||
|
err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
|
||||||
|
ATA_LOG_CURRENT_SETTINGS,
|
||||||
|
ap->sector_buf, 1);
|
||||||
|
if (err_mask)
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
val = get_unaligned_le64(&ap->sector_buf[8]);
|
||||||
|
cdl_enabled = val & BIT_ULL(63) && val & BIT_ULL(21);
|
||||||
|
if (dev->flags & ATA_DFLAG_CDL_ENABLED) {
|
||||||
|
if (!cdl_enabled) {
|
||||||
|
/* Enable CDL on the device */
|
||||||
|
err_mask = ata_dev_set_feature(dev, SETFEATURES_CDL, 1);
|
||||||
|
if (err_mask) {
|
||||||
|
ata_dev_err(dev,
|
||||||
|
"Enable CDL feature failed\n");
|
||||||
|
goto not_supported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cdl_enabled) {
|
||||||
|
/* Disable CDL on the device */
|
||||||
|
err_mask = ata_dev_set_feature(dev, SETFEATURES_CDL, 0);
|
||||||
|
if (err_mask) {
|
||||||
|
ata_dev_err(dev,
|
||||||
|
"Disable CDL feature failed\n");
|
||||||
|
goto not_supported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While CDL itself has to be enabled using sysfs, CDL requires that
|
||||||
|
* sense data for successful NCQ commands is enabled to work properly.
|
||||||
|
* Just like ata_dev_config_sense_reporting(), enable it unconditionally
|
||||||
|
* if supported.
|
||||||
|
*/
|
||||||
|
if (!(val & BIT_ULL(63)) || !(val & BIT_ULL(18))) {
|
||||||
|
err_mask = ata_dev_set_feature(dev,
|
||||||
|
SETFEATURE_SENSE_DATA_SUCC_NCQ, 0x1);
|
||||||
|
if (err_mask) {
|
||||||
|
ata_dev_warn(dev,
|
||||||
|
"failed to enable Sense Data for successful NCQ commands, Emask 0x%x\n",
|
||||||
|
err_mask);
|
||||||
|
goto not_supported;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a buffer to handle reading the sense data for successful
|
||||||
|
* NCQ Commands log page for commands using a CDL with one of the limit
|
||||||
|
* policy set to 0xD (successful completion with sense data available
|
||||||
|
* bit set).
|
||||||
|
*/
|
||||||
|
if (!ap->ncq_sense_buf) {
|
||||||
|
ap->ncq_sense_buf = kmalloc(ATA_LOG_SENSE_NCQ_SIZE, GFP_KERNEL);
|
||||||
|
if (!ap->ncq_sense_buf)
|
||||||
|
goto not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command duration limits is supported: cache the CDL log page 18h
|
||||||
|
* (command duration descriptors).
|
||||||
|
*/
|
||||||
|
err_mask = ata_read_log_page(dev, ATA_LOG_CDL, 0, ap->sector_buf, 1);
|
||||||
|
if (err_mask) {
|
||||||
|
ata_dev_warn(dev, "Read Command Duration Limits log failed\n");
|
||||||
|
goto not_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dev->cdl, ap->sector_buf, ATA_LOG_CDL_SIZE);
|
||||||
|
dev->flags |= ATA_DFLAG_CDL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
not_supported:
|
||||||
|
dev->flags &= ~(ATA_DFLAG_CDL | ATA_DFLAG_CDL_ENABLED);
|
||||||
|
kfree(ap->ncq_sense_buf);
|
||||||
|
ap->ncq_sense_buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int ata_dev_config_lba(struct ata_device *dev)
|
static int ata_dev_config_lba(struct ata_device *dev)
|
||||||
{
|
{
|
||||||
const u16 *id = dev->id;
|
const u16 *id = dev->id;
|
||||||
@@ -2534,13 +2697,14 @@ static void ata_dev_print_features(struct ata_device *dev)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ata_dev_info(dev,
|
ata_dev_info(dev,
|
||||||
"Features:%s%s%s%s%s%s%s\n",
|
"Features:%s%s%s%s%s%s%s%s\n",
|
||||||
dev->flags & ATA_DFLAG_FUA ? " FUA" : "",
|
dev->flags & ATA_DFLAG_FUA ? " FUA" : "",
|
||||||
dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "",
|
dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "",
|
||||||
dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "",
|
dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "",
|
||||||
dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "",
|
dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "",
|
||||||
dev->flags & ATA_DFLAG_NCQ_SEND_RECV ? " NCQ-sndrcv" : "",
|
dev->flags & ATA_DFLAG_NCQ_SEND_RECV ? " NCQ-sndrcv" : "",
|
||||||
dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : "",
|
dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : "",
|
||||||
|
dev->flags & ATA_DFLAG_CDL ? " CDL" : "",
|
||||||
dev->cpr_log ? " CPR" : "");
|
dev->cpr_log ? " CPR" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2702,6 +2866,7 @@ int ata_dev_configure(struct ata_device *dev)
|
|||||||
ata_dev_config_zac(dev);
|
ata_dev_config_zac(dev);
|
||||||
ata_dev_config_trusted(dev);
|
ata_dev_config_trusted(dev);
|
||||||
ata_dev_config_cpr(dev);
|
ata_dev_config_cpr(dev);
|
||||||
|
ata_dev_config_cdl(dev);
|
||||||
dev->cdb_len = 32;
|
dev->cdb_len = 32;
|
||||||
|
|
||||||
if (print_info)
|
if (print_info)
|
||||||
@@ -4762,6 +4927,36 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
|
|||||||
fill_result_tf(qc);
|
fill_result_tf(qc);
|
||||||
|
|
||||||
trace_ata_qc_complete_done(qc);
|
trace_ata_qc_complete_done(qc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For CDL commands that completed without an error, check if
|
||||||
|
* we have sense data (ATA_SENSE is set). If we do, then the
|
||||||
|
* command may have been aborted by the device due to a limit
|
||||||
|
* timeout using the policy 0xD. For these commands, invoke EH
|
||||||
|
* to get the command sense data.
|
||||||
|
*/
|
||||||
|
if (qc->result_tf.status & ATA_SENSE &&
|
||||||
|
((ata_is_ncq(qc->tf.protocol) &&
|
||||||
|
dev->flags & ATA_DFLAG_CDL_ENABLED) ||
|
||||||
|
(!(ata_is_ncq(qc->tf.protocol) &&
|
||||||
|
ata_id_sense_reporting_enabled(dev->id))))) {
|
||||||
|
/*
|
||||||
|
* Tell SCSI EH to not overwrite scmd->result even if
|
||||||
|
* this command is finished with result SAM_STAT_GOOD.
|
||||||
|
*/
|
||||||
|
qc->scsicmd->flags |= SCMD_FORCE_EH_SUCCESS;
|
||||||
|
qc->flags |= ATA_QCFLAG_EH_SUCCESS_CMD;
|
||||||
|
ehi->dev_action[dev->devno] |= ATA_EH_GET_SUCCESS_SENSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set pending so that ata_qc_schedule_eh() does not
|
||||||
|
* trigger fast drain, and freeze the port.
|
||||||
|
*/
|
||||||
|
ap->pflags |= ATA_PFLAG_EH_PENDING;
|
||||||
|
ata_qc_schedule_eh(qc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Some commands need post-processing after successful
|
/* Some commands need post-processing after successful
|
||||||
* completion.
|
* completion.
|
||||||
*/
|
*/
|
||||||
@@ -5394,6 +5589,7 @@ static void ata_host_release(struct kref *kref)
|
|||||||
|
|
||||||
kfree(ap->pmp_link);
|
kfree(ap->pmp_link);
|
||||||
kfree(ap->slave_link);
|
kfree(ap->slave_link);
|
||||||
|
kfree(ap->ncq_sense_buf);
|
||||||
kfree(ap);
|
kfree(ap);
|
||||||
host->ports[i] = NULL;
|
host->ports[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1401,8 +1401,11 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
|
|||||||
*
|
*
|
||||||
* LOCKING:
|
* LOCKING:
|
||||||
* Kernel thread context (may sleep).
|
* Kernel thread context (may sleep).
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* true if sense data could be fetched, false otherwise.
|
||||||
*/
|
*/
|
||||||
static void ata_eh_request_sense(struct ata_queued_cmd *qc)
|
static bool ata_eh_request_sense(struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||||
struct ata_device *dev = qc->dev;
|
struct ata_device *dev = qc->dev;
|
||||||
@@ -1411,15 +1414,12 @@ static void ata_eh_request_sense(struct ata_queued_cmd *qc)
|
|||||||
|
|
||||||
if (ata_port_is_frozen(qc->ap)) {
|
if (ata_port_is_frozen(qc->ap)) {
|
||||||
ata_dev_warn(dev, "sense data available but port frozen\n");
|
ata_dev_warn(dev, "sense data available but port frozen\n");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd || qc->flags & ATA_QCFLAG_SENSE_VALID)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!ata_id_sense_reporting_enabled(dev->id)) {
|
if (!ata_id_sense_reporting_enabled(dev->id)) {
|
||||||
ata_dev_warn(qc->dev, "sense data reporting disabled\n");
|
ata_dev_warn(qc->dev, "sense data reporting disabled\n");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ata_tf_init(dev, &tf);
|
ata_tf_init(dev, &tf);
|
||||||
@@ -1432,13 +1432,19 @@ static void ata_eh_request_sense(struct ata_queued_cmd *qc)
|
|||||||
/* Ignore err_mask; ATA_ERR might be set */
|
/* Ignore err_mask; ATA_ERR might be set */
|
||||||
if (tf.status & ATA_SENSE) {
|
if (tf.status & ATA_SENSE) {
|
||||||
if (ata_scsi_sense_is_valid(tf.lbah, tf.lbam, tf.lbal)) {
|
if (ata_scsi_sense_is_valid(tf.lbah, tf.lbam, tf.lbal)) {
|
||||||
ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal);
|
/* Set sense without also setting scsicmd->result */
|
||||||
|
scsi_build_sense_buffer(dev->flags & ATA_DFLAG_D_SENSE,
|
||||||
|
cmd->sense_buffer, tf.lbah,
|
||||||
|
tf.lbam, tf.lbal);
|
||||||
qc->flags |= ATA_QCFLAG_SENSE_VALID;
|
qc->flags |= ATA_QCFLAG_SENSE_VALID;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
|
ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
|
||||||
tf.status, err_mask);
|
tf.status, err_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1588,8 +1594,9 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc)
|
|||||||
* was not included in the NCQ command error log
|
* was not included in the NCQ command error log
|
||||||
* (i.e. NCQ autosense is not supported by the device).
|
* (i.e. NCQ autosense is not supported by the device).
|
||||||
*/
|
*/
|
||||||
if (!(qc->flags & ATA_QCFLAG_SENSE_VALID) && (stat & ATA_SENSE))
|
if (!(qc->flags & ATA_QCFLAG_SENSE_VALID) &&
|
||||||
ata_eh_request_sense(qc);
|
(stat & ATA_SENSE) && ata_eh_request_sense(qc))
|
||||||
|
set_status_byte(qc->scsicmd, SAM_STAT_CHECK_CONDITION);
|
||||||
if (err & ATA_ICRC)
|
if (err & ATA_ICRC)
|
||||||
qc->err_mask |= AC_ERR_ATA_BUS;
|
qc->err_mask |= AC_ERR_ATA_BUS;
|
||||||
if (err & (ATA_UNC | ATA_AMNF))
|
if (err & (ATA_UNC | ATA_AMNF))
|
||||||
@@ -1908,6 +1915,99 @@ static inline bool ata_eh_quiet(struct ata_queued_cmd *qc)
|
|||||||
return qc->flags & ATA_QCFLAG_QUIET;
|
return qc->flags & ATA_QCFLAG_QUIET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ata_eh_read_sense_success_non_ncq(struct ata_link *link)
|
||||||
|
{
|
||||||
|
struct ata_port *ap = link->ap;
|
||||||
|
struct ata_queued_cmd *qc;
|
||||||
|
|
||||||
|
qc = __ata_qc_from_tag(ap, link->active_tag);
|
||||||
|
if (!qc)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
||||||
|
!(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) ||
|
||||||
|
qc->err_mask)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (!ata_eh_request_sense(qc))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have sense data, call scsi_check_sense() in order to set the
|
||||||
|
* correct SCSI ML byte (if any). No point in checking the return value,
|
||||||
|
* since the command has already completed successfully.
|
||||||
|
*/
|
||||||
|
scsi_check_sense(qc->scsicmd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ata_eh_get_success_sense(struct ata_link *link)
|
||||||
|
{
|
||||||
|
struct ata_eh_context *ehc = &link->eh_context;
|
||||||
|
struct ata_device *dev = link->device;
|
||||||
|
struct ata_port *ap = link->ap;
|
||||||
|
struct ata_queued_cmd *qc;
|
||||||
|
int tag, ret = 0;
|
||||||
|
|
||||||
|
if (!(ehc->i.dev_action[dev->devno] & ATA_EH_GET_SUCCESS_SENSE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* if frozen, we can't do much */
|
||||||
|
if (ata_port_is_frozen(ap)) {
|
||||||
|
ata_dev_warn(dev,
|
||||||
|
"successful sense data available but port frozen\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the link has sactive set, then we have outstanding NCQ commands
|
||||||
|
* and have to read the Successful NCQ Commands log to get the sense
|
||||||
|
* data. Otherwise, we are dealing with a non-NCQ command and use
|
||||||
|
* request sense ext command to retrieve the sense data.
|
||||||
|
*/
|
||||||
|
if (link->sactive)
|
||||||
|
ret = ata_eh_read_sense_success_ncq_log(link);
|
||||||
|
else
|
||||||
|
ret = ata_eh_read_sense_success_non_ncq(link);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ata_eh_done(link, dev, ATA_EH_GET_SUCCESS_SENSE);
|
||||||
|
return;
|
||||||
|
|
||||||
|
out:
|
||||||
|
/*
|
||||||
|
* If we failed to get sense data for a successful command that ought to
|
||||||
|
* have sense data, we cannot simply return BLK_STS_OK to user space.
|
||||||
|
* This is because we can't know if the sense data that we couldn't get
|
||||||
|
* was actually "DATA CURRENTLY UNAVAILABLE". Reporting such a command
|
||||||
|
* as success to user space would result in a silent data corruption.
|
||||||
|
* Thus, add a bogus ABORTED_COMMAND sense data to such commands, such
|
||||||
|
* that SCSI will report these commands as BLK_STS_IOERR to user space.
|
||||||
|
*/
|
||||||
|
ata_qc_for_each_raw(ap, qc, tag) {
|
||||||
|
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
||||||
|
!(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) ||
|
||||||
|
qc->err_mask ||
|
||||||
|
ata_dev_phys_link(qc->dev) != link)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* We managed to get sense for this success command, skip. */
|
||||||
|
if (qc->flags & ATA_QCFLAG_SENSE_VALID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* This success command did not have any sense data, skip. */
|
||||||
|
if (!(qc->result_tf.status & ATA_SENSE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* This success command had sense data, but we failed to get. */
|
||||||
|
ata_scsi_set_sense(dev, qc->scsicmd, ABORTED_COMMAND, 0, 0);
|
||||||
|
qc->flags |= ATA_QCFLAG_SENSE_VALID;
|
||||||
|
}
|
||||||
|
ata_eh_done(link, dev, ATA_EH_GET_SUCCESS_SENSE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_eh_link_autopsy - analyze error and determine recovery action
|
* ata_eh_link_autopsy - analyze error and determine recovery action
|
||||||
* @link: host link to perform autopsy on
|
* @link: host link to perform autopsy on
|
||||||
@@ -1948,6 +2048,14 @@ static void ata_eh_link_autopsy(struct ata_link *link)
|
|||||||
/* analyze NCQ failure */
|
/* analyze NCQ failure */
|
||||||
ata_eh_analyze_ncq_error(link);
|
ata_eh_analyze_ncq_error(link);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if this was a successful command that simply needs sense data.
|
||||||
|
* Since the sense data is not part of the completion, we need to fetch
|
||||||
|
* it using an additional command. Since this can't be done from irq
|
||||||
|
* context, the sense data for successful commands are fetched by EH.
|
||||||
|
*/
|
||||||
|
ata_eh_get_success_sense(link);
|
||||||
|
|
||||||
/* any real error trumps AC_ERR_OTHER */
|
/* any real error trumps AC_ERR_OTHER */
|
||||||
if (ehc->i.err_mask & ~AC_ERR_OTHER)
|
if (ehc->i.err_mask & ~AC_ERR_OTHER)
|
||||||
ehc->i.err_mask &= ~AC_ERR_OTHER;
|
ehc->i.err_mask &= ~AC_ERR_OTHER;
|
||||||
@@ -1957,6 +2065,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
|
|||||||
ata_qc_for_each_raw(ap, qc, tag) {
|
ata_qc_for_each_raw(ap, qc, tag) {
|
||||||
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
||||||
qc->flags & ATA_QCFLAG_RETRY ||
|
qc->flags & ATA_QCFLAG_RETRY ||
|
||||||
|
qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD ||
|
||||||
ata_dev_phys_link(qc->dev) != link)
|
ata_dev_phys_link(qc->dev) != link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -3823,7 +3932,8 @@ void ata_eh_finish(struct ata_port *ap)
|
|||||||
ata_eh_qc_complete(qc);
|
ata_eh_qc_complete(qc);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
|
if (qc->flags & ATA_QCFLAG_SENSE_VALID ||
|
||||||
|
qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) {
|
||||||
ata_eh_qc_complete(qc);
|
ata_eh_qc_complete(qc);
|
||||||
} else {
|
} else {
|
||||||
/* feed zero TF to sense generation */
|
/* feed zero TF to sense generation */
|
||||||
|
|||||||
@@ -11,7 +11,9 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <scsi/scsi_cmnd.h>
|
#include <scsi/scsi_cmnd.h>
|
||||||
#include <scsi/scsi_device.h>
|
#include <scsi/scsi_device.h>
|
||||||
|
#include <scsi/scsi_eh.h>
|
||||||
#include <linux/libata.h>
|
#include <linux/libata.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#include "libata.h"
|
#include "libata.h"
|
||||||
#include "libata-transport.h"
|
#include "libata-transport.h"
|
||||||
@@ -907,10 +909,17 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device,
|
|||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input)
|
if (input) {
|
||||||
|
if (dev->flags & ATA_DFLAG_CDL_ENABLED) {
|
||||||
|
ata_dev_err(dev,
|
||||||
|
"CDL must be disabled to enable NCQ priority\n");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLED;
|
dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||||
else
|
} else {
|
||||||
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED;
|
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
spin_unlock_irq(ap->lock);
|
spin_unlock_irq(ap->lock);
|
||||||
@@ -1413,6 +1422,95 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ata_eh_read_sense_success_ncq_log - Read the sense data for successful
|
||||||
|
* NCQ commands log
|
||||||
|
* @link: ATA link to get sense data for
|
||||||
|
*
|
||||||
|
* Read the sense data for successful NCQ commands log page to obtain
|
||||||
|
* sense data for all NCQ commands that completed successfully with
|
||||||
|
* the sense data available bit set.
|
||||||
|
*
|
||||||
|
* LOCKING:
|
||||||
|
* Kernel thread context (may sleep).
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success, -errno otherwise.
|
||||||
|
*/
|
||||||
|
int ata_eh_read_sense_success_ncq_log(struct ata_link *link)
|
||||||
|
{
|
||||||
|
struct ata_device *dev = link->device;
|
||||||
|
struct ata_port *ap = dev->link->ap;
|
||||||
|
u8 *buf = ap->ncq_sense_buf;
|
||||||
|
struct ata_queued_cmd *qc;
|
||||||
|
unsigned int err_mask, tag;
|
||||||
|
u8 *sense, sk = 0, asc = 0, ascq = 0;
|
||||||
|
u64 sense_valid, val;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
err_mask = ata_read_log_page(dev, ATA_LOG_SENSE_NCQ, 0, buf, 2);
|
||||||
|
if (err_mask) {
|
||||||
|
ata_dev_err(dev,
|
||||||
|
"Failed to read Sense Data for Successful NCQ Commands log\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the log header */
|
||||||
|
val = get_unaligned_le64(&buf[0]);
|
||||||
|
if ((val & 0xffff) != 1 || ((val >> 16) & 0xff) != 0x0f) {
|
||||||
|
ata_dev_err(dev,
|
||||||
|
"Invalid Sense Data for Successful NCQ Commands log\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
sense_valid = (u64)buf[8] | ((u64)buf[9] << 8) |
|
||||||
|
((u64)buf[10] << 16) | ((u64)buf[11] << 24);
|
||||||
|
|
||||||
|
ata_qc_for_each_raw(ap, qc, tag) {
|
||||||
|
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
||||||
|
!(qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD) ||
|
||||||
|
qc->err_mask ||
|
||||||
|
ata_dev_phys_link(qc->dev) != link)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the command does not have any sense data, clear ATA_SENSE.
|
||||||
|
* Keep ATA_QCFLAG_EH_SUCCESS_CMD so that command is finished.
|
||||||
|
*/
|
||||||
|
if (!(sense_valid & (1ULL << tag))) {
|
||||||
|
qc->result_tf.status &= ~ATA_SENSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sense = &buf[32 + 24 * tag];
|
||||||
|
sk = sense[0];
|
||||||
|
asc = sense[1];
|
||||||
|
ascq = sense[2];
|
||||||
|
|
||||||
|
if (!ata_scsi_sense_is_valid(sk, asc, ascq)) {
|
||||||
|
ret = -EIO;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set sense without also setting scsicmd->result */
|
||||||
|
scsi_build_sense_buffer(dev->flags & ATA_DFLAG_D_SENSE,
|
||||||
|
qc->scsicmd->sense_buffer, sk,
|
||||||
|
asc, ascq);
|
||||||
|
qc->flags |= ATA_QCFLAG_SENSE_VALID;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have sense data, call scsi_check_sense() in order to
|
||||||
|
* set the correct SCSI ML byte (if any). No point in checking
|
||||||
|
* the return value, since the command has already completed
|
||||||
|
* successfully.
|
||||||
|
*/
|
||||||
|
scsi_check_sense(qc->scsicmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ata_eh_read_sense_success_ncq_log);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_eh_analyze_ncq_error - analyze NCQ error
|
* ata_eh_analyze_ncq_error - analyze NCQ error
|
||||||
* @link: ATA link to analyze NCQ error for
|
* @link: ATA link to analyze NCQ error for
|
||||||
@@ -1493,6 +1591,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
|
|||||||
|
|
||||||
ata_qc_for_each_raw(ap, qc, tag) {
|
ata_qc_for_each_raw(ap, qc, tag) {
|
||||||
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
||||||
|
qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD ||
|
||||||
ata_dev_phys_link(qc->dev) != link)
|
ata_dev_phys_link(qc->dev) != link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#include "libata.h"
|
#include "libata.h"
|
||||||
#include "libata-transport.h"
|
#include "libata-transport.h"
|
||||||
|
|
||||||
#define ATA_SCSI_RBUF_SIZE 576
|
#define ATA_SCSI_RBUF_SIZE 2048
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
|
static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
|
||||||
static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];
|
static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];
|
||||||
@@ -47,15 +47,19 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
|
|||||||
static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
|
static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
|
||||||
const struct scsi_device *scsidev);
|
const struct scsi_device *scsidev);
|
||||||
|
|
||||||
#define RW_RECOVERY_MPAGE 0x1
|
#define RW_RECOVERY_MPAGE 0x1
|
||||||
#define RW_RECOVERY_MPAGE_LEN 12
|
#define RW_RECOVERY_MPAGE_LEN 12
|
||||||
#define CACHE_MPAGE 0x8
|
#define CACHE_MPAGE 0x8
|
||||||
#define CACHE_MPAGE_LEN 20
|
#define CACHE_MPAGE_LEN 20
|
||||||
#define CONTROL_MPAGE 0xa
|
#define CONTROL_MPAGE 0xa
|
||||||
#define CONTROL_MPAGE_LEN 12
|
#define CONTROL_MPAGE_LEN 12
|
||||||
#define ALL_MPAGES 0x3f
|
#define ALL_MPAGES 0x3f
|
||||||
#define ALL_SUB_MPAGES 0xff
|
#define ALL_SUB_MPAGES 0xff
|
||||||
|
#define CDL_T2A_SUB_MPAGE 0x07
|
||||||
|
#define CDL_T2B_SUB_MPAGE 0x08
|
||||||
|
#define CDL_T2_SUB_MPAGE_LEN 232
|
||||||
|
#define ATA_FEATURE_SUB_MPAGE 0xf2
|
||||||
|
#define ATA_FEATURE_SUB_MPAGE_LEN 16
|
||||||
|
|
||||||
static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
|
static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
|
||||||
RW_RECOVERY_MPAGE,
|
RW_RECOVERY_MPAGE,
|
||||||
@@ -209,9 +213,6 @@ void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd,
|
|||||||
{
|
{
|
||||||
bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
|
bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
|
||||||
|
|
||||||
if (!cmd)
|
|
||||||
return;
|
|
||||||
|
|
||||||
scsi_build_sense(cmd, d_sense, sk, asc, ascq);
|
scsi_build_sense(cmd, d_sense, sk, asc, ascq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,9 +222,6 @@ void ata_scsi_set_sense_information(struct ata_device *dev,
|
|||||||
{
|
{
|
||||||
u64 information;
|
u64 information;
|
||||||
|
|
||||||
if (!cmd)
|
|
||||||
return;
|
|
||||||
|
|
||||||
information = ata_tf_read_block(tf, dev);
|
information = ata_tf_read_block(tf, dev);
|
||||||
if (information == U64_MAX)
|
if (information == U64_MAX)
|
||||||
return;
|
return;
|
||||||
@@ -1382,6 +1380,18 @@ static inline void scsi_16_lba_len(const u8 *cdb, u64 *plba, u32 *plen)
|
|||||||
*plen = get_unaligned_be32(&cdb[10]);
|
*plen = get_unaligned_be32(&cdb[10]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scsi_dld - Get duration limit descriptor index
|
||||||
|
* @cdb: SCSI command to translate
|
||||||
|
*
|
||||||
|
* Returns the dld bits indicating the index of a command duration limit
|
||||||
|
* descriptor.
|
||||||
|
*/
|
||||||
|
static inline int scsi_dld(const u8 *cdb)
|
||||||
|
{
|
||||||
|
return ((cdb[1] & 0x01) << 2) | ((cdb[14] >> 6) & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
|
* ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
|
||||||
* @qc: Storage for translated ATA taskfile
|
* @qc: Storage for translated ATA taskfile
|
||||||
@@ -1550,6 +1560,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
|
|||||||
struct request *rq = scsi_cmd_to_rq(scmd);
|
struct request *rq = scsi_cmd_to_rq(scmd);
|
||||||
int class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq));
|
int class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq));
|
||||||
unsigned int tf_flags = 0;
|
unsigned int tf_flags = 0;
|
||||||
|
int dld = 0;
|
||||||
u64 block;
|
u64 block;
|
||||||
u32 n_block;
|
u32 n_block;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -1600,6 +1611,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
|
|||||||
goto invalid_fld;
|
goto invalid_fld;
|
||||||
}
|
}
|
||||||
scsi_16_lba_len(cdb, &block, &n_block);
|
scsi_16_lba_len(cdb, &block, &n_block);
|
||||||
|
dld = scsi_dld(cdb);
|
||||||
if (cdb[1] & (1 << 3))
|
if (cdb[1] & (1 << 3))
|
||||||
tf_flags |= ATA_TFLAG_FUA;
|
tf_flags |= ATA_TFLAG_FUA;
|
||||||
if (!ata_check_nblocks(scmd, n_block))
|
if (!ata_check_nblocks(scmd, n_block))
|
||||||
@@ -1624,7 +1636,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
|
|||||||
qc->flags |= ATA_QCFLAG_IO;
|
qc->flags |= ATA_QCFLAG_IO;
|
||||||
qc->nbytes = n_block * scmd->device->sector_size;
|
qc->nbytes = n_block * scmd->device->sector_size;
|
||||||
|
|
||||||
rc = ata_build_rw_tf(qc, block, n_block, tf_flags, class);
|
rc = ata_build_rw_tf(qc, block, n_block, tf_flags, dld, class);
|
||||||
if (likely(rc == 0))
|
if (likely(rc == 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -2203,10 +2215,123 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
|
|||||||
return sizeof(def_cache_mpage);
|
return sizeof(def_cache_mpage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simulate MODE SENSE control mode page, sub-page 0.
|
||||||
|
*/
|
||||||
|
static unsigned int ata_msense_control_spg0(struct ata_device *dev, u8 *buf,
|
||||||
|
bool changeable)
|
||||||
|
{
|
||||||
|
modecpy(buf, def_control_mpage,
|
||||||
|
sizeof(def_control_mpage), changeable);
|
||||||
|
if (changeable) {
|
||||||
|
/* ata_mselect_control() */
|
||||||
|
buf[2] |= (1 << 2);
|
||||||
|
} else {
|
||||||
|
bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
|
||||||
|
|
||||||
|
/* descriptor format sense data */
|
||||||
|
buf[2] |= (d_sense << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sizeof(def_control_mpage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate an ATA duration limit in microseconds to a SCSI duration limit
|
||||||
|
* using the t2cdlunits 0xa (10ms). Since the SCSI duration limits are 2-bytes
|
||||||
|
* only, take care of overflows.
|
||||||
|
*/
|
||||||
|
static inline u16 ata_xlat_cdl_limit(u8 *buf)
|
||||||
|
{
|
||||||
|
u32 limit = get_unaligned_le32(buf);
|
||||||
|
|
||||||
|
return min_t(u32, limit / 10000, 65535);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simulate MODE SENSE control mode page, sub-pages 07h and 08h
|
||||||
|
* (command duration limits T2A and T2B mode pages).
|
||||||
|
*/
|
||||||
|
static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf,
|
||||||
|
u8 spg)
|
||||||
|
{
|
||||||
|
u8 *b, *cdl = dev->cdl, *desc;
|
||||||
|
u32 policy;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill the subpage. The first four bytes of the T2A/T2B mode pages
|
||||||
|
* are a header. The PAGE LENGTH field is the size of the page
|
||||||
|
* excluding the header.
|
||||||
|
*/
|
||||||
|
buf[0] = CONTROL_MPAGE;
|
||||||
|
buf[1] = spg;
|
||||||
|
put_unaligned_be16(CDL_T2_SUB_MPAGE_LEN - 4, &buf[2]);
|
||||||
|
if (spg == CDL_T2A_SUB_MPAGE) {
|
||||||
|
/*
|
||||||
|
* Read descriptors map to the T2A page:
|
||||||
|
* set perf_vs_duration_guidleine.
|
||||||
|
*/
|
||||||
|
buf[7] = (cdl[0] & 0x03) << 4;
|
||||||
|
desc = cdl + 64;
|
||||||
|
} else {
|
||||||
|
/* Write descriptors map to the T2B page */
|
||||||
|
desc = cdl + 288;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the T2 page descriptors */
|
||||||
|
b = &buf[8];
|
||||||
|
policy = get_unaligned_le32(&cdl[0]);
|
||||||
|
for (i = 0; i < 7; i++, b += 32, desc += 32) {
|
||||||
|
/* t2cdlunits: fixed to 10ms */
|
||||||
|
b[0] = 0x0a;
|
||||||
|
|
||||||
|
/* Max inactive time and its policy */
|
||||||
|
put_unaligned_be16(ata_xlat_cdl_limit(&desc[8]), &b[2]);
|
||||||
|
b[6] = ((policy >> 8) & 0x0f) << 4;
|
||||||
|
|
||||||
|
/* Max active time and its policy */
|
||||||
|
put_unaligned_be16(ata_xlat_cdl_limit(&desc[4]), &b[4]);
|
||||||
|
b[6] |= (policy >> 4) & 0x0f;
|
||||||
|
|
||||||
|
/* Command duration guideline and its policy */
|
||||||
|
put_unaligned_be16(ata_xlat_cdl_limit(&desc[16]), &b[10]);
|
||||||
|
b[14] = policy & 0x0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CDL_T2_SUB_MPAGE_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simulate MODE SENSE control mode page, sub-page f2h
|
||||||
|
* (ATA feature control mode page).
|
||||||
|
*/
|
||||||
|
static unsigned int ata_msense_control_ata_feature(struct ata_device *dev,
|
||||||
|
u8 *buf)
|
||||||
|
{
|
||||||
|
/* PS=0, SPF=1 */
|
||||||
|
buf[0] = CONTROL_MPAGE | (1 << 6);
|
||||||
|
buf[1] = ATA_FEATURE_SUB_MPAGE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The first four bytes of ATA Feature Control mode page are a header.
|
||||||
|
* The PAGE LENGTH field is the size of the page excluding the header.
|
||||||
|
*/
|
||||||
|
put_unaligned_be16(ATA_FEATURE_SUB_MPAGE_LEN - 4, &buf[2]);
|
||||||
|
|
||||||
|
if (dev->flags & ATA_DFLAG_CDL)
|
||||||
|
buf[4] = 0x02; /* Support T2A and T2B pages */
|
||||||
|
else
|
||||||
|
buf[4] = 0;
|
||||||
|
|
||||||
|
return ATA_FEATURE_SUB_MPAGE_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_msense_control - Simulate MODE SENSE control mode page
|
* ata_msense_control - Simulate MODE SENSE control mode page
|
||||||
* @dev: ATA device of interest
|
* @dev: ATA device of interest
|
||||||
* @buf: output buffer
|
* @buf: output buffer
|
||||||
|
* @spg: sub-page code
|
||||||
* @changeable: whether changeable parameters are requested
|
* @changeable: whether changeable parameters are requested
|
||||||
*
|
*
|
||||||
* Generate a generic MODE SENSE control mode page.
|
* Generate a generic MODE SENSE control mode page.
|
||||||
@@ -2215,17 +2340,27 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
|
|||||||
* None.
|
* None.
|
||||||
*/
|
*/
|
||||||
static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf,
|
static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf,
|
||||||
bool changeable)
|
u8 spg, bool changeable)
|
||||||
{
|
{
|
||||||
modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable);
|
unsigned int n;
|
||||||
if (changeable) {
|
|
||||||
buf[2] |= (1 << 2); /* ata_mselect_control() */
|
|
||||||
} else {
|
|
||||||
bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
|
|
||||||
|
|
||||||
buf[2] |= (d_sense << 2); /* descriptor format sense data */
|
switch (spg) {
|
||||||
|
case 0:
|
||||||
|
return ata_msense_control_spg0(dev, buf, changeable);
|
||||||
|
case CDL_T2A_SUB_MPAGE:
|
||||||
|
case CDL_T2B_SUB_MPAGE:
|
||||||
|
return ata_msense_control_spgt2(dev, buf, spg);
|
||||||
|
case ATA_FEATURE_SUB_MPAGE:
|
||||||
|
return ata_msense_control_ata_feature(dev, buf);
|
||||||
|
case ALL_SUB_MPAGES:
|
||||||
|
n = ata_msense_control_spg0(dev, buf, changeable);
|
||||||
|
n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE);
|
||||||
|
n += ata_msense_control_spgt2(dev, buf + n, CDL_T2A_SUB_MPAGE);
|
||||||
|
n += ata_msense_control_ata_feature(dev, buf + n);
|
||||||
|
return n;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return sizeof(def_control_mpage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2298,13 +2433,25 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
|
|||||||
|
|
||||||
pg = scsicmd[2] & 0x3f;
|
pg = scsicmd[2] & 0x3f;
|
||||||
spg = scsicmd[3];
|
spg = scsicmd[3];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No mode subpages supported (yet) but asking for _all_
|
* Supported subpages: all subpages and sub-pages 07h, 08h and f2h of
|
||||||
* subpages may be valid
|
* the control page.
|
||||||
*/
|
*/
|
||||||
if (spg && (spg != ALL_SUB_MPAGES)) {
|
if (spg) {
|
||||||
fp = 3;
|
switch (spg) {
|
||||||
goto invalid_fld;
|
case ALL_SUB_MPAGES:
|
||||||
|
break;
|
||||||
|
case CDL_T2A_SUB_MPAGE:
|
||||||
|
case CDL_T2B_SUB_MPAGE:
|
||||||
|
case ATA_FEATURE_SUB_MPAGE:
|
||||||
|
if (dev->flags & ATA_DFLAG_CDL && pg == CONTROL_MPAGE)
|
||||||
|
break;
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
fp = 3;
|
||||||
|
goto invalid_fld;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(pg) {
|
switch(pg) {
|
||||||
@@ -2317,13 +2464,13 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CONTROL_MPAGE:
|
case CONTROL_MPAGE:
|
||||||
p += ata_msense_control(args->dev, p, page_control == 1);
|
p += ata_msense_control(args->dev, p, spg, page_control == 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALL_MPAGES:
|
case ALL_MPAGES:
|
||||||
p += ata_msense_rw_recovery(p, page_control == 1);
|
p += ata_msense_rw_recovery(p, page_control == 1);
|
||||||
p += ata_msense_caching(args->id, p, page_control == 1);
|
p += ata_msense_caching(args->id, p, page_control == 1);
|
||||||
p += ata_msense_control(args->dev, p, page_control == 1);
|
p += ata_msense_control(args->dev, p, spg, page_control == 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* invalid page code */
|
default: /* invalid page code */
|
||||||
@@ -2342,10 +2489,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
|
|||||||
memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc));
|
memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned int output_len = p - rbuf - 2;
|
put_unaligned_be16(p - rbuf - 2, &rbuf[0]);
|
||||||
|
|
||||||
rbuf[0] = output_len >> 8;
|
|
||||||
rbuf[1] = output_len;
|
|
||||||
rbuf[3] |= dpofua;
|
rbuf[3] |= dpofua;
|
||||||
if (ebd) {
|
if (ebd) {
|
||||||
rbuf[7] = sizeof(sat_blk_desc);
|
rbuf[7] = sizeof(sat_blk_desc);
|
||||||
@@ -3260,7 +3404,7 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
|
|||||||
{
|
{
|
||||||
struct ata_device *dev = args->dev;
|
struct ata_device *dev = args->dev;
|
||||||
u8 *cdb = args->cmd->cmnd;
|
u8 *cdb = args->cmd->cmnd;
|
||||||
u8 supported = 0;
|
u8 supported = 0, cdlp = 0, rwcdlp = 0;
|
||||||
unsigned int err = 0;
|
unsigned int err = 0;
|
||||||
|
|
||||||
if (cdb[2] != 1 && cdb[2] != 3) {
|
if (cdb[2] != 1 && cdb[2] != 3) {
|
||||||
@@ -3287,10 +3431,8 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
|
|||||||
case MAINTENANCE_IN:
|
case MAINTENANCE_IN:
|
||||||
case READ_6:
|
case READ_6:
|
||||||
case READ_10:
|
case READ_10:
|
||||||
case READ_16:
|
|
||||||
case WRITE_6:
|
case WRITE_6:
|
||||||
case WRITE_10:
|
case WRITE_10:
|
||||||
case WRITE_16:
|
|
||||||
case ATA_12:
|
case ATA_12:
|
||||||
case ATA_16:
|
case ATA_16:
|
||||||
case VERIFY:
|
case VERIFY:
|
||||||
@@ -3300,6 +3442,28 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
|
|||||||
case START_STOP:
|
case START_STOP:
|
||||||
supported = 3;
|
supported = 3;
|
||||||
break;
|
break;
|
||||||
|
case READ_16:
|
||||||
|
supported = 3;
|
||||||
|
if (dev->flags & ATA_DFLAG_CDL) {
|
||||||
|
/*
|
||||||
|
* CDL read descriptors map to the T2A page, that is,
|
||||||
|
* rwcdlp = 0x01 and cdlp = 0x01
|
||||||
|
*/
|
||||||
|
rwcdlp = 0x01;
|
||||||
|
cdlp = 0x01 << 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WRITE_16:
|
||||||
|
supported = 3;
|
||||||
|
if (dev->flags & ATA_DFLAG_CDL) {
|
||||||
|
/*
|
||||||
|
* CDL write descriptors map to the T2B page, that is,
|
||||||
|
* rwcdlp = 0x01 and cdlp = 0x02
|
||||||
|
*/
|
||||||
|
rwcdlp = 0x01;
|
||||||
|
cdlp = 0x02 << 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ZBC_IN:
|
case ZBC_IN:
|
||||||
case ZBC_OUT:
|
case ZBC_OUT:
|
||||||
if (ata_id_zoned_cap(dev->id) ||
|
if (ata_id_zoned_cap(dev->id) ||
|
||||||
@@ -3315,7 +3479,9 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
rbuf[1] = supported; /* supported */
|
/* One command format */
|
||||||
|
rbuf[0] = rwcdlp;
|
||||||
|
rbuf[1] = cdlp | supported;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3605,20 +3771,11 @@ static int ata_mselect_caching(struct ata_queued_cmd *qc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* ata_mselect_control - Simulate MODE SELECT for control page
|
* Simulate MODE SELECT control mode page, sub-page 0.
|
||||||
* @qc: Storage for translated ATA taskfile
|
|
||||||
* @buf: input buffer
|
|
||||||
* @len: number of valid bytes in the input buffer
|
|
||||||
* @fp: out parameter for the failed field on error
|
|
||||||
*
|
|
||||||
* Prepare a taskfile to modify caching information for the device.
|
|
||||||
*
|
|
||||||
* LOCKING:
|
|
||||||
* None.
|
|
||||||
*/
|
*/
|
||||||
static int ata_mselect_control(struct ata_queued_cmd *qc,
|
static int ata_mselect_control_spg0(struct ata_queued_cmd *qc,
|
||||||
const u8 *buf, int len, u16 *fp)
|
const u8 *buf, int len, u16 *fp)
|
||||||
{
|
{
|
||||||
struct ata_device *dev = qc->dev;
|
struct ata_device *dev = qc->dev;
|
||||||
u8 mpage[CONTROL_MPAGE_LEN];
|
u8 mpage[CONTROL_MPAGE_LEN];
|
||||||
@@ -3640,7 +3797,7 @@ static int ata_mselect_control(struct ata_queued_cmd *qc,
|
|||||||
/*
|
/*
|
||||||
* Check that read-only bits are not modified.
|
* Check that read-only bits are not modified.
|
||||||
*/
|
*/
|
||||||
ata_msense_control(dev, mpage, false);
|
ata_msense_control_spg0(dev, mpage, false);
|
||||||
for (i = 0; i < CONTROL_MPAGE_LEN - 2; i++) {
|
for (i = 0; i < CONTROL_MPAGE_LEN - 2; i++) {
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -3656,6 +3813,84 @@ static int ata_mselect_control(struct ata_queued_cmd *qc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate MODE SELECT control mode page, sub-pages f2h (ATA feature mode
|
||||||
|
* page) into a SET FEATURES command.
|
||||||
|
*/
|
||||||
|
static unsigned int ata_mselect_control_ata_feature(struct ata_queued_cmd *qc,
|
||||||
|
const u8 *buf, int len,
|
||||||
|
u16 *fp)
|
||||||
|
{
|
||||||
|
struct ata_device *dev = qc->dev;
|
||||||
|
struct ata_taskfile *tf = &qc->tf;
|
||||||
|
u8 cdl_action;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The first four bytes of ATA Feature Control mode page are a header,
|
||||||
|
* so offsets in mpage are off by 4 compared to buf. Same for len.
|
||||||
|
*/
|
||||||
|
if (len != ATA_FEATURE_SUB_MPAGE_LEN - 4) {
|
||||||
|
*fp = min(len, ATA_FEATURE_SUB_MPAGE_LEN - 4);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check cdl_ctrl */
|
||||||
|
switch (buf[0] & 0x03) {
|
||||||
|
case 0:
|
||||||
|
/* Disable CDL */
|
||||||
|
cdl_action = 0;
|
||||||
|
dev->flags &= ~ATA_DFLAG_CDL_ENABLED;
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
/* Enable CDL T2A/T2B: NCQ priority must be disabled */
|
||||||
|
if (dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLED) {
|
||||||
|
ata_dev_err(dev,
|
||||||
|
"NCQ priority must be disabled to enable CDL\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
cdl_action = 1;
|
||||||
|
dev->flags |= ATA_DFLAG_CDL_ENABLED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*fp = 0;
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
|
||||||
|
tf->protocol = ATA_PROT_NODATA;
|
||||||
|
tf->command = ATA_CMD_SET_FEATURES;
|
||||||
|
tf->feature = SETFEATURES_CDL;
|
||||||
|
tf->nsect = cdl_action;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ata_mselect_control - Simulate MODE SELECT for control page
|
||||||
|
* @qc: Storage for translated ATA taskfile
|
||||||
|
* @spg: target sub-page of the control page
|
||||||
|
* @buf: input buffer
|
||||||
|
* @len: number of valid bytes in the input buffer
|
||||||
|
* @fp: out parameter for the failed field on error
|
||||||
|
*
|
||||||
|
* Prepare a taskfile to modify caching information for the device.
|
||||||
|
*
|
||||||
|
* LOCKING:
|
||||||
|
* None.
|
||||||
|
*/
|
||||||
|
static int ata_mselect_control(struct ata_queued_cmd *qc, u8 spg,
|
||||||
|
const u8 *buf, int len, u16 *fp)
|
||||||
|
{
|
||||||
|
switch (spg) {
|
||||||
|
case 0:
|
||||||
|
return ata_mselect_control_spg0(qc, buf, len, fp);
|
||||||
|
case ATA_FEATURE_SUB_MPAGE:
|
||||||
|
return ata_mselect_control_ata_feature(qc, buf, len, fp);
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_scsi_mode_select_xlat - Simulate MODE SELECT 6, 10 commands
|
* ata_scsi_mode_select_xlat - Simulate MODE SELECT 6, 10 commands
|
||||||
* @qc: Storage for translated ATA taskfile
|
* @qc: Storage for translated ATA taskfile
|
||||||
@@ -3673,7 +3908,7 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
|
|||||||
const u8 *cdb = scmd->cmnd;
|
const u8 *cdb = scmd->cmnd;
|
||||||
u8 pg, spg;
|
u8 pg, spg;
|
||||||
unsigned six_byte, pg_len, hdr_len, bd_len;
|
unsigned six_byte, pg_len, hdr_len, bd_len;
|
||||||
int len;
|
int len, ret;
|
||||||
u16 fp = (u16)-1;
|
u16 fp = (u16)-1;
|
||||||
u8 bp = 0xff;
|
u8 bp = 0xff;
|
||||||
u8 buffer[64];
|
u8 buffer[64];
|
||||||
@@ -3758,13 +3993,29 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No mode subpages supported (yet) but asking for _all_
|
* Supported subpages: all subpages and ATA feature sub-page f2h of
|
||||||
* subpages may be valid
|
* the control page.
|
||||||
*/
|
*/
|
||||||
if (spg && (spg != ALL_SUB_MPAGES)) {
|
if (spg) {
|
||||||
fp = (p[0] & 0x40) ? 1 : 0;
|
switch (spg) {
|
||||||
fp += hdr_len + bd_len;
|
case ALL_SUB_MPAGES:
|
||||||
goto invalid_param;
|
/* All subpages is not supported for the control page */
|
||||||
|
if (pg == CONTROL_MPAGE) {
|
||||||
|
fp = (p[0] & 0x40) ? 1 : 0;
|
||||||
|
fp += hdr_len + bd_len;
|
||||||
|
goto invalid_param;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ATA_FEATURE_SUB_MPAGE:
|
||||||
|
if (qc->dev->flags & ATA_DFLAG_CDL &&
|
||||||
|
pg == CONTROL_MPAGE)
|
||||||
|
break;
|
||||||
|
fallthrough;
|
||||||
|
default:
|
||||||
|
fp = (p[0] & 0x40) ? 1 : 0;
|
||||||
|
fp += hdr_len + bd_len;
|
||||||
|
goto invalid_param;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (pg_len > len)
|
if (pg_len > len)
|
||||||
goto invalid_param_len;
|
goto invalid_param_len;
|
||||||
@@ -3777,14 +4028,16 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CONTROL_MPAGE:
|
case CONTROL_MPAGE:
|
||||||
if (ata_mselect_control(qc, p, pg_len, &fp) < 0) {
|
ret = ata_mselect_control(qc, spg, p, pg_len, &fp);
|
||||||
|
if (ret < 0) {
|
||||||
fp += hdr_len + bd_len;
|
fp += hdr_len + bd_len;
|
||||||
goto invalid_param;
|
goto invalid_param;
|
||||||
} else {
|
|
||||||
goto skip; /* No ATA command to send */
|
|
||||||
}
|
}
|
||||||
|
if (!ret)
|
||||||
|
goto skip; /* No ATA command to send */
|
||||||
break;
|
break;
|
||||||
default: /* invalid page code */
|
default:
|
||||||
|
/* Invalid page code */
|
||||||
fp = bd_len + hdr_len;
|
fp = bd_len + hdr_len;
|
||||||
goto invalid_param;
|
goto invalid_param;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ static inline void ata_force_cbl(struct ata_port *ap) { }
|
|||||||
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
||||||
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
|
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
|
||||||
extern int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
|
extern int ata_build_rw_tf(struct ata_queued_cmd *qc, u64 block, u32 n_block,
|
||||||
unsigned int tf_flags, int class);
|
unsigned int tf_flags, int dld, int class);
|
||||||
extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
|
extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
|
||||||
struct ata_device *dev);
|
struct ata_device *dev);
|
||||||
extern unsigned ata_exec_internal(struct ata_device *dev,
|
extern unsigned ata_exec_internal(struct ata_device *dev,
|
||||||
|
|||||||
@@ -3143,6 +3143,8 @@ struct dm_pr {
|
|||||||
bool fail_early;
|
bool fail_early;
|
||||||
int ret;
|
int ret;
|
||||||
enum pr_type type;
|
enum pr_type type;
|
||||||
|
struct pr_keys *read_keys;
|
||||||
|
struct pr_held_reservation *rsv;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dm_call_pr(struct block_device *bdev, iterate_devices_callout_fn fn,
|
static int dm_call_pr(struct block_device *bdev, iterate_devices_callout_fn fn,
|
||||||
@@ -3375,12 +3377,79 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __dm_pr_read_keys(struct dm_target *ti, struct dm_dev *dev,
|
||||||
|
sector_t start, sector_t len, void *data)
|
||||||
|
{
|
||||||
|
struct dm_pr *pr = data;
|
||||||
|
const struct pr_ops *ops = dev->bdev->bd_disk->fops->pr_ops;
|
||||||
|
|
||||||
|
if (!ops || !ops->pr_read_keys) {
|
||||||
|
pr->ret = -EOPNOTSUPP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr->ret = ops->pr_read_keys(dev->bdev, pr->read_keys);
|
||||||
|
if (!pr->ret)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dm_pr_read_keys(struct block_device *bdev, struct pr_keys *keys)
|
||||||
|
{
|
||||||
|
struct dm_pr pr = {
|
||||||
|
.read_keys = keys,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = dm_call_pr(bdev, __dm_pr_read_keys, &pr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return pr.ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __dm_pr_read_reservation(struct dm_target *ti, struct dm_dev *dev,
|
||||||
|
sector_t start, sector_t len, void *data)
|
||||||
|
{
|
||||||
|
struct dm_pr *pr = data;
|
||||||
|
const struct pr_ops *ops = dev->bdev->bd_disk->fops->pr_ops;
|
||||||
|
|
||||||
|
if (!ops || !ops->pr_read_reservation) {
|
||||||
|
pr->ret = -EOPNOTSUPP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr->ret = ops->pr_read_reservation(dev->bdev, pr->rsv);
|
||||||
|
if (!pr->ret)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dm_pr_read_reservation(struct block_device *bdev,
|
||||||
|
struct pr_held_reservation *rsv)
|
||||||
|
{
|
||||||
|
struct dm_pr pr = {
|
||||||
|
.rsv = rsv,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = dm_call_pr(bdev, __dm_pr_read_reservation, &pr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return pr.ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct pr_ops dm_pr_ops = {
|
static const struct pr_ops dm_pr_ops = {
|
||||||
.pr_register = dm_pr_register,
|
.pr_register = dm_pr_register,
|
||||||
.pr_reserve = dm_pr_reserve,
|
.pr_reserve = dm_pr_reserve,
|
||||||
.pr_release = dm_pr_release,
|
.pr_release = dm_pr_release,
|
||||||
.pr_preempt = dm_pr_preempt,
|
.pr_preempt = dm_pr_preempt,
|
||||||
.pr_clear = dm_pr_clear,
|
.pr_clear = dm_pr_clear,
|
||||||
|
.pr_read_keys = dm_pr_read_keys,
|
||||||
|
.pr_read_reservation = dm_pr_read_reservation,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct block_device_operations dm_blk_dops = {
|
static const struct block_device_operations dm_blk_dops = {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
menuconfig FUSION
|
menuconfig FUSION
|
||||||
bool "Fusion MPT device support"
|
bool "Fusion MPT device support"
|
||||||
depends on PCI
|
depends on PCI && HAS_IOPORT
|
||||||
help
|
help
|
||||||
Say Y here to get to see options for Fusion Message
|
Say Y here to get to see options for Fusion Message
|
||||||
Passing Technology (MPT) drivers.
|
Passing Technology (MPT) drivers.
|
||||||
|
|||||||
@@ -712,7 +712,7 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
|
|||||||
MptDriverClass[cb_idx] = dclass;
|
MptDriverClass[cb_idx] = dclass;
|
||||||
MptEvHandlers[cb_idx] = NULL;
|
MptEvHandlers[cb_idx] = NULL;
|
||||||
last_drv_idx = cb_idx;
|
last_drv_idx = cb_idx;
|
||||||
strlcpy(MptCallbacksName[cb_idx], func_name,
|
strscpy(MptCallbacksName[cb_idx], func_name,
|
||||||
MPT_MAX_CALLBACKNAME_LEN+1);
|
MPT_MAX_CALLBACKNAME_LEN+1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -7666,7 +7666,7 @@ mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ds)
|
if (ds)
|
||||||
strlcpy(evStr, ds, EVENT_DESCR_STR_SZ);
|
strscpy(evStr, ds, EVENT_DESCR_STR_SZ);
|
||||||
|
|
||||||
|
|
||||||
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||||
|
|||||||
@@ -2408,7 +2408,7 @@ mptctl_hp_hostinfo(MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size)
|
|||||||
if (mpt_config(ioc, &cfg) == 0) {
|
if (mpt_config(ioc, &cfg) == 0) {
|
||||||
ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
|
ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
|
||||||
if (strlen(pdata->BoardTracerNumber) > 1) {
|
if (strlen(pdata->BoardTracerNumber) > 1) {
|
||||||
strlcpy(karg.serial_number,
|
strscpy(karg.serial_number,
|
||||||
pdata->BoardTracerNumber, 24);
|
pdata->BoardTracerNumber, 24);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ obj-$(CONFIG_NVME_FC) += nvme-fc.o
|
|||||||
obj-$(CONFIG_NVME_TCP) += nvme-tcp.o
|
obj-$(CONFIG_NVME_TCP) += nvme-tcp.o
|
||||||
obj-$(CONFIG_NVME_APPLE) += nvme-apple.o
|
obj-$(CONFIG_NVME_APPLE) += nvme-apple.o
|
||||||
|
|
||||||
nvme-core-y += core.o ioctl.o sysfs.o
|
nvme-core-y += core.o ioctl.o sysfs.o pr.o
|
||||||
nvme-core-$(CONFIG_NVME_VERBOSE_ERRORS) += constants.o
|
nvme-core-$(CONFIG_NVME_VERBOSE_ERRORS) += constants.o
|
||||||
nvme-core-$(CONFIG_TRACING) += trace.o
|
nvme-core-$(CONFIG_TRACING) += trace.o
|
||||||
nvme-core-$(CONFIG_NVME_MULTIPATH) += multipath.o
|
nvme-core-$(CONFIG_NVME_MULTIPATH) += multipath.o
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ static blk_status_t nvme_error_status(u16 status)
|
|||||||
case NVME_SC_INVALID_PI:
|
case NVME_SC_INVALID_PI:
|
||||||
return BLK_STS_PROTECTION;
|
return BLK_STS_PROTECTION;
|
||||||
case NVME_SC_RESERVATION_CONFLICT:
|
case NVME_SC_RESERVATION_CONFLICT:
|
||||||
return BLK_STS_NEXUS;
|
return BLK_STS_RESV_CONFLICT;
|
||||||
case NVME_SC_HOST_PATH_ERROR:
|
case NVME_SC_HOST_PATH_ERROR:
|
||||||
return BLK_STS_TRANSPORT;
|
return BLK_STS_TRANSPORT;
|
||||||
case NVME_SC_ZONE_TOO_MANY_ACTIVE:
|
case NVME_SC_ZONE_TOO_MANY_ACTIVE:
|
||||||
@@ -2105,153 +2105,6 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char nvme_pr_type(enum pr_type type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case PR_WRITE_EXCLUSIVE:
|
|
||||||
return 1;
|
|
||||||
case PR_EXCLUSIVE_ACCESS:
|
|
||||||
return 2;
|
|
||||||
case PR_WRITE_EXCLUSIVE_REG_ONLY:
|
|
||||||
return 3;
|
|
||||||
case PR_EXCLUSIVE_ACCESS_REG_ONLY:
|
|
||||||
return 4;
|
|
||||||
case PR_WRITE_EXCLUSIVE_ALL_REGS:
|
|
||||||
return 5;
|
|
||||||
case PR_EXCLUSIVE_ACCESS_ALL_REGS:
|
|
||||||
return 6;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_send_ns_head_pr_command(struct block_device *bdev,
|
|
||||||
struct nvme_command *c, u8 data[16])
|
|
||||||
{
|
|
||||||
struct nvme_ns_head *head = bdev->bd_disk->private_data;
|
|
||||||
int srcu_idx = srcu_read_lock(&head->srcu);
|
|
||||||
struct nvme_ns *ns = nvme_find_path(head);
|
|
||||||
int ret = -EWOULDBLOCK;
|
|
||||||
|
|
||||||
if (ns) {
|
|
||||||
c->common.nsid = cpu_to_le32(ns->head->ns_id);
|
|
||||||
ret = nvme_submit_sync_cmd(ns->queue, c, data, 16);
|
|
||||||
}
|
|
||||||
srcu_read_unlock(&head->srcu, srcu_idx);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_send_ns_pr_command(struct nvme_ns *ns, struct nvme_command *c,
|
|
||||||
u8 data[16])
|
|
||||||
{
|
|
||||||
c->common.nsid = cpu_to_le32(ns->head->ns_id);
|
|
||||||
return nvme_submit_sync_cmd(ns->queue, c, data, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_sc_to_pr_err(int nvme_sc)
|
|
||||||
{
|
|
||||||
if (nvme_is_path_error(nvme_sc))
|
|
||||||
return PR_STS_PATH_FAILED;
|
|
||||||
|
|
||||||
switch (nvme_sc) {
|
|
||||||
case NVME_SC_SUCCESS:
|
|
||||||
return PR_STS_SUCCESS;
|
|
||||||
case NVME_SC_RESERVATION_CONFLICT:
|
|
||||||
return PR_STS_RESERVATION_CONFLICT;
|
|
||||||
case NVME_SC_ONCS_NOT_SUPPORTED:
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
case NVME_SC_BAD_ATTRIBUTES:
|
|
||||||
case NVME_SC_INVALID_OPCODE:
|
|
||||||
case NVME_SC_INVALID_FIELD:
|
|
||||||
case NVME_SC_INVALID_NS:
|
|
||||||
return -EINVAL;
|
|
||||||
default:
|
|
||||||
return PR_STS_IOERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
|
|
||||||
u64 key, u64 sa_key, u8 op)
|
|
||||||
{
|
|
||||||
struct nvme_command c = { };
|
|
||||||
u8 data[16] = { 0, };
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
put_unaligned_le64(key, &data[0]);
|
|
||||||
put_unaligned_le64(sa_key, &data[8]);
|
|
||||||
|
|
||||||
c.common.opcode = op;
|
|
||||||
c.common.cdw10 = cpu_to_le32(cdw10);
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
|
|
||||||
bdev->bd_disk->fops == &nvme_ns_head_ops)
|
|
||||||
ret = nvme_send_ns_head_pr_command(bdev, &c, data);
|
|
||||||
else
|
|
||||||
ret = nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c,
|
|
||||||
data);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return nvme_sc_to_pr_err(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_pr_register(struct block_device *bdev, u64 old,
|
|
||||||
u64 new, unsigned flags)
|
|
||||||
{
|
|
||||||
u32 cdw10;
|
|
||||||
|
|
||||||
if (flags & ~PR_FL_IGNORE_KEY)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
cdw10 = old ? 2 : 0;
|
|
||||||
cdw10 |= (flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0;
|
|
||||||
cdw10 |= (1 << 30) | (1 << 31); /* PTPL=1 */
|
|
||||||
return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_register);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_pr_reserve(struct block_device *bdev, u64 key,
|
|
||||||
enum pr_type type, unsigned flags)
|
|
||||||
{
|
|
||||||
u32 cdw10;
|
|
||||||
|
|
||||||
if (flags & ~PR_FL_IGNORE_KEY)
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
cdw10 = nvme_pr_type(type) << 8;
|
|
||||||
cdw10 |= ((flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0);
|
|
||||||
return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_acquire);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new,
|
|
||||||
enum pr_type type, bool abort)
|
|
||||||
{
|
|
||||||
u32 cdw10 = nvme_pr_type(type) << 8 | (abort ? 2 : 1);
|
|
||||||
|
|
||||||
return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_pr_clear(struct block_device *bdev, u64 key)
|
|
||||||
{
|
|
||||||
u32 cdw10 = 1 | (key ? 0 : 1 << 3);
|
|
||||||
|
|
||||||
return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
|
|
||||||
{
|
|
||||||
u32 cdw10 = nvme_pr_type(type) << 8 | (key ? 0 : 1 << 3);
|
|
||||||
|
|
||||||
return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct pr_ops nvme_pr_ops = {
|
|
||||||
.pr_register = nvme_pr_register,
|
|
||||||
.pr_reserve = nvme_pr_reserve,
|
|
||||||
.pr_release = nvme_pr_release,
|
|
||||||
.pr_preempt = nvme_pr_preempt,
|
|
||||||
.pr_clear = nvme_pr_clear,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_SED_OPAL
|
#ifdef CONFIG_BLK_SED_OPAL
|
||||||
static int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
|
static int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
|
||||||
bool send)
|
bool send)
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include <trace/events/block.h>
|
#include <trace/events/block.h>
|
||||||
|
|
||||||
|
extern const struct pr_ops nvme_pr_ops;
|
||||||
|
|
||||||
extern unsigned int nvme_io_timeout;
|
extern unsigned int nvme_io_timeout;
|
||||||
#define NVME_IO_TIMEOUT (nvme_io_timeout * HZ)
|
#define NVME_IO_TIMEOUT (nvme_io_timeout * HZ)
|
||||||
|
|
||||||
|
|||||||
315
drivers/nvme/host/pr.c
Normal file
315
drivers/nvme/host/pr.c
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Intel Corporation
|
||||||
|
* Keith Busch <kbusch@kernel.org>
|
||||||
|
*/
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/pr.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
|
#include "nvme.h"
|
||||||
|
|
||||||
|
static enum nvme_pr_type nvme_pr_type_from_blk(enum pr_type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case PR_WRITE_EXCLUSIVE:
|
||||||
|
return NVME_PR_WRITE_EXCLUSIVE;
|
||||||
|
case PR_EXCLUSIVE_ACCESS:
|
||||||
|
return NVME_PR_EXCLUSIVE_ACCESS;
|
||||||
|
case PR_WRITE_EXCLUSIVE_REG_ONLY:
|
||||||
|
return NVME_PR_WRITE_EXCLUSIVE_REG_ONLY;
|
||||||
|
case PR_EXCLUSIVE_ACCESS_REG_ONLY:
|
||||||
|
return NVME_PR_EXCLUSIVE_ACCESS_REG_ONLY;
|
||||||
|
case PR_WRITE_EXCLUSIVE_ALL_REGS:
|
||||||
|
return NVME_PR_WRITE_EXCLUSIVE_ALL_REGS;
|
||||||
|
case PR_EXCLUSIVE_ACCESS_ALL_REGS:
|
||||||
|
return NVME_PR_EXCLUSIVE_ACCESS_ALL_REGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum pr_type block_pr_type_from_nvme(enum nvme_pr_type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case NVME_PR_WRITE_EXCLUSIVE:
|
||||||
|
return PR_WRITE_EXCLUSIVE;
|
||||||
|
case NVME_PR_EXCLUSIVE_ACCESS:
|
||||||
|
return PR_EXCLUSIVE_ACCESS;
|
||||||
|
case NVME_PR_WRITE_EXCLUSIVE_REG_ONLY:
|
||||||
|
return PR_WRITE_EXCLUSIVE_REG_ONLY;
|
||||||
|
case NVME_PR_EXCLUSIVE_ACCESS_REG_ONLY:
|
||||||
|
return PR_EXCLUSIVE_ACCESS_REG_ONLY;
|
||||||
|
case NVME_PR_WRITE_EXCLUSIVE_ALL_REGS:
|
||||||
|
return PR_WRITE_EXCLUSIVE_ALL_REGS;
|
||||||
|
case NVME_PR_EXCLUSIVE_ACCESS_ALL_REGS:
|
||||||
|
return PR_EXCLUSIVE_ACCESS_ALL_REGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_send_ns_head_pr_command(struct block_device *bdev,
|
||||||
|
struct nvme_command *c, void *data, unsigned int data_len)
|
||||||
|
{
|
||||||
|
struct nvme_ns_head *head = bdev->bd_disk->private_data;
|
||||||
|
int srcu_idx = srcu_read_lock(&head->srcu);
|
||||||
|
struct nvme_ns *ns = nvme_find_path(head);
|
||||||
|
int ret = -EWOULDBLOCK;
|
||||||
|
|
||||||
|
if (ns) {
|
||||||
|
c->common.nsid = cpu_to_le32(ns->head->ns_id);
|
||||||
|
ret = nvme_submit_sync_cmd(ns->queue, c, data, data_len);
|
||||||
|
}
|
||||||
|
srcu_read_unlock(&head->srcu, srcu_idx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_send_ns_pr_command(struct nvme_ns *ns, struct nvme_command *c,
|
||||||
|
void *data, unsigned int data_len)
|
||||||
|
{
|
||||||
|
c->common.nsid = cpu_to_le32(ns->head->ns_id);
|
||||||
|
return nvme_submit_sync_cmd(ns->queue, c, data, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_sc_to_pr_err(int nvme_sc)
|
||||||
|
{
|
||||||
|
if (nvme_is_path_error(nvme_sc))
|
||||||
|
return PR_STS_PATH_FAILED;
|
||||||
|
|
||||||
|
switch (nvme_sc) {
|
||||||
|
case NVME_SC_SUCCESS:
|
||||||
|
return PR_STS_SUCCESS;
|
||||||
|
case NVME_SC_RESERVATION_CONFLICT:
|
||||||
|
return PR_STS_RESERVATION_CONFLICT;
|
||||||
|
case NVME_SC_ONCS_NOT_SUPPORTED:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
case NVME_SC_BAD_ATTRIBUTES:
|
||||||
|
case NVME_SC_INVALID_OPCODE:
|
||||||
|
case NVME_SC_INVALID_FIELD:
|
||||||
|
case NVME_SC_INVALID_NS:
|
||||||
|
return -EINVAL;
|
||||||
|
default:
|
||||||
|
return PR_STS_IOERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_send_pr_command(struct block_device *bdev,
|
||||||
|
struct nvme_command *c, void *data, unsigned int data_len)
|
||||||
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
|
||||||
|
bdev->bd_disk->fops == &nvme_ns_head_ops)
|
||||||
|
return nvme_send_ns_head_pr_command(bdev, c, data, data_len);
|
||||||
|
|
||||||
|
return nvme_send_ns_pr_command(bdev->bd_disk->private_data, c, data,
|
||||||
|
data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
|
||||||
|
u64 key, u64 sa_key, u8 op)
|
||||||
|
{
|
||||||
|
struct nvme_command c = { };
|
||||||
|
u8 data[16] = { 0, };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
put_unaligned_le64(key, &data[0]);
|
||||||
|
put_unaligned_le64(sa_key, &data[8]);
|
||||||
|
|
||||||
|
c.common.opcode = op;
|
||||||
|
c.common.cdw10 = cpu_to_le32(cdw10);
|
||||||
|
|
||||||
|
ret = nvme_send_pr_command(bdev, &c, data, sizeof(data));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return nvme_sc_to_pr_err(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_register(struct block_device *bdev, u64 old,
|
||||||
|
u64 new, unsigned flags)
|
||||||
|
{
|
||||||
|
u32 cdw10;
|
||||||
|
|
||||||
|
if (flags & ~PR_FL_IGNORE_KEY)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
cdw10 = old ? 2 : 0;
|
||||||
|
cdw10 |= (flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0;
|
||||||
|
cdw10 |= (1 << 30) | (1 << 31); /* PTPL=1 */
|
||||||
|
return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_register);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_reserve(struct block_device *bdev, u64 key,
|
||||||
|
enum pr_type type, unsigned flags)
|
||||||
|
{
|
||||||
|
u32 cdw10;
|
||||||
|
|
||||||
|
if (flags & ~PR_FL_IGNORE_KEY)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
cdw10 = nvme_pr_type_from_blk(type) << 8;
|
||||||
|
cdw10 |= ((flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0);
|
||||||
|
return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new,
|
||||||
|
enum pr_type type, bool abort)
|
||||||
|
{
|
||||||
|
u32 cdw10 = nvme_pr_type_from_blk(type) << 8 | (abort ? 2 : 1);
|
||||||
|
|
||||||
|
return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_clear(struct block_device *bdev, u64 key)
|
||||||
|
{
|
||||||
|
u32 cdw10 = 1 | (key ? 0 : 1 << 3);
|
||||||
|
|
||||||
|
return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
|
||||||
|
{
|
||||||
|
u32 cdw10 = nvme_pr_type_from_blk(type) << 8 | (key ? 0 : 1 << 3);
|
||||||
|
|
||||||
|
return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_resv_report(struct block_device *bdev, void *data,
|
||||||
|
u32 data_len, bool *eds)
|
||||||
|
{
|
||||||
|
struct nvme_command c = { };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
c.common.opcode = nvme_cmd_resv_report;
|
||||||
|
c.common.cdw10 = cpu_to_le32(nvme_bytes_to_numd(data_len));
|
||||||
|
c.common.cdw11 = cpu_to_le32(NVME_EXTENDED_DATA_STRUCT);
|
||||||
|
*eds = true;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
ret = nvme_send_pr_command(bdev, &c, data, data_len);
|
||||||
|
if (ret == NVME_SC_HOST_ID_INCONSIST &&
|
||||||
|
c.common.cdw11 == cpu_to_le32(NVME_EXTENDED_DATA_STRUCT)) {
|
||||||
|
c.common.cdw11 = 0;
|
||||||
|
*eds = false;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return nvme_sc_to_pr_err(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_read_keys(struct block_device *bdev,
|
||||||
|
struct pr_keys *keys_info)
|
||||||
|
{
|
||||||
|
u32 rse_len, num_keys = keys_info->num_keys;
|
||||||
|
struct nvme_reservation_status_ext *rse;
|
||||||
|
int ret, i;
|
||||||
|
bool eds;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assume we are using 128-bit host IDs and allocate a buffer large
|
||||||
|
* enough to get enough keys to fill the return keys buffer.
|
||||||
|
*/
|
||||||
|
rse_len = struct_size(rse, regctl_eds, num_keys);
|
||||||
|
rse = kzalloc(rse_len, GFP_KERNEL);
|
||||||
|
if (!rse)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = nvme_pr_resv_report(bdev, rse, rse_len, &eds);
|
||||||
|
if (ret)
|
||||||
|
goto free_rse;
|
||||||
|
|
||||||
|
keys_info->generation = le32_to_cpu(rse->gen);
|
||||||
|
keys_info->num_keys = get_unaligned_le16(&rse->regctl);
|
||||||
|
|
||||||
|
num_keys = min(num_keys, keys_info->num_keys);
|
||||||
|
for (i = 0; i < num_keys; i++) {
|
||||||
|
if (eds) {
|
||||||
|
keys_info->keys[i] =
|
||||||
|
le64_to_cpu(rse->regctl_eds[i].rkey);
|
||||||
|
} else {
|
||||||
|
struct nvme_reservation_status *rs;
|
||||||
|
|
||||||
|
rs = (struct nvme_reservation_status *)rse;
|
||||||
|
keys_info->keys[i] = le64_to_cpu(rs->regctl_ds[i].rkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_rse:
|
||||||
|
kfree(rse);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_pr_read_reservation(struct block_device *bdev,
|
||||||
|
struct pr_held_reservation *resv)
|
||||||
|
{
|
||||||
|
struct nvme_reservation_status_ext tmp_rse, *rse;
|
||||||
|
int ret, i, num_regs;
|
||||||
|
u32 rse_len;
|
||||||
|
bool eds;
|
||||||
|
|
||||||
|
get_num_regs:
|
||||||
|
/*
|
||||||
|
* Get the number of registrations so we know how big to allocate
|
||||||
|
* the response buffer.
|
||||||
|
*/
|
||||||
|
ret = nvme_pr_resv_report(bdev, &tmp_rse, sizeof(tmp_rse), &eds);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
num_regs = get_unaligned_le16(&tmp_rse.regctl);
|
||||||
|
if (!num_regs) {
|
||||||
|
resv->generation = le32_to_cpu(tmp_rse.gen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rse_len = struct_size(rse, regctl_eds, num_regs);
|
||||||
|
rse = kzalloc(rse_len, GFP_KERNEL);
|
||||||
|
if (!rse)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = nvme_pr_resv_report(bdev, rse, rse_len, &eds);
|
||||||
|
if (ret)
|
||||||
|
goto free_rse;
|
||||||
|
|
||||||
|
if (num_regs != get_unaligned_le16(&rse->regctl)) {
|
||||||
|
kfree(rse);
|
||||||
|
goto get_num_regs;
|
||||||
|
}
|
||||||
|
|
||||||
|
resv->generation = le32_to_cpu(rse->gen);
|
||||||
|
resv->type = block_pr_type_from_nvme(rse->rtype);
|
||||||
|
|
||||||
|
for (i = 0; i < num_regs; i++) {
|
||||||
|
if (eds) {
|
||||||
|
if (rse->regctl_eds[i].rcsts) {
|
||||||
|
resv->key = le64_to_cpu(rse->regctl_eds[i].rkey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct nvme_reservation_status *rs;
|
||||||
|
|
||||||
|
rs = (struct nvme_reservation_status *)rse;
|
||||||
|
if (rs->regctl_ds[i].rcsts) {
|
||||||
|
resv->key = le64_to_cpu(rs->regctl_ds[i].rkey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_rse:
|
||||||
|
kfree(rse);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct pr_ops nvme_pr_ops = {
|
||||||
|
.pr_register = nvme_pr_register,
|
||||||
|
.pr_reserve = nvme_pr_reserve,
|
||||||
|
.pr_release = nvme_pr_release,
|
||||||
|
.pr_preempt = nvme_pr_preempt,
|
||||||
|
.pr_clear = nvme_pr_clear,
|
||||||
|
.pr_read_keys = nvme_pr_read_keys,
|
||||||
|
.pr_read_reservation = nvme_pr_read_reservation,
|
||||||
|
};
|
||||||
@@ -2737,7 +2737,12 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
|
|||||||
else if (status == 0) {
|
else if (status == 0) {
|
||||||
switch (cqr->intrc) {
|
switch (cqr->intrc) {
|
||||||
case -EPERM:
|
case -EPERM:
|
||||||
error = BLK_STS_NEXUS;
|
/*
|
||||||
|
* DASD doesn't implement SCSI/NVMe reservations, but it
|
||||||
|
* implements a locking scheme similar to them. We
|
||||||
|
* return this error when we no longer have the lock.
|
||||||
|
*/
|
||||||
|
error = BLK_STS_RESV_CONFLICT;
|
||||||
break;
|
break;
|
||||||
case -ENOLINK:
|
case -ENOLINK:
|
||||||
error = BLK_STS_TRANSPORT;
|
error = BLK_STS_TRANSPORT;
|
||||||
|
|||||||
@@ -2305,8 +2305,10 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
|
|||||||
TW_DISABLE_INTERRUPTS(tw_dev);
|
TW_DISABLE_INTERRUPTS(tw_dev);
|
||||||
|
|
||||||
/* Initialize the card */
|
/* Initialize the card */
|
||||||
if (tw_reset_sequence(tw_dev))
|
if (tw_reset_sequence(tw_dev)) {
|
||||||
|
retval = -EINVAL;
|
||||||
goto out_release_mem_region;
|
goto out_release_mem_region;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set host specific parameters */
|
/* Set host specific parameters */
|
||||||
host->max_id = TW_MAX_UNITS;
|
host->max_id = TW_MAX_UNITS;
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ config SGIWD93_SCSI
|
|||||||
|
|
||||||
config BLK_DEV_3W_XXXX_RAID
|
config BLK_DEV_3W_XXXX_RAID
|
||||||
tristate "3ware 5/6/7/8xxx ATA-RAID support"
|
tristate "3ware 5/6/7/8xxx ATA-RAID support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
help
|
help
|
||||||
3ware is the only hardware ATA-Raid product in Linux to date.
|
3ware is the only hardware ATA-Raid product in Linux to date.
|
||||||
This card is 2,4, or 8 channel master mode support only.
|
This card is 2,4, or 8 channel master mode support only.
|
||||||
@@ -381,7 +381,7 @@ config SCSI_3W_SAS
|
|||||||
|
|
||||||
config SCSI_ACARD
|
config SCSI_ACARD
|
||||||
tristate "ACARD SCSI support"
|
tristate "ACARD SCSI support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
help
|
help
|
||||||
This driver supports the ACARD SCSI host adapter.
|
This driver supports the ACARD SCSI host adapter.
|
||||||
Support Chip <ATP870 ATP876 ATP880 ATP885>
|
Support Chip <ATP870 ATP876 ATP880 ATP885>
|
||||||
@@ -462,7 +462,7 @@ config SCSI_MVUMI
|
|||||||
config SCSI_ADVANSYS
|
config SCSI_ADVANSYS
|
||||||
tristate "AdvanSys SCSI support"
|
tristate "AdvanSys SCSI support"
|
||||||
depends on SCSI
|
depends on SCSI
|
||||||
depends on ISA || EISA || PCI
|
depends on (ISA || EISA || PCI) && HAS_IOPORT
|
||||||
depends on ISA_DMA_API || !ISA
|
depends on ISA_DMA_API || !ISA
|
||||||
help
|
help
|
||||||
This is a driver for all SCSI host adapters manufactured by
|
This is a driver for all SCSI host adapters manufactured by
|
||||||
@@ -503,7 +503,7 @@ config SCSI_HPTIOP
|
|||||||
|
|
||||||
config SCSI_BUSLOGIC
|
config SCSI_BUSLOGIC
|
||||||
tristate "BusLogic SCSI support"
|
tristate "BusLogic SCSI support"
|
||||||
depends on PCI && SCSI
|
depends on SCSI && PCI && HAS_IOPORT
|
||||||
help
|
help
|
||||||
This is support for BusLogic MultiMaster and FlashPoint SCSI Host
|
This is support for BusLogic MultiMaster and FlashPoint SCSI Host
|
||||||
Adapters. Consult the SCSI-HOWTO, available from
|
Adapters. Consult the SCSI-HOWTO, available from
|
||||||
@@ -518,7 +518,7 @@ config SCSI_BUSLOGIC
|
|||||||
|
|
||||||
config SCSI_FLASHPOINT
|
config SCSI_FLASHPOINT
|
||||||
bool "FlashPoint support"
|
bool "FlashPoint support"
|
||||||
depends on SCSI_BUSLOGIC && PCI
|
depends on SCSI_BUSLOGIC && PCI && HAS_IOPORT
|
||||||
help
|
help
|
||||||
This option allows you to add FlashPoint support to the
|
This option allows you to add FlashPoint support to the
|
||||||
BusLogic SCSI driver. The FlashPoint SCCB Manager code is
|
BusLogic SCSI driver. The FlashPoint SCCB Manager code is
|
||||||
@@ -632,7 +632,7 @@ config SCSI_SNIC_DEBUG_FS
|
|||||||
|
|
||||||
config SCSI_DMX3191D
|
config SCSI_DMX3191D
|
||||||
tristate "DMX3191D SCSI support"
|
tristate "DMX3191D SCSI support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
select SCSI_SPI_ATTRS
|
select SCSI_SPI_ATTRS
|
||||||
help
|
help
|
||||||
This is support for Domex DMX3191D SCSI Host Adapters.
|
This is support for Domex DMX3191D SCSI Host Adapters.
|
||||||
@@ -646,7 +646,7 @@ config SCSI_FDOMAIN
|
|||||||
|
|
||||||
config SCSI_FDOMAIN_PCI
|
config SCSI_FDOMAIN_PCI
|
||||||
tristate "Future Domain TMC-3260/AHA-2920A PCI SCSI support"
|
tristate "Future Domain TMC-3260/AHA-2920A PCI SCSI support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
select SCSI_FDOMAIN
|
select SCSI_FDOMAIN
|
||||||
help
|
help
|
||||||
This is support for Future Domain's PCI SCSI host adapters (TMC-3260)
|
This is support for Future Domain's PCI SCSI host adapters (TMC-3260)
|
||||||
@@ -699,7 +699,7 @@ config SCSI_GENERIC_NCR5380
|
|||||||
|
|
||||||
config SCSI_IPS
|
config SCSI_IPS
|
||||||
tristate "IBM ServeRAID support"
|
tristate "IBM ServeRAID support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
help
|
help
|
||||||
This is support for the IBM ServeRAID hardware RAID controllers.
|
This is support for the IBM ServeRAID hardware RAID controllers.
|
||||||
See <http://www.developer.ibm.com/welcome/netfinity/serveraid.html>
|
See <http://www.developer.ibm.com/welcome/netfinity/serveraid.html>
|
||||||
@@ -759,7 +759,7 @@ config SCSI_IBMVFC_TRACE
|
|||||||
|
|
||||||
config SCSI_INITIO
|
config SCSI_INITIO
|
||||||
tristate "Initio 9100U(W) support"
|
tristate "Initio 9100U(W) support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
help
|
help
|
||||||
This is support for the Initio 91XXU(W) SCSI host adapter. Please
|
This is support for the Initio 91XXU(W) SCSI host adapter. Please
|
||||||
read the SCSI-HOWTO, available from
|
read the SCSI-HOWTO, available from
|
||||||
@@ -770,7 +770,7 @@ config SCSI_INITIO
|
|||||||
|
|
||||||
config SCSI_INIA100
|
config SCSI_INIA100
|
||||||
tristate "Initio INI-A100U2W support"
|
tristate "Initio INI-A100U2W support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
help
|
help
|
||||||
This is support for the Initio INI-A100U2W SCSI host adapter.
|
This is support for the Initio INI-A100U2W SCSI host adapter.
|
||||||
Please read the SCSI-HOWTO, available from
|
Please read the SCSI-HOWTO, available from
|
||||||
@@ -782,6 +782,7 @@ config SCSI_INIA100
|
|||||||
config SCSI_PPA
|
config SCSI_PPA
|
||||||
tristate "IOMEGA parallel port (ppa - older drives)"
|
tristate "IOMEGA parallel port (ppa - older drives)"
|
||||||
depends on SCSI && PARPORT_PC
|
depends on SCSI && PARPORT_PC
|
||||||
|
depends on HAS_IOPORT
|
||||||
help
|
help
|
||||||
This driver supports older versions of IOMEGA's parallel port ZIP
|
This driver supports older versions of IOMEGA's parallel port ZIP
|
||||||
drive (a 100 MB removable media device).
|
drive (a 100 MB removable media device).
|
||||||
@@ -1175,7 +1176,7 @@ config SCSI_SIM710
|
|||||||
|
|
||||||
config SCSI_DC395x
|
config SCSI_DC395x
|
||||||
tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support"
|
tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
select SCSI_SPI_ATTRS
|
select SCSI_SPI_ATTRS
|
||||||
help
|
help
|
||||||
This driver supports PCI SCSI host adapters based on the ASIC
|
This driver supports PCI SCSI host adapters based on the ASIC
|
||||||
@@ -1207,7 +1208,7 @@ config SCSI_AM53C974
|
|||||||
|
|
||||||
config SCSI_NSP32
|
config SCSI_NSP32
|
||||||
tristate "Workbit NinjaSCSI-32Bi/UDE support"
|
tristate "Workbit NinjaSCSI-32Bi/UDE support"
|
||||||
depends on PCI && SCSI && !64BIT
|
depends on PCI && SCSI && !64BIT && HAS_IOPORT
|
||||||
help
|
help
|
||||||
This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
|
This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
|
||||||
SCSI host adapter. Please read the SCSI-HOWTO, available from
|
SCSI host adapter. Please read the SCSI-HOWTO, available from
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#
|
#
|
||||||
config SCSI_AIC79XX
|
config SCSI_AIC79XX
|
||||||
tristate "Adaptec AIC79xx U320 support"
|
tristate "Adaptec AIC79xx U320 support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
select SCSI_SPI_ATTRS
|
select SCSI_SPI_ATTRS
|
||||||
help
|
help
|
||||||
This driver supports all of Adaptec's Ultra 320 PCI-X
|
This driver supports all of Adaptec's Ultra 320 PCI-X
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#
|
#
|
||||||
config SCSI_AIC7XXX
|
config SCSI_AIC7XXX
|
||||||
tristate "Adaptec AIC7xxx Fast -> U160 support"
|
tristate "Adaptec AIC7xxx Fast -> U160 support"
|
||||||
depends on (PCI || EISA) && SCSI
|
depends on (PCI || EISA) && HAS_IOPORT && SCSI
|
||||||
select SCSI_SPI_ATTRS
|
select SCSI_SPI_ATTRS
|
||||||
help
|
help
|
||||||
This driver supports all of Adaptec's Fast through Ultra 160 PCI
|
This driver supports all of Adaptec's Fast through Ultra 160 PCI
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
config SCSI_AIC94XX
|
config SCSI_AIC94XX
|
||||||
tristate "Adaptec AIC94xx SAS/SATA support"
|
tristate "Adaptec AIC94xx SAS/SATA support"
|
||||||
depends on PCI
|
depends on PCI && HAS_IOPORT
|
||||||
select SCSI_SAS_LIBSAS
|
select SCSI_SAS_LIBSAS
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
help
|
help
|
||||||
|
|||||||
@@ -1134,7 +1134,7 @@ fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
|
|||||||
memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
|
memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
|
||||||
|
|
||||||
rspnid->dap = s_id;
|
rspnid->dap = s_id;
|
||||||
strlcpy(rspnid->spn, name, sizeof(rspnid->spn));
|
strscpy(rspnid->spn, name, sizeof(rspnid->spn));
|
||||||
rspnid->spn_len = (u8) strlen(rspnid->spn);
|
rspnid->spn_len = (u8) strlen(rspnid->spn);
|
||||||
|
|
||||||
return sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s);
|
return sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s);
|
||||||
@@ -1155,7 +1155,7 @@ fc_rsnn_nn_build(struct fchs_s *fchs, void *pyld, u32 s_id,
|
|||||||
memset(rsnn_nn, 0, sizeof(struct fcgs_rsnn_nn_req_s));
|
memset(rsnn_nn, 0, sizeof(struct fcgs_rsnn_nn_req_s));
|
||||||
|
|
||||||
rsnn_nn->node_name = node_name;
|
rsnn_nn->node_name = node_name;
|
||||||
strlcpy(rsnn_nn->snn, name, sizeof(rsnn_nn->snn));
|
strscpy(rsnn_nn->snn, name, sizeof(rsnn_nn->snn));
|
||||||
rsnn_nn->snn_len = (u8) strlen(rsnn_nn->snn);
|
rsnn_nn->snn_len = (u8) strlen(rsnn_nn->snn);
|
||||||
|
|
||||||
return sizeof(struct fcgs_rsnn_nn_req_s) + sizeof(struct ct_hdr_s);
|
return sizeof(struct fcgs_rsnn_nn_req_s) + sizeof(struct ct_hdr_s);
|
||||||
|
|||||||
@@ -761,7 +761,7 @@ bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric)
|
|||||||
bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
|
bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
|
||||||
|
|
||||||
/* Model name/number */
|
/* Model name/number */
|
||||||
strlcpy(port_cfg->sym_name.symname, model,
|
strscpy(port_cfg->sym_name.symname, model,
|
||||||
BFA_SYMNAME_MAXLEN);
|
BFA_SYMNAME_MAXLEN);
|
||||||
strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
|
strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
|
||||||
BFA_SYMNAME_MAXLEN);
|
BFA_SYMNAME_MAXLEN);
|
||||||
@@ -822,7 +822,7 @@ bfa_fcs_fabric_nsymb_init(struct bfa_fcs_fabric_s *fabric)
|
|||||||
bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
|
bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model);
|
||||||
|
|
||||||
/* Model name/number */
|
/* Model name/number */
|
||||||
strlcpy(port_cfg->node_sym_name.symname, model,
|
strscpy(port_cfg->node_sym_name.symname, model,
|
||||||
BFA_SYMNAME_MAXLEN);
|
BFA_SYMNAME_MAXLEN);
|
||||||
strlcat(port_cfg->node_sym_name.symname,
|
strlcat(port_cfg->node_sym_name.symname,
|
||||||
BFA_FCS_PORT_SYMBNAME_SEPARATOR,
|
BFA_FCS_PORT_SYMBNAME_SEPARATOR,
|
||||||
|
|||||||
@@ -2642,10 +2642,10 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
|
|||||||
bfa_ioc_get_adapter_fw_ver(&port->fcs->bfa->ioc,
|
bfa_ioc_get_adapter_fw_ver(&port->fcs->bfa->ioc,
|
||||||
hba_attr->fw_version);
|
hba_attr->fw_version);
|
||||||
|
|
||||||
strlcpy(hba_attr->driver_version, (char *)driver_info->version,
|
strscpy(hba_attr->driver_version, (char *)driver_info->version,
|
||||||
sizeof(hba_attr->driver_version));
|
sizeof(hba_attr->driver_version));
|
||||||
|
|
||||||
strlcpy(hba_attr->os_name, driver_info->host_os_name,
|
strscpy(hba_attr->os_name, driver_info->host_os_name,
|
||||||
sizeof(hba_attr->os_name));
|
sizeof(hba_attr->os_name));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2663,13 +2663,13 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
|
|||||||
bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr);
|
bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr);
|
||||||
hba_attr->max_ct_pyld = fcs_port_attr.max_frm_size;
|
hba_attr->max_ct_pyld = fcs_port_attr.max_frm_size;
|
||||||
|
|
||||||
strlcpy(hba_attr->node_sym_name.symname,
|
strscpy(hba_attr->node_sym_name.symname,
|
||||||
port->port_cfg.node_sym_name.symname, BFA_SYMNAME_MAXLEN);
|
port->port_cfg.node_sym_name.symname, BFA_SYMNAME_MAXLEN);
|
||||||
strcpy(hba_attr->vendor_info, "QLogic");
|
strcpy(hba_attr->vendor_info, "QLogic");
|
||||||
hba_attr->num_ports =
|
hba_attr->num_ports =
|
||||||
cpu_to_be32(bfa_ioc_get_nports(&port->fcs->bfa->ioc));
|
cpu_to_be32(bfa_ioc_get_nports(&port->fcs->bfa->ioc));
|
||||||
hba_attr->fabric_name = port->fabric->lps->pr_nwwn;
|
hba_attr->fabric_name = port->fabric->lps->pr_nwwn;
|
||||||
strlcpy(hba_attr->bios_ver, hba_attr->option_rom_ver, BFA_VERSION_LEN);
|
strscpy(hba_attr->bios_ver, hba_attr->option_rom_ver, BFA_VERSION_LEN);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2736,19 +2736,19 @@ bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi,
|
|||||||
/*
|
/*
|
||||||
* OS device Name
|
* OS device Name
|
||||||
*/
|
*/
|
||||||
strlcpy(port_attr->os_device_name, driver_info->os_device_name,
|
strscpy(port_attr->os_device_name, driver_info->os_device_name,
|
||||||
sizeof(port_attr->os_device_name));
|
sizeof(port_attr->os_device_name));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Host name
|
* Host name
|
||||||
*/
|
*/
|
||||||
strlcpy(port_attr->host_name, driver_info->host_machine_name,
|
strscpy(port_attr->host_name, driver_info->host_machine_name,
|
||||||
sizeof(port_attr->host_name));
|
sizeof(port_attr->host_name));
|
||||||
|
|
||||||
port_attr->node_name = bfa_fcs_lport_get_nwwn(port);
|
port_attr->node_name = bfa_fcs_lport_get_nwwn(port);
|
||||||
port_attr->port_name = bfa_fcs_lport_get_pwwn(port);
|
port_attr->port_name = bfa_fcs_lport_get_pwwn(port);
|
||||||
|
|
||||||
strlcpy(port_attr->port_sym_name.symname,
|
strscpy(port_attr->port_sym_name.symname,
|
||||||
bfa_fcs_lport_get_psym_name(port).symname, BFA_SYMNAME_MAXLEN);
|
bfa_fcs_lport_get_psym_name(port).symname, BFA_SYMNAME_MAXLEN);
|
||||||
bfa_fcs_lport_get_attr(port, &lport_attr);
|
bfa_fcs_lport_get_attr(port, &lport_attr);
|
||||||
port_attr->port_type = cpu_to_be32(lport_attr.port_type);
|
port_attr->port_type = cpu_to_be32(lport_attr.port_type);
|
||||||
@@ -3229,7 +3229,7 @@ bfa_fcs_lport_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp,
|
|||||||
rsp_str[gmal_entry->len-1] = 0;
|
rsp_str[gmal_entry->len-1] = 0;
|
||||||
|
|
||||||
/* copy IP Address to fabric */
|
/* copy IP Address to fabric */
|
||||||
strlcpy(bfa_fcs_lport_get_fabric_ipaddr(port),
|
strscpy(bfa_fcs_lport_get_fabric_ipaddr(port),
|
||||||
gmal_entry->ip_addr,
|
gmal_entry->ip_addr,
|
||||||
BFA_FCS_FABRIC_IPADDR_SZ);
|
BFA_FCS_FABRIC_IPADDR_SZ);
|
||||||
break;
|
break;
|
||||||
@@ -4667,7 +4667,7 @@ bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
|
|||||||
* to that of the base port.
|
* to that of the base port.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
strlcpy(symbl,
|
strscpy(symbl,
|
||||||
(char *)&(bfa_fcs_lport_get_psym_name
|
(char *)&(bfa_fcs_lport_get_psym_name
|
||||||
(bfa_fcs_get_base_port(port->fcs))),
|
(bfa_fcs_get_base_port(port->fcs))),
|
||||||
sizeof(symbl));
|
sizeof(symbl));
|
||||||
@@ -5194,7 +5194,7 @@ bfa_fcs_lport_ns_util_send_rspn_id(void *cbarg, struct bfa_fcxp_s *fcxp_alloced)
|
|||||||
* For Vports, we append the vport's port symbolic name
|
* For Vports, we append the vport's port symbolic name
|
||||||
* to that of the base port.
|
* to that of the base port.
|
||||||
*/
|
*/
|
||||||
strlcpy(symbl, (char *)&(bfa_fcs_lport_get_psym_name
|
strscpy(symbl, (char *)&(bfa_fcs_lport_get_psym_name
|
||||||
(bfa_fcs_get_base_port(port->fcs))),
|
(bfa_fcs_get_base_port(port->fcs))),
|
||||||
sizeof(symbl));
|
sizeof(symbl));
|
||||||
|
|
||||||
|
|||||||
@@ -2788,7 +2788,7 @@ void
|
|||||||
bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
|
bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
|
||||||
{
|
{
|
||||||
memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
|
memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);
|
||||||
strlcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
|
strscpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
|
|||||||
lp.eid = event;
|
lp.eid = event;
|
||||||
lp.log_type = BFA_PL_LOG_TYPE_STRING;
|
lp.log_type = BFA_PL_LOG_TYPE_STRING;
|
||||||
lp.misc = misc;
|
lp.misc = misc;
|
||||||
strlcpy(lp.log_entry.string_log, log_str,
|
strscpy(lp.log_entry.string_log, log_str,
|
||||||
BFA_PL_STRING_LOG_SZ);
|
BFA_PL_STRING_LOG_SZ);
|
||||||
lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0';
|
lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0';
|
||||||
bfa_plog_add(plog, &lp);
|
bfa_plog_add(plog, &lp);
|
||||||
|
|||||||
@@ -965,19 +965,19 @@ bfad_start_ops(struct bfad_s *bfad) {
|
|||||||
|
|
||||||
/* Fill the driver_info info to fcs*/
|
/* Fill the driver_info info to fcs*/
|
||||||
memset(&driver_info, 0, sizeof(driver_info));
|
memset(&driver_info, 0, sizeof(driver_info));
|
||||||
strlcpy(driver_info.version, BFAD_DRIVER_VERSION,
|
strscpy(driver_info.version, BFAD_DRIVER_VERSION,
|
||||||
sizeof(driver_info.version));
|
sizeof(driver_info.version));
|
||||||
if (host_name)
|
if (host_name)
|
||||||
strlcpy(driver_info.host_machine_name, host_name,
|
strscpy(driver_info.host_machine_name, host_name,
|
||||||
sizeof(driver_info.host_machine_name));
|
sizeof(driver_info.host_machine_name));
|
||||||
if (os_name)
|
if (os_name)
|
||||||
strlcpy(driver_info.host_os_name, os_name,
|
strscpy(driver_info.host_os_name, os_name,
|
||||||
sizeof(driver_info.host_os_name));
|
sizeof(driver_info.host_os_name));
|
||||||
if (os_patch)
|
if (os_patch)
|
||||||
strlcpy(driver_info.host_os_patch, os_patch,
|
strscpy(driver_info.host_os_patch, os_patch,
|
||||||
sizeof(driver_info.host_os_patch));
|
sizeof(driver_info.host_os_patch));
|
||||||
|
|
||||||
strlcpy(driver_info.os_device_name, bfad->pci_name,
|
strscpy(driver_info.os_device_name, bfad->pci_name,
|
||||||
sizeof(driver_info.os_device_name));
|
sizeof(driver_info.os_device_name));
|
||||||
|
|
||||||
/* FCS driver info init */
|
/* FCS driver info init */
|
||||||
|
|||||||
@@ -834,7 +834,7 @@ bfad_im_symbolic_name_show(struct device *dev, struct device_attribute *attr,
|
|||||||
char symname[BFA_SYMNAME_MAXLEN];
|
char symname[BFA_SYMNAME_MAXLEN];
|
||||||
|
|
||||||
bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr);
|
bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr);
|
||||||
strlcpy(symname, port_attr.port_cfg.sym_name.symname,
|
strscpy(symname, port_attr.port_cfg.sym_name.symname,
|
||||||
BFA_SYMNAME_MAXLEN);
|
BFA_SYMNAME_MAXLEN);
|
||||||
return sysfs_emit(buf, "%s\n", symname);
|
return sysfs_emit(buf, "%s\n", symname);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ bfad_iocmd_ioc_get_attr(struct bfad_s *bfad, void *cmd)
|
|||||||
|
|
||||||
/* fill in driver attr info */
|
/* fill in driver attr info */
|
||||||
strcpy(iocmd->ioc_attr.driver_attr.driver, BFAD_DRIVER_NAME);
|
strcpy(iocmd->ioc_attr.driver_attr.driver, BFAD_DRIVER_NAME);
|
||||||
strlcpy(iocmd->ioc_attr.driver_attr.driver_ver,
|
strscpy(iocmd->ioc_attr.driver_attr.driver_ver,
|
||||||
BFAD_DRIVER_VERSION, BFA_VERSION_LEN);
|
BFAD_DRIVER_VERSION, BFA_VERSION_LEN);
|
||||||
strcpy(iocmd->ioc_attr.driver_attr.fw_ver,
|
strcpy(iocmd->ioc_attr.driver_attr.fw_ver,
|
||||||
iocmd->ioc_attr.adapter_attr.fw_ver);
|
iocmd->ioc_attr.adapter_attr.fw_ver);
|
||||||
@@ -307,7 +307,7 @@ bfad_iocmd_port_get_attr(struct bfad_s *bfad, void *cmd)
|
|||||||
iocmd->attr.port_type = port_attr.port_type;
|
iocmd->attr.port_type = port_attr.port_type;
|
||||||
iocmd->attr.loopback = port_attr.loopback;
|
iocmd->attr.loopback = port_attr.loopback;
|
||||||
iocmd->attr.authfail = port_attr.authfail;
|
iocmd->attr.authfail = port_attr.authfail;
|
||||||
strlcpy(iocmd->attr.port_symname.symname,
|
strscpy(iocmd->attr.port_symname.symname,
|
||||||
port_attr.port_cfg.sym_name.symname,
|
port_attr.port_cfg.sym_name.symname,
|
||||||
sizeof(iocmd->attr.port_symname.symname));
|
sizeof(iocmd->attr.port_symname.symname));
|
||||||
|
|
||||||
|
|||||||
@@ -1046,7 +1046,7 @@ bfad_fc_host_init(struct bfad_im_port_s *im_port)
|
|||||||
/* For fibre channel services type 0x20 */
|
/* For fibre channel services type 0x20 */
|
||||||
fc_host_supported_fc4s(host)[7] = 1;
|
fc_host_supported_fc4s(host)[7] = 1;
|
||||||
|
|
||||||
strlcpy(symname, bfad->bfa_fcs.fabric.bport.port_cfg.sym_name.symname,
|
strscpy(symname, bfad->bfa_fcs.fabric.bport.port_cfg.sym_name.symname,
|
||||||
BFA_SYMNAME_MAXLEN);
|
BFA_SYMNAME_MAXLEN);
|
||||||
sprintf(fc_host_symbolic_name(host), "%s", symname);
|
sprintf(fc_host_symbolic_name(host), "%s", symname);
|
||||||
|
|
||||||
|
|||||||
@@ -711,7 +711,7 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer)
|
|||||||
char ifname[IFNAMSIZ + 2];
|
char ifname[IFNAMSIZ + 2];
|
||||||
|
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
strlcpy(ifname, buffer, IFNAMSIZ);
|
strscpy(ifname, buffer, IFNAMSIZ);
|
||||||
cp = ifname + strlen(ifname);
|
cp = ifname + strlen(ifname);
|
||||||
while (--cp >= ifname && *cp == '\n')
|
while (--cp >= ifname && *cp == '\n')
|
||||||
*cp = '\0';
|
*cp = '\0';
|
||||||
|
|||||||
@@ -201,25 +201,21 @@ static int fnic_trace_debugfs_open(struct inode *inode,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (*rdata_ptr == fc_trc_flag->fnic_trace) {
|
if (*rdata_ptr == fc_trc_flag->fnic_trace) {
|
||||||
fnic_dbg_prt->buffer = vmalloc(array3_size(3, trace_max_pages,
|
fnic_dbg_prt->buffer = vzalloc(array3_size(3, trace_max_pages,
|
||||||
PAGE_SIZE));
|
PAGE_SIZE));
|
||||||
if (!fnic_dbg_prt->buffer) {
|
if (!fnic_dbg_prt->buffer) {
|
||||||
kfree(fnic_dbg_prt);
|
kfree(fnic_dbg_prt);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
memset((void *)fnic_dbg_prt->buffer, 0,
|
|
||||||
3 * (trace_max_pages * PAGE_SIZE));
|
|
||||||
fnic_dbg_prt->buffer_len = fnic_get_trace_data(fnic_dbg_prt);
|
fnic_dbg_prt->buffer_len = fnic_get_trace_data(fnic_dbg_prt);
|
||||||
} else {
|
} else {
|
||||||
fnic_dbg_prt->buffer =
|
fnic_dbg_prt->buffer =
|
||||||
vmalloc(array3_size(3, fnic_fc_trace_max_pages,
|
vzalloc(array3_size(3, fnic_fc_trace_max_pages,
|
||||||
PAGE_SIZE));
|
PAGE_SIZE));
|
||||||
if (!fnic_dbg_prt->buffer) {
|
if (!fnic_dbg_prt->buffer) {
|
||||||
kfree(fnic_dbg_prt);
|
kfree(fnic_dbg_prt);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
memset((void *)fnic_dbg_prt->buffer, 0,
|
|
||||||
3 * (fnic_fc_trace_max_pages * PAGE_SIZE));
|
|
||||||
fnic_dbg_prt->buffer_len =
|
fnic_dbg_prt->buffer_len =
|
||||||
fnic_fc_trace_get_data(fnic_dbg_prt, *rdata_ptr);
|
fnic_fc_trace_get_data(fnic_dbg_prt, *rdata_ptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -642,7 +642,7 @@ extern void hisi_sas_sata_done(struct sas_task *task,
|
|||||||
extern int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba);
|
extern int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba);
|
||||||
extern int hisi_sas_probe(struct platform_device *pdev,
|
extern int hisi_sas_probe(struct platform_device *pdev,
|
||||||
const struct hisi_sas_hw *ops);
|
const struct hisi_sas_hw *ops);
|
||||||
extern int hisi_sas_remove(struct platform_device *pdev);
|
extern void hisi_sas_remove(struct platform_device *pdev);
|
||||||
|
|
||||||
extern int hisi_sas_slave_configure(struct scsi_device *sdev);
|
extern int hisi_sas_slave_configure(struct scsi_device *sdev);
|
||||||
extern int hisi_sas_slave_alloc(struct scsi_device *sdev);
|
extern int hisi_sas_slave_alloc(struct scsi_device *sdev);
|
||||||
|
|||||||
@@ -2560,7 +2560,7 @@ err_out_ha:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hisi_sas_probe);
|
EXPORT_SYMBOL_GPL(hisi_sas_probe);
|
||||||
|
|
||||||
int hisi_sas_remove(struct platform_device *pdev)
|
void hisi_sas_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sas_ha_struct *sha = platform_get_drvdata(pdev);
|
struct sas_ha_struct *sha = platform_get_drvdata(pdev);
|
||||||
struct hisi_hba *hisi_hba = sha->lldd_ha;
|
struct hisi_hba *hisi_hba = sha->lldd_ha;
|
||||||
@@ -2573,7 +2573,6 @@ int hisi_sas_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
hisi_sas_free(hisi_hba);
|
hisi_sas_free(hisi_hba);
|
||||||
scsi_host_put(shost);
|
scsi_host_put(shost);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hisi_sas_remove);
|
EXPORT_SYMBOL_GPL(hisi_sas_remove);
|
||||||
|
|
||||||
|
|||||||
@@ -1790,11 +1790,6 @@ static int hisi_sas_v1_probe(struct platform_device *pdev)
|
|||||||
return hisi_sas_probe(pdev, &hisi_sas_v1_hw);
|
return hisi_sas_probe(pdev, &hisi_sas_v1_hw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hisi_sas_v1_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
return hisi_sas_remove(pdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id sas_v1_of_match[] = {
|
static const struct of_device_id sas_v1_of_match[] = {
|
||||||
{ .compatible = "hisilicon,hip05-sas-v1",},
|
{ .compatible = "hisilicon,hip05-sas-v1",},
|
||||||
{},
|
{},
|
||||||
@@ -1810,7 +1805,7 @@ MODULE_DEVICE_TABLE(acpi, sas_v1_acpi_match);
|
|||||||
|
|
||||||
static struct platform_driver hisi_sas_v1_driver = {
|
static struct platform_driver hisi_sas_v1_driver = {
|
||||||
.probe = hisi_sas_v1_probe,
|
.probe = hisi_sas_v1_probe,
|
||||||
.remove = hisi_sas_v1_remove,
|
.remove_new = hisi_sas_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = DRV_NAME,
|
.name = DRV_NAME,
|
||||||
.of_match_table = sas_v1_of_match,
|
.of_match_table = sas_v1_of_match,
|
||||||
|
|||||||
@@ -3619,11 +3619,6 @@ static int hisi_sas_v2_probe(struct platform_device *pdev)
|
|||||||
return hisi_sas_probe(pdev, &hisi_sas_v2_hw);
|
return hisi_sas_probe(pdev, &hisi_sas_v2_hw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hisi_sas_v2_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
return hisi_sas_remove(pdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id sas_v2_of_match[] = {
|
static const struct of_device_id sas_v2_of_match[] = {
|
||||||
{ .compatible = "hisilicon,hip06-sas-v2",},
|
{ .compatible = "hisilicon,hip06-sas-v2",},
|
||||||
{ .compatible = "hisilicon,hip07-sas-v2",},
|
{ .compatible = "hisilicon,hip07-sas-v2",},
|
||||||
@@ -3640,7 +3635,7 @@ MODULE_DEVICE_TABLE(acpi, sas_v2_acpi_match);
|
|||||||
|
|
||||||
static struct platform_driver hisi_sas_v2_driver = {
|
static struct platform_driver hisi_sas_v2_driver = {
|
||||||
.probe = hisi_sas_v2_probe,
|
.probe = hisi_sas_v2_probe,
|
||||||
.remove = hisi_sas_v2_remove,
|
.remove_new = hisi_sas_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = DRV_NAME,
|
.name = DRV_NAME,
|
||||||
.of_match_table = sas_v2_of_match,
|
.of_match_table = sas_v2_of_match,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#define SATA_INITI_D2H_STORE_ADDR_LO 0x60
|
#define SATA_INITI_D2H_STORE_ADDR_LO 0x60
|
||||||
#define SATA_INITI_D2H_STORE_ADDR_HI 0x64
|
#define SATA_INITI_D2H_STORE_ADDR_HI 0x64
|
||||||
#define CFG_MAX_TAG 0x68
|
#define CFG_MAX_TAG 0x68
|
||||||
|
#define TRANS_LOCK_ICT_TIME 0X70
|
||||||
#define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL 0x84
|
#define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL 0x84
|
||||||
#define HGC_SAS_TXFAIL_RETRY_CTRL 0x88
|
#define HGC_SAS_TXFAIL_RETRY_CTRL 0x88
|
||||||
#define HGC_GET_ITV_TIME 0x90
|
#define HGC_GET_ITV_TIME 0x90
|
||||||
@@ -627,13 +628,15 @@ static void interrupt_enable_v3_hw(struct hisi_hba *hisi_hba)
|
|||||||
|
|
||||||
static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
|
static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
|
||||||
{
|
{
|
||||||
|
struct pci_dev *pdev = hisi_hba->pci_dev;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
/* Global registers init */
|
/* Global registers init */
|
||||||
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
|
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
|
||||||
(u32)((1ULL << hisi_hba->queue_count) - 1));
|
(u32)((1ULL << hisi_hba->queue_count) - 1));
|
||||||
hisi_sas_write32(hisi_hba, SAS_AXI_USER3, 0);
|
|
||||||
hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400);
|
hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400);
|
||||||
|
/* time / CLK_AHB = 2.5s / 2ns = 0x4A817C80 */
|
||||||
|
hisi_sas_write32(hisi_hba, TRANS_LOCK_ICT_TIME, 0x4A817C80);
|
||||||
hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
|
hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108);
|
||||||
hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
|
hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1);
|
||||||
hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
|
hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1);
|
||||||
@@ -652,6 +655,9 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
|
|||||||
hisi_sas_write32(hisi_hba, ARQOS_ARCACHE_CFG, 0xf0f0);
|
hisi_sas_write32(hisi_hba, ARQOS_ARCACHE_CFG, 0xf0f0);
|
||||||
hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
|
hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
|
||||||
|
|
||||||
|
if (pdev->revision < 0x30)
|
||||||
|
hisi_sas_write32(hisi_hba, SAS_AXI_USER3, 0);
|
||||||
|
|
||||||
interrupt_enable_v3_hw(hisi_hba);
|
interrupt_enable_v3_hw(hisi_hba);
|
||||||
for (i = 0; i < hisi_hba->n_phy; i++) {
|
for (i = 0; i < hisi_hba->n_phy; i++) {
|
||||||
enum sas_linkrate max;
|
enum sas_linkrate max;
|
||||||
@@ -669,7 +675,6 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
|
|||||||
prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max);
|
prog_phy_link_rate |= hisi_sas_get_prog_phy_linkrate_mask(max);
|
||||||
hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE,
|
hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE,
|
||||||
prog_phy_link_rate);
|
prog_phy_link_rate);
|
||||||
hisi_sas_phy_write32(hisi_hba, i, SERDES_CFG, 0xffc00);
|
|
||||||
hisi_sas_phy_write32(hisi_hba, i, SAS_RX_TRAIN_TIMER, 0x13e80);
|
hisi_sas_phy_write32(hisi_hba, i, SAS_RX_TRAIN_TIMER, 0x13e80);
|
||||||
hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
|
hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, 0xffffffff);
|
||||||
hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
|
hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, 0xffffffff);
|
||||||
@@ -680,13 +685,18 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
|
|||||||
hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x1);
|
hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x1);
|
||||||
hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7f7a120);
|
hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7f7a120);
|
||||||
hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x2a0a01);
|
hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x2a0a01);
|
||||||
hisi_sas_phy_write32(hisi_hba, i, SAS_SSP_CON_TIMER_CFG, 0x32);
|
|
||||||
hisi_sas_phy_write32(hisi_hba, i, SAS_EC_INT_COAL_TIME,
|
hisi_sas_phy_write32(hisi_hba, i, SAS_EC_INT_COAL_TIME,
|
||||||
0x30f4240);
|
0x30f4240);
|
||||||
/* used for 12G negotiate */
|
|
||||||
hisi_sas_phy_write32(hisi_hba, i, COARSETUNE_TIME, 0x1e);
|
|
||||||
hisi_sas_phy_write32(hisi_hba, i, AIP_LIMIT, 0x2ffff);
|
hisi_sas_phy_write32(hisi_hba, i, AIP_LIMIT, 0x2ffff);
|
||||||
|
|
||||||
|
/* set value through firmware for 920B and later version */
|
||||||
|
if (pdev->revision < 0x30) {
|
||||||
|
hisi_sas_phy_write32(hisi_hba, i, SAS_SSP_CON_TIMER_CFG, 0x32);
|
||||||
|
hisi_sas_phy_write32(hisi_hba, i, SERDES_CFG, 0xffc00);
|
||||||
|
/* used for 12G negotiate */
|
||||||
|
hisi_sas_phy_write32(hisi_hba, i, COARSETUNE_TIME, 0x1e);
|
||||||
|
}
|
||||||
|
|
||||||
/* get default FFE configuration for BIST */
|
/* get default FFE configuration for BIST */
|
||||||
for (j = 0; j < FFE_CFG_MAX; j++) {
|
for (j = 0; j < FFE_CFG_MAX; j++) {
|
||||||
u32 val = hisi_sas_phy_read32(hisi_hba, i,
|
u32 val = hisi_sas_phy_read32(hisi_hba, i,
|
||||||
@@ -2206,6 +2216,7 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
|
|||||||
u32 trans_tx_fail_type = le32_to_cpu(record->trans_tx_fail_type);
|
u32 trans_tx_fail_type = le32_to_cpu(record->trans_tx_fail_type);
|
||||||
u16 sipc_rx_err_type = le16_to_cpu(record->sipc_rx_err_type);
|
u16 sipc_rx_err_type = le16_to_cpu(record->sipc_rx_err_type);
|
||||||
u32 dw3 = le32_to_cpu(complete_hdr->dw3);
|
u32 dw3 = le32_to_cpu(complete_hdr->dw3);
|
||||||
|
u32 dw0 = le32_to_cpu(complete_hdr->dw0);
|
||||||
|
|
||||||
switch (task->task_proto) {
|
switch (task->task_proto) {
|
||||||
case SAS_PROTOCOL_SSP:
|
case SAS_PROTOCOL_SSP:
|
||||||
@@ -2215,8 +2226,8 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
|
|||||||
* but I/O information has been written to the host memory, we examine
|
* but I/O information has been written to the host memory, we examine
|
||||||
* response IU.
|
* response IU.
|
||||||
*/
|
*/
|
||||||
if (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_GOOD_MSK) &&
|
if (!(dw0 & CMPLT_HDR_RSPNS_GOOD_MSK) &&
|
||||||
(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))
|
(dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ts->residual = trans_tx_fail_type;
|
ts->residual = trans_tx_fail_type;
|
||||||
@@ -2232,7 +2243,7 @@ slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
|
|||||||
case SAS_PROTOCOL_SATA:
|
case SAS_PROTOCOL_SATA:
|
||||||
case SAS_PROTOCOL_STP:
|
case SAS_PROTOCOL_STP:
|
||||||
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
|
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
|
||||||
if ((complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) &&
|
if ((dw0 & CMPLT_HDR_RSPNS_XFRD_MSK) &&
|
||||||
(sipc_rx_err_type & RX_FIS_STATUS_ERR_MSK)) {
|
(sipc_rx_err_type & RX_FIS_STATUS_ERR_MSK)) {
|
||||||
ts->stat = SAS_PROTO_RESPONSE;
|
ts->stat = SAS_PROTO_RESPONSE;
|
||||||
} else if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
|
} else if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
|
||||||
@@ -2999,6 +3010,7 @@ static const struct hisi_sas_debugfs_reg_lu debugfs_global_reg_lu[] = {
|
|||||||
HISI_SAS_DEBUGFS_REG(SATA_INITI_D2H_STORE_ADDR_LO),
|
HISI_SAS_DEBUGFS_REG(SATA_INITI_D2H_STORE_ADDR_LO),
|
||||||
HISI_SAS_DEBUGFS_REG(SATA_INITI_D2H_STORE_ADDR_HI),
|
HISI_SAS_DEBUGFS_REG(SATA_INITI_D2H_STORE_ADDR_HI),
|
||||||
HISI_SAS_DEBUGFS_REG(CFG_MAX_TAG),
|
HISI_SAS_DEBUGFS_REG(CFG_MAX_TAG),
|
||||||
|
HISI_SAS_DEBUGFS_REG(TRANS_LOCK_ICT_TIME),
|
||||||
HISI_SAS_DEBUGFS_REG(HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL),
|
HISI_SAS_DEBUGFS_REG(HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL),
|
||||||
HISI_SAS_DEBUGFS_REG(HGC_SAS_TXFAIL_RETRY_CTRL),
|
HISI_SAS_DEBUGFS_REG(HGC_SAS_TXFAIL_RETRY_CTRL),
|
||||||
HISI_SAS_DEBUGFS_REG(HGC_GET_ITV_TIME),
|
HISI_SAS_DEBUGFS_REG(HGC_GET_ITV_TIME),
|
||||||
|
|||||||
@@ -441,6 +441,7 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv
|
|||||||
shost->cmd_per_lun = sht->cmd_per_lun;
|
shost->cmd_per_lun = sht->cmd_per_lun;
|
||||||
shost->no_write_same = sht->no_write_same;
|
shost->no_write_same = sht->no_write_same;
|
||||||
shost->host_tagset = sht->host_tagset;
|
shost->host_tagset = sht->host_tagset;
|
||||||
|
shost->queuecommand_may_block = sht->queuecommand_may_block;
|
||||||
|
|
||||||
if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler)
|
if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler)
|
||||||
shost->eh_deadline = -1;
|
shost->eh_deadline = -1;
|
||||||
|
|||||||
@@ -1198,37 +1198,37 @@ static void sas_print_parent_topology_bug(struct domain_device *child,
|
|||||||
sas_route_char(child, child_phy));
|
sas_route_char(child, child_phy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sas_eeds_valid(struct domain_device *parent,
|
||||||
|
struct domain_device *child)
|
||||||
|
{
|
||||||
|
struct sas_discovery *disc = &parent->port->disc;
|
||||||
|
|
||||||
|
return (SAS_ADDR(disc->eeds_a) == SAS_ADDR(parent->sas_addr) ||
|
||||||
|
SAS_ADDR(disc->eeds_a) == SAS_ADDR(child->sas_addr)) &&
|
||||||
|
(SAS_ADDR(disc->eeds_b) == SAS_ADDR(parent->sas_addr) ||
|
||||||
|
SAS_ADDR(disc->eeds_b) == SAS_ADDR(child->sas_addr));
|
||||||
|
}
|
||||||
|
|
||||||
static int sas_check_eeds(struct domain_device *child,
|
static int sas_check_eeds(struct domain_device *child,
|
||||||
struct ex_phy *parent_phy,
|
struct ex_phy *parent_phy,
|
||||||
struct ex_phy *child_phy)
|
struct ex_phy *child_phy)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
struct domain_device *parent = child->parent;
|
struct domain_device *parent = child->parent;
|
||||||
|
struct sas_discovery *disc = &parent->port->disc;
|
||||||
|
|
||||||
if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) {
|
if (SAS_ADDR(disc->fanout_sas_addr) != 0) {
|
||||||
res = -ENODEV;
|
res = -ENODEV;
|
||||||
pr_warn("edge ex %016llx phy S:%02d <--> edge ex %016llx phy S:%02d, while there is a fanout ex %016llx\n",
|
pr_warn("edge ex %016llx phy S:%02d <--> edge ex %016llx phy S:%02d, while there is a fanout ex %016llx\n",
|
||||||
SAS_ADDR(parent->sas_addr),
|
SAS_ADDR(parent->sas_addr),
|
||||||
parent_phy->phy_id,
|
parent_phy->phy_id,
|
||||||
SAS_ADDR(child->sas_addr),
|
SAS_ADDR(child->sas_addr),
|
||||||
child_phy->phy_id,
|
child_phy->phy_id,
|
||||||
SAS_ADDR(parent->port->disc.fanout_sas_addr));
|
SAS_ADDR(disc->fanout_sas_addr));
|
||||||
} else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) {
|
} else if (SAS_ADDR(disc->eeds_a) == 0) {
|
||||||
memcpy(parent->port->disc.eeds_a, parent->sas_addr,
|
memcpy(disc->eeds_a, parent->sas_addr, SAS_ADDR_SIZE);
|
||||||
SAS_ADDR_SIZE);
|
memcpy(disc->eeds_b, child->sas_addr, SAS_ADDR_SIZE);
|
||||||
memcpy(parent->port->disc.eeds_b, child->sas_addr,
|
} else if (!sas_eeds_valid(parent, child)) {
|
||||||
SAS_ADDR_SIZE);
|
|
||||||
} else if (((SAS_ADDR(parent->port->disc.eeds_a) ==
|
|
||||||
SAS_ADDR(parent->sas_addr)) ||
|
|
||||||
(SAS_ADDR(parent->port->disc.eeds_a) ==
|
|
||||||
SAS_ADDR(child->sas_addr)))
|
|
||||||
&&
|
|
||||||
((SAS_ADDR(parent->port->disc.eeds_b) ==
|
|
||||||
SAS_ADDR(parent->sas_addr)) ||
|
|
||||||
(SAS_ADDR(parent->port->disc.eeds_b) ==
|
|
||||||
SAS_ADDR(child->sas_addr))))
|
|
||||||
;
|
|
||||||
else {
|
|
||||||
res = -ENODEV;
|
res = -ENODEV;
|
||||||
pr_warn("edge ex %016llx phy%02d <--> edge ex %016llx phy%02d link forms a third EEDS!\n",
|
pr_warn("edge ex %016llx phy%02d <--> edge ex %016llx phy%02d link forms a third EEDS!\n",
|
||||||
SAS_ADDR(parent->sas_addr),
|
SAS_ADDR(parent->sas_addr),
|
||||||
@@ -1240,11 +1240,56 @@ static int sas_check_eeds(struct domain_device *child,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Here we spill over 80 columns. It is intentional.
|
static int sas_check_edge_expander_topo(struct domain_device *child,
|
||||||
*/
|
struct ex_phy *parent_phy)
|
||||||
static int sas_check_parent_topology(struct domain_device *child)
|
|
||||||
{
|
{
|
||||||
struct expander_device *child_ex = &child->ex_dev;
|
struct expander_device *child_ex = &child->ex_dev;
|
||||||
|
struct expander_device *parent_ex = &child->parent->ex_dev;
|
||||||
|
struct ex_phy *child_phy;
|
||||||
|
|
||||||
|
child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
|
||||||
|
|
||||||
|
if (child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
|
||||||
|
if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
|
||||||
|
child_phy->routing_attr != TABLE_ROUTING)
|
||||||
|
goto error;
|
||||||
|
} else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) {
|
||||||
|
if (child_phy->routing_attr == SUBTRACTIVE_ROUTING)
|
||||||
|
return sas_check_eeds(child, parent_phy, child_phy);
|
||||||
|
else if (child_phy->routing_attr != TABLE_ROUTING)
|
||||||
|
goto error;
|
||||||
|
} else if (parent_phy->routing_attr == TABLE_ROUTING) {
|
||||||
|
if (child_phy->routing_attr != SUBTRACTIVE_ROUTING &&
|
||||||
|
(child_phy->routing_attr != TABLE_ROUTING ||
|
||||||
|
!child_ex->t2t_supp || !parent_ex->t2t_supp))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
sas_print_parent_topology_bug(child, parent_phy, child_phy);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sas_check_fanout_expander_topo(struct domain_device *child,
|
||||||
|
struct ex_phy *parent_phy)
|
||||||
|
{
|
||||||
|
struct expander_device *child_ex = &child->ex_dev;
|
||||||
|
struct ex_phy *child_phy;
|
||||||
|
|
||||||
|
child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
|
||||||
|
|
||||||
|
if (parent_phy->routing_attr == TABLE_ROUTING &&
|
||||||
|
child_phy->routing_attr == SUBTRACTIVE_ROUTING)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sas_print_parent_topology_bug(child, parent_phy, child_phy);
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sas_check_parent_topology(struct domain_device *child)
|
||||||
|
{
|
||||||
struct expander_device *parent_ex;
|
struct expander_device *parent_ex;
|
||||||
int i;
|
int i;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
@@ -1259,7 +1304,6 @@ static int sas_check_parent_topology(struct domain_device *child)
|
|||||||
|
|
||||||
for (i = 0; i < parent_ex->num_phys; i++) {
|
for (i = 0; i < parent_ex->num_phys; i++) {
|
||||||
struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
|
struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
|
||||||
struct ex_phy *child_phy;
|
|
||||||
|
|
||||||
if (parent_phy->phy_state == PHY_VACANT ||
|
if (parent_phy->phy_state == PHY_VACANT ||
|
||||||
parent_phy->phy_state == PHY_NOT_PRESENT)
|
parent_phy->phy_state == PHY_NOT_PRESENT)
|
||||||
@@ -1268,40 +1312,14 @@ static int sas_check_parent_topology(struct domain_device *child)
|
|||||||
if (!sas_phy_match_dev_addr(child, parent_phy))
|
if (!sas_phy_match_dev_addr(child, parent_phy))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
|
|
||||||
|
|
||||||
switch (child->parent->dev_type) {
|
switch (child->parent->dev_type) {
|
||||||
case SAS_EDGE_EXPANDER_DEVICE:
|
case SAS_EDGE_EXPANDER_DEVICE:
|
||||||
if (child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
|
if (sas_check_edge_expander_topo(child, parent_phy))
|
||||||
if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
|
res = -ENODEV;
|
||||||
child_phy->routing_attr != TABLE_ROUTING) {
|
|
||||||
sas_print_parent_topology_bug(child, parent_phy, child_phy);
|
|
||||||
res = -ENODEV;
|
|
||||||
}
|
|
||||||
} else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) {
|
|
||||||
if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) {
|
|
||||||
res = sas_check_eeds(child, parent_phy, child_phy);
|
|
||||||
} else if (child_phy->routing_attr != TABLE_ROUTING) {
|
|
||||||
sas_print_parent_topology_bug(child, parent_phy, child_phy);
|
|
||||||
res = -ENODEV;
|
|
||||||
}
|
|
||||||
} else if (parent_phy->routing_attr == TABLE_ROUTING) {
|
|
||||||
if (child_phy->routing_attr == SUBTRACTIVE_ROUTING ||
|
|
||||||
(child_phy->routing_attr == TABLE_ROUTING &&
|
|
||||||
child_ex->t2t_supp && parent_ex->t2t_supp)) {
|
|
||||||
/* All good */;
|
|
||||||
} else {
|
|
||||||
sas_print_parent_topology_bug(child, parent_phy, child_phy);
|
|
||||||
res = -ENODEV;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case SAS_FANOUT_EXPANDER_DEVICE:
|
case SAS_FANOUT_EXPANDER_DEVICE:
|
||||||
if (parent_phy->routing_attr != TABLE_ROUTING ||
|
if (sas_check_fanout_expander_topo(child, parent_phy))
|
||||||
child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
|
|
||||||
sas_print_parent_topology_bug(child, parent_phy, child_phy);
|
|
||||||
res = -ENODEV;
|
res = -ENODEV;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -429,6 +429,15 @@ struct lpfc_cgn_param {
|
|||||||
/* Max number of days of congestion data */
|
/* Max number of days of congestion data */
|
||||||
#define LPFC_MAX_CGN_DAYS 10
|
#define LPFC_MAX_CGN_DAYS 10
|
||||||
|
|
||||||
|
struct lpfc_cgn_ts {
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t day;
|
||||||
|
uint8_t year;
|
||||||
|
uint8_t hour;
|
||||||
|
uint8_t minute;
|
||||||
|
uint8_t second;
|
||||||
|
};
|
||||||
|
|
||||||
/* Format of congestion buffer info
|
/* Format of congestion buffer info
|
||||||
* This structure defines memory thats allocated and registered with
|
* This structure defines memory thats allocated and registered with
|
||||||
* the HBA firmware. When adding or removing fields from this structure
|
* the HBA firmware. When adding or removing fields from this structure
|
||||||
@@ -442,6 +451,7 @@ struct lpfc_cgn_info {
|
|||||||
#define LPFC_CGN_INFO_V1 1
|
#define LPFC_CGN_INFO_V1 1
|
||||||
#define LPFC_CGN_INFO_V2 2
|
#define LPFC_CGN_INFO_V2 2
|
||||||
#define LPFC_CGN_INFO_V3 3
|
#define LPFC_CGN_INFO_V3 3
|
||||||
|
#define LPFC_CGN_INFO_V4 4
|
||||||
uint8_t cgn_info_mode; /* 0=off 1=managed 2=monitor only */
|
uint8_t cgn_info_mode; /* 0=off 1=managed 2=monitor only */
|
||||||
uint8_t cgn_info_detect;
|
uint8_t cgn_info_detect;
|
||||||
uint8_t cgn_info_action;
|
uint8_t cgn_info_action;
|
||||||
@@ -450,12 +460,7 @@ struct lpfc_cgn_info {
|
|||||||
uint8_t cgn_info_level2;
|
uint8_t cgn_info_level2;
|
||||||
|
|
||||||
/* Start Time */
|
/* Start Time */
|
||||||
uint8_t cgn_info_month;
|
struct lpfc_cgn_ts base_time;
|
||||||
uint8_t cgn_info_day;
|
|
||||||
uint8_t cgn_info_year;
|
|
||||||
uint8_t cgn_info_hour;
|
|
||||||
uint8_t cgn_info_minute;
|
|
||||||
uint8_t cgn_info_second;
|
|
||||||
|
|
||||||
/* minute / hours / daily indices */
|
/* minute / hours / daily indices */
|
||||||
uint8_t cgn_index_minute;
|
uint8_t cgn_index_minute;
|
||||||
@@ -496,45 +501,17 @@ struct lpfc_cgn_info {
|
|||||||
uint8_t cgn_stat_npm; /* Notifications per minute */
|
uint8_t cgn_stat_npm; /* Notifications per minute */
|
||||||
|
|
||||||
/* Start Time */
|
/* Start Time */
|
||||||
uint8_t cgn_stat_month;
|
struct lpfc_cgn_ts stat_start; /* Base time */
|
||||||
uint8_t cgn_stat_day;
|
uint8_t cgn_pad2;
|
||||||
uint8_t cgn_stat_year;
|
|
||||||
uint8_t cgn_stat_hour;
|
|
||||||
uint8_t cgn_stat_minute;
|
|
||||||
uint8_t cgn_pad2[2];
|
|
||||||
|
|
||||||
__le32 cgn_notification;
|
__le32 cgn_notification;
|
||||||
__le32 cgn_peer_notification;
|
__le32 cgn_peer_notification;
|
||||||
__le32 link_integ_notification;
|
__le32 link_integ_notification;
|
||||||
__le32 delivery_notification;
|
__le32 delivery_notification;
|
||||||
|
struct lpfc_cgn_ts stat_fpin; /* Last congestion notification FPIN */
|
||||||
uint8_t cgn_stat_cgn_month; /* Last congestion notification FPIN */
|
struct lpfc_cgn_ts stat_peer; /* Last peer congestion FPIN */
|
||||||
uint8_t cgn_stat_cgn_day;
|
struct lpfc_cgn_ts stat_lnk; /* Last link integrity FPIN */
|
||||||
uint8_t cgn_stat_cgn_year;
|
struct lpfc_cgn_ts stat_delivery; /* Last delivery notification FPIN */
|
||||||
uint8_t cgn_stat_cgn_hour;
|
|
||||||
uint8_t cgn_stat_cgn_min;
|
|
||||||
uint8_t cgn_stat_cgn_sec;
|
|
||||||
|
|
||||||
uint8_t cgn_stat_peer_month; /* Last peer congestion FPIN */
|
|
||||||
uint8_t cgn_stat_peer_day;
|
|
||||||
uint8_t cgn_stat_peer_year;
|
|
||||||
uint8_t cgn_stat_peer_hour;
|
|
||||||
uint8_t cgn_stat_peer_min;
|
|
||||||
uint8_t cgn_stat_peer_sec;
|
|
||||||
|
|
||||||
uint8_t cgn_stat_lnk_month; /* Last link integrity FPIN */
|
|
||||||
uint8_t cgn_stat_lnk_day;
|
|
||||||
uint8_t cgn_stat_lnk_year;
|
|
||||||
uint8_t cgn_stat_lnk_hour;
|
|
||||||
uint8_t cgn_stat_lnk_min;
|
|
||||||
uint8_t cgn_stat_lnk_sec;
|
|
||||||
|
|
||||||
uint8_t cgn_stat_del_month; /* Last delivery notification FPIN */
|
|
||||||
uint8_t cgn_stat_del_day;
|
|
||||||
uint8_t cgn_stat_del_year;
|
|
||||||
uint8_t cgn_stat_del_hour;
|
|
||||||
uint8_t cgn_stat_del_min;
|
|
||||||
uint8_t cgn_stat_del_sec;
|
|
||||||
);
|
);
|
||||||
|
|
||||||
__le32 cgn_info_crc;
|
__le32 cgn_info_crc;
|
||||||
@@ -932,8 +909,6 @@ struct lpfc_hba {
|
|||||||
void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *,
|
void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *,
|
||||||
struct lpfc_iocbq *);
|
struct lpfc_iocbq *);
|
||||||
int (*lpfc_hba_down_post)(struct lpfc_hba *phba);
|
int (*lpfc_hba_down_post)(struct lpfc_hba *phba);
|
||||||
void (*lpfc_scsi_cmd_iocb_cmpl)
|
|
||||||
(struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *);
|
|
||||||
|
|
||||||
/* MBOX interface function jump table entries */
|
/* MBOX interface function jump table entries */
|
||||||
int (*lpfc_sli_issue_mbox)
|
int (*lpfc_sli_issue_mbox)
|
||||||
@@ -1045,8 +1020,6 @@ struct lpfc_hba {
|
|||||||
* capability
|
* capability
|
||||||
*/
|
*/
|
||||||
#define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */
|
#define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */
|
||||||
#define HBA_SHORT_CMF 0x200000 /* shorter CMF timer routine */
|
|
||||||
#define HBA_CGN_DAY_WRAP 0x400000 /* HBA Congestion info day wraps */
|
|
||||||
#define HBA_DEFER_FLOGI 0x800000 /* Defer FLOGI till read_sparm cmpl */
|
#define HBA_DEFER_FLOGI 0x800000 /* Defer FLOGI till read_sparm cmpl */
|
||||||
#define HBA_SETUP 0x1000000 /* Signifies HBA setup is completed */
|
#define HBA_SETUP 0x1000000 /* Signifies HBA setup is completed */
|
||||||
#define HBA_NEEDS_CFG_PORT 0x2000000 /* SLI3 - needs a CONFIG_PORT mbox */
|
#define HBA_NEEDS_CFG_PORT 0x2000000 /* SLI3 - needs a CONFIG_PORT mbox */
|
||||||
@@ -1529,6 +1502,7 @@ struct lpfc_hba {
|
|||||||
uint64_t cmf_last_sync_bw;
|
uint64_t cmf_last_sync_bw;
|
||||||
#define LPFC_CMF_BLK_SIZE 512
|
#define LPFC_CMF_BLK_SIZE 512
|
||||||
struct hrtimer cmf_timer;
|
struct hrtimer cmf_timer;
|
||||||
|
struct hrtimer cmf_stats_timer; /* 1 minute stats timer */
|
||||||
atomic_t cmf_bw_wait;
|
atomic_t cmf_bw_wait;
|
||||||
atomic_t cmf_busy;
|
atomic_t cmf_busy;
|
||||||
atomic_t cmf_stop_io; /* To block request and stop IO's */
|
atomic_t cmf_stop_io; /* To block request and stop IO's */
|
||||||
@@ -1576,12 +1550,11 @@ struct lpfc_hba {
|
|||||||
atomic_t cgn_sync_alarm_cnt; /* Total alarm events for SYNC wqe */
|
atomic_t cgn_sync_alarm_cnt; /* Total alarm events for SYNC wqe */
|
||||||
atomic_t cgn_driver_evt_cnt; /* Total driver cgn events for fmw */
|
atomic_t cgn_driver_evt_cnt; /* Total driver cgn events for fmw */
|
||||||
atomic_t cgn_latency_evt_cnt;
|
atomic_t cgn_latency_evt_cnt;
|
||||||
struct timespec64 cgn_daily_ts;
|
|
||||||
atomic64_t cgn_latency_evt; /* Avg latency per minute */
|
atomic64_t cgn_latency_evt; /* Avg latency per minute */
|
||||||
unsigned long cgn_evt_timestamp;
|
unsigned long cgn_evt_timestamp;
|
||||||
#define LPFC_CGN_TIMER_TO_MIN 60000 /* ms in a minute */
|
#define LPFC_CGN_TIMER_TO_MIN 60000 /* ms in a minute */
|
||||||
uint32_t cgn_evt_minute;
|
uint32_t cgn_evt_minute;
|
||||||
#define LPFC_SEC_MIN 60
|
#define LPFC_SEC_MIN 60UL
|
||||||
#define LPFC_MIN_HOUR 60
|
#define LPFC_MIN_HOUR 60
|
||||||
#define LPFC_HOUR_DAY 24
|
#define LPFC_HOUR_DAY 24
|
||||||
#define LPFC_MIN_DAY (LPFC_MIN_HOUR * LPFC_HOUR_DAY)
|
#define LPFC_MIN_DAY (LPFC_MIN_HOUR * LPFC_HOUR_DAY)
|
||||||
|
|||||||
@@ -5858,8 +5858,8 @@ int lpfc_fabric_cgn_frequency = 100; /* 100 ms default */
|
|||||||
module_param(lpfc_fabric_cgn_frequency, int, 0444);
|
module_param(lpfc_fabric_cgn_frequency, int, 0444);
|
||||||
MODULE_PARM_DESC(lpfc_fabric_cgn_frequency, "Congestion signaling fabric freq");
|
MODULE_PARM_DESC(lpfc_fabric_cgn_frequency, "Congestion signaling fabric freq");
|
||||||
|
|
||||||
int lpfc_acqe_cgn_frequency = 10; /* 10 sec default */
|
unsigned char lpfc_acqe_cgn_frequency = 10; /* 10 sec default */
|
||||||
module_param(lpfc_acqe_cgn_frequency, int, 0444);
|
module_param(lpfc_acqe_cgn_frequency, byte, 0444);
|
||||||
MODULE_PARM_DESC(lpfc_acqe_cgn_frequency, "Congestion signaling ACQE freq");
|
MODULE_PARM_DESC(lpfc_acqe_cgn_frequency, "Congestion signaling ACQE freq");
|
||||||
|
|
||||||
int lpfc_use_cgn_signal = 1; /* 0 - only use FPINs, 1 - Use signals if avail */
|
int lpfc_use_cgn_signal = 1; /* 0 - only use FPINs, 1 - Use signals if avail */
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ void lpfc_check_nlp_post_devloss(struct lpfc_vport *vport,
|
|||||||
struct lpfc_nodelist *ndlp);
|
struct lpfc_nodelist *ndlp);
|
||||||
void lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
void lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||||
struct lpfc_iocbq *rspiocb);
|
struct lpfc_iocbq *rspiocb);
|
||||||
int lpfc_nlp_not_used(struct lpfc_nodelist *ndlp);
|
|
||||||
struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
|
struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
|
||||||
void lpfc_disc_list_loopmap(struct lpfc_vport *);
|
void lpfc_disc_list_loopmap(struct lpfc_vport *);
|
||||||
void lpfc_disc_start(struct lpfc_vport *);
|
void lpfc_disc_start(struct lpfc_vport *);
|
||||||
@@ -248,6 +247,7 @@ irqreturn_t lpfc_sli_sp_intr_handler(int, void *);
|
|||||||
irqreturn_t lpfc_sli_fp_intr_handler(int, void *);
|
irqreturn_t lpfc_sli_fp_intr_handler(int, void *);
|
||||||
irqreturn_t lpfc_sli4_intr_handler(int, void *);
|
irqreturn_t lpfc_sli4_intr_handler(int, void *);
|
||||||
irqreturn_t lpfc_sli4_hba_intr_handler(int, void *);
|
irqreturn_t lpfc_sli4_hba_intr_handler(int, void *);
|
||||||
|
irqreturn_t lpfc_sli4_hba_intr_handler_th(int irq, void *dev_id);
|
||||||
|
|
||||||
int lpfc_read_object(struct lpfc_hba *phba, char *s, uint32_t *datap,
|
int lpfc_read_object(struct lpfc_hba *phba, char *s, uint32_t *datap,
|
||||||
uint32_t len);
|
uint32_t len);
|
||||||
@@ -664,7 +664,7 @@ extern int lpfc_enable_nvmet_cnt;
|
|||||||
extern unsigned long long lpfc_enable_nvmet[];
|
extern unsigned long long lpfc_enable_nvmet[];
|
||||||
extern int lpfc_no_hba_reset_cnt;
|
extern int lpfc_no_hba_reset_cnt;
|
||||||
extern unsigned long lpfc_no_hba_reset[];
|
extern unsigned long lpfc_no_hba_reset[];
|
||||||
extern int lpfc_acqe_cgn_frequency;
|
extern unsigned char lpfc_acqe_cgn_frequency;
|
||||||
extern int lpfc_fabric_cgn_frequency;
|
extern int lpfc_fabric_cgn_frequency;
|
||||||
extern int lpfc_use_cgn_signal;
|
extern int lpfc_use_cgn_signal;
|
||||||
|
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq)
|
|||||||
u32 ulp_status = get_job_ulpstatus(phba, ctiocbq);
|
u32 ulp_status = get_job_ulpstatus(phba, ctiocbq);
|
||||||
u32 ulp_word4 = get_job_word4(phba, ctiocbq);
|
u32 ulp_word4 = get_job_word4(phba, ctiocbq);
|
||||||
u32 did;
|
u32 did;
|
||||||
u32 mi_cmd;
|
u16 mi_cmd;
|
||||||
|
|
||||||
did = bf_get(els_rsp64_sid, &ctiocbq->wqe.xmit_els_rsp);
|
did = bf_get(els_rsp64_sid, &ctiocbq->wqe.xmit_els_rsp);
|
||||||
if (ulp_status) {
|
if (ulp_status) {
|
||||||
@@ -311,7 +311,7 @@ lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq)
|
|||||||
|
|
||||||
ct_req = (struct lpfc_sli_ct_request *)ctiocbq->cmd_dmabuf->virt;
|
ct_req = (struct lpfc_sli_ct_request *)ctiocbq->cmd_dmabuf->virt;
|
||||||
|
|
||||||
mi_cmd = ct_req->CommandResponse.bits.CmdRsp;
|
mi_cmd = be16_to_cpu(ct_req->CommandResponse.bits.CmdRsp);
|
||||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
||||||
"6442 : MI Cmd : x%x Not Supported\n", mi_cmd);
|
"6442 : MI Cmd : x%x Not Supported\n", mi_cmd);
|
||||||
lpfc_ct_reject_event(ndlp, ct_req,
|
lpfc_ct_reject_event(ndlp, ct_req,
|
||||||
@@ -486,7 +486,7 @@ lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct lpfc_dmabuf *
|
static struct lpfc_dmabuf *
|
||||||
lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
|
lpfc_alloc_ct_rsp(struct lpfc_hba *phba, __be16 cmdcode, struct ulp_bde64 *bpl,
|
||||||
uint32_t size, int *entries)
|
uint32_t size, int *entries)
|
||||||
{
|
{
|
||||||
struct lpfc_dmabuf *mlist = NULL;
|
struct lpfc_dmabuf *mlist = NULL;
|
||||||
@@ -507,8 +507,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
|
|||||||
|
|
||||||
INIT_LIST_HEAD(&mp->list);
|
INIT_LIST_HEAD(&mp->list);
|
||||||
|
|
||||||
if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) ||
|
if (be16_to_cpu(cmdcode) == SLI_CTNS_GID_FT ||
|
||||||
cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID))
|
be16_to_cpu(cmdcode) == SLI_CTNS_GFF_ID)
|
||||||
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
|
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
|
||||||
else
|
else
|
||||||
mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
|
mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
|
||||||
@@ -671,7 +671,7 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
|
|||||||
struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt;
|
struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt;
|
||||||
struct lpfc_dmabuf *outmp;
|
struct lpfc_dmabuf *outmp;
|
||||||
int cnt = 0, status;
|
int cnt = 0, status;
|
||||||
int cmdcode = ((struct lpfc_sli_ct_request *) inmp->virt)->
|
__be16 cmdcode = ((struct lpfc_sli_ct_request *)inmp->virt)->
|
||||||
CommandResponse.bits.CmdRsp;
|
CommandResponse.bits.CmdRsp;
|
||||||
|
|
||||||
bpl++; /* Skip past ct request */
|
bpl++; /* Skip past ct request */
|
||||||
@@ -1043,8 +1043,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
outp,
|
outp,
|
||||||
CTreq->un.gid.Fc4Type,
|
CTreq->un.gid.Fc4Type,
|
||||||
get_job_data_placed(phba, rspiocb));
|
get_job_data_placed(phba, rspiocb));
|
||||||
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
|
} else if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
|
SLI_CT_RESPONSE_FS_RJT) {
|
||||||
/* NameServer Rsp Error */
|
/* NameServer Rsp Error */
|
||||||
if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
|
if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
|
||||||
&& (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
|
&& (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
|
||||||
@@ -1052,14 +1052,14 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
LOG_DISCOVERY,
|
LOG_DISCOVERY,
|
||||||
"0269 No NameServer Entries "
|
"0269 No NameServer Entries "
|
||||||
"Data: x%x x%x x%x x%x\n",
|
"Data: x%x x%x x%x x%x\n",
|
||||||
CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t) CTrsp->ReasonCode,
|
(uint32_t) CTrsp->ReasonCode,
|
||||||
(uint32_t) CTrsp->Explanation,
|
(uint32_t) CTrsp->Explanation,
|
||||||
vport->fc_flag);
|
vport->fc_flag);
|
||||||
|
|
||||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||||
"GID_FT no entry cmd:x%x rsn:x%x exp:x%x",
|
"GID_FT no entry cmd:x%x rsn:x%x exp:x%x",
|
||||||
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t) CTrsp->ReasonCode,
|
(uint32_t) CTrsp->ReasonCode,
|
||||||
(uint32_t) CTrsp->Explanation);
|
(uint32_t) CTrsp->Explanation);
|
||||||
} else {
|
} else {
|
||||||
@@ -1067,14 +1067,14 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
LOG_DISCOVERY,
|
LOG_DISCOVERY,
|
||||||
"0240 NameServer Rsp Error "
|
"0240 NameServer Rsp Error "
|
||||||
"Data: x%x x%x x%x x%x\n",
|
"Data: x%x x%x x%x x%x\n",
|
||||||
CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t) CTrsp->ReasonCode,
|
(uint32_t) CTrsp->ReasonCode,
|
||||||
(uint32_t) CTrsp->Explanation,
|
(uint32_t) CTrsp->Explanation,
|
||||||
vport->fc_flag);
|
vport->fc_flag);
|
||||||
|
|
||||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||||
"GID_FT rsp err1 cmd:x%x rsn:x%x exp:x%x",
|
"GID_FT rsp err1 cmd:x%x rsn:x%x exp:x%x",
|
||||||
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t) CTrsp->ReasonCode,
|
(uint32_t) CTrsp->ReasonCode,
|
||||||
(uint32_t) CTrsp->Explanation);
|
(uint32_t) CTrsp->Explanation);
|
||||||
}
|
}
|
||||||
@@ -1085,14 +1085,14 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
"0241 NameServer Rsp Error "
|
"0241 NameServer Rsp Error "
|
||||||
"Data: x%x x%x x%x x%x\n",
|
"Data: x%x x%x x%x x%x\n",
|
||||||
CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t) CTrsp->ReasonCode,
|
(uint32_t) CTrsp->ReasonCode,
|
||||||
(uint32_t) CTrsp->Explanation,
|
(uint32_t) CTrsp->Explanation,
|
||||||
vport->fc_flag);
|
vport->fc_flag);
|
||||||
|
|
||||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||||
"GID_FT rsp err2 cmd:x%x rsn:x%x exp:x%x",
|
"GID_FT rsp err2 cmd:x%x rsn:x%x exp:x%x",
|
||||||
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t) CTrsp->ReasonCode,
|
(uint32_t) CTrsp->ReasonCode,
|
||||||
(uint32_t) CTrsp->Explanation);
|
(uint32_t) CTrsp->Explanation);
|
||||||
}
|
}
|
||||||
@@ -1247,8 +1247,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
/* Good status, continue checking */
|
/* Good status, continue checking */
|
||||||
CTreq = (struct lpfc_sli_ct_request *)inp->virt;
|
CTreq = (struct lpfc_sli_ct_request *)inp->virt;
|
||||||
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
||||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) {
|
SLI_CT_RESPONSE_FS_ACC) {
|
||||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
||||||
"4105 NameServer Rsp Data: x%x x%x "
|
"4105 NameServer Rsp Data: x%x x%x "
|
||||||
"x%x x%x sz x%x\n",
|
"x%x x%x sz x%x\n",
|
||||||
@@ -1262,8 +1262,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
outp,
|
outp,
|
||||||
CTreq->un.gid.Fc4Type,
|
CTreq->un.gid.Fc4Type,
|
||||||
get_job_data_placed(phba, rspiocb));
|
get_job_data_placed(phba, rspiocb));
|
||||||
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
|
} else if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
|
SLI_CT_RESPONSE_FS_RJT) {
|
||||||
/* NameServer Rsp Error */
|
/* NameServer Rsp Error */
|
||||||
if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
|
if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
|
||||||
&& (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
|
&& (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
|
||||||
@@ -1271,7 +1271,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
vport, KERN_INFO, LOG_DISCOVERY,
|
vport, KERN_INFO, LOG_DISCOVERY,
|
||||||
"4106 No NameServer Entries "
|
"4106 No NameServer Entries "
|
||||||
"Data: x%x x%x x%x x%x\n",
|
"Data: x%x x%x x%x x%x\n",
|
||||||
CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t)CTrsp->ReasonCode,
|
(uint32_t)CTrsp->ReasonCode,
|
||||||
(uint32_t)CTrsp->Explanation,
|
(uint32_t)CTrsp->Explanation,
|
||||||
vport->fc_flag);
|
vport->fc_flag);
|
||||||
@@ -1279,7 +1279,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
lpfc_debugfs_disc_trc(
|
lpfc_debugfs_disc_trc(
|
||||||
vport, LPFC_DISC_TRC_CT,
|
vport, LPFC_DISC_TRC_CT,
|
||||||
"GID_PT no entry cmd:x%x rsn:x%x exp:x%x",
|
"GID_PT no entry cmd:x%x rsn:x%x exp:x%x",
|
||||||
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t)CTrsp->ReasonCode,
|
(uint32_t)CTrsp->ReasonCode,
|
||||||
(uint32_t)CTrsp->Explanation);
|
(uint32_t)CTrsp->Explanation);
|
||||||
} else {
|
} else {
|
||||||
@@ -1287,7 +1287,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
vport, KERN_INFO, LOG_DISCOVERY,
|
vport, KERN_INFO, LOG_DISCOVERY,
|
||||||
"4107 NameServer Rsp Error "
|
"4107 NameServer Rsp Error "
|
||||||
"Data: x%x x%x x%x x%x\n",
|
"Data: x%x x%x x%x x%x\n",
|
||||||
CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t)CTrsp->ReasonCode,
|
(uint32_t)CTrsp->ReasonCode,
|
||||||
(uint32_t)CTrsp->Explanation,
|
(uint32_t)CTrsp->Explanation,
|
||||||
vport->fc_flag);
|
vport->fc_flag);
|
||||||
@@ -1295,7 +1295,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
lpfc_debugfs_disc_trc(
|
lpfc_debugfs_disc_trc(
|
||||||
vport, LPFC_DISC_TRC_CT,
|
vport, LPFC_DISC_TRC_CT,
|
||||||
"GID_PT rsp err1 cmd:x%x rsn:x%x exp:x%x",
|
"GID_PT rsp err1 cmd:x%x rsn:x%x exp:x%x",
|
||||||
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t)CTrsp->ReasonCode,
|
(uint32_t)CTrsp->ReasonCode,
|
||||||
(uint32_t)CTrsp->Explanation);
|
(uint32_t)CTrsp->Explanation);
|
||||||
}
|
}
|
||||||
@@ -1304,7 +1304,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
"4109 NameServer Rsp Error "
|
"4109 NameServer Rsp Error "
|
||||||
"Data: x%x x%x x%x x%x\n",
|
"Data: x%x x%x x%x x%x\n",
|
||||||
CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t)CTrsp->ReasonCode,
|
(uint32_t)CTrsp->ReasonCode,
|
||||||
(uint32_t)CTrsp->Explanation,
|
(uint32_t)CTrsp->Explanation,
|
||||||
vport->fc_flag);
|
vport->fc_flag);
|
||||||
@@ -1312,7 +1312,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
lpfc_debugfs_disc_trc(
|
lpfc_debugfs_disc_trc(
|
||||||
vport, LPFC_DISC_TRC_CT,
|
vport, LPFC_DISC_TRC_CT,
|
||||||
"GID_PT rsp err2 cmd:x%x rsn:x%x exp:x%x",
|
"GID_PT rsp err2 cmd:x%x rsn:x%x exp:x%x",
|
||||||
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
(uint32_t)CTrsp->ReasonCode,
|
(uint32_t)CTrsp->ReasonCode,
|
||||||
(uint32_t)CTrsp->Explanation);
|
(uint32_t)CTrsp->Explanation);
|
||||||
}
|
}
|
||||||
@@ -1391,8 +1391,8 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
(fbits & FC4_FEATURE_INIT) ? "Initiator" : " ",
|
(fbits & FC4_FEATURE_INIT) ? "Initiator" : " ",
|
||||||
(fbits & FC4_FEATURE_TARGET) ? "Target" : " ");
|
(fbits & FC4_FEATURE_TARGET) ? "Target" : " ");
|
||||||
|
|
||||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
|
SLI_CT_RESPONSE_FS_ACC) {
|
||||||
if ((fbits & FC4_FEATURE_INIT) &&
|
if ((fbits & FC4_FEATURE_INIT) &&
|
||||||
!(fbits & FC4_FEATURE_TARGET)) {
|
!(fbits & FC4_FEATURE_TARGET)) {
|
||||||
lpfc_printf_vlog(vport, KERN_INFO,
|
lpfc_printf_vlog(vport, KERN_INFO,
|
||||||
@@ -1631,7 +1631,7 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
"0209 CT Request completes, latt %d, "
|
"0209 CT Request completes, latt %d, "
|
||||||
"ulp_status x%x CmdRsp x%x, Context x%x, Tag x%x\n",
|
"ulp_status x%x CmdRsp x%x, Context x%x, Tag x%x\n",
|
||||||
latt, ulp_status,
|
latt, ulp_status,
|
||||||
CTrsp->CommandResponse.bits.CmdRsp,
|
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||||
get_job_ulpcontext(phba, cmdiocb), cmdiocb->iotag);
|
get_job_ulpcontext(phba, cmdiocb), cmdiocb->iotag);
|
||||||
|
|
||||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||||
@@ -1681,8 +1681,8 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
|
|
||||||
outp = cmdiocb->rsp_dmabuf;
|
outp = cmdiocb->rsp_dmabuf;
|
||||||
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
||||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
SLI_CT_RESPONSE_FS_ACC)
|
||||||
vport->ct_flags |= FC_CT_RFT_ID;
|
vport->ct_flags |= FC_CT_RFT_ID;
|
||||||
}
|
}
|
||||||
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
||||||
@@ -1702,8 +1702,8 @@ lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
|
|
||||||
outp = cmdiocb->rsp_dmabuf;
|
outp = cmdiocb->rsp_dmabuf;
|
||||||
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
||||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
SLI_CT_RESPONSE_FS_ACC)
|
||||||
vport->ct_flags |= FC_CT_RNN_ID;
|
vport->ct_flags |= FC_CT_RNN_ID;
|
||||||
}
|
}
|
||||||
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
||||||
@@ -1723,8 +1723,8 @@ lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
|
|
||||||
outp = cmdiocb->rsp_dmabuf;
|
outp = cmdiocb->rsp_dmabuf;
|
||||||
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
||||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
SLI_CT_RESPONSE_FS_ACC)
|
||||||
vport->ct_flags |= FC_CT_RSPN_ID;
|
vport->ct_flags |= FC_CT_RSPN_ID;
|
||||||
}
|
}
|
||||||
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
||||||
@@ -1744,8 +1744,8 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
|
|
||||||
outp = cmdiocb->rsp_dmabuf;
|
outp = cmdiocb->rsp_dmabuf;
|
||||||
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
||||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
SLI_CT_RESPONSE_FS_ACC)
|
||||||
vport->ct_flags |= FC_CT_RSNN_NN;
|
vport->ct_flags |= FC_CT_RSNN_NN;
|
||||||
}
|
}
|
||||||
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
||||||
@@ -1777,8 +1777,8 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
|
|
||||||
outp = cmdiocb->rsp_dmabuf;
|
outp = cmdiocb->rsp_dmabuf;
|
||||||
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
||||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
SLI_CT_RESPONSE_FS_ACC)
|
||||||
vport->ct_flags |= FC_CT_RFF_ID;
|
vport->ct_flags |= FC_CT_RFF_ID;
|
||||||
}
|
}
|
||||||
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
||||||
@@ -2217,8 +2217,8 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf;
|
struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf;
|
||||||
struct lpfc_sli_ct_request *CTcmd = inp->virt;
|
struct lpfc_sli_ct_request *CTcmd = inp->virt;
|
||||||
struct lpfc_sli_ct_request *CTrsp = outp->virt;
|
struct lpfc_sli_ct_request *CTrsp = outp->virt;
|
||||||
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
|
__be16 fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
|
||||||
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
|
__be16 fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
|
||||||
struct lpfc_nodelist *ndlp, *free_ndlp = NULL;
|
struct lpfc_nodelist *ndlp, *free_ndlp = NULL;
|
||||||
uint32_t latt, cmd, err;
|
uint32_t latt, cmd, err;
|
||||||
u32 ulp_status = get_job_ulpstatus(phba, rspiocb);
|
u32 ulp_status = get_job_ulpstatus(phba, rspiocb);
|
||||||
@@ -2278,7 +2278,7 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
|
|
||||||
/* Check for a CT LS_RJT response */
|
/* Check for a CT LS_RJT response */
|
||||||
cmd = be16_to_cpu(fdmi_cmd);
|
cmd = be16_to_cpu(fdmi_cmd);
|
||||||
if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) {
|
if (be16_to_cpu(fdmi_rsp) == SLI_CT_RESPONSE_FS_RJT) {
|
||||||
/* FDMI rsp failed */
|
/* FDMI rsp failed */
|
||||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_ELS,
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_ELS,
|
||||||
"0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
|
"0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
|
||||||
@@ -3110,7 +3110,7 @@ lpfc_fdmi_vendor_attr_mi(struct lpfc_vport *vport, void *attr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* RHBA attribute jump table */
|
/* RHBA attribute jump table */
|
||||||
int (*lpfc_fdmi_hba_action[])
|
static int (*lpfc_fdmi_hba_action[])
|
||||||
(struct lpfc_vport *vport, void *attrbuf) = {
|
(struct lpfc_vport *vport, void *attrbuf) = {
|
||||||
/* Action routine Mask bit Attribute type */
|
/* Action routine Mask bit Attribute type */
|
||||||
lpfc_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */
|
lpfc_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */
|
||||||
@@ -3134,7 +3134,7 @@ int (*lpfc_fdmi_hba_action[])
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* RPA / RPRT attribute jump table */
|
/* RPA / RPRT attribute jump table */
|
||||||
int (*lpfc_fdmi_port_action[])
|
static int (*lpfc_fdmi_port_action[])
|
||||||
(struct lpfc_vport *vport, void *attrbuf) = {
|
(struct lpfc_vport *vport, void *attrbuf) = {
|
||||||
/* Action routine Mask bit Attribute type */
|
/* Action routine Mask bit Attribute type */
|
||||||
lpfc_fdmi_port_attr_fc4type, /* bit0 RPRT_SUPPORT_FC4_TYPES */
|
lpfc_fdmi_port_attr_fc4type, /* bit0 RPRT_SUPPORT_FC4_TYPES */
|
||||||
@@ -3570,7 +3570,7 @@ lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf;
|
struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf;
|
||||||
struct lpfc_sli_ct_request *ctcmd = inp->virt;
|
struct lpfc_sli_ct_request *ctcmd = inp->virt;
|
||||||
struct lpfc_sli_ct_request *ctrsp = outp->virt;
|
struct lpfc_sli_ct_request *ctrsp = outp->virt;
|
||||||
u16 rsp = ctrsp->CommandResponse.bits.CmdRsp;
|
__be16 rsp = ctrsp->CommandResponse.bits.CmdRsp;
|
||||||
struct app_id_object *app;
|
struct app_id_object *app;
|
||||||
struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
|
struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
|
||||||
u32 cmd, hash, bucket;
|
u32 cmd, hash, bucket;
|
||||||
@@ -3587,7 +3587,7 @@ lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
goto free_res;
|
goto free_res;
|
||||||
}
|
}
|
||||||
/* Check for a CT LS_RJT response */
|
/* Check for a CT LS_RJT response */
|
||||||
if (rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
|
if (be16_to_cpu(rsp) == SLI_CT_RESPONSE_FS_RJT) {
|
||||||
if (cmd != SLI_CTAS_DALLAPP_ID)
|
if (cmd != SLI_CTAS_DALLAPP_ID)
|
||||||
lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
|
lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
|
||||||
"3306 VMID FS_RJT Data: x%x x%x x%x\n",
|
"3306 VMID FS_RJT Data: x%x x%x x%x\n",
|
||||||
@@ -3748,7 +3748,7 @@ lpfc_vmid_cmd(struct lpfc_vport *vport,
|
|||||||
rap->obj[0].entity_id_len = vmid->vmid_len;
|
rap->obj[0].entity_id_len = vmid->vmid_len;
|
||||||
memcpy(rap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
|
memcpy(rap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
|
||||||
size = RAPP_IDENT_OFFSET +
|
size = RAPP_IDENT_OFFSET +
|
||||||
sizeof(struct lpfc_vmid_rapp_ident_list);
|
struct_size(rap, obj, be32_to_cpu(rap->no_of_objects));
|
||||||
retry = 1;
|
retry = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3767,7 +3767,7 @@ lpfc_vmid_cmd(struct lpfc_vport *vport,
|
|||||||
dap->obj[0].entity_id_len = vmid->vmid_len;
|
dap->obj[0].entity_id_len = vmid->vmid_len;
|
||||||
memcpy(dap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
|
memcpy(dap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
|
||||||
size = DAPP_IDENT_OFFSET +
|
size = DAPP_IDENT_OFFSET +
|
||||||
sizeof(struct lpfc_vmid_dapp_ident_list);
|
struct_size(dap, obj, be32_to_cpu(dap->no_of_objects));
|
||||||
write_lock(&vport->vmid_lock);
|
write_lock(&vport->vmid_lock);
|
||||||
vmid->flag &= ~LPFC_VMID_REGISTERED;
|
vmid->flag &= ~LPFC_VMID_REGISTERED;
|
||||||
write_unlock(&vport->vmid_lock);
|
write_unlock(&vport->vmid_lock);
|
||||||
|
|||||||
@@ -2259,11 +2259,15 @@ lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&phba->hbalock);
|
spin_unlock_irq(&phba->hbalock);
|
||||||
debug = kmalloc(sizeof(*debug), GFP_KERNEL);
|
|
||||||
|
if (check_mul_overflow(LPFC_RAS_MIN_BUFF_POST_SIZE,
|
||||||
|
phba->cfg_ras_fwlog_buffsize, &size))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
debug = kzalloc(sizeof(*debug), GFP_KERNEL);
|
||||||
if (!debug)
|
if (!debug)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
size = LPFC_RAS_MIN_BUFF_POST_SIZE * phba->cfg_ras_fwlog_buffsize;
|
|
||||||
debug->buffer = vmalloc(size);
|
debug->buffer = vmalloc(size);
|
||||||
if (!debug->buffer)
|
if (!debug->buffer)
|
||||||
goto free_debug;
|
goto free_debug;
|
||||||
|
|||||||
@@ -5205,14 +5205,9 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
|
|||||||
*
|
*
|
||||||
* This routine is the completion callback function to the Logout (LOGO)
|
* This routine is the completion callback function to the Logout (LOGO)
|
||||||
* Accept (ACC) Response ELS command. This routine is invoked to indicate
|
* Accept (ACC) Response ELS command. This routine is invoked to indicate
|
||||||
* the completion of the LOGO process. It invokes the lpfc_nlp_not_used() to
|
* the completion of the LOGO process. If the node has transitioned to NPR,
|
||||||
* release the ndlp if it has the last reference remaining (reference count
|
* this routine unregisters the RPI if it is still registered. The
|
||||||
* is 1). If succeeded (meaning ndlp released), it sets the iocb ndlp
|
* lpfc_els_free_iocb() is invoked to release the IOCB data structure.
|
||||||
* field to NULL to inform the following lpfc_els_free_iocb() routine no
|
|
||||||
* ndlp reference count needs to be decremented. Otherwise, the ndlp
|
|
||||||
* reference use-count shall be decremented by the lpfc_els_free_iocb()
|
|
||||||
* routine. Finally, the lpfc_els_free_iocb() is invoked to release the
|
|
||||||
* IOCB data structure.
|
|
||||||
**/
|
**/
|
||||||
static void
|
static void
|
||||||
lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||||
@@ -5253,19 +5248,9 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
(ndlp->nlp_last_elscmd == ELS_CMD_PLOGI))
|
(ndlp->nlp_last_elscmd == ELS_CMD_PLOGI))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* NPort Recovery mode or node is just allocated */
|
if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
|
||||||
if (!lpfc_nlp_not_used(ndlp)) {
|
|
||||||
/* A LOGO is completing and the node is in NPR state.
|
|
||||||
* Just unregister the RPI because the node is still
|
|
||||||
* required.
|
|
||||||
*/
|
|
||||||
lpfc_unreg_rpi(vport, ndlp);
|
lpfc_unreg_rpi(vport, ndlp);
|
||||||
} else {
|
|
||||||
/* Indicate the node has already released, should
|
|
||||||
* not reference to it from within lpfc_els_free_iocb.
|
|
||||||
*/
|
|
||||||
cmdiocb->ndlp = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
/*
|
/*
|
||||||
@@ -5285,9 +5270,8 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|||||||
* RPI (Remote Port Index) mailbox command to the @phba. It simply releases
|
* RPI (Remote Port Index) mailbox command to the @phba. It simply releases
|
||||||
* the associated lpfc Direct Memory Access (DMA) buffer back to the pool and
|
* the associated lpfc Direct Memory Access (DMA) buffer back to the pool and
|
||||||
* decrements the ndlp reference count held for this completion callback
|
* decrements the ndlp reference count held for this completion callback
|
||||||
* function. After that, it invokes the lpfc_nlp_not_used() to check
|
* function. After that, it invokes the lpfc_drop_node to check
|
||||||
* whether there is only one reference left on the ndlp. If so, it will
|
* whether it is appropriate to release the node.
|
||||||
* perform one more decrement and trigger the release of the ndlp.
|
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
||||||
@@ -5468,9 +5452,19 @@ out:
|
|||||||
ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
|
ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
|
||||||
spin_unlock_irq(&ndlp->lock);
|
spin_unlock_irq(&ndlp->lock);
|
||||||
}
|
}
|
||||||
|
lpfc_drop_node(vport, ndlp);
|
||||||
|
} else if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE &&
|
||||||
|
ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE &&
|
||||||
|
ndlp->nlp_state != NLP_STE_PRLI_ISSUE) {
|
||||||
|
/* Drop ndlp if there is no planned or outstanding
|
||||||
|
* issued PRLI.
|
||||||
|
*
|
||||||
|
* In cases when the ndlp is acting as both an initiator
|
||||||
|
* and target function, let our issued PRLI determine
|
||||||
|
* the final ndlp kref drop.
|
||||||
|
*/
|
||||||
|
lpfc_drop_node(vport, ndlp);
|
||||||
}
|
}
|
||||||
|
|
||||||
lpfc_drop_node(vport, ndlp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the originating I/O reference. */
|
/* Release the originating I/O reference. */
|
||||||
|
|||||||
@@ -458,11 +458,9 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
|
|||||||
if (ndlp->nlp_type & NLP_FABRIC) {
|
if (ndlp->nlp_type & NLP_FABRIC) {
|
||||||
spin_lock_irqsave(&ndlp->lock, iflags);
|
spin_lock_irqsave(&ndlp->lock, iflags);
|
||||||
|
|
||||||
/* In massive vport configuration settings or when the FLOGI
|
/* The driver has to account for a race between any fabric
|
||||||
* completes with a sequence timeout, it's possible
|
* node that's in recovery when dev_loss_tmo expires. When this
|
||||||
* dev_loss_tmo fired during node recovery. The driver has to
|
* happens, the driver has to allow node recovery.
|
||||||
* account for this race to allow for recovery and keep
|
|
||||||
* the reference counting correct.
|
|
||||||
*/
|
*/
|
||||||
switch (ndlp->nlp_DID) {
|
switch (ndlp->nlp_DID) {
|
||||||
case Fabric_DID:
|
case Fabric_DID:
|
||||||
@@ -489,6 +487,17 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
|
|||||||
ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE)
|
ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE)
|
||||||
recovering = true;
|
recovering = true;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
/* Ensure the nlp_DID at least has the correct prefix.
|
||||||
|
* The fabric domain controller's last three nibbles
|
||||||
|
* vary so we handle it in the default case.
|
||||||
|
*/
|
||||||
|
if (ndlp->nlp_DID & Fabric_DID_MASK) {
|
||||||
|
if (ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE &&
|
||||||
|
ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE)
|
||||||
|
recovering = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&ndlp->lock, iflags);
|
spin_unlock_irqrestore(&ndlp->lock, iflags);
|
||||||
|
|
||||||
@@ -556,6 +565,9 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
|
|||||||
ndlp->nlp_DID, ndlp->nlp_flag,
|
ndlp->nlp_DID, ndlp->nlp_flag,
|
||||||
ndlp->nlp_state, ndlp->nlp_rpi);
|
ndlp->nlp_state, ndlp->nlp_rpi);
|
||||||
}
|
}
|
||||||
|
spin_lock_irqsave(&ndlp->lock, iflags);
|
||||||
|
ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS;
|
||||||
|
spin_unlock_irqrestore(&ndlp->lock, iflags);
|
||||||
|
|
||||||
/* If we are devloss, but we are in the process of rediscovering the
|
/* If we are devloss, but we are in the process of rediscovering the
|
||||||
* ndlp, don't issue a NLP_EVT_DEVICE_RM event.
|
* ndlp, don't issue a NLP_EVT_DEVICE_RM event.
|
||||||
@@ -565,9 +577,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
|
|||||||
return fcf_inuse;
|
return fcf_inuse;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&ndlp->lock, iflags);
|
|
||||||
ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS;
|
|
||||||
spin_unlock_irqrestore(&ndlp->lock, iflags);
|
|
||||||
if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD))
|
if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD))
|
||||||
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
|
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
|
||||||
|
|
||||||
@@ -4333,13 +4342,14 @@ out:
|
|||||||
|
|
||||||
/* If the node is not registered with the scsi or nvme
|
/* If the node is not registered with the scsi or nvme
|
||||||
* transport, remove the fabric node. The failed reg_login
|
* transport, remove the fabric node. The failed reg_login
|
||||||
* is terminal.
|
* is terminal and forces the removal of the last node
|
||||||
|
* reference.
|
||||||
*/
|
*/
|
||||||
if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) {
|
if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) {
|
||||||
spin_lock_irq(&ndlp->lock);
|
spin_lock_irq(&ndlp->lock);
|
||||||
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
|
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
|
||||||
spin_unlock_irq(&ndlp->lock);
|
spin_unlock_irq(&ndlp->lock);
|
||||||
lpfc_nlp_not_used(ndlp);
|
lpfc_nlp_put(ndlp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
|
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
|
||||||
@@ -4497,14 +4507,6 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
|
|||||||
if (vport->load_flag & FC_UNLOADING)
|
if (vport->load_flag & FC_UNLOADING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
|
||||||
* Disassociate any older association between this ndlp and rport
|
|
||||||
*/
|
|
||||||
if (ndlp->rport) {
|
|
||||||
rdata = ndlp->rport->dd_data;
|
|
||||||
rdata->pnode = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids);
|
ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids);
|
||||||
if (!rport) {
|
if (!rport) {
|
||||||
dev_printk(KERN_WARNING, &phba->pcidev->dev,
|
dev_printk(KERN_WARNING, &phba->pcidev->dev,
|
||||||
@@ -4835,7 +4837,7 @@ lpfc_nlp_state_name(char *buffer, size_t size, int state)
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (state < NLP_STE_MAX_STATE && states[state])
|
if (state < NLP_STE_MAX_STATE && states[state])
|
||||||
strlcpy(buffer, states[state], size);
|
strscpy(buffer, states[state], size);
|
||||||
else
|
else
|
||||||
snprintf(buffer, size, "unknown (%d)", state);
|
snprintf(buffer, size, "unknown (%d)", state);
|
||||||
return buffer;
|
return buffer;
|
||||||
@@ -6704,25 +6706,6 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp)
|
|||||||
return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
|
return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This routine free's the specified nodelist if it is not in use
|
|
||||||
* by any other discovery thread. This routine returns 1 if the
|
|
||||||
* ndlp has been freed. A return value of 0 indicates the ndlp is
|
|
||||||
* not yet been released.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
lpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
|
|
||||||
{
|
|
||||||
lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
|
|
||||||
"node not used: did:x%x flg:x%x refcnt:x%x",
|
|
||||||
ndlp->nlp_DID, ndlp->nlp_flag,
|
|
||||||
kref_read(&ndlp->kref));
|
|
||||||
|
|
||||||
if (kref_read(&ndlp->kref) == 1)
|
|
||||||
if (lpfc_nlp_put(ndlp))
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_fcf_inuse - Check if FCF can be unregistered.
|
* lpfc_fcf_inuse - Check if FCF can be unregistered.
|
||||||
* @phba: Pointer to hba context object.
|
* @phba: Pointer to hba context object.
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ union CtRevisionId {
|
|||||||
union CtCommandResponse {
|
union CtCommandResponse {
|
||||||
/* Structure is in Big Endian format */
|
/* Structure is in Big Endian format */
|
||||||
struct {
|
struct {
|
||||||
uint32_t CmdRsp:16;
|
__be16 CmdRsp;
|
||||||
uint32_t Size:16;
|
__be16 Size;
|
||||||
} bits;
|
} bits;
|
||||||
uint32_t word;
|
uint32_t word;
|
||||||
};
|
};
|
||||||
@@ -124,7 +124,7 @@ struct lpfc_sli_ct_request {
|
|||||||
#define LPFC_CT_PREAMBLE 20 /* Size of CTReq + 4 up to here */
|
#define LPFC_CT_PREAMBLE 20 /* Size of CTReq + 4 up to here */
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint32_t PortID;
|
__be32 PortID;
|
||||||
struct gid {
|
struct gid {
|
||||||
uint8_t PortType; /* for GID_PT requests */
|
uint8_t PortType; /* for GID_PT requests */
|
||||||
#define GID_PT_N_PORT 1
|
#define GID_PT_N_PORT 1
|
||||||
@@ -1408,19 +1408,19 @@ struct entity_id_object {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct app_id_object {
|
struct app_id_object {
|
||||||
uint32_t port_id;
|
__be32 port_id;
|
||||||
uint32_t app_id;
|
__be32 app_id;
|
||||||
struct entity_id_object obj;
|
struct entity_id_object obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lpfc_vmid_rapp_ident_list {
|
struct lpfc_vmid_rapp_ident_list {
|
||||||
uint32_t no_of_objects;
|
__be32 no_of_objects;
|
||||||
struct entity_id_object obj[1];
|
struct entity_id_object obj[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lpfc_vmid_dapp_ident_list {
|
struct lpfc_vmid_dapp_ident_list {
|
||||||
uint32_t no_of_objects;
|
__be32 no_of_objects;
|
||||||
struct entity_id_object obj[1];
|
struct entity_id_object obj[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GALLAPPIA_ID_LAST 0x80
|
#define GALLAPPIA_ID_LAST 0x80
|
||||||
@@ -1512,7 +1512,7 @@ struct lpfc_fdmi_hba_ident {
|
|||||||
* Registered Port List Format
|
* Registered Port List Format
|
||||||
*/
|
*/
|
||||||
struct lpfc_fdmi_reg_port_list {
|
struct lpfc_fdmi_reg_port_list {
|
||||||
uint32_t EntryCnt;
|
__be32 EntryCnt;
|
||||||
struct lpfc_fdmi_port_entry pe;
|
struct lpfc_fdmi_port_entry pe;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
|||||||
@@ -395,9 +395,6 @@ struct lpfc_cqe {
|
|||||||
#define CQE_STATUS_NEED_BUFF_ENTRY 0xf
|
#define CQE_STATUS_NEED_BUFF_ENTRY 0xf
|
||||||
#define CQE_STATUS_DI_ERROR 0x16
|
#define CQE_STATUS_DI_ERROR 0x16
|
||||||
|
|
||||||
/* Used when mapping CQE status to IOCB */
|
|
||||||
#define LPFC_IOCB_STATUS_MASK 0xf
|
|
||||||
|
|
||||||
/* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */
|
/* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */
|
||||||
#define CQE_HW_STATUS_NO_ERR 0x0
|
#define CQE_HW_STATUS_NO_ERR 0x0
|
||||||
#define CQE_HW_STATUS_UNDERRUN 0x1
|
#define CQE_HW_STATUS_UNDERRUN 0x1
|
||||||
@@ -536,9 +533,9 @@ struct sli4_wcqe_xri_aborted {
|
|||||||
/* completion queue entry structure for rqe completion */
|
/* completion queue entry structure for rqe completion */
|
||||||
struct lpfc_rcqe {
|
struct lpfc_rcqe {
|
||||||
uint32_t word0;
|
uint32_t word0;
|
||||||
#define lpfc_rcqe_bindex_SHIFT 16
|
#define lpfc_rcqe_iv_SHIFT 31
|
||||||
#define lpfc_rcqe_bindex_MASK 0x0000FFF
|
#define lpfc_rcqe_iv_MASK 0x00000001
|
||||||
#define lpfc_rcqe_bindex_WORD word0
|
#define lpfc_rcqe_iv_WORD word0
|
||||||
#define lpfc_rcqe_status_SHIFT 8
|
#define lpfc_rcqe_status_SHIFT 8
|
||||||
#define lpfc_rcqe_status_MASK 0x000000FF
|
#define lpfc_rcqe_status_MASK 0x000000FF
|
||||||
#define lpfc_rcqe_status_WORD word0
|
#define lpfc_rcqe_status_WORD word0
|
||||||
@@ -546,6 +543,7 @@ struct lpfc_rcqe {
|
|||||||
#define FC_STATUS_RQ_BUF_LEN_EXCEEDED 0x11 /* payload truncated */
|
#define FC_STATUS_RQ_BUF_LEN_EXCEEDED 0x11 /* payload truncated */
|
||||||
#define FC_STATUS_INSUFF_BUF_NEED_BUF 0x12 /* Insufficient buffers */
|
#define FC_STATUS_INSUFF_BUF_NEED_BUF 0x12 /* Insufficient buffers */
|
||||||
#define FC_STATUS_INSUFF_BUF_FRM_DISC 0x13 /* Frame Discard */
|
#define FC_STATUS_INSUFF_BUF_FRM_DISC 0x13 /* Frame Discard */
|
||||||
|
#define FC_STATUS_RQ_DMA_FAILURE 0x14 /* DMA failure */
|
||||||
uint32_t word1;
|
uint32_t word1;
|
||||||
#define lpfc_rcqe_fcf_id_v1_SHIFT 0
|
#define lpfc_rcqe_fcf_id_v1_SHIFT 0
|
||||||
#define lpfc_rcqe_fcf_id_v1_MASK 0x0000003F
|
#define lpfc_rcqe_fcf_id_v1_MASK 0x0000003F
|
||||||
@@ -4813,8 +4811,8 @@ struct cmf_sync_wqe {
|
|||||||
#define cmf_sync_cqid_WORD word11
|
#define cmf_sync_cqid_WORD word11
|
||||||
uint32_t read_bytes;
|
uint32_t read_bytes;
|
||||||
uint32_t word13;
|
uint32_t word13;
|
||||||
#define cmf_sync_period_SHIFT 16
|
#define cmf_sync_period_SHIFT 24
|
||||||
#define cmf_sync_period_MASK 0x0000ffff
|
#define cmf_sync_period_MASK 0x000000ff
|
||||||
#define cmf_sync_period_WORD word13
|
#define cmf_sync_period_WORD word13
|
||||||
uint32_t word14;
|
uint32_t word14;
|
||||||
uint32_t word15;
|
uint32_t word15;
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
|
|||||||
static DEFINE_IDR(lpfc_hba_index);
|
static DEFINE_IDR(lpfc_hba_index);
|
||||||
#define LPFC_NVMET_BUF_POST 254
|
#define LPFC_NVMET_BUF_POST 254
|
||||||
static int lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport);
|
static int lpfc_vmid_res_alloc(struct lpfc_hba *phba, struct lpfc_vport *vport);
|
||||||
|
static void lpfc_cgn_update_tstamp(struct lpfc_hba *phba, struct lpfc_cgn_ts *ts);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_config_port_prep - Perform lpfc initialization prior to config port
|
* lpfc_config_port_prep - Perform lpfc initialization prior to config port
|
||||||
@@ -1279,7 +1280,7 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
|
|||||||
/*
|
/*
|
||||||
* lpfc_idle_stat_delay_work - idle_stat tracking
|
* lpfc_idle_stat_delay_work - idle_stat tracking
|
||||||
*
|
*
|
||||||
* This routine tracks per-cq idle_stat and determines polling decisions.
|
* This routine tracks per-eq idle_stat and determines polling decisions.
|
||||||
*
|
*
|
||||||
* Return codes:
|
* Return codes:
|
||||||
* None
|
* None
|
||||||
@@ -1290,7 +1291,7 @@ lpfc_idle_stat_delay_work(struct work_struct *work)
|
|||||||
struct lpfc_hba *phba = container_of(to_delayed_work(work),
|
struct lpfc_hba *phba = container_of(to_delayed_work(work),
|
||||||
struct lpfc_hba,
|
struct lpfc_hba,
|
||||||
idle_stat_delay_work);
|
idle_stat_delay_work);
|
||||||
struct lpfc_queue *cq;
|
struct lpfc_queue *eq;
|
||||||
struct lpfc_sli4_hdw_queue *hdwq;
|
struct lpfc_sli4_hdw_queue *hdwq;
|
||||||
struct lpfc_idle_stat *idle_stat;
|
struct lpfc_idle_stat *idle_stat;
|
||||||
u32 i, idle_percent;
|
u32 i, idle_percent;
|
||||||
@@ -1306,10 +1307,10 @@ lpfc_idle_stat_delay_work(struct work_struct *work)
|
|||||||
|
|
||||||
for_each_present_cpu(i) {
|
for_each_present_cpu(i) {
|
||||||
hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq];
|
hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq];
|
||||||
cq = hdwq->io_cq;
|
eq = hdwq->hba_eq;
|
||||||
|
|
||||||
/* Skip if we've already handled this cq's primary CPU */
|
/* Skip if we've already handled this eq's primary CPU */
|
||||||
if (cq->chann != i)
|
if (eq->chann != i)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
idle_stat = &phba->sli4_hba.idle_stat[i];
|
idle_stat = &phba->sli4_hba.idle_stat[i];
|
||||||
@@ -1333,9 +1334,9 @@ lpfc_idle_stat_delay_work(struct work_struct *work)
|
|||||||
idle_percent = 100 - idle_percent;
|
idle_percent = 100 - idle_percent;
|
||||||
|
|
||||||
if (idle_percent < 15)
|
if (idle_percent < 15)
|
||||||
cq->poll_mode = LPFC_QUEUE_WORK;
|
eq->poll_mode = LPFC_QUEUE_WORK;
|
||||||
else
|
else
|
||||||
cq->poll_mode = LPFC_IRQ_POLL;
|
eq->poll_mode = LPFC_THREADED_IRQ;
|
||||||
|
|
||||||
idle_stat->prev_idle = wall_idle;
|
idle_stat->prev_idle = wall_idle;
|
||||||
idle_stat->prev_wall = wall;
|
idle_stat->prev_wall = wall;
|
||||||
@@ -3197,6 +3198,7 @@ lpfc_cmf_stop(struct lpfc_hba *phba)
|
|||||||
"6221 Stop CMF / Cancel Timer\n");
|
"6221 Stop CMF / Cancel Timer\n");
|
||||||
|
|
||||||
/* Cancel the CMF timer */
|
/* Cancel the CMF timer */
|
||||||
|
hrtimer_cancel(&phba->cmf_stats_timer);
|
||||||
hrtimer_cancel(&phba->cmf_timer);
|
hrtimer_cancel(&phba->cmf_timer);
|
||||||
|
|
||||||
/* Zero CMF counters */
|
/* Zero CMF counters */
|
||||||
@@ -3283,7 +3285,10 @@ lpfc_cmf_start(struct lpfc_hba *phba)
|
|||||||
|
|
||||||
phba->cmf_timer_cnt = 0;
|
phba->cmf_timer_cnt = 0;
|
||||||
hrtimer_start(&phba->cmf_timer,
|
hrtimer_start(&phba->cmf_timer,
|
||||||
ktime_set(0, LPFC_CMF_INTERVAL * 1000000),
|
ktime_set(0, LPFC_CMF_INTERVAL * NSEC_PER_MSEC),
|
||||||
|
HRTIMER_MODE_REL);
|
||||||
|
hrtimer_start(&phba->cmf_stats_timer,
|
||||||
|
ktime_set(0, LPFC_SEC_MIN * NSEC_PER_SEC),
|
||||||
HRTIMER_MODE_REL);
|
HRTIMER_MODE_REL);
|
||||||
/* Setup for latency check in IO cmpl routines */
|
/* Setup for latency check in IO cmpl routines */
|
||||||
ktime_get_real_ts64(&phba->cmf_latency);
|
ktime_get_real_ts64(&phba->cmf_latency);
|
||||||
@@ -4357,6 +4362,7 @@ lpfc_io_buf_replenish(struct lpfc_hba *phba, struct list_head *cbuf)
|
|||||||
struct lpfc_sli4_hdw_queue *qp;
|
struct lpfc_sli4_hdw_queue *qp;
|
||||||
struct lpfc_io_buf *lpfc_cmd;
|
struct lpfc_io_buf *lpfc_cmd;
|
||||||
int idx, cnt;
|
int idx, cnt;
|
||||||
|
unsigned long iflags;
|
||||||
|
|
||||||
qp = phba->sli4_hba.hdwq;
|
qp = phba->sli4_hba.hdwq;
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
@@ -4371,12 +4377,13 @@ lpfc_io_buf_replenish(struct lpfc_hba *phba, struct list_head *cbuf)
|
|||||||
lpfc_cmd->hdwq_no = idx;
|
lpfc_cmd->hdwq_no = idx;
|
||||||
lpfc_cmd->hdwq = qp;
|
lpfc_cmd->hdwq = qp;
|
||||||
lpfc_cmd->cur_iocbq.cmd_cmpl = NULL;
|
lpfc_cmd->cur_iocbq.cmd_cmpl = NULL;
|
||||||
spin_lock(&qp->io_buf_list_put_lock);
|
spin_lock_irqsave(&qp->io_buf_list_put_lock, iflags);
|
||||||
list_add_tail(&lpfc_cmd->list,
|
list_add_tail(&lpfc_cmd->list,
|
||||||
&qp->lpfc_io_buf_list_put);
|
&qp->lpfc_io_buf_list_put);
|
||||||
qp->put_io_bufs++;
|
qp->put_io_bufs++;
|
||||||
qp->total_io_bufs++;
|
qp->total_io_bufs++;
|
||||||
spin_unlock(&qp->io_buf_list_put_lock);
|
spin_unlock_irqrestore(&qp->io_buf_list_put_lock,
|
||||||
|
iflags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cnt;
|
return cnt;
|
||||||
@@ -5593,81 +5600,74 @@ void
|
|||||||
lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag)
|
lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag)
|
||||||
{
|
{
|
||||||
struct lpfc_cgn_info *cp;
|
struct lpfc_cgn_info *cp;
|
||||||
struct tm broken;
|
|
||||||
struct timespec64 cur_time;
|
|
||||||
u32 cnt;
|
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
/* Make sure we have a congestion info buffer */
|
/* Make sure we have a congestion info buffer */
|
||||||
if (!phba->cgn_i)
|
if (!phba->cgn_i)
|
||||||
return;
|
return;
|
||||||
cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;
|
cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;
|
||||||
ktime_get_real_ts64(&cur_time);
|
|
||||||
time64_to_tm(cur_time.tv_sec, 0, &broken);
|
|
||||||
|
|
||||||
/* Update congestion statistics */
|
/* Update congestion statistics */
|
||||||
switch (dtag) {
|
switch (dtag) {
|
||||||
case ELS_DTAG_LNK_INTEGRITY:
|
case ELS_DTAG_LNK_INTEGRITY:
|
||||||
cnt = le32_to_cpu(cp->link_integ_notification);
|
le32_add_cpu(&cp->link_integ_notification, 1);
|
||||||
cnt++;
|
lpfc_cgn_update_tstamp(phba, &cp->stat_lnk);
|
||||||
cp->link_integ_notification = cpu_to_le32(cnt);
|
|
||||||
|
|
||||||
cp->cgn_stat_lnk_month = broken.tm_mon + 1;
|
|
||||||
cp->cgn_stat_lnk_day = broken.tm_mday;
|
|
||||||
cp->cgn_stat_lnk_year = broken.tm_year - 100;
|
|
||||||
cp->cgn_stat_lnk_hour = broken.tm_hour;
|
|
||||||
cp->cgn_stat_lnk_min = broken.tm_min;
|
|
||||||
cp->cgn_stat_lnk_sec = broken.tm_sec;
|
|
||||||
break;
|
break;
|
||||||
case ELS_DTAG_DELIVERY:
|
case ELS_DTAG_DELIVERY:
|
||||||
cnt = le32_to_cpu(cp->delivery_notification);
|
le32_add_cpu(&cp->delivery_notification, 1);
|
||||||
cnt++;
|
lpfc_cgn_update_tstamp(phba, &cp->stat_delivery);
|
||||||
cp->delivery_notification = cpu_to_le32(cnt);
|
|
||||||
|
|
||||||
cp->cgn_stat_del_month = broken.tm_mon + 1;
|
|
||||||
cp->cgn_stat_del_day = broken.tm_mday;
|
|
||||||
cp->cgn_stat_del_year = broken.tm_year - 100;
|
|
||||||
cp->cgn_stat_del_hour = broken.tm_hour;
|
|
||||||
cp->cgn_stat_del_min = broken.tm_min;
|
|
||||||
cp->cgn_stat_del_sec = broken.tm_sec;
|
|
||||||
break;
|
break;
|
||||||
case ELS_DTAG_PEER_CONGEST:
|
case ELS_DTAG_PEER_CONGEST:
|
||||||
cnt = le32_to_cpu(cp->cgn_peer_notification);
|
le32_add_cpu(&cp->cgn_peer_notification, 1);
|
||||||
cnt++;
|
lpfc_cgn_update_tstamp(phba, &cp->stat_peer);
|
||||||
cp->cgn_peer_notification = cpu_to_le32(cnt);
|
|
||||||
|
|
||||||
cp->cgn_stat_peer_month = broken.tm_mon + 1;
|
|
||||||
cp->cgn_stat_peer_day = broken.tm_mday;
|
|
||||||
cp->cgn_stat_peer_year = broken.tm_year - 100;
|
|
||||||
cp->cgn_stat_peer_hour = broken.tm_hour;
|
|
||||||
cp->cgn_stat_peer_min = broken.tm_min;
|
|
||||||
cp->cgn_stat_peer_sec = broken.tm_sec;
|
|
||||||
break;
|
break;
|
||||||
case ELS_DTAG_CONGESTION:
|
case ELS_DTAG_CONGESTION:
|
||||||
cnt = le32_to_cpu(cp->cgn_notification);
|
le32_add_cpu(&cp->cgn_notification, 1);
|
||||||
cnt++;
|
lpfc_cgn_update_tstamp(phba, &cp->stat_fpin);
|
||||||
cp->cgn_notification = cpu_to_le32(cnt);
|
|
||||||
|
|
||||||
cp->cgn_stat_cgn_month = broken.tm_mon + 1;
|
|
||||||
cp->cgn_stat_cgn_day = broken.tm_mday;
|
|
||||||
cp->cgn_stat_cgn_year = broken.tm_year - 100;
|
|
||||||
cp->cgn_stat_cgn_hour = broken.tm_hour;
|
|
||||||
cp->cgn_stat_cgn_min = broken.tm_min;
|
|
||||||
cp->cgn_stat_cgn_sec = broken.tm_sec;
|
|
||||||
}
|
}
|
||||||
if (phba->cgn_fpin_frequency &&
|
if (phba->cgn_fpin_frequency &&
|
||||||
phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) {
|
phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) {
|
||||||
value = LPFC_CGN_TIMER_TO_MIN / phba->cgn_fpin_frequency;
|
value = LPFC_CGN_TIMER_TO_MIN / phba->cgn_fpin_frequency;
|
||||||
cp->cgn_stat_npm = value;
|
cp->cgn_stat_npm = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ,
|
value = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ,
|
||||||
LPFC_CGN_CRC32_SEED);
|
LPFC_CGN_CRC32_SEED);
|
||||||
cp->cgn_info_crc = cpu_to_le32(value);
|
cp->cgn_info_crc = cpu_to_le32(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_cgn_save_evt_cnt - Save data into registered congestion buffer
|
* lpfc_cgn_update_tstamp - Update cmf timestamp
|
||||||
* @phba: pointer to lpfc hba data structure.
|
* @phba: pointer to lpfc hba data structure.
|
||||||
|
* @ts: structure to write the timestamp to.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lpfc_cgn_update_tstamp(struct lpfc_hba *phba, struct lpfc_cgn_ts *ts)
|
||||||
|
{
|
||||||
|
struct timespec64 cur_time;
|
||||||
|
struct tm tm_val;
|
||||||
|
|
||||||
|
ktime_get_real_ts64(&cur_time);
|
||||||
|
time64_to_tm(cur_time.tv_sec, 0, &tm_val);
|
||||||
|
|
||||||
|
ts->month = tm_val.tm_mon + 1;
|
||||||
|
ts->day = tm_val.tm_mday;
|
||||||
|
ts->year = tm_val.tm_year - 100;
|
||||||
|
ts->hour = tm_val.tm_hour;
|
||||||
|
ts->minute = tm_val.tm_min;
|
||||||
|
ts->second = tm_val.tm_sec;
|
||||||
|
|
||||||
|
lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
|
||||||
|
"2646 Updated CMF timestamp : "
|
||||||
|
"%u/%u/%u %u:%u:%u\n",
|
||||||
|
ts->day, ts->month,
|
||||||
|
ts->year, ts->hour,
|
||||||
|
ts->minute, ts->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lpfc_cmf_stats_timer - Save data into registered congestion buffer
|
||||||
|
* @timer: Timer cookie to access lpfc private data
|
||||||
*
|
*
|
||||||
* Save the congestion event data every minute.
|
* Save the congestion event data every minute.
|
||||||
* On the hour collapse all the minute data into hour data. Every day
|
* On the hour collapse all the minute data into hour data. Every day
|
||||||
@@ -5675,12 +5675,11 @@ lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag)
|
|||||||
* and fabrc congestion event counters that will be saved out
|
* and fabrc congestion event counters that will be saved out
|
||||||
* to the registered congestion buffer every minute.
|
* to the registered congestion buffer every minute.
|
||||||
*/
|
*/
|
||||||
static void
|
static enum hrtimer_restart
|
||||||
lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
lpfc_cmf_stats_timer(struct hrtimer *timer)
|
||||||
{
|
{
|
||||||
|
struct lpfc_hba *phba;
|
||||||
struct lpfc_cgn_info *cp;
|
struct lpfc_cgn_info *cp;
|
||||||
struct tm broken;
|
|
||||||
struct timespec64 cur_time;
|
|
||||||
uint32_t i, index;
|
uint32_t i, index;
|
||||||
uint16_t value, mvalue;
|
uint16_t value, mvalue;
|
||||||
uint64_t bps;
|
uint64_t bps;
|
||||||
@@ -5691,21 +5690,18 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
|||||||
__le32 *lptr;
|
__le32 *lptr;
|
||||||
__le16 *mptr;
|
__le16 *mptr;
|
||||||
|
|
||||||
|
phba = container_of(timer, struct lpfc_hba, cmf_stats_timer);
|
||||||
/* Make sure we have a congestion info buffer */
|
/* Make sure we have a congestion info buffer */
|
||||||
if (!phba->cgn_i)
|
if (!phba->cgn_i)
|
||||||
return;
|
return HRTIMER_NORESTART;
|
||||||
cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;
|
cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;
|
||||||
|
|
||||||
if (time_before(jiffies, phba->cgn_evt_timestamp))
|
|
||||||
return;
|
|
||||||
phba->cgn_evt_timestamp = jiffies +
|
phba->cgn_evt_timestamp = jiffies +
|
||||||
msecs_to_jiffies(LPFC_CGN_TIMER_TO_MIN);
|
msecs_to_jiffies(LPFC_CGN_TIMER_TO_MIN);
|
||||||
phba->cgn_evt_minute++;
|
phba->cgn_evt_minute++;
|
||||||
|
|
||||||
/* We should get to this point in the routine on 1 minute intervals */
|
/* We should get to this point in the routine on 1 minute intervals */
|
||||||
|
lpfc_cgn_update_tstamp(phba, &cp->base_time);
|
||||||
ktime_get_real_ts64(&cur_time);
|
|
||||||
time64_to_tm(cur_time.tv_sec, 0, &broken);
|
|
||||||
|
|
||||||
if (phba->cgn_fpin_frequency &&
|
if (phba->cgn_fpin_frequency &&
|
||||||
phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) {
|
phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) {
|
||||||
@@ -5858,31 +5854,6 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
|||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Anytime we overwrite daily index 0, after we wrap,
|
|
||||||
* we will be overwriting the oldest day, so we must
|
|
||||||
* update the congestion data start time for that day.
|
|
||||||
* That start time should have previously been saved after
|
|
||||||
* we wrote the last days worth of data.
|
|
||||||
*/
|
|
||||||
if ((phba->hba_flag & HBA_CGN_DAY_WRAP) && index == 0) {
|
|
||||||
time64_to_tm(phba->cgn_daily_ts.tv_sec, 0, &broken);
|
|
||||||
|
|
||||||
cp->cgn_info_month = broken.tm_mon + 1;
|
|
||||||
cp->cgn_info_day = broken.tm_mday;
|
|
||||||
cp->cgn_info_year = broken.tm_year - 100;
|
|
||||||
cp->cgn_info_hour = broken.tm_hour;
|
|
||||||
cp->cgn_info_minute = broken.tm_min;
|
|
||||||
cp->cgn_info_second = broken.tm_sec;
|
|
||||||
|
|
||||||
lpfc_printf_log
|
|
||||||
(phba, KERN_INFO, LOG_CGN_MGMT,
|
|
||||||
"2646 CGNInfo idx0 Start Time: "
|
|
||||||
"%d/%d/%d %d:%d:%d\n",
|
|
||||||
cp->cgn_info_day, cp->cgn_info_month,
|
|
||||||
cp->cgn_info_year, cp->cgn_info_hour,
|
|
||||||
cp->cgn_info_minute, cp->cgn_info_second);
|
|
||||||
}
|
|
||||||
|
|
||||||
dvalue = 0;
|
dvalue = 0;
|
||||||
wvalue = 0;
|
wvalue = 0;
|
||||||
lvalue = 0;
|
lvalue = 0;
|
||||||
@@ -5916,15 +5887,6 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
|||||||
"2420 Congestion Info - daily (%d): "
|
"2420 Congestion Info - daily (%d): "
|
||||||
"%d %d %d %d %d\n",
|
"%d %d %d %d %d\n",
|
||||||
index, dvalue, wvalue, lvalue, mvalue, avalue);
|
index, dvalue, wvalue, lvalue, mvalue, avalue);
|
||||||
|
|
||||||
/* We just wrote LPFC_MAX_CGN_DAYS of data,
|
|
||||||
* so we are wrapped on any data after this.
|
|
||||||
* Save this as the start time for the next day.
|
|
||||||
*/
|
|
||||||
if (index == (LPFC_MAX_CGN_DAYS - 1)) {
|
|
||||||
phba->hba_flag |= HBA_CGN_DAY_WRAP;
|
|
||||||
ktime_get_real_ts64(&phba->cgn_daily_ts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the frequency found in the last rcv'ed FPIN */
|
/* Use the frequency found in the last rcv'ed FPIN */
|
||||||
@@ -5935,6 +5897,10 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
|||||||
lvalue = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ,
|
lvalue = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ,
|
||||||
LPFC_CGN_CRC32_SEED);
|
LPFC_CGN_CRC32_SEED);
|
||||||
cp->cgn_info_crc = cpu_to_le32(lvalue);
|
cp->cgn_info_crc = cpu_to_le32(lvalue);
|
||||||
|
|
||||||
|
hrtimer_forward_now(timer, ktime_set(0, LPFC_SEC_MIN * NSEC_PER_SEC));
|
||||||
|
|
||||||
|
return HRTIMER_RESTART;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -6065,13 +6031,6 @@ lpfc_cmf_timer(struct hrtimer *timer)
|
|||||||
if (ms && ms < LPFC_CMF_INTERVAL) {
|
if (ms && ms < LPFC_CMF_INTERVAL) {
|
||||||
cnt = div_u64(total, ms); /* bytes per ms */
|
cnt = div_u64(total, ms); /* bytes per ms */
|
||||||
cnt *= LPFC_CMF_INTERVAL; /* what total should be */
|
cnt *= LPFC_CMF_INTERVAL; /* what total should be */
|
||||||
|
|
||||||
/* If the timeout is scheduled to be shorter,
|
|
||||||
* this value may skew the data, so cap it at mbpi.
|
|
||||||
*/
|
|
||||||
if ((phba->hba_flag & HBA_SHORT_CMF) && cnt > mbpi)
|
|
||||||
cnt = mbpi;
|
|
||||||
|
|
||||||
extra = cnt - total;
|
extra = cnt - total;
|
||||||
}
|
}
|
||||||
lpfc_issue_cmf_sync_wqe(phba, LPFC_CMF_INTERVAL, total + extra);
|
lpfc_issue_cmf_sync_wqe(phba, LPFC_CMF_INTERVAL, total + extra);
|
||||||
@@ -6141,34 +6100,6 @@ lpfc_cmf_timer(struct hrtimer *timer)
|
|||||||
}
|
}
|
||||||
phba->rx_block_cnt += div_u64(rcv, 512); /* save 512 byte block cnt */
|
phba->rx_block_cnt += div_u64(rcv, 512); /* save 512 byte block cnt */
|
||||||
|
|
||||||
/* Each minute save Fabric and Driver congestion information */
|
|
||||||
lpfc_cgn_save_evt_cnt(phba);
|
|
||||||
|
|
||||||
phba->hba_flag &= ~HBA_SHORT_CMF;
|
|
||||||
|
|
||||||
/* Since we need to call lpfc_cgn_save_evt_cnt every minute, on the
|
|
||||||
* minute, adjust our next timer interval, if needed, to ensure a
|
|
||||||
* 1 minute granularity when we get the next timer interrupt.
|
|
||||||
*/
|
|
||||||
if (time_after(jiffies + msecs_to_jiffies(LPFC_CMF_INTERVAL),
|
|
||||||
phba->cgn_evt_timestamp)) {
|
|
||||||
timer_interval = jiffies_to_msecs(phba->cgn_evt_timestamp -
|
|
||||||
jiffies);
|
|
||||||
if (timer_interval <= 0)
|
|
||||||
timer_interval = LPFC_CMF_INTERVAL;
|
|
||||||
else
|
|
||||||
phba->hba_flag |= HBA_SHORT_CMF;
|
|
||||||
|
|
||||||
/* If we adjust timer_interval, max_bytes_per_interval
|
|
||||||
* needs to be adjusted as well.
|
|
||||||
*/
|
|
||||||
phba->cmf_link_byte_count = div_u64(phba->cmf_max_line_rate *
|
|
||||||
timer_interval, 1000);
|
|
||||||
if (phba->cmf_active_mode == LPFC_CFG_MONITOR)
|
|
||||||
phba->cmf_max_bytes_per_interval =
|
|
||||||
phba->cmf_link_byte_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Since total_bytes has already been zero'ed, its okay to unblock
|
/* Since total_bytes has already been zero'ed, its okay to unblock
|
||||||
* after max_bytes_per_interval is setup.
|
* after max_bytes_per_interval is setup.
|
||||||
*/
|
*/
|
||||||
@@ -8014,6 +7945,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
|||||||
/* CMF congestion timer */
|
/* CMF congestion timer */
|
||||||
hrtimer_init(&phba->cmf_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
hrtimer_init(&phba->cmf_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||||
phba->cmf_timer.function = lpfc_cmf_timer;
|
phba->cmf_timer.function = lpfc_cmf_timer;
|
||||||
|
/* CMF 1 minute stats collection timer */
|
||||||
|
hrtimer_init(&phba->cmf_stats_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||||
|
phba->cmf_stats_timer.function = lpfc_cmf_stats_timer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Control structure for handling external multi-buffer mailbox
|
* Control structure for handling external multi-buffer mailbox
|
||||||
@@ -13117,8 +13051,10 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
|
|||||||
}
|
}
|
||||||
eqhdl->irq = rc;
|
eqhdl->irq = rc;
|
||||||
|
|
||||||
rc = request_irq(eqhdl->irq, &lpfc_sli4_hba_intr_handler, 0,
|
rc = request_threaded_irq(eqhdl->irq,
|
||||||
name, eqhdl);
|
&lpfc_sli4_hba_intr_handler,
|
||||||
|
&lpfc_sli4_hba_intr_handler_th,
|
||||||
|
IRQF_ONESHOT, name, eqhdl);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
||||||
"0486 MSI-X fast-path (%d) "
|
"0486 MSI-X fast-path (%d) "
|
||||||
@@ -13521,6 +13457,7 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
|
|||||||
struct pci_dev *pdev = phba->pcidev;
|
struct pci_dev *pdev = phba->pcidev;
|
||||||
|
|
||||||
lpfc_stop_hba_timers(phba);
|
lpfc_stop_hba_timers(phba);
|
||||||
|
hrtimer_cancel(&phba->cmf_stats_timer);
|
||||||
hrtimer_cancel(&phba->cmf_timer);
|
hrtimer_cancel(&phba->cmf_timer);
|
||||||
|
|
||||||
if (phba->pport)
|
if (phba->pport)
|
||||||
@@ -13645,8 +13582,6 @@ void
|
|||||||
lpfc_init_congestion_buf(struct lpfc_hba *phba)
|
lpfc_init_congestion_buf(struct lpfc_hba *phba)
|
||||||
{
|
{
|
||||||
struct lpfc_cgn_info *cp;
|
struct lpfc_cgn_info *cp;
|
||||||
struct timespec64 cmpl_time;
|
|
||||||
struct tm broken;
|
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
|
|
||||||
@@ -13666,11 +13601,10 @@ lpfc_init_congestion_buf(struct lpfc_hba *phba)
|
|||||||
atomic_set(&phba->cgn_latency_evt_cnt, 0);
|
atomic_set(&phba->cgn_latency_evt_cnt, 0);
|
||||||
atomic64_set(&phba->cgn_latency_evt, 0);
|
atomic64_set(&phba->cgn_latency_evt, 0);
|
||||||
phba->cgn_evt_minute = 0;
|
phba->cgn_evt_minute = 0;
|
||||||
phba->hba_flag &= ~HBA_CGN_DAY_WRAP;
|
|
||||||
|
|
||||||
memset(cp, 0xff, offsetof(struct lpfc_cgn_info, cgn_stat));
|
memset(cp, 0xff, offsetof(struct lpfc_cgn_info, cgn_stat));
|
||||||
cp->cgn_info_size = cpu_to_le16(LPFC_CGN_INFO_SZ);
|
cp->cgn_info_size = cpu_to_le16(LPFC_CGN_INFO_SZ);
|
||||||
cp->cgn_info_version = LPFC_CGN_INFO_V3;
|
cp->cgn_info_version = LPFC_CGN_INFO_V4;
|
||||||
|
|
||||||
/* cgn parameters */
|
/* cgn parameters */
|
||||||
cp->cgn_info_mode = phba->cgn_p.cgn_param_mode;
|
cp->cgn_info_mode = phba->cgn_p.cgn_param_mode;
|
||||||
@@ -13678,22 +13612,7 @@ lpfc_init_congestion_buf(struct lpfc_hba *phba)
|
|||||||
cp->cgn_info_level1 = phba->cgn_p.cgn_param_level1;
|
cp->cgn_info_level1 = phba->cgn_p.cgn_param_level1;
|
||||||
cp->cgn_info_level2 = phba->cgn_p.cgn_param_level2;
|
cp->cgn_info_level2 = phba->cgn_p.cgn_param_level2;
|
||||||
|
|
||||||
ktime_get_real_ts64(&cmpl_time);
|
lpfc_cgn_update_tstamp(phba, &cp->base_time);
|
||||||
time64_to_tm(cmpl_time.tv_sec, 0, &broken);
|
|
||||||
|
|
||||||
cp->cgn_info_month = broken.tm_mon + 1;
|
|
||||||
cp->cgn_info_day = broken.tm_mday;
|
|
||||||
cp->cgn_info_year = broken.tm_year - 100; /* relative to 2000 */
|
|
||||||
cp->cgn_info_hour = broken.tm_hour;
|
|
||||||
cp->cgn_info_minute = broken.tm_min;
|
|
||||||
cp->cgn_info_second = broken.tm_sec;
|
|
||||||
|
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT,
|
|
||||||
"2643 CGNInfo Init: Start Time "
|
|
||||||
"%d/%d/%d %d:%d:%d\n",
|
|
||||||
cp->cgn_info_day, cp->cgn_info_month,
|
|
||||||
cp->cgn_info_year, cp->cgn_info_hour,
|
|
||||||
cp->cgn_info_minute, cp->cgn_info_second);
|
|
||||||
|
|
||||||
/* Fill in default LUN qdepth */
|
/* Fill in default LUN qdepth */
|
||||||
if (phba->pport) {
|
if (phba->pport) {
|
||||||
@@ -13716,8 +13635,6 @@ void
|
|||||||
lpfc_init_congestion_stat(struct lpfc_hba *phba)
|
lpfc_init_congestion_stat(struct lpfc_hba *phba)
|
||||||
{
|
{
|
||||||
struct lpfc_cgn_info *cp;
|
struct lpfc_cgn_info *cp;
|
||||||
struct timespec64 cmpl_time;
|
|
||||||
struct tm broken;
|
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
|
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
|
lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
|
||||||
@@ -13729,22 +13646,7 @@ lpfc_init_congestion_stat(struct lpfc_hba *phba)
|
|||||||
cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;
|
cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;
|
||||||
memset(&cp->cgn_stat, 0, sizeof(cp->cgn_stat));
|
memset(&cp->cgn_stat, 0, sizeof(cp->cgn_stat));
|
||||||
|
|
||||||
ktime_get_real_ts64(&cmpl_time);
|
lpfc_cgn_update_tstamp(phba, &cp->stat_start);
|
||||||
time64_to_tm(cmpl_time.tv_sec, 0, &broken);
|
|
||||||
|
|
||||||
cp->cgn_stat_month = broken.tm_mon + 1;
|
|
||||||
cp->cgn_stat_day = broken.tm_mday;
|
|
||||||
cp->cgn_stat_year = broken.tm_year - 100; /* relative to 2000 */
|
|
||||||
cp->cgn_stat_hour = broken.tm_hour;
|
|
||||||
cp->cgn_stat_minute = broken.tm_min;
|
|
||||||
|
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT | LOG_INIT,
|
|
||||||
"2647 CGNstat Init: Start Time "
|
|
||||||
"%d/%d/%d %d:%d\n",
|
|
||||||
cp->cgn_stat_day, cp->cgn_stat_month,
|
|
||||||
cp->cgn_stat_year, cp->cgn_stat_hour,
|
|
||||||
cp->cgn_stat_minute);
|
|
||||||
|
|
||||||
crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED);
|
crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED);
|
||||||
cp->cgn_info_crc = cpu_to_le32(crc);
|
cp->cgn_info_crc = cpu_to_le32(crc);
|
||||||
}
|
}
|
||||||
@@ -14743,10 +14645,10 @@ lpfc_write_firmware(const struct firmware *fw, void *context)
|
|||||||
INIT_LIST_HEAD(&dma_buffer_list);
|
INIT_LIST_HEAD(&dma_buffer_list);
|
||||||
lpfc_decode_firmware_rev(phba, fwrev, 1);
|
lpfc_decode_firmware_rev(phba, fwrev, 1);
|
||||||
if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
|
if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_log_msg(phba, KERN_NOTICE, LOG_INIT | LOG_SLI,
|
||||||
"3023 Updating Firmware, Current Version:%s "
|
"3023 Updating Firmware, Current Version:%s "
|
||||||
"New Version:%s\n",
|
"New Version:%s\n",
|
||||||
fwrev, image->revision);
|
fwrev, image->revision);
|
||||||
for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {
|
for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {
|
||||||
dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
|
dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
@@ -14793,10 +14695,10 @@ lpfc_write_firmware(const struct firmware *fw, void *context)
|
|||||||
}
|
}
|
||||||
rc = offset;
|
rc = offset;
|
||||||
} else
|
} else
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_log_msg(phba, KERN_NOTICE, LOG_INIT | LOG_SLI,
|
||||||
"3029 Skipped Firmware update, Current "
|
"3029 Skipped Firmware update, Current "
|
||||||
"Version:%s New Version:%s\n",
|
"Version:%s New Version:%s\n",
|
||||||
fwrev, image->revision);
|
fwrev, image->revision);
|
||||||
|
|
||||||
release_out:
|
release_out:
|
||||||
list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) {
|
list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) {
|
||||||
@@ -14808,11 +14710,11 @@ release_out:
|
|||||||
release_firmware(fw);
|
release_firmware(fw);
|
||||||
out:
|
out:
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_log_msg(phba, KERN_ERR, LOG_INIT | LOG_SLI,
|
||||||
"3062 Firmware update error, status %d.\n", rc);
|
"3062 Firmware update error, status %d.\n", rc);
|
||||||
else
|
else
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_log_msg(phba, KERN_NOTICE, LOG_INIT | LOG_SLI,
|
||||||
"3024 Firmware update success: size %d.\n", rc);
|
"3024 Firmware update success: size %d.\n", rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
|
* Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
|
||||||
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
|
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
|
||||||
* Copyright (C) 2004-2009 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2009 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
@@ -55,7 +55,7 @@ void lpfc_dbg_print(struct lpfc_hba *phba, const char *fmt, ...);
|
|||||||
|
|
||||||
/* generate message by verbose log setting or severity */
|
/* generate message by verbose log setting or severity */
|
||||||
#define lpfc_vlog_msg(vport, level, mask, fmt, arg...) \
|
#define lpfc_vlog_msg(vport, level, mask, fmt, arg...) \
|
||||||
{ if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '4')) \
|
{ if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '5')) \
|
||||||
dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
|
dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
|
||||||
fmt, (vport)->phba->brd_no, vport->vpi, ##arg); }
|
fmt, (vport)->phba->brd_no, vport->vpi, ##arg); }
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ do { \
|
|||||||
{ uint32_t log_verbose = (phba)->pport ? \
|
{ uint32_t log_verbose = (phba)->pport ? \
|
||||||
(phba)->pport->cfg_log_verbose : \
|
(phba)->pport->cfg_log_verbose : \
|
||||||
(phba)->cfg_log_verbose; \
|
(phba)->cfg_log_verbose; \
|
||||||
if (((mask) & log_verbose) || (level[1] <= '4')) \
|
if (((mask) & log_verbose) || (level[1] <= '5')) \
|
||||||
dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
|
dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
|
||||||
fmt, phba->brd_no, ##arg); \
|
fmt, phba->brd_no, ##arg); \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@@ -310,20 +310,20 @@ lpfc_nvme_handle_lsreq(struct lpfc_hba *phba,
|
|||||||
* for the LS request.
|
* for the LS request.
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
__lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport,
|
__lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport,
|
||||||
struct lpfc_iocbq *cmdwqe,
|
struct lpfc_iocbq *cmdwqe,
|
||||||
struct lpfc_wcqe_complete *wcqe)
|
struct lpfc_wcqe_complete *wcqe)
|
||||||
{
|
{
|
||||||
struct nvmefc_ls_req *pnvme_lsreq;
|
struct nvmefc_ls_req *pnvme_lsreq;
|
||||||
struct lpfc_dmabuf *buf_ptr;
|
struct lpfc_dmabuf *buf_ptr;
|
||||||
struct lpfc_nodelist *ndlp;
|
struct lpfc_nodelist *ndlp;
|
||||||
uint32_t status;
|
int status;
|
||||||
|
|
||||||
pnvme_lsreq = cmdwqe->context_un.nvme_lsreq;
|
pnvme_lsreq = cmdwqe->context_un.nvme_lsreq;
|
||||||
ndlp = cmdwqe->ndlp;
|
ndlp = cmdwqe->ndlp;
|
||||||
buf_ptr = cmdwqe->bpl_dmabuf;
|
buf_ptr = cmdwqe->bpl_dmabuf;
|
||||||
|
|
||||||
status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK;
|
status = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||||
|
|
||||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
|
||||||
"6047 NVMEx LS REQ x%px cmpl DID %x Xri: %x "
|
"6047 NVMEx LS REQ x%px cmpl DID %x Xri: %x "
|
||||||
@@ -343,14 +343,17 @@ __lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport,
|
|||||||
kfree(buf_ptr);
|
kfree(buf_ptr);
|
||||||
cmdwqe->bpl_dmabuf = NULL;
|
cmdwqe->bpl_dmabuf = NULL;
|
||||||
}
|
}
|
||||||
if (pnvme_lsreq->done)
|
if (pnvme_lsreq->done) {
|
||||||
|
if (status != CQE_STATUS_SUCCESS)
|
||||||
|
status = -ENXIO;
|
||||||
pnvme_lsreq->done(pnvme_lsreq, status);
|
pnvme_lsreq->done(pnvme_lsreq, status);
|
||||||
else
|
} else {
|
||||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
"6046 NVMEx cmpl without done call back? "
|
"6046 NVMEx cmpl without done call back? "
|
||||||
"Data x%px DID %x Xri: %x status %x\n",
|
"Data x%px DID %x Xri: %x status %x\n",
|
||||||
pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0,
|
pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0,
|
||||||
cmdwqe->sli4_xritag, status);
|
cmdwqe->sli4_xritag, status);
|
||||||
|
}
|
||||||
if (ndlp) {
|
if (ndlp) {
|
||||||
lpfc_nlp_put(ndlp);
|
lpfc_nlp_put(ndlp);
|
||||||
cmdwqe->ndlp = NULL;
|
cmdwqe->ndlp = NULL;
|
||||||
@@ -367,7 +370,7 @@ lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
|
|||||||
uint32_t status;
|
uint32_t status;
|
||||||
struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl;
|
struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl;
|
||||||
|
|
||||||
status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK;
|
status = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||||
|
|
||||||
if (vport->localport) {
|
if (vport->localport) {
|
||||||
lport = (struct lpfc_nvme_lport *)vport->localport->private;
|
lport = (struct lpfc_nvme_lport *)vport->localport->private;
|
||||||
@@ -1040,7 +1043,7 @@ lpfc_nvme_io_cmd_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
nCmd->rcv_rsplen = LPFC_NVME_ERSP_LEN;
|
nCmd->rcv_rsplen = LPFC_NVME_ERSP_LEN;
|
||||||
nCmd->transferred_length = nCmd->payload_length;
|
nCmd->transferred_length = nCmd->payload_length;
|
||||||
} else {
|
} else {
|
||||||
lpfc_ncmd->status = (status & LPFC_IOCB_STATUS_MASK);
|
lpfc_ncmd->status = status;
|
||||||
lpfc_ncmd->result = (wcqe->parameter & IOERR_PARAM_MASK);
|
lpfc_ncmd->result = (wcqe->parameter & IOERR_PARAM_MASK);
|
||||||
|
|
||||||
/* For NVME, the only failure path that results in an
|
/* For NVME, the only failure path that results in an
|
||||||
@@ -1893,13 +1896,30 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
|
|||||||
pnvme_rport->port_id,
|
pnvme_rport->port_id,
|
||||||
pnvme_fcreq);
|
pnvme_fcreq);
|
||||||
|
|
||||||
|
lpfc_nbuf = freqpriv->nvme_buf;
|
||||||
|
if (!lpfc_nbuf) {
|
||||||
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
|
"6140 NVME IO req has no matching lpfc nvme "
|
||||||
|
"io buffer. Skipping abort req.\n");
|
||||||
|
return;
|
||||||
|
} else if (!lpfc_nbuf->nvmeCmd) {
|
||||||
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
|
"6141 lpfc NVME IO req has no nvme_fcreq "
|
||||||
|
"io buffer. Skipping abort req.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Guard against IO completion being called at same time */
|
||||||
|
spin_lock_irqsave(&lpfc_nbuf->buf_lock, flags);
|
||||||
|
|
||||||
/* If the hba is getting reset, this flag is set. It is
|
/* If the hba is getting reset, this flag is set. It is
|
||||||
* cleared when the reset is complete and rings reestablished.
|
* cleared when the reset is complete and rings reestablished.
|
||||||
*/
|
*/
|
||||||
spin_lock_irqsave(&phba->hbalock, flags);
|
spin_lock(&phba->hbalock);
|
||||||
/* driver queued commands are in process of being flushed */
|
/* driver queued commands are in process of being flushed */
|
||||||
if (phba->hba_flag & HBA_IOQ_FLUSH) {
|
if (phba->hba_flag & HBA_IOQ_FLUSH) {
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
spin_unlock(&phba->hbalock);
|
||||||
|
spin_unlock_irqrestore(&lpfc_nbuf->buf_lock, flags);
|
||||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
"6139 Driver in reset cleanup - flushing "
|
"6139 Driver in reset cleanup - flushing "
|
||||||
"NVME Req now. hba_flag x%x\n",
|
"NVME Req now. hba_flag x%x\n",
|
||||||
@@ -1907,25 +1927,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lpfc_nbuf = freqpriv->nvme_buf;
|
|
||||||
if (!lpfc_nbuf) {
|
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
|
||||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
|
||||||
"6140 NVME IO req has no matching lpfc nvme "
|
|
||||||
"io buffer. Skipping abort req.\n");
|
|
||||||
return;
|
|
||||||
} else if (!lpfc_nbuf->nvmeCmd) {
|
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
|
||||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
|
||||||
"6141 lpfc NVME IO req has no nvme_fcreq "
|
|
||||||
"io buffer. Skipping abort req.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
nvmereq_wqe = &lpfc_nbuf->cur_iocbq;
|
nvmereq_wqe = &lpfc_nbuf->cur_iocbq;
|
||||||
|
|
||||||
/* Guard against IO completion being called at same time */
|
|
||||||
spin_lock(&lpfc_nbuf->buf_lock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The lpfc_nbuf and the mapped nvme_fcreq in the driver's
|
* The lpfc_nbuf and the mapped nvme_fcreq in the driver's
|
||||||
* state must match the nvme_fcreq passed by the nvme
|
* state must match the nvme_fcreq passed by the nvme
|
||||||
@@ -1971,8 +1974,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
|
|||||||
ret_val = lpfc_sli4_issue_abort_iotag(phba, nvmereq_wqe,
|
ret_val = lpfc_sli4_issue_abort_iotag(phba, nvmereq_wqe,
|
||||||
lpfc_nvme_abort_fcreq_cmpl);
|
lpfc_nvme_abort_fcreq_cmpl);
|
||||||
|
|
||||||
spin_unlock(&lpfc_nbuf->buf_lock);
|
spin_unlock(&phba->hbalock);
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
spin_unlock_irqrestore(&lpfc_nbuf->buf_lock, flags);
|
||||||
|
|
||||||
/* Make sure HBA is alive */
|
/* Make sure HBA is alive */
|
||||||
lpfc_issue_hb_tmo(phba);
|
lpfc_issue_hb_tmo(phba);
|
||||||
@@ -1998,8 +2001,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
spin_unlock(&lpfc_nbuf->buf_lock);
|
spin_unlock(&phba->hbalock);
|
||||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
spin_unlock_irqrestore(&lpfc_nbuf->buf_lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* This file is part of the Emulex Linux Device Driver for *
|
* This file is part of the Emulex Linux Device Driver for *
|
||||||
* Fibre Channel Host Bus Adapters. *
|
* Fibre Channel Host Bus Adapters. *
|
||||||
* Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
|
* Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
|
||||||
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
|
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
|
||||||
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
|
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
|
||||||
* EMULEX and SLI are trademarks of Emulex. *
|
* EMULEX and SLI are trademarks of Emulex. *
|
||||||
@@ -300,7 +300,7 @@ __lpfc_nvme_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
|
|||||||
struct nvmefc_ls_rsp *ls_rsp = &axchg->ls_rsp;
|
struct nvmefc_ls_rsp *ls_rsp = &axchg->ls_rsp;
|
||||||
uint32_t status, result;
|
uint32_t status, result;
|
||||||
|
|
||||||
status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK;
|
status = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||||
result = wcqe->parameter;
|
result = wcqe->parameter;
|
||||||
|
|
||||||
if (axchg->state != LPFC_NVME_STE_LS_RSP || axchg->entry_cnt != 2) {
|
if (axchg->state != LPFC_NVME_STE_LS_RSP || axchg->entry_cnt != 2) {
|
||||||
@@ -350,7 +350,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
|
|||||||
if (!phba->targetport)
|
if (!phba->targetport)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK;
|
status = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||||
result = wcqe->parameter;
|
result = wcqe->parameter;
|
||||||
|
|
||||||
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
|
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
|
||||||
|
|||||||
@@ -4026,7 +4026,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
struct lpfc_fast_path_event *fast_path_evt;
|
struct lpfc_fast_path_event *fast_path_evt;
|
||||||
struct Scsi_Host *shost;
|
struct Scsi_Host *shost;
|
||||||
u32 logit = LOG_FCP;
|
u32 logit = LOG_FCP;
|
||||||
u32 status, idx;
|
u32 idx;
|
||||||
u32 lat;
|
u32 lat;
|
||||||
u8 wait_xb_clr = 0;
|
u8 wait_xb_clr = 0;
|
||||||
|
|
||||||
@@ -4061,8 +4061,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
#endif
|
#endif
|
||||||
shost = cmd->device->host;
|
shost = cmd->device->host;
|
||||||
|
|
||||||
status = bf_get(lpfc_wcqe_c_status, wcqe);
|
lpfc_cmd->status = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||||
lpfc_cmd->status = (status & LPFC_IOCB_STATUS_MASK);
|
|
||||||
lpfc_cmd->result = (wcqe->parameter & IOERR_PARAM_MASK);
|
lpfc_cmd->result = (wcqe->parameter & IOERR_PARAM_MASK);
|
||||||
|
|
||||||
lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
|
lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY;
|
||||||
@@ -4104,11 +4103,6 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (unlikely(lpfc_cmd->status)) {
|
if (unlikely(lpfc_cmd->status)) {
|
||||||
if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
|
|
||||||
(lpfc_cmd->result & IOERR_DRVR_MASK))
|
|
||||||
lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
|
|
||||||
else if (lpfc_cmd->status >= IOSTAT_CNT)
|
|
||||||
lpfc_cmd->status = IOSTAT_DEFAULT;
|
|
||||||
if (lpfc_cmd->status == IOSTAT_FCP_RSP_ERROR &&
|
if (lpfc_cmd->status == IOSTAT_FCP_RSP_ERROR &&
|
||||||
!lpfc_cmd->fcp_rsp->rspStatus3 &&
|
!lpfc_cmd->fcp_rsp->rspStatus3 &&
|
||||||
(lpfc_cmd->fcp_rsp->rspStatus2 & RESID_UNDER) &&
|
(lpfc_cmd->fcp_rsp->rspStatus2 & RESID_UNDER) &&
|
||||||
@@ -4133,16 +4127,16 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (lpfc_cmd->status) {
|
switch (lpfc_cmd->status) {
|
||||||
case IOSTAT_SUCCESS:
|
case CQE_STATUS_SUCCESS:
|
||||||
cmd->result = DID_OK << 16;
|
cmd->result = DID_OK << 16;
|
||||||
break;
|
break;
|
||||||
case IOSTAT_FCP_RSP_ERROR:
|
case CQE_STATUS_FCP_RSP_FAILURE:
|
||||||
lpfc_handle_fcp_err(vport, lpfc_cmd,
|
lpfc_handle_fcp_err(vport, lpfc_cmd,
|
||||||
pwqeIn->wqe.fcp_iread.total_xfer_len -
|
pwqeIn->wqe.fcp_iread.total_xfer_len -
|
||||||
wcqe->total_data_placed);
|
wcqe->total_data_placed);
|
||||||
break;
|
break;
|
||||||
case IOSTAT_NPORT_BSY:
|
case CQE_STATUS_NPORT_BSY:
|
||||||
case IOSTAT_FABRIC_BSY:
|
case CQE_STATUS_FABRIC_BSY:
|
||||||
cmd->result = DID_TRANSPORT_DISRUPTED << 16;
|
cmd->result = DID_TRANSPORT_DISRUPTED << 16;
|
||||||
fast_path_evt = lpfc_alloc_fast_evt(phba);
|
fast_path_evt = lpfc_alloc_fast_evt(phba);
|
||||||
if (!fast_path_evt)
|
if (!fast_path_evt)
|
||||||
@@ -4185,7 +4179,27 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
wcqe->total_data_placed,
|
wcqe->total_data_placed,
|
||||||
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
|
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
|
||||||
break;
|
break;
|
||||||
case IOSTAT_REMOTE_STOP:
|
case CQE_STATUS_DI_ERROR:
|
||||||
|
if (bf_get(lpfc_wcqe_c_bg_edir, wcqe))
|
||||||
|
lpfc_cmd->result = IOERR_RX_DMA_FAILED;
|
||||||
|
else
|
||||||
|
lpfc_cmd->result = IOERR_TX_DMA_FAILED;
|
||||||
|
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||||
|
"9048 DI Error xri x%x status x%x DI ext "
|
||||||
|
"status x%x data placed x%x\n",
|
||||||
|
lpfc_cmd->cur_iocbq.sli4_xritag,
|
||||||
|
lpfc_cmd->status, wcqe->parameter,
|
||||||
|
wcqe->total_data_placed);
|
||||||
|
if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
|
||||||
|
/* BG enabled cmd. Parse BG error */
|
||||||
|
lpfc_parse_bg_err(phba, lpfc_cmd, pwqeOut);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cmd->result = DID_ERROR << 16;
|
||||||
|
lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
|
||||||
|
"9040 DI Error on unprotected cmd\n");
|
||||||
|
break;
|
||||||
|
case CQE_STATUS_REMOTE_STOP:
|
||||||
if (ndlp) {
|
if (ndlp) {
|
||||||
/* This I/O was aborted by the target, we don't
|
/* This I/O was aborted by the target, we don't
|
||||||
* know the rxid and because we did not send the
|
* know the rxid and because we did not send the
|
||||||
@@ -4196,7 +4210,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
0, 0);
|
0, 0);
|
||||||
}
|
}
|
||||||
fallthrough;
|
fallthrough;
|
||||||
case IOSTAT_LOCAL_REJECT:
|
case CQE_STATUS_LOCAL_REJECT:
|
||||||
if (lpfc_cmd->result & IOERR_DRVR_MASK)
|
if (lpfc_cmd->result & IOERR_DRVR_MASK)
|
||||||
lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
|
lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
|
||||||
if (lpfc_cmd->result == IOERR_ELXSEC_KEY_UNWRAP_ERROR ||
|
if (lpfc_cmd->result == IOERR_ELXSEC_KEY_UNWRAP_ERROR ||
|
||||||
@@ -4217,24 +4231,6 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
cmd->result = DID_TRANSPORT_DISRUPTED << 16;
|
cmd->result = DID_TRANSPORT_DISRUPTED << 16;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED ||
|
|
||||||
lpfc_cmd->result == IOERR_TX_DMA_FAILED) &&
|
|
||||||
status == CQE_STATUS_DI_ERROR) {
|
|
||||||
if (scsi_get_prot_op(cmd) !=
|
|
||||||
SCSI_PROT_NORMAL) {
|
|
||||||
/*
|
|
||||||
* This is a response for a BG enabled
|
|
||||||
* cmd. Parse BG error
|
|
||||||
*/
|
|
||||||
lpfc_parse_bg_err(phba, lpfc_cmd, pwqeOut);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
lpfc_printf_vlog(vport, KERN_WARNING,
|
|
||||||
LOG_BG,
|
|
||||||
"9040 non-zero BGSTAT "
|
|
||||||
"on unprotected cmd\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lpfc_printf_vlog(vport, KERN_WARNING, logit,
|
lpfc_printf_vlog(vport, KERN_WARNING, logit,
|
||||||
"9036 Local Reject FCP cmd x%x failed"
|
"9036 Local Reject FCP cmd x%x failed"
|
||||||
" <%d/%lld> "
|
" <%d/%lld> "
|
||||||
@@ -4253,10 +4249,8 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
|
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
|
||||||
fallthrough;
|
fallthrough;
|
||||||
default:
|
default:
|
||||||
if (lpfc_cmd->status >= IOSTAT_CNT)
|
|
||||||
lpfc_cmd->status = IOSTAT_DEFAULT;
|
|
||||||
cmd->result = DID_ERROR << 16;
|
cmd->result = DID_ERROR << 16;
|
||||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR,
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
|
||||||
"9037 FCP Completion Error: xri %x "
|
"9037 FCP Completion Error: xri %x "
|
||||||
"status x%x result x%x [x%x] "
|
"status x%x result x%x [x%x] "
|
||||||
"placed x%x\n",
|
"placed x%x\n",
|
||||||
@@ -4273,7 +4267,8 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
|||||||
"x%x SNS x%x x%x LBA x%llx Data: x%x x%x\n",
|
"x%x SNS x%x x%x LBA x%llx Data: x%x x%x\n",
|
||||||
cmd->device->id, cmd->device->lun, cmd,
|
cmd->device->id, cmd->device->lun, cmd,
|
||||||
cmd->result, *lp, *(lp + 3),
|
cmd->result, *lp, *(lp + 3),
|
||||||
(u64)scsi_get_lba(cmd),
|
(cmd->device->sector_size) ?
|
||||||
|
(u64)scsi_get_lba(cmd) : 0,
|
||||||
cmd->retries, scsi_get_resid(cmd));
|
cmd->retries, scsi_get_resid(cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5009,7 +5004,6 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
|
phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
|
||||||
phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ static int lpfc_sli4_post_sgl_list(struct lpfc_hba *, struct list_head *,
|
|||||||
int);
|
int);
|
||||||
static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba,
|
static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba,
|
||||||
struct lpfc_queue *eq,
|
struct lpfc_queue *eq,
|
||||||
struct lpfc_eqe *eqe);
|
struct lpfc_eqe *eqe,
|
||||||
|
enum lpfc_poll_mode poll_mode);
|
||||||
static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba);
|
static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba);
|
||||||
static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba);
|
static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba);
|
||||||
static struct lpfc_cqe *lpfc_sli4_cq_get(struct lpfc_queue *q);
|
static struct lpfc_cqe *lpfc_sli4_cq_get(struct lpfc_queue *q);
|
||||||
@@ -629,7 +630,7 @@ lpfc_sli4_eqcq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq,
|
lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq,
|
||||||
uint8_t rearm)
|
u8 rearm, enum lpfc_poll_mode poll_mode)
|
||||||
{
|
{
|
||||||
struct lpfc_eqe *eqe;
|
struct lpfc_eqe *eqe;
|
||||||
int count = 0, consumed = 0;
|
int count = 0, consumed = 0;
|
||||||
@@ -639,7 +640,7 @@ lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq,
|
|||||||
|
|
||||||
eqe = lpfc_sli4_eq_get(eq);
|
eqe = lpfc_sli4_eq_get(eq);
|
||||||
while (eqe) {
|
while (eqe) {
|
||||||
lpfc_sli4_hba_handle_eqe(phba, eq, eqe);
|
lpfc_sli4_hba_handle_eqe(phba, eq, eqe, poll_mode);
|
||||||
__lpfc_sli4_consume_eqe(phba, eq, eqe);
|
__lpfc_sli4_consume_eqe(phba, eq, eqe);
|
||||||
|
|
||||||
consumed++;
|
consumed++;
|
||||||
@@ -1931,7 +1932,7 @@ lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total)
|
|||||||
unsigned long iflags;
|
unsigned long iflags;
|
||||||
u32 ret_val;
|
u32 ret_val;
|
||||||
u32 atot, wtot, max;
|
u32 atot, wtot, max;
|
||||||
u16 warn_sync_period = 0;
|
u8 warn_sync_period = 0;
|
||||||
|
|
||||||
/* First address any alarm / warning activity */
|
/* First address any alarm / warning activity */
|
||||||
atot = atomic_xchg(&phba->cgn_sync_alarm_cnt, 0);
|
atot = atomic_xchg(&phba->cgn_sync_alarm_cnt, 0);
|
||||||
@@ -7957,7 +7958,7 @@ out_rdf:
|
|||||||
* lpfc_init_idle_stat_hb - Initialize idle_stat tracking
|
* lpfc_init_idle_stat_hb - Initialize idle_stat tracking
|
||||||
* @phba: pointer to lpfc hba data structure.
|
* @phba: pointer to lpfc hba data structure.
|
||||||
*
|
*
|
||||||
* This routine initializes the per-cq idle_stat to dynamically dictate
|
* This routine initializes the per-eq idle_stat to dynamically dictate
|
||||||
* polling decisions.
|
* polling decisions.
|
||||||
*
|
*
|
||||||
* Return codes:
|
* Return codes:
|
||||||
@@ -7967,16 +7968,16 @@ static void lpfc_init_idle_stat_hb(struct lpfc_hba *phba)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct lpfc_sli4_hdw_queue *hdwq;
|
struct lpfc_sli4_hdw_queue *hdwq;
|
||||||
struct lpfc_queue *cq;
|
struct lpfc_queue *eq;
|
||||||
struct lpfc_idle_stat *idle_stat;
|
struct lpfc_idle_stat *idle_stat;
|
||||||
u64 wall;
|
u64 wall;
|
||||||
|
|
||||||
for_each_present_cpu(i) {
|
for_each_present_cpu(i) {
|
||||||
hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq];
|
hdwq = &phba->sli4_hba.hdwq[phba->sli4_hba.cpu_map[i].hdwq];
|
||||||
cq = hdwq->io_cq;
|
eq = hdwq->hba_eq;
|
||||||
|
|
||||||
/* Skip if we've already handled this cq's primary CPU */
|
/* Skip if we've already handled this eq's primary CPU */
|
||||||
if (cq->chann != i)
|
if (eq->chann != i)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
idle_stat = &phba->sli4_hba.idle_stat[i];
|
idle_stat = &phba->sli4_hba.idle_stat[i];
|
||||||
@@ -7985,13 +7986,14 @@ static void lpfc_init_idle_stat_hb(struct lpfc_hba *phba)
|
|||||||
idle_stat->prev_wall = wall;
|
idle_stat->prev_wall = wall;
|
||||||
|
|
||||||
if (phba->nvmet_support ||
|
if (phba->nvmet_support ||
|
||||||
phba->cmf_active_mode != LPFC_CFG_OFF)
|
phba->cmf_active_mode != LPFC_CFG_OFF ||
|
||||||
cq->poll_mode = LPFC_QUEUE_WORK;
|
phba->intr_type != MSIX)
|
||||||
|
eq->poll_mode = LPFC_QUEUE_WORK;
|
||||||
else
|
else
|
||||||
cq->poll_mode = LPFC_IRQ_POLL;
|
eq->poll_mode = LPFC_THREADED_IRQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!phba->nvmet_support)
|
if (!phba->nvmet_support && phba->intr_type == MSIX)
|
||||||
schedule_delayed_work(&phba->idle_stat_delay_work,
|
schedule_delayed_work(&phba->idle_stat_delay_work,
|
||||||
msecs_to_jiffies(LPFC_IDLE_STAT_DELAY));
|
msecs_to_jiffies(LPFC_IDLE_STAT_DELAY));
|
||||||
}
|
}
|
||||||
@@ -9218,7 +9220,8 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
|
|||||||
|
|
||||||
if (mbox_pending)
|
if (mbox_pending)
|
||||||
/* process and rearm the EQ */
|
/* process and rearm the EQ */
|
||||||
lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM);
|
lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM,
|
||||||
|
LPFC_QUEUE_WORK);
|
||||||
else
|
else
|
||||||
/* Always clear and re-arm the EQ */
|
/* Always clear and re-arm the EQ */
|
||||||
sli4_hba->sli4_write_eq_db(phba, fpeq, 0, LPFC_QUEUE_REARM);
|
sli4_hba->sli4_write_eq_db(phba, fpeq, 0, LPFC_QUEUE_REARM);
|
||||||
@@ -11254,7 +11257,8 @@ inline void lpfc_sli4_poll_eq(struct lpfc_queue *eq)
|
|||||||
* will be handled through a sched from polling timer
|
* will be handled through a sched from polling timer
|
||||||
* function which is currently triggered every 1msec.
|
* function which is currently triggered every 1msec.
|
||||||
*/
|
*/
|
||||||
lpfc_sli4_process_eq(phba, eq, LPFC_QUEUE_NOARM);
|
lpfc_sli4_process_eq(phba, eq, LPFC_QUEUE_NOARM,
|
||||||
|
LPFC_QUEUE_WORK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14682,6 +14686,38 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
|
|||||||
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||||
workposted = true;
|
workposted = true;
|
||||||
break;
|
break;
|
||||||
|
case FC_STATUS_RQ_DMA_FAILURE:
|
||||||
|
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
|
"2564 RQE DMA Error x%x, x%08x x%08x x%08x "
|
||||||
|
"x%08x\n",
|
||||||
|
status, rcqe->word0, rcqe->word1,
|
||||||
|
rcqe->word2, rcqe->word3);
|
||||||
|
|
||||||
|
/* If IV set, no further recovery */
|
||||||
|
if (bf_get(lpfc_rcqe_iv, rcqe))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* recycle consumed resource */
|
||||||
|
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||||
|
lpfc_sli4_rq_release(hrq, drq);
|
||||||
|
dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list);
|
||||||
|
if (!dma_buf) {
|
||||||
|
hrq->RQ_no_buf_found++;
|
||||||
|
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hrq->RQ_rcv_buf++;
|
||||||
|
hrq->RQ_buf_posted--;
|
||||||
|
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||||
|
lpfc_in_buf_free(phba, &dma_buf->dbuf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
|
"2565 Unexpected RQE Status x%x, w0-3 x%08x "
|
||||||
|
"x%08x x%08x x%08x\n",
|
||||||
|
status, rcqe->word0, rcqe->word1,
|
||||||
|
rcqe->word2, rcqe->word3);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return workposted;
|
return workposted;
|
||||||
@@ -14803,7 +14839,6 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
|
|||||||
* @cq: Pointer to CQ to be processed
|
* @cq: Pointer to CQ to be processed
|
||||||
* @handler: Routine to process each cqe
|
* @handler: Routine to process each cqe
|
||||||
* @delay: Pointer to usdelay to set in case of rescheduling of the handler
|
* @delay: Pointer to usdelay to set in case of rescheduling of the handler
|
||||||
* @poll_mode: Polling mode we were called from
|
|
||||||
*
|
*
|
||||||
* This routine processes completion queue entries in a CQ. While a valid
|
* This routine processes completion queue entries in a CQ. While a valid
|
||||||
* queue element is found, the handler is called. During processing checks
|
* queue element is found, the handler is called. During processing checks
|
||||||
@@ -14821,8 +14856,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
|
|||||||
static bool
|
static bool
|
||||||
__lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
__lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
||||||
bool (*handler)(struct lpfc_hba *, struct lpfc_queue *,
|
bool (*handler)(struct lpfc_hba *, struct lpfc_queue *,
|
||||||
struct lpfc_cqe *), unsigned long *delay,
|
struct lpfc_cqe *), unsigned long *delay)
|
||||||
enum lpfc_poll_mode poll_mode)
|
|
||||||
{
|
{
|
||||||
struct lpfc_cqe *cqe;
|
struct lpfc_cqe *cqe;
|
||||||
bool workposted = false;
|
bool workposted = false;
|
||||||
@@ -14863,10 +14897,6 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
|||||||
arm = false;
|
arm = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: complete the irq_poll softirq before rearming CQ */
|
|
||||||
if (poll_mode == LPFC_IRQ_POLL)
|
|
||||||
irq_poll_complete(&cq->iop);
|
|
||||||
|
|
||||||
/* Track the max number of CQEs processed in 1 EQ */
|
/* Track the max number of CQEs processed in 1 EQ */
|
||||||
if (count > cq->CQ_max_cqe)
|
if (count > cq->CQ_max_cqe)
|
||||||
cq->CQ_max_cqe = count;
|
cq->CQ_max_cqe = count;
|
||||||
@@ -14916,17 +14946,17 @@ __lpfc_sli4_sp_process_cq(struct lpfc_queue *cq)
|
|||||||
case LPFC_MCQ:
|
case LPFC_MCQ:
|
||||||
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
||||||
lpfc_sli4_sp_handle_mcqe,
|
lpfc_sli4_sp_handle_mcqe,
|
||||||
&delay, LPFC_QUEUE_WORK);
|
&delay);
|
||||||
break;
|
break;
|
||||||
case LPFC_WCQ:
|
case LPFC_WCQ:
|
||||||
if (cq->subtype == LPFC_IO)
|
if (cq->subtype == LPFC_IO)
|
||||||
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
||||||
lpfc_sli4_fp_handle_cqe,
|
lpfc_sli4_fp_handle_cqe,
|
||||||
&delay, LPFC_QUEUE_WORK);
|
&delay);
|
||||||
else
|
else
|
||||||
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
||||||
lpfc_sli4_sp_handle_cqe,
|
lpfc_sli4_sp_handle_cqe,
|
||||||
&delay, LPFC_QUEUE_WORK);
|
&delay);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
@@ -15203,6 +15233,38 @@ drop:
|
|||||||
hrq->RQ_no_posted_buf++;
|
hrq->RQ_no_posted_buf++;
|
||||||
/* Post more buffers if possible */
|
/* Post more buffers if possible */
|
||||||
break;
|
break;
|
||||||
|
case FC_STATUS_RQ_DMA_FAILURE:
|
||||||
|
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
|
"2575 RQE DMA Error x%x, x%08x x%08x x%08x "
|
||||||
|
"x%08x\n",
|
||||||
|
status, rcqe->word0, rcqe->word1,
|
||||||
|
rcqe->word2, rcqe->word3);
|
||||||
|
|
||||||
|
/* If IV set, no further recovery */
|
||||||
|
if (bf_get(lpfc_rcqe_iv, rcqe))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* recycle consumed resource */
|
||||||
|
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||||
|
lpfc_sli4_rq_release(hrq, drq);
|
||||||
|
dma_buf = lpfc_sli_rqbuf_get(phba, hrq);
|
||||||
|
if (!dma_buf) {
|
||||||
|
hrq->RQ_no_buf_found++;
|
||||||
|
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hrq->RQ_rcv_buf++;
|
||||||
|
hrq->RQ_buf_posted--;
|
||||||
|
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||||
|
lpfc_rq_buf_free(phba, &dma_buf->hbuf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
|
"2576 Unexpected RQE Status x%x, w0-3 x%08x "
|
||||||
|
"x%08x x%08x x%08x\n",
|
||||||
|
status, rcqe->word0, rcqe->word1,
|
||||||
|
rcqe->word2, rcqe->word3);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return workposted;
|
return workposted;
|
||||||
@@ -15271,45 +15333,64 @@ lpfc_sli4_fp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lpfc_sli4_sched_cq_work - Schedules cq work
|
* __lpfc_sli4_hba_process_cq - Process a fast-path event queue entry
|
||||||
* @phba: Pointer to HBA context object.
|
* @cq: Pointer to CQ to be processed
|
||||||
* @cq: Pointer to CQ
|
|
||||||
* @cqid: CQ ID
|
|
||||||
*
|
*
|
||||||
* This routine checks the poll mode of the CQ corresponding to
|
* This routine calls the cq processing routine with the handler for
|
||||||
* cq->chann, then either schedules a softirq or queue_work to complete
|
* fast path CQEs.
|
||||||
* cq work.
|
|
||||||
*
|
|
||||||
* queue_work path is taken if in NVMET mode, or if poll_mode is in
|
|
||||||
* LPFC_QUEUE_WORK mode. Otherwise, softirq path is taken.
|
|
||||||
*
|
*
|
||||||
|
* The CQ routine returns two values: the first is the calling status,
|
||||||
|
* which indicates whether work was queued to the background discovery
|
||||||
|
* thread. If true, the routine should wakeup the discovery thread;
|
||||||
|
* the second is the delay parameter. If non-zero, rather than rearming
|
||||||
|
* the CQ and yet another interrupt, the CQ handler should be queued so
|
||||||
|
* that it is processed in a subsequent polling action. The value of
|
||||||
|
* the delay indicates when to reschedule it.
|
||||||
**/
|
**/
|
||||||
static void lpfc_sli4_sched_cq_work(struct lpfc_hba *phba,
|
static void
|
||||||
struct lpfc_queue *cq, uint16_t cqid)
|
__lpfc_sli4_hba_process_cq(struct lpfc_queue *cq)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
struct lpfc_hba *phba = cq->phba;
|
||||||
|
unsigned long delay;
|
||||||
|
bool workposted = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
switch (cq->poll_mode) {
|
/* process and rearm the CQ */
|
||||||
case LPFC_IRQ_POLL:
|
workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe,
|
||||||
/* CGN mgmt is mutually exclusive from softirq processing */
|
&delay);
|
||||||
if (phba->cmf_active_mode == LPFC_CFG_OFF) {
|
|
||||||
irq_poll_sched(&cq->iop);
|
if (delay) {
|
||||||
break;
|
|
||||||
}
|
|
||||||
fallthrough;
|
|
||||||
case LPFC_QUEUE_WORK:
|
|
||||||
default:
|
|
||||||
if (is_kdump_kernel())
|
if (is_kdump_kernel())
|
||||||
ret = queue_work(phba->wq, &cq->irqwork);
|
ret = queue_delayed_work(phba->wq, &cq->sched_irqwork,
|
||||||
|
delay);
|
||||||
else
|
else
|
||||||
ret = queue_work_on(cq->chann, phba->wq, &cq->irqwork);
|
ret = queue_delayed_work_on(cq->chann, phba->wq,
|
||||||
|
&cq->sched_irqwork, delay);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
"0383 Cannot schedule queue work "
|
"0367 Cannot schedule queue work "
|
||||||
"for CQ eqcqid=%d, cqid=%d on CPU %d\n",
|
"for cqid=%d on CPU %d\n",
|
||||||
cqid, cq->queue_id,
|
cq->queue_id, cq->chann);
|
||||||
raw_smp_processor_id());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* wake up worker thread if there are works to be done */
|
||||||
|
if (workposted)
|
||||||
|
lpfc_worker_wake_up(phba);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lpfc_sli4_hba_process_cq - fast-path work handler when started by
|
||||||
|
* interrupt
|
||||||
|
* @work: pointer to work element
|
||||||
|
*
|
||||||
|
* translates from the work handler and calls the fast-path handler.
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
lpfc_sli4_hba_process_cq(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct lpfc_queue *cq = container_of(work, struct lpfc_queue, irqwork);
|
||||||
|
|
||||||
|
__lpfc_sli4_hba_process_cq(cq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15317,6 +15398,7 @@ static void lpfc_sli4_sched_cq_work(struct lpfc_hba *phba,
|
|||||||
* @phba: Pointer to HBA context object.
|
* @phba: Pointer to HBA context object.
|
||||||
* @eq: Pointer to the queue structure.
|
* @eq: Pointer to the queue structure.
|
||||||
* @eqe: Pointer to fast-path event queue entry.
|
* @eqe: Pointer to fast-path event queue entry.
|
||||||
|
* @poll_mode: poll_mode to execute processing the cq.
|
||||||
*
|
*
|
||||||
* This routine process a event queue entry from the fast-path event queue.
|
* This routine process a event queue entry from the fast-path event queue.
|
||||||
* It will check the MajorCode and MinorCode to determine this is for a
|
* It will check the MajorCode and MinorCode to determine this is for a
|
||||||
@@ -15327,11 +15409,12 @@ static void lpfc_sli4_sched_cq_work(struct lpfc_hba *phba,
|
|||||||
**/
|
**/
|
||||||
static void
|
static void
|
||||||
lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq,
|
lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq,
|
||||||
struct lpfc_eqe *eqe)
|
struct lpfc_eqe *eqe, enum lpfc_poll_mode poll_mode)
|
||||||
{
|
{
|
||||||
struct lpfc_queue *cq = NULL;
|
struct lpfc_queue *cq = NULL;
|
||||||
uint32_t qidx = eq->hdwq;
|
uint32_t qidx = eq->hdwq;
|
||||||
uint16_t cqid, id;
|
uint16_t cqid, id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
|
if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
@@ -15391,70 +15474,25 @@ work_cq:
|
|||||||
else
|
else
|
||||||
cq->isr_timestamp = 0;
|
cq->isr_timestamp = 0;
|
||||||
#endif
|
#endif
|
||||||
lpfc_sli4_sched_cq_work(phba, cq, cqid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
switch (poll_mode) {
|
||||||
* __lpfc_sli4_hba_process_cq - Process a fast-path event queue entry
|
case LPFC_THREADED_IRQ:
|
||||||
* @cq: Pointer to CQ to be processed
|
__lpfc_sli4_hba_process_cq(cq);
|
||||||
* @poll_mode: Enum lpfc_poll_state to determine poll mode
|
break;
|
||||||
*
|
case LPFC_QUEUE_WORK:
|
||||||
* This routine calls the cq processing routine with the handler for
|
default:
|
||||||
* fast path CQEs.
|
|
||||||
*
|
|
||||||
* The CQ routine returns two values: the first is the calling status,
|
|
||||||
* which indicates whether work was queued to the background discovery
|
|
||||||
* thread. If true, the routine should wakeup the discovery thread;
|
|
||||||
* the second is the delay parameter. If non-zero, rather than rearming
|
|
||||||
* the CQ and yet another interrupt, the CQ handler should be queued so
|
|
||||||
* that it is processed in a subsequent polling action. The value of
|
|
||||||
* the delay indicates when to reschedule it.
|
|
||||||
**/
|
|
||||||
static void
|
|
||||||
__lpfc_sli4_hba_process_cq(struct lpfc_queue *cq,
|
|
||||||
enum lpfc_poll_mode poll_mode)
|
|
||||||
{
|
|
||||||
struct lpfc_hba *phba = cq->phba;
|
|
||||||
unsigned long delay;
|
|
||||||
bool workposted = false;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* process and rearm the CQ */
|
|
||||||
workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe,
|
|
||||||
&delay, poll_mode);
|
|
||||||
|
|
||||||
if (delay) {
|
|
||||||
if (is_kdump_kernel())
|
if (is_kdump_kernel())
|
||||||
ret = queue_delayed_work(phba->wq, &cq->sched_irqwork,
|
ret = queue_work(phba->wq, &cq->irqwork);
|
||||||
delay);
|
|
||||||
else
|
else
|
||||||
ret = queue_delayed_work_on(cq->chann, phba->wq,
|
ret = queue_work_on(cq->chann, phba->wq, &cq->irqwork);
|
||||||
&cq->sched_irqwork, delay);
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||||
"0367 Cannot schedule queue work "
|
"0383 Cannot schedule queue work "
|
||||||
"for cqid=%d on CPU %d\n",
|
"for CQ eqcqid=%d, cqid=%d on CPU %d\n",
|
||||||
cq->queue_id, cq->chann);
|
cqid, cq->queue_id,
|
||||||
|
raw_smp_processor_id());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wake up worker thread if there are works to be done */
|
|
||||||
if (workposted)
|
|
||||||
lpfc_worker_wake_up(phba);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* lpfc_sli4_hba_process_cq - fast-path work handler when started by
|
|
||||||
* interrupt
|
|
||||||
* @work: pointer to work element
|
|
||||||
*
|
|
||||||
* translates from the work handler and calls the fast-path handler.
|
|
||||||
**/
|
|
||||||
static void
|
|
||||||
lpfc_sli4_hba_process_cq(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct lpfc_queue *cq = container_of(work, struct lpfc_queue, irqwork);
|
|
||||||
|
|
||||||
__lpfc_sli4_hba_process_cq(cq, LPFC_QUEUE_WORK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15469,7 +15507,7 @@ lpfc_sli4_dly_hba_process_cq(struct work_struct *work)
|
|||||||
struct lpfc_queue *cq = container_of(to_delayed_work(work),
|
struct lpfc_queue *cq = container_of(to_delayed_work(work),
|
||||||
struct lpfc_queue, sched_irqwork);
|
struct lpfc_queue, sched_irqwork);
|
||||||
|
|
||||||
__lpfc_sli4_hba_process_cq(cq, LPFC_QUEUE_WORK);
|
__lpfc_sli4_hba_process_cq(cq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15495,8 +15533,9 @@ lpfc_sli4_dly_hba_process_cq(struct work_struct *work)
|
|||||||
* and returns for these events. This function is called without any lock
|
* and returns for these events. This function is called without any lock
|
||||||
* held. It gets the hbalock to access and update SLI data structures.
|
* held. It gets the hbalock to access and update SLI data structures.
|
||||||
*
|
*
|
||||||
* This function returns IRQ_HANDLED when interrupt is handled else it
|
* This function returns IRQ_HANDLED when interrupt is handled, IRQ_WAKE_THREAD
|
||||||
* returns IRQ_NONE.
|
* when interrupt is scheduled to be handled from a threaded irq context, or
|
||||||
|
* else returns IRQ_NONE.
|
||||||
**/
|
**/
|
||||||
irqreturn_t
|
irqreturn_t
|
||||||
lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
|
lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
|
||||||
@@ -15505,8 +15544,8 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
|
|||||||
struct lpfc_hba_eq_hdl *hba_eq_hdl;
|
struct lpfc_hba_eq_hdl *hba_eq_hdl;
|
||||||
struct lpfc_queue *fpeq;
|
struct lpfc_queue *fpeq;
|
||||||
unsigned long iflag;
|
unsigned long iflag;
|
||||||
int ecount = 0;
|
|
||||||
int hba_eqidx;
|
int hba_eqidx;
|
||||||
|
int ecount = 0;
|
||||||
struct lpfc_eq_intr_info *eqi;
|
struct lpfc_eq_intr_info *eqi;
|
||||||
|
|
||||||
/* Get the driver's phba structure from the dev_id */
|
/* Get the driver's phba structure from the dev_id */
|
||||||
@@ -15535,30 +15574,41 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id)
|
|||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
eqi = this_cpu_ptr(phba->sli4_hba.eq_info);
|
switch (fpeq->poll_mode) {
|
||||||
eqi->icnt++;
|
case LPFC_THREADED_IRQ:
|
||||||
|
/* CGN mgmt is mutually exclusive from irq processing */
|
||||||
|
if (phba->cmf_active_mode == LPFC_CFG_OFF)
|
||||||
|
return IRQ_WAKE_THREAD;
|
||||||
|
fallthrough;
|
||||||
|
case LPFC_QUEUE_WORK:
|
||||||
|
default:
|
||||||
|
eqi = this_cpu_ptr(phba->sli4_hba.eq_info);
|
||||||
|
eqi->icnt++;
|
||||||
|
|
||||||
fpeq->last_cpu = raw_smp_processor_id();
|
fpeq->last_cpu = raw_smp_processor_id();
|
||||||
|
|
||||||
if (eqi->icnt > LPFC_EQD_ISR_TRIGGER &&
|
if (eqi->icnt > LPFC_EQD_ISR_TRIGGER &&
|
||||||
fpeq->q_flag & HBA_EQ_DELAY_CHK &&
|
fpeq->q_flag & HBA_EQ_DELAY_CHK &&
|
||||||
phba->cfg_auto_imax &&
|
phba->cfg_auto_imax &&
|
||||||
fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY &&
|
fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY &&
|
||||||
phba->sli.sli_flag & LPFC_SLI_USE_EQDR)
|
phba->sli.sli_flag & LPFC_SLI_USE_EQDR)
|
||||||
lpfc_sli4_mod_hba_eq_delay(phba, fpeq, LPFC_MAX_AUTO_EQ_DELAY);
|
lpfc_sli4_mod_hba_eq_delay(phba, fpeq,
|
||||||
|
LPFC_MAX_AUTO_EQ_DELAY);
|
||||||
|
|
||||||
/* process and rearm the EQ */
|
/* process and rearm the EQ */
|
||||||
ecount = lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM);
|
ecount = lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM,
|
||||||
|
LPFC_QUEUE_WORK);
|
||||||
|
|
||||||
if (unlikely(ecount == 0)) {
|
if (unlikely(ecount == 0)) {
|
||||||
fpeq->EQ_no_entry++;
|
fpeq->EQ_no_entry++;
|
||||||
if (phba->intr_type == MSIX)
|
if (phba->intr_type == MSIX)
|
||||||
/* MSI-X treated interrupt served as no EQ share INT */
|
/* MSI-X treated interrupt served as no EQ share INT */
|
||||||
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
|
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
|
||||||
"0358 MSI-X interrupt with no EQE\n");
|
"0358 MSI-X interrupt with no EQE\n");
|
||||||
else
|
else
|
||||||
/* Non MSI-X treated on interrupt as EQ share INT */
|
/* Non MSI-X treated on interrupt as EQ share INT */
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
@@ -16115,13 +16165,69 @@ out:
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lpfc_cq_poll_hdler(struct irq_poll *iop, int budget)
|
/**
|
||||||
|
* lpfc_sli4_hba_intr_handler_th - SLI4 HBA threaded interrupt handler
|
||||||
|
* @irq: Interrupt number.
|
||||||
|
* @dev_id: The device context pointer.
|
||||||
|
*
|
||||||
|
* This routine is a mirror of lpfc_sli4_hba_intr_handler, but executed within
|
||||||
|
* threaded irq context.
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* IRQ_HANDLED - interrupt is handled
|
||||||
|
* IRQ_NONE - otherwise
|
||||||
|
**/
|
||||||
|
irqreturn_t lpfc_sli4_hba_intr_handler_th(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct lpfc_queue *cq = container_of(iop, struct lpfc_queue, iop);
|
struct lpfc_hba *phba;
|
||||||
|
struct lpfc_hba_eq_hdl *hba_eq_hdl;
|
||||||
|
struct lpfc_queue *fpeq;
|
||||||
|
int ecount = 0;
|
||||||
|
int hba_eqidx;
|
||||||
|
struct lpfc_eq_intr_info *eqi;
|
||||||
|
|
||||||
__lpfc_sli4_hba_process_cq(cq, LPFC_IRQ_POLL);
|
/* Get the driver's phba structure from the dev_id */
|
||||||
|
hba_eq_hdl = (struct lpfc_hba_eq_hdl *)dev_id;
|
||||||
|
phba = hba_eq_hdl->phba;
|
||||||
|
hba_eqidx = hba_eq_hdl->idx;
|
||||||
|
|
||||||
return 1;
|
if (unlikely(!phba))
|
||||||
|
return IRQ_NONE;
|
||||||
|
if (unlikely(!phba->sli4_hba.hdwq))
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
/* Get to the EQ struct associated with this vector */
|
||||||
|
fpeq = phba->sli4_hba.hba_eq_hdl[hba_eqidx].eq;
|
||||||
|
if (unlikely(!fpeq))
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
eqi = per_cpu_ptr(phba->sli4_hba.eq_info, raw_smp_processor_id());
|
||||||
|
eqi->icnt++;
|
||||||
|
|
||||||
|
fpeq->last_cpu = raw_smp_processor_id();
|
||||||
|
|
||||||
|
if (eqi->icnt > LPFC_EQD_ISR_TRIGGER &&
|
||||||
|
fpeq->q_flag & HBA_EQ_DELAY_CHK &&
|
||||||
|
phba->cfg_auto_imax &&
|
||||||
|
fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY &&
|
||||||
|
phba->sli.sli_flag & LPFC_SLI_USE_EQDR)
|
||||||
|
lpfc_sli4_mod_hba_eq_delay(phba, fpeq, LPFC_MAX_AUTO_EQ_DELAY);
|
||||||
|
|
||||||
|
/* process and rearm the EQ */
|
||||||
|
ecount = lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM,
|
||||||
|
LPFC_THREADED_IRQ);
|
||||||
|
|
||||||
|
if (unlikely(ecount == 0)) {
|
||||||
|
fpeq->EQ_no_entry++;
|
||||||
|
if (phba->intr_type == MSIX)
|
||||||
|
/* MSI-X treated interrupt served as no EQ share INT */
|
||||||
|
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
|
||||||
|
"3358 MSI-X interrupt with no EQE\n");
|
||||||
|
else
|
||||||
|
/* Non MSI-X treated on interrupt as EQ share INT */
|
||||||
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16265,8 +16371,6 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
|||||||
|
|
||||||
if (cq->queue_id > phba->sli4_hba.cq_max)
|
if (cq->queue_id > phba->sli4_hba.cq_max)
|
||||||
phba->sli4_hba.cq_max = cq->queue_id;
|
phba->sli4_hba.cq_max = cq->queue_id;
|
||||||
|
|
||||||
irq_poll_init(&cq->iop, LPFC_IRQ_POLL_WEIGHT, lpfc_cq_poll_hdler);
|
|
||||||
out:
|
out:
|
||||||
mempool_free(mbox, phba->mbox_mem_pool);
|
mempool_free(mbox, phba->mbox_mem_pool);
|
||||||
return status;
|
return status;
|
||||||
@@ -20696,23 +20800,23 @@ lpfc_log_fw_write_cmpl(struct lpfc_hba *phba, u32 shdr_status,
|
|||||||
if (shdr_add_status == LPFC_ADD_STATUS_INCOMPAT_OBJ) {
|
if (shdr_add_status == LPFC_ADD_STATUS_INCOMPAT_OBJ) {
|
||||||
switch (shdr_add_status_2) {
|
switch (shdr_add_status_2) {
|
||||||
case LPFC_ADD_STATUS_2_INCOMPAT_FLASH:
|
case LPFC_ADD_STATUS_2_INCOMPAT_FLASH:
|
||||||
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||||
"4199 Firmware write failed: "
|
"4199 Firmware write failed: "
|
||||||
"image incompatible with flash x%02x\n",
|
"image incompatible with flash x%02x\n",
|
||||||
phba->sli4_hba.flash_id);
|
phba->sli4_hba.flash_id);
|
||||||
break;
|
break;
|
||||||
case LPFC_ADD_STATUS_2_INCORRECT_ASIC:
|
case LPFC_ADD_STATUS_2_INCORRECT_ASIC:
|
||||||
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||||
"4200 Firmware write failed: "
|
"4200 Firmware write failed: "
|
||||||
"image incompatible with ASIC "
|
"image incompatible with ASIC "
|
||||||
"architecture x%02x\n",
|
"architecture x%02x\n",
|
||||||
phba->sli4_hba.asic_rev);
|
phba->sli4_hba.asic_rev);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||||
"4210 Firmware write failed: "
|
"4210 Firmware write failed: "
|
||||||
"add_status_2 x%02x\n",
|
"add_status_2 x%02x\n",
|
||||||
shdr_add_status_2);
|
shdr_add_status_2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (!shdr_status && !shdr_add_status) {
|
} else if (!shdr_status && !shdr_add_status) {
|
||||||
@@ -20725,26 +20829,26 @@ lpfc_log_fw_write_cmpl(struct lpfc_hba *phba, u32 shdr_status,
|
|||||||
|
|
||||||
switch (shdr_change_status) {
|
switch (shdr_change_status) {
|
||||||
case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET):
|
case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET):
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
|
lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
|
||||||
"3198 Firmware write complete: System "
|
"3198 Firmware write complete: System "
|
||||||
"reboot required to instantiate\n");
|
"reboot required to instantiate\n");
|
||||||
break;
|
break;
|
||||||
case (LPFC_CHANGE_STATUS_FW_RESET):
|
case (LPFC_CHANGE_STATUS_FW_RESET):
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
|
lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
|
||||||
"3199 Firmware write complete: "
|
"3199 Firmware write complete: "
|
||||||
"Firmware reset required to "
|
"Firmware reset required to "
|
||||||
"instantiate\n");
|
"instantiate\n");
|
||||||
break;
|
break;
|
||||||
case (LPFC_CHANGE_STATUS_PORT_MIGRATION):
|
case (LPFC_CHANGE_STATUS_PORT_MIGRATION):
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
|
lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
|
||||||
"3200 Firmware write complete: Port "
|
"3200 Firmware write complete: Port "
|
||||||
"Migration or PCI Reset required to "
|
"Migration or PCI Reset required to "
|
||||||
"instantiate\n");
|
"instantiate\n");
|
||||||
break;
|
break;
|
||||||
case (LPFC_CHANGE_STATUS_PCI_RESET):
|
case (LPFC_CHANGE_STATUS_PCI_RESET):
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
|
lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
|
||||||
"3201 Firmware write complete: PCI "
|
"3201 Firmware write complete: PCI "
|
||||||
"Reset required to instantiate\n");
|
"Reset required to instantiate\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ struct lpfc_rqb {
|
|||||||
|
|
||||||
enum lpfc_poll_mode {
|
enum lpfc_poll_mode {
|
||||||
LPFC_QUEUE_WORK,
|
LPFC_QUEUE_WORK,
|
||||||
LPFC_IRQ_POLL
|
LPFC_THREADED_IRQ,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lpfc_idle_stat {
|
struct lpfc_idle_stat {
|
||||||
@@ -279,8 +279,6 @@ struct lpfc_queue {
|
|||||||
struct list_head _poll_list;
|
struct list_head _poll_list;
|
||||||
void **q_pgs; /* array to index entries per page */
|
void **q_pgs; /* array to index entries per page */
|
||||||
|
|
||||||
#define LPFC_IRQ_POLL_WEIGHT 256
|
|
||||||
struct irq_poll iop;
|
|
||||||
enum lpfc_poll_mode poll_mode;
|
enum lpfc_poll_mode poll_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
* included with this package. *
|
* included with this package. *
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
|
|
||||||
#define LPFC_DRIVER_VERSION "14.2.0.11"
|
#define LPFC_DRIVER_VERSION "14.2.0.13"
|
||||||
#define LPFC_DRIVER_NAME "lpfc"
|
#define LPFC_DRIVER_NAME "lpfc"
|
||||||
|
|
||||||
/* Used for SLI 2/3 */
|
/* Used for SLI 2/3 */
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
config MEGARAID_NEWGEN
|
config MEGARAID_NEWGEN
|
||||||
bool "LSI Logic New Generation RAID Device Drivers"
|
bool "LSI Logic New Generation RAID Device Drivers"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
help
|
help
|
||||||
LSI Logic RAID Device Drivers
|
LSI Logic RAID Device Drivers
|
||||||
|
|
||||||
config MEGARAID_MM
|
config MEGARAID_MM
|
||||||
tristate "LSI Logic Management Module (New Driver)"
|
tristate "LSI Logic Management Module (New Driver)"
|
||||||
depends on PCI && SCSI && MEGARAID_NEWGEN
|
depends on PCI && HAS_IOPORT && SCSI && MEGARAID_NEWGEN
|
||||||
help
|
help
|
||||||
Management Module provides ioctl, sysfs support for LSI Logic
|
Management Module provides ioctl, sysfs support for LSI Logic
|
||||||
RAID controllers.
|
RAID controllers.
|
||||||
@@ -67,7 +67,7 @@ config MEGARAID_MAILBOX
|
|||||||
|
|
||||||
config MEGARAID_LEGACY
|
config MEGARAID_LEGACY
|
||||||
tristate "LSI Logic Legacy MegaRAID Driver"
|
tristate "LSI Logic Legacy MegaRAID Driver"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
help
|
help
|
||||||
This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490
|
This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490
|
||||||
and 467 SCSI host adapters. This driver also support the all U320
|
and 467 SCSI host adapters. This driver also support the all U320
|
||||||
|
|||||||
@@ -1722,11 +1722,9 @@ struct megasas_sge_skinny {
|
|||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
union megasas_sgl {
|
union megasas_sgl {
|
||||||
|
DECLARE_FLEX_ARRAY(struct megasas_sge32, sge32);
|
||||||
struct megasas_sge32 sge32[1];
|
DECLARE_FLEX_ARRAY(struct megasas_sge64, sge64);
|
||||||
struct megasas_sge64 sge64[1];
|
DECLARE_FLEX_ARRAY(struct megasas_sge_skinny, sge_skinny);
|
||||||
struct megasas_sge_skinny sge_skinny[1];
|
|
||||||
|
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct megasas_header {
|
struct megasas_header {
|
||||||
|
|||||||
@@ -1133,18 +1133,18 @@ struct mpi3mr_ioc {
|
|||||||
u32 chain_buf_count;
|
u32 chain_buf_count;
|
||||||
struct dma_pool *chain_buf_pool;
|
struct dma_pool *chain_buf_pool;
|
||||||
struct chain_element *chain_sgl_list;
|
struct chain_element *chain_sgl_list;
|
||||||
void *chain_bitmap;
|
unsigned long *chain_bitmap;
|
||||||
spinlock_t chain_buf_lock;
|
spinlock_t chain_buf_lock;
|
||||||
|
|
||||||
struct mpi3mr_drv_cmd bsg_cmds;
|
struct mpi3mr_drv_cmd bsg_cmds;
|
||||||
struct mpi3mr_drv_cmd host_tm_cmds;
|
struct mpi3mr_drv_cmd host_tm_cmds;
|
||||||
struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD];
|
struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD];
|
||||||
struct mpi3mr_drv_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD];
|
struct mpi3mr_drv_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD];
|
||||||
void *devrem_bitmap;
|
unsigned long *devrem_bitmap;
|
||||||
u16 dev_handle_bitmap_bits;
|
u16 dev_handle_bitmap_bits;
|
||||||
void *removepend_bitmap;
|
unsigned long *removepend_bitmap;
|
||||||
struct list_head delayed_rmhs_list;
|
struct list_head delayed_rmhs_list;
|
||||||
void *evtack_cmds_bitmap;
|
unsigned long *evtack_cmds_bitmap;
|
||||||
struct list_head delayed_evtack_cmds_list;
|
struct list_head delayed_evtack_cmds_list;
|
||||||
|
|
||||||
u32 ts_update_counter;
|
u32 ts_update_counter;
|
||||||
|
|||||||
@@ -402,6 +402,11 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
|
|||||||
memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
|
memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
|
||||||
mrioc->reply_sz);
|
mrioc->reply_sz);
|
||||||
}
|
}
|
||||||
|
if (sense_buf && cmdptr->sensebuf) {
|
||||||
|
cmdptr->is_sense = 1;
|
||||||
|
memcpy(cmdptr->sensebuf, sense_buf,
|
||||||
|
MPI3MR_SENSE_BUF_SZ);
|
||||||
|
}
|
||||||
if (cmdptr->is_waiting) {
|
if (cmdptr->is_waiting) {
|
||||||
complete(&cmdptr->done);
|
complete(&cmdptr->done);
|
||||||
cmdptr->is_waiting = 0;
|
cmdptr->is_waiting = 0;
|
||||||
@@ -1134,7 +1139,7 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
|
|||||||
static int
|
static int
|
||||||
mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
|
mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
|
||||||
{
|
{
|
||||||
void *removepend_bitmap;
|
unsigned long *removepend_bitmap;
|
||||||
|
|
||||||
if (mrioc->facts.reply_sz > mrioc->reply_sz) {
|
if (mrioc->facts.reply_sz > mrioc->reply_sz) {
|
||||||
ioc_err(mrioc,
|
ioc_err(mrioc,
|
||||||
|
|||||||
@@ -2058,7 +2058,7 @@ int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
|
|||||||
sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node),
|
sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!sas_expander)
|
if (!sas_expander)
|
||||||
return -1;
|
return -ENOMEM;
|
||||||
|
|
||||||
sas_expander->handle = handle;
|
sas_expander->handle = handle;
|
||||||
sas_expander->num_phys = expander_pg0.num_phys;
|
sas_expander->num_phys = expander_pg0.num_phys;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
config SCSI_MVSAS
|
config SCSI_MVSAS
|
||||||
tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support"
|
tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support"
|
||||||
depends on PCI
|
depends on PCI && HAS_IOPORT
|
||||||
select SCSI_SAS_LIBSAS
|
select SCSI_SAS_LIBSAS
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
help
|
help
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m
|
|||||||
|
|
||||||
config PCMCIA_AHA152X
|
config PCMCIA_AHA152X
|
||||||
tristate "Adaptec AHA152X PCMCIA support"
|
tristate "Adaptec AHA152X PCMCIA support"
|
||||||
|
depends on HAS_IOPORT
|
||||||
select SCSI_SPI_ATTRS
|
select SCSI_SPI_ATTRS
|
||||||
help
|
help
|
||||||
Say Y here if you intend to attach this type of PCMCIA SCSI host
|
Say Y here if you intend to attach this type of PCMCIA SCSI host
|
||||||
@@ -22,6 +23,7 @@ config PCMCIA_AHA152X
|
|||||||
|
|
||||||
config PCMCIA_FDOMAIN
|
config PCMCIA_FDOMAIN
|
||||||
tristate "Future Domain PCMCIA support"
|
tristate "Future Domain PCMCIA support"
|
||||||
|
depends on HAS_IOPORT
|
||||||
select SCSI_FDOMAIN
|
select SCSI_FDOMAIN
|
||||||
help
|
help
|
||||||
Say Y here if you intend to attach this type of PCMCIA SCSI host
|
Say Y here if you intend to attach this type of PCMCIA SCSI host
|
||||||
@@ -32,7 +34,7 @@ config PCMCIA_FDOMAIN
|
|||||||
|
|
||||||
config PCMCIA_NINJA_SCSI
|
config PCMCIA_NINJA_SCSI
|
||||||
tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
|
tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
|
||||||
depends on !64BIT || COMPILE_TEST
|
depends on (!64BIT || COMPILE_TEST) && HAS_IOPORT
|
||||||
help
|
help
|
||||||
If you intend to attach this type of PCMCIA SCSI host adapter to
|
If you intend to attach this type of PCMCIA SCSI host adapter to
|
||||||
your computer, say Y here and read
|
your computer, say Y here and read
|
||||||
@@ -66,6 +68,7 @@ config PCMCIA_NINJA_SCSI
|
|||||||
|
|
||||||
config PCMCIA_QLOGIC
|
config PCMCIA_QLOGIC
|
||||||
tristate "Qlogic PCMCIA support"
|
tristate "Qlogic PCMCIA support"
|
||||||
|
depends on HAS_IOPORT
|
||||||
help
|
help
|
||||||
Say Y here if you intend to attach this type of PCMCIA SCSI host
|
Say Y here if you intend to attach this type of PCMCIA SCSI host
|
||||||
adapter to your computer.
|
adapter to your computer.
|
||||||
@@ -75,6 +78,7 @@ config PCMCIA_QLOGIC
|
|||||||
|
|
||||||
config PCMCIA_SYM53C500
|
config PCMCIA_SYM53C500
|
||||||
tristate "Symbios 53c500 PCMCIA support"
|
tristate "Symbios 53c500 PCMCIA support"
|
||||||
|
depends on HAS_IOPORT
|
||||||
help
|
help
|
||||||
Say Y here if you have a New Media Bus Toaster or other PCMCIA
|
Say Y here if you have a New Media Bus Toaster or other PCMCIA
|
||||||
SCSI adapter based on the Symbios 53c500 controller.
|
SCSI adapter based on the Symbios 53c500 controller.
|
||||||
|
|||||||
@@ -43,7 +43,8 @@
|
|||||||
#include "pm8001_chips.h"
|
#include "pm8001_chips.h"
|
||||||
#include "pm80xx_hwi.h"
|
#include "pm80xx_hwi.h"
|
||||||
|
|
||||||
static ulong logging_level = PM8001_FAIL_LOGGING | PM8001_IOERR_LOGGING;
|
static ulong logging_level = PM8001_FAIL_LOGGING | PM8001_IOERR_LOGGING |
|
||||||
|
PM8001_EVENT_LOGGING | PM8001_INIT_LOGGING;
|
||||||
module_param(logging_level, ulong, 0644);
|
module_param(logging_level, ulong, 0644);
|
||||||
MODULE_PARM_DESC(logging_level, " bits for enabling logging info.");
|
MODULE_PARM_DESC(logging_level, " bits for enabling logging info.");
|
||||||
|
|
||||||
@@ -666,7 +667,7 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost,
|
|||||||
* Currently we just set the fixed SAS address to our HBA, for manufacture,
|
* Currently we just set the fixed SAS address to our HBA, for manufacture,
|
||||||
* it should read from the EEPROM
|
* it should read from the EEPROM
|
||||||
*/
|
*/
|
||||||
static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
|
static int pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
|
||||||
{
|
{
|
||||||
u8 i, j;
|
u8 i, j;
|
||||||
u8 sas_add[8];
|
u8 sas_add[8];
|
||||||
@@ -679,6 +680,12 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
|
|||||||
struct pm8001_ioctl_payload payload;
|
struct pm8001_ioctl_payload payload;
|
||||||
u16 deviceid;
|
u16 deviceid;
|
||||||
int rc;
|
int rc;
|
||||||
|
unsigned long time_remaining;
|
||||||
|
|
||||||
|
if (PM8001_CHIP_DISP->fatal_errors(pm8001_ha)) {
|
||||||
|
pm8001_dbg(pm8001_ha, FAIL, "controller is in fatal error state\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
|
pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
|
||||||
pm8001_ha->nvmd_completion = &completion;
|
pm8001_ha->nvmd_completion = &completion;
|
||||||
@@ -703,16 +710,23 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
|
|||||||
payload.offset = 0;
|
payload.offset = 0;
|
||||||
payload.func_specific = kzalloc(payload.rd_length, GFP_KERNEL);
|
payload.func_specific = kzalloc(payload.rd_length, GFP_KERNEL);
|
||||||
if (!payload.func_specific) {
|
if (!payload.func_specific) {
|
||||||
pm8001_dbg(pm8001_ha, INIT, "mem alloc fail\n");
|
pm8001_dbg(pm8001_ha, FAIL, "mem alloc fail\n");
|
||||||
return;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
|
rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(payload.func_specific);
|
kfree(payload.func_specific);
|
||||||
pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n");
|
pm8001_dbg(pm8001_ha, FAIL, "nvmd failed\n");
|
||||||
return;
|
return -EIO;
|
||||||
}
|
}
|
||||||
wait_for_completion(&completion);
|
time_remaining = wait_for_completion_timeout(&completion,
|
||||||
|
msecs_to_jiffies(60*1000)); // 1 min
|
||||||
|
if (!time_remaining) {
|
||||||
|
kfree(payload.func_specific);
|
||||||
|
pm8001_dbg(pm8001_ha, FAIL, "get_nvmd_req timeout\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
for (i = 0, j = 0; i <= 7; i++, j++) {
|
for (i = 0, j = 0; i <= 7; i++, j++) {
|
||||||
if (pm8001_ha->chip_id == chip_8001) {
|
if (pm8001_ha->chip_id == chip_8001) {
|
||||||
@@ -751,6 +765,7 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
|
|||||||
memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr,
|
memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr,
|
||||||
SAS_ADDR_SIZE);
|
SAS_ADDR_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1166,7 +1181,8 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
|
|||||||
pm80xx_set_thermal_config(pm8001_ha);
|
pm80xx_set_thermal_config(pm8001_ha);
|
||||||
}
|
}
|
||||||
|
|
||||||
pm8001_init_sas_add(pm8001_ha);
|
if (pm8001_init_sas_add(pm8001_ha))
|
||||||
|
goto err_out_shost;
|
||||||
/* phy setting support for motherboard controller */
|
/* phy setting support for motherboard controller */
|
||||||
rc = pm8001_configure_phy_settings(pm8001_ha);
|
rc = pm8001_configure_phy_settings(pm8001_ha);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
|||||||
@@ -167,6 +167,17 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
|
|||||||
pm8001_ha = sas_phy->ha->lldd_ha;
|
pm8001_ha = sas_phy->ha->lldd_ha;
|
||||||
phy = &pm8001_ha->phy[phy_id];
|
phy = &pm8001_ha->phy[phy_id];
|
||||||
pm8001_ha->phy[phy_id].enable_completion = &completion;
|
pm8001_ha->phy[phy_id].enable_completion = &completion;
|
||||||
|
|
||||||
|
if (PM8001_CHIP_DISP->fatal_errors(pm8001_ha)) {
|
||||||
|
/*
|
||||||
|
* If the controller is in fatal error state,
|
||||||
|
* we will not get a response from the controller
|
||||||
|
*/
|
||||||
|
pm8001_dbg(pm8001_ha, FAIL,
|
||||||
|
"Phy control failed due to fatal errors\n");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
switch (func) {
|
switch (func) {
|
||||||
case PHY_FUNC_SET_LINK_RATE:
|
case PHY_FUNC_SET_LINK_RATE:
|
||||||
rates = funcdata;
|
rates = funcdata;
|
||||||
@@ -908,6 +919,17 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun)
|
|||||||
struct pm8001_device *pm8001_dev = dev->lldd_dev;
|
struct pm8001_device *pm8001_dev = dev->lldd_dev;
|
||||||
struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
|
struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
|
||||||
DECLARE_COMPLETION_ONSTACK(completion_setstate);
|
DECLARE_COMPLETION_ONSTACK(completion_setstate);
|
||||||
|
|
||||||
|
if (PM8001_CHIP_DISP->fatal_errors(pm8001_ha)) {
|
||||||
|
/*
|
||||||
|
* If the controller is in fatal error state,
|
||||||
|
* we will not get a response from the controller
|
||||||
|
*/
|
||||||
|
pm8001_dbg(pm8001_ha, FAIL,
|
||||||
|
"LUN reset failed due to fatal errors\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
if (dev_is_sata(dev)) {
|
if (dev_is_sata(dev)) {
|
||||||
struct sas_phy *phy = sas_get_local_phy(dev);
|
struct sas_phy *phy = sas_get_local_phy(dev);
|
||||||
sas_execute_internal_abort_dev(dev, 0, NULL);
|
sas_execute_internal_abort_dev(dev, 0, NULL);
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
#define PM8001_DEV_LOGGING 0x80 /* development message logging */
|
#define PM8001_DEV_LOGGING 0x80 /* development message logging */
|
||||||
#define PM8001_DEVIO_LOGGING 0x100 /* development io message logging */
|
#define PM8001_DEVIO_LOGGING 0x100 /* development io message logging */
|
||||||
#define PM8001_IOERR_LOGGING 0x200 /* development io err message logging */
|
#define PM8001_IOERR_LOGGING 0x200 /* development io err message logging */
|
||||||
|
#define PM8001_EVENT_LOGGING 0x400 /* HW event logging */
|
||||||
|
|
||||||
#define pm8001_info(HBA, fmt, ...) \
|
#define pm8001_info(HBA, fmt, ...) \
|
||||||
pr_info("%s:: %s %d: " fmt, \
|
pr_info("%s:: %s %d: " fmt, \
|
||||||
|
|||||||
@@ -3239,9 +3239,9 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
struct pm8001_port *port = &pm8001_ha->port[port_id];
|
struct pm8001_port *port = &pm8001_ha->port[port_id];
|
||||||
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
|
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
pm8001_dbg(pm8001_ha, DEVIO,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
"port id %d, phy id %d link_rate %d portstate 0x%x\n",
|
"HW_EVENT_SATA_PHY_UP phyid:%#x port_id:%#x link_rate:%d portstate:%#x\n",
|
||||||
port_id, phy_id, link_rate, portstate);
|
phy_id, port_id, link_rate, portstate);
|
||||||
|
|
||||||
phy->port = port;
|
phy->port = port;
|
||||||
port->port_id = port_id;
|
port->port_id = port_id;
|
||||||
@@ -3291,10 +3291,14 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
phy->phy_attached = 0;
|
phy->phy_attached = 0;
|
||||||
switch (portstate) {
|
switch (portstate) {
|
||||||
case PORT_VALID:
|
case PORT_VALID:
|
||||||
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_VALID\n",
|
||||||
|
phy_id, port_id);
|
||||||
break;
|
break;
|
||||||
case PORT_INVALID:
|
case PORT_INVALID:
|
||||||
pm8001_dbg(pm8001_ha, MSG, " PortInvalid portID %d\n",
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
port_id);
|
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_INVALID\n",
|
||||||
|
phy_id, port_id);
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
pm8001_dbg(pm8001_ha, MSG,
|
||||||
" Last phy Down and port invalid\n");
|
" Last phy Down and port invalid\n");
|
||||||
if (port_sata) {
|
if (port_sata) {
|
||||||
@@ -3306,18 +3310,21 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
sas_phy_disconnected(&phy->sas_phy);
|
sas_phy_disconnected(&phy->sas_phy);
|
||||||
break;
|
break;
|
||||||
case PORT_IN_RESET:
|
case PORT_IN_RESET:
|
||||||
pm8001_dbg(pm8001_ha, MSG, " Port In Reset portID %d\n",
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
port_id);
|
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_IN_RESET\n",
|
||||||
|
phy_id, port_id);
|
||||||
break;
|
break;
|
||||||
case PORT_NOT_ESTABLISHED:
|
case PORT_NOT_ESTABLISHED:
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
" Phy Down and PORT_NOT_ESTABLISHED\n");
|
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_NOT_ESTABLISHED\n",
|
||||||
|
phy_id, port_id);
|
||||||
port->port_attached = 0;
|
port->port_attached = 0;
|
||||||
break;
|
break;
|
||||||
case PORT_LOSTCOMM:
|
case PORT_LOSTCOMM:
|
||||||
pm8001_dbg(pm8001_ha, MSG, " Phy Down and PORT_LOSTCOMM\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_LOSTCOMM\n",
|
||||||
" Last phy Down and port invalid\n");
|
phy_id, port_id);
|
||||||
|
pm8001_dbg(pm8001_ha, MSG, " Last phy Down and port invalid\n");
|
||||||
if (port_sata) {
|
if (port_sata) {
|
||||||
port->port_attached = 0;
|
port->port_attached = 0;
|
||||||
phy->phy_type = 0;
|
phy->phy_type = 0;
|
||||||
@@ -3328,9 +3335,9 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
port->port_attached = 0;
|
port->port_attached = 0;
|
||||||
pm8001_dbg(pm8001_ha, DEVIO,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
" Phy Down and(default) = 0x%x\n",
|
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate:%#x\n",
|
||||||
portstate);
|
phy_id, port_id, portstate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3410,6 +3417,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF);
|
u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF);
|
||||||
u8 phy_id =
|
u8 phy_id =
|
||||||
(u8)((phyid_npip_portstate & 0xFF0000) >> 16);
|
(u8)((phyid_npip_portstate & 0xFF0000) >> 16);
|
||||||
|
u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F);
|
||||||
u16 eventType =
|
u16 eventType =
|
||||||
(u16)((lr_status_evt_portid & 0x00FFFF00) >> 8);
|
(u16)((lr_status_evt_portid & 0x00FFFF00) >> 8);
|
||||||
u8 status =
|
u8 status =
|
||||||
@@ -3425,26 +3433,29 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
|
|
||||||
case HW_EVENT_SAS_PHY_UP:
|
case HW_EVENT_SAS_PHY_UP:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_SAS_PHY_UP phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
hw_event_sas_phy_up(pm8001_ha, piomb);
|
hw_event_sas_phy_up(pm8001_ha, piomb);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_SATA_PHY_UP:
|
case HW_EVENT_SATA_PHY_UP:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_PHY_UP\n");
|
|
||||||
hw_event_sata_phy_up(pm8001_ha, piomb);
|
hw_event_sata_phy_up(pm8001_ha, piomb);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_SATA_SPINUP_HOLD:
|
case HW_EVENT_SATA_SPINUP_HOLD:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_SPINUP_HOLD\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_SATA_SPINUP_HOLD phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
sas_notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD,
|
sas_notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD,
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_PHY_DOWN:
|
case HW_EVENT_PHY_DOWN:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_DOWN\n");
|
|
||||||
hw_event_phy_down(pm8001_ha, piomb);
|
hw_event_phy_down(pm8001_ha, piomb);
|
||||||
phy->phy_attached = 0;
|
|
||||||
phy->phy_state = PHY_LINK_DISABLE;
|
phy->phy_state = PHY_LINK_DISABLE;
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_PORT_INVALID:
|
case HW_EVENT_PORT_INVALID:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_INVALID\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_PORT_INVALID phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
sas_phy_disconnected(sas_phy);
|
sas_phy_disconnected(sas_phy);
|
||||||
phy->phy_attached = 0;
|
phy->phy_attached = 0;
|
||||||
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
|
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
|
||||||
@@ -3463,7 +3474,9 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_PHY_ERROR:
|
case HW_EVENT_PHY_ERROR:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_ERROR\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_PHY_ERROR phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
sas_phy_disconnected(&phy->sas_phy);
|
sas_phy_disconnected(&phy->sas_phy);
|
||||||
phy->phy_attached = 0;
|
phy->phy_attached = 0;
|
||||||
sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR, GFP_ATOMIC);
|
sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR, GFP_ATOMIC);
|
||||||
@@ -3477,34 +3490,39 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_LINK_ERR_INVALID_DWORD:
|
case HW_EVENT_LINK_ERR_INVALID_DWORD:
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
"HW_EVENT_LINK_ERR_INVALID_DWORD\n");
|
"HW_EVENT_LINK_ERR_INVALID_DWORD phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||||
HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0);
|
HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_LINK_ERR_DISPARITY_ERROR:
|
case HW_EVENT_LINK_ERR_DISPARITY_ERROR:
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
"HW_EVENT_LINK_ERR_DISPARITY_ERROR\n");
|
"HW_EVENT_LINK_ERR_DISPARITY_ERROR phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||||
HW_EVENT_LINK_ERR_DISPARITY_ERROR,
|
HW_EVENT_LINK_ERR_DISPARITY_ERROR,
|
||||||
port_id, phy_id, 0, 0);
|
port_id, phy_id, 0, 0);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_LINK_ERR_CODE_VIOLATION:
|
case HW_EVENT_LINK_ERR_CODE_VIOLATION:
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
"HW_EVENT_LINK_ERR_CODE_VIOLATION\n");
|
"HW_EVENT_LINK_ERR_CODE_VIOLATION phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||||
HW_EVENT_LINK_ERR_CODE_VIOLATION,
|
HW_EVENT_LINK_ERR_CODE_VIOLATION,
|
||||||
port_id, phy_id, 0, 0);
|
port_id, phy_id, 0, 0);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH:
|
case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH:
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
"HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n");
|
"HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||||
HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH,
|
HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH,
|
||||||
port_id, phy_id, 0, 0);
|
port_id, phy_id, 0, 0);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_MALFUNCTION:
|
case HW_EVENT_MALFUNCTION:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_MALFUNCTION\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_MALFUNCTION phyid:%#x\n", phy_id);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_BROADCAST_SES:
|
case HW_EVENT_BROADCAST_SES:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n");
|
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n");
|
||||||
@@ -3515,25 +3533,30 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_INBOUND_CRC_ERROR:
|
case HW_EVENT_INBOUND_CRC_ERROR:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_INBOUND_CRC_ERROR\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_INBOUND_CRC_ERROR phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||||
HW_EVENT_INBOUND_CRC_ERROR,
|
HW_EVENT_INBOUND_CRC_ERROR,
|
||||||
port_id, phy_id, 0, 0);
|
port_id, phy_id, 0, 0);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_HARD_RESET_RECEIVED:
|
case HW_EVENT_HARD_RESET_RECEIVED:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_HARD_RESET_RECEIVED\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_HARD_RESET_RECEIVED phyid:%#x\n", phy_id);
|
||||||
sas_notify_port_event(sas_phy, PORTE_HARD_RESET, GFP_ATOMIC);
|
sas_notify_port_event(sas_phy, PORTE_HARD_RESET, GFP_ATOMIC);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_ID_FRAME_TIMEOUT:
|
case HW_EVENT_ID_FRAME_TIMEOUT:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_ID_FRAME_TIMEOUT\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_ID_FRAME_TIMEOUT phyid:%#x\n", phy_id);
|
||||||
sas_phy_disconnected(sas_phy);
|
sas_phy_disconnected(sas_phy);
|
||||||
phy->phy_attached = 0;
|
phy->phy_attached = 0;
|
||||||
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
|
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_LINK_ERR_PHY_RESET_FAILED:
|
case HW_EVENT_LINK_ERR_PHY_RESET_FAILED:
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
"HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n");
|
"HW_EVENT_LINK_ERR_PHY_RESET_FAILED phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||||
HW_EVENT_LINK_ERR_PHY_RESET_FAILED,
|
HW_EVENT_LINK_ERR_PHY_RESET_FAILED,
|
||||||
port_id, phy_id, 0, 0);
|
port_id, phy_id, 0, 0);
|
||||||
@@ -3543,13 +3566,16 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_PORT_RESET_TIMER_TMO:
|
case HW_EVENT_PORT_RESET_TIMER_TMO:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_TIMER_TMO\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_PORT_RESET_TIMER_TMO phyid:%#x port_id:%#x portstate:%#x\n",
|
||||||
|
phy_id, port_id, portstate);
|
||||||
if (!pm8001_ha->phy[phy_id].reset_completion) {
|
if (!pm8001_ha->phy[phy_id].reset_completion) {
|
||||||
pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
|
pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
|
||||||
port_id, phy_id, 0, 0);
|
port_id, phy_id, 0, 0);
|
||||||
}
|
}
|
||||||
sas_phy_disconnected(sas_phy);
|
sas_phy_disconnected(sas_phy);
|
||||||
phy->phy_attached = 0;
|
phy->phy_attached = 0;
|
||||||
|
port->port_state = portstate;
|
||||||
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
|
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
if (pm8001_ha->phy[phy_id].reset_completion) {
|
if (pm8001_ha->phy[phy_id].reset_completion) {
|
||||||
@@ -3560,8 +3586,9 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_PORT_RECOVERY_TIMER_TMO:
|
case HW_EVENT_PORT_RECOVERY_TIMER_TMO:
|
||||||
pm8001_dbg(pm8001_ha, MSG,
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
"HW_EVENT_PORT_RECOVERY_TIMER_TMO\n");
|
"HW_EVENT_PORT_RECOVERY_TIMER_TMO phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||||
HW_EVENT_PORT_RECOVERY_TIMER_TMO,
|
HW_EVENT_PORT_RECOVERY_TIMER_TMO,
|
||||||
port_id, phy_id, 0, 0);
|
port_id, phy_id, 0, 0);
|
||||||
@@ -3575,24 +3602,32 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_PORT_RECOVER:
|
case HW_EVENT_PORT_RECOVER:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RECOVER\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_PORT_RECOVER phyid:%#x port_id:%#x\n",
|
||||||
|
phy_id, port_id);
|
||||||
hw_event_port_recover(pm8001_ha, piomb);
|
hw_event_port_recover(pm8001_ha, piomb);
|
||||||
break;
|
break;
|
||||||
case HW_EVENT_PORT_RESET_COMPLETE:
|
case HW_EVENT_PORT_RESET_COMPLETE:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_COMPLETE\n");
|
pm8001_dbg(pm8001_ha, EVENT,
|
||||||
|
"HW_EVENT_PORT_RESET_COMPLETE phyid:%#x port_id:%#x portstate:%#x\n",
|
||||||
|
phy_id, port_id, portstate);
|
||||||
if (pm8001_ha->phy[phy_id].reset_completion) {
|
if (pm8001_ha->phy[phy_id].reset_completion) {
|
||||||
pm8001_ha->phy[phy_id].port_reset_status =
|
pm8001_ha->phy[phy_id].port_reset_status =
|
||||||
PORT_RESET_SUCCESS;
|
PORT_RESET_SUCCESS;
|
||||||
complete(pm8001_ha->phy[phy_id].reset_completion);
|
complete(pm8001_ha->phy[phy_id].reset_completion);
|
||||||
pm8001_ha->phy[phy_id].reset_completion = NULL;
|
pm8001_ha->phy[phy_id].reset_completion = NULL;
|
||||||
}
|
}
|
||||||
|
phy->phy_attached = 1;
|
||||||
|
phy->phy_state = PHY_STATE_LINK_UP_SPCV;
|
||||||
|
port->port_state = portstate;
|
||||||
break;
|
break;
|
||||||
case EVENT_BROADCAST_ASYNCH_EVENT:
|
case EVENT_BROADCAST_ASYNCH_EVENT:
|
||||||
pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n");
|
pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pm8001_dbg(pm8001_ha, DEVIO, "Unknown event type 0x%x\n",
|
pm8001_dbg(pm8001_ha, DEVIO,
|
||||||
eventType);
|
"Unknown event portid:%d phyid:%d event:0x%x status:0x%x\n",
|
||||||
|
port_id, phy_id, eventType, status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4726,6 +4761,9 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
|
|||||||
memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr,
|
memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr,
|
||||||
SAS_ADDR_SIZE);
|
SAS_ADDR_SIZE);
|
||||||
|
|
||||||
|
pm8001_dbg(pm8001_ha, INIT,
|
||||||
|
"register device req phy_id 0x%x port_id 0x%x\n", phy_id,
|
||||||
|
(port->port_id & 0xFF));
|
||||||
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
|
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
|
||||||
sizeof(payload), 0);
|
sizeof(payload), 0);
|
||||||
if (rc)
|
if (rc)
|
||||||
@@ -4815,7 +4853,7 @@ static void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha,
|
|||||||
payload.tag = cpu_to_le32(tag);
|
payload.tag = cpu_to_le32(tag);
|
||||||
payload.ppc_phyid =
|
payload.ppc_phyid =
|
||||||
cpu_to_le32(((operation & 0xF) << 8) | (phyid & 0xFF));
|
cpu_to_le32(((operation & 0xF) << 8) | (phyid & 0xFF));
|
||||||
pm8001_dbg(pm8001_ha, INIT,
|
pm8001_dbg(pm8001_ha, DISC,
|
||||||
" phy profile command for phy %x ,length is %d\n",
|
" phy profile command for phy %x ,length is %d\n",
|
||||||
le32_to_cpu(payload.ppc_phyid), length);
|
le32_to_cpu(payload.ppc_phyid), length);
|
||||||
for (i = length; i < (length + PHY_DWORD_LENGTH - 1); i++) {
|
for (i = length; i < (length + PHY_DWORD_LENGTH - 1); i++) {
|
||||||
|
|||||||
@@ -3041,9 +3041,8 @@ static int qedf_alloc_global_queues(struct qedf_ctx *qedf)
|
|||||||
* addresses of our queues
|
* addresses of our queues
|
||||||
*/
|
*/
|
||||||
if (!qedf->p_cpuq) {
|
if (!qedf->p_cpuq) {
|
||||||
status = -EINVAL;
|
|
||||||
QEDF_ERR(&qedf->dbg_ctx, "p_cpuq is NULL.\n");
|
QEDF_ERR(&qedf->dbg_ctx, "p_cpuq is NULL.\n");
|
||||||
goto mem_alloc_failure;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
qedf->global_queues = kzalloc((sizeof(struct global_queue *)
|
qedf->global_queues = kzalloc((sizeof(struct global_queue *)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
config SCSI_QLA_FC
|
config SCSI_QLA_FC
|
||||||
tristate "QLogic QLA2XXX Fibre Channel Support"
|
tristate "QLogic QLA2XXX Fibre Channel Support"
|
||||||
depends on PCI && SCSI
|
depends on PCI && HAS_IOPORT && SCSI
|
||||||
depends on SCSI_FC_ATTRS
|
depends on SCSI_FC_ATTRS
|
||||||
depends on NVME_FC || !NVME_FC
|
depends on NVME_FC || !NVME_FC
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
|
|||||||
@@ -2750,6 +2750,7 @@ static void
|
|||||||
qla2x00_terminate_rport_io(struct fc_rport *rport)
|
qla2x00_terminate_rport_io(struct fc_rport *rport)
|
||||||
{
|
{
|
||||||
fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
|
fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
|
||||||
|
scsi_qla_host_t *vha;
|
||||||
|
|
||||||
if (!fcport)
|
if (!fcport)
|
||||||
return;
|
return;
|
||||||
@@ -2759,9 +2760,12 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
|
|||||||
|
|
||||||
if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
|
if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
|
||||||
return;
|
return;
|
||||||
|
vha = fcport->vha;
|
||||||
|
|
||||||
if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) {
|
if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) {
|
||||||
qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16);
|
qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16);
|
||||||
|
qla2x00_eh_wait_for_pending_commands(fcport->vha, fcport->d_id.b24,
|
||||||
|
0, WAIT_TARGET);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -2786,6 +2790,15 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
|
|||||||
qla2x00_port_logout(fcport->vha, fcport);
|
qla2x00_port_logout(fcport->vha, fcport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check for any straggling io left behind */
|
||||||
|
if (qla2x00_eh_wait_for_pending_commands(fcport->vha, fcport->d_id.b24, 0, WAIT_TARGET)) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x300b,
|
||||||
|
"IO not return. Resetting. \n");
|
||||||
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||||
|
qla2xxx_wake_dpc(vha);
|
||||||
|
qla2x00_wait_for_chip_reset(vha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|||||||
@@ -283,6 +283,10 @@ qla2x00_process_els(struct bsg_job *bsg_job)
|
|||||||
|
|
||||||
if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
|
if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
|
||||||
rport = fc_bsg_to_rport(bsg_job);
|
rport = fc_bsg_to_rport(bsg_job);
|
||||||
|
if (!rport) {
|
||||||
|
rval = -ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
fcport = *(fc_port_t **) rport->dd_data;
|
fcport = *(fc_port_t **) rport->dd_data;
|
||||||
host = rport_to_shost(rport);
|
host = rport_to_shost(rport);
|
||||||
vha = shost_priv(host);
|
vha = shost_priv(host);
|
||||||
@@ -2992,6 +2996,8 @@ qla24xx_bsg_request(struct bsg_job *bsg_job)
|
|||||||
|
|
||||||
if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
|
if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
|
||||||
rport = fc_bsg_to_rport(bsg_job);
|
rport = fc_bsg_to_rport(bsg_job);
|
||||||
|
if (!rport)
|
||||||
|
return ret;
|
||||||
host = rport_to_shost(rport);
|
host = rport_to_shost(rport);
|
||||||
vha = shost_priv(host);
|
vha = shost_priv(host);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -465,6 +465,15 @@ static inline be_id_t port_id_to_be_id(port_id_t port_id)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tmf_arg {
|
||||||
|
struct qla_qpair *qpair;
|
||||||
|
struct fc_port *fcport;
|
||||||
|
struct scsi_qla_host *vha;
|
||||||
|
u64 lun;
|
||||||
|
u32 flags;
|
||||||
|
uint8_t modifier;
|
||||||
|
};
|
||||||
|
|
||||||
struct els_logo_payload {
|
struct els_logo_payload {
|
||||||
uint8_t opcode;
|
uint8_t opcode;
|
||||||
uint8_t rsvd[3];
|
uint8_t rsvd[3];
|
||||||
@@ -544,6 +553,10 @@ struct srb_iocb {
|
|||||||
uint32_t data;
|
uint32_t data;
|
||||||
struct completion comp;
|
struct completion comp;
|
||||||
__le16 comp_status;
|
__le16 comp_status;
|
||||||
|
|
||||||
|
uint8_t modifier;
|
||||||
|
uint8_t vp_index;
|
||||||
|
uint16_t loop_id;
|
||||||
} tmf;
|
} tmf;
|
||||||
struct {
|
struct {
|
||||||
#define SRB_FXDISC_REQ_DMA_VALID BIT_0
|
#define SRB_FXDISC_REQ_DMA_VALID BIT_0
|
||||||
@@ -647,6 +660,7 @@ struct srb_iocb {
|
|||||||
#define SRB_SA_UPDATE 25
|
#define SRB_SA_UPDATE 25
|
||||||
#define SRB_ELS_CMD_HST_NOLOGIN 26
|
#define SRB_ELS_CMD_HST_NOLOGIN 26
|
||||||
#define SRB_SA_REPLACE 27
|
#define SRB_SA_REPLACE 27
|
||||||
|
#define SRB_MARKER 28
|
||||||
|
|
||||||
struct qla_els_pt_arg {
|
struct qla_els_pt_arg {
|
||||||
u8 els_opcode;
|
u8 els_opcode;
|
||||||
@@ -689,7 +703,6 @@ typedef struct srb {
|
|||||||
struct iocb_resource iores;
|
struct iocb_resource iores;
|
||||||
struct kref cmd_kref; /* need to migrate ref_count over to this */
|
struct kref cmd_kref; /* need to migrate ref_count over to this */
|
||||||
void *priv;
|
void *priv;
|
||||||
wait_queue_head_t nvme_ls_waitq;
|
|
||||||
struct fc_port *fcport;
|
struct fc_port *fcport;
|
||||||
struct scsi_qla_host *vha;
|
struct scsi_qla_host *vha;
|
||||||
unsigned int start_timer:1;
|
unsigned int start_timer:1;
|
||||||
@@ -2528,6 +2541,7 @@ enum rscn_addr_format {
|
|||||||
typedef struct fc_port {
|
typedef struct fc_port {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct scsi_qla_host *vha;
|
struct scsi_qla_host *vha;
|
||||||
|
struct list_head tmf_pending;
|
||||||
|
|
||||||
unsigned int conf_compl_supported:1;
|
unsigned int conf_compl_supported:1;
|
||||||
unsigned int deleted:2;
|
unsigned int deleted:2;
|
||||||
@@ -2548,6 +2562,8 @@ typedef struct fc_port {
|
|||||||
unsigned int do_prli_nvme:1;
|
unsigned int do_prli_nvme:1;
|
||||||
|
|
||||||
uint8_t nvme_flag;
|
uint8_t nvme_flag;
|
||||||
|
uint8_t active_tmf;
|
||||||
|
#define MAX_ACTIVE_TMF 8
|
||||||
|
|
||||||
uint8_t node_name[WWN_SIZE];
|
uint8_t node_name[WWN_SIZE];
|
||||||
uint8_t port_name[WWN_SIZE];
|
uint8_t port_name[WWN_SIZE];
|
||||||
@@ -3157,12 +3173,12 @@ struct ct_sns_gpnft_rsp {
|
|||||||
uint8_t vendor_unique;
|
uint8_t vendor_unique;
|
||||||
};
|
};
|
||||||
/* Assume the largest number of targets for the union */
|
/* Assume the largest number of targets for the union */
|
||||||
struct ct_sns_gpn_ft_data {
|
DECLARE_FLEX_ARRAY(struct ct_sns_gpn_ft_data {
|
||||||
u8 control_byte;
|
u8 control_byte;
|
||||||
u8 port_id[3];
|
u8 port_id[3];
|
||||||
u32 reserved;
|
u32 reserved;
|
||||||
u8 port_name[8];
|
u8 port_name[8];
|
||||||
} entries[1];
|
}, entries);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* CT command response */
|
/* CT command response */
|
||||||
@@ -5499,4 +5515,8 @@ struct ql_vnd_tgt_stats_resp {
|
|||||||
_fp->disc_state, _fp->scan_state, _fp->loop_id, _fp->deleted, \
|
_fp->disc_state, _fp->scan_state, _fp->loop_id, _fp->deleted, \
|
||||||
_fp->flags
|
_fp->flags
|
||||||
|
|
||||||
|
#define TMF_NOT_READY(_fcport) \
|
||||||
|
(!_fcport || IS_SESSION_DELETED(_fcport) || atomic_read(&_fcport->state) != FCS_ONLINE || \
|
||||||
|
!_fcport->vha->hw->flags.fw_started)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2361,8 +2361,8 @@ qla24xx_issue_sa_replace_iocb(scsi_qla_host_t *vha, struct qla_work_evt *e)
|
|||||||
if (!sa_ctl) {
|
if (!sa_ctl) {
|
||||||
ql_dbg(ql_dbg_edif, vha, 0x70e6,
|
ql_dbg(ql_dbg_edif, vha, 0x70e6,
|
||||||
"sa_ctl allocation failed\n");
|
"sa_ctl allocation failed\n");
|
||||||
rval = -ENOMEM;
|
rval = -ENOMEM;
|
||||||
goto done;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
fcport = sa_ctl->fcport;
|
fcport = sa_ctl->fcport;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
|
|||||||
extern int qla2x00_async_prlo(struct scsi_qla_host *, fc_port_t *);
|
extern int qla2x00_async_prlo(struct scsi_qla_host *, fc_port_t *);
|
||||||
extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
|
extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
|
||||||
uint16_t *);
|
uint16_t *);
|
||||||
extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
|
extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint64_t, uint32_t);
|
||||||
struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
|
struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
|
||||||
enum qla_work_type);
|
enum qla_work_type);
|
||||||
extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
|
extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
|
||||||
|
|||||||
@@ -3776,8 +3776,8 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp)
|
|||||||
sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE;
|
sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE;
|
||||||
|
|
||||||
rspsz = sizeof(struct ct_sns_gpnft_rsp) +
|
rspsz = sizeof(struct ct_sns_gpnft_rsp) +
|
||||||
((vha->hw->max_fibre_devices - 1) *
|
vha->hw->max_fibre_devices *
|
||||||
sizeof(struct ct_sns_gpn_ft_data));
|
sizeof(struct ct_sns_gpn_ft_data);
|
||||||
|
|
||||||
sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev,
|
sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev,
|
||||||
rspsz,
|
rspsz,
|
||||||
|
|||||||
@@ -1996,6 +1996,11 @@ qla2x00_tmf_iocb_timeout(void *data)
|
|||||||
int rc, h;
|
int rc, h;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (sp->type == SRB_MARKER) {
|
||||||
|
complete(&tmf->u.tmf.comp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rc = qla24xx_async_abort_cmd(sp, false);
|
rc = qla24xx_async_abort_cmd(sp, false);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
|
spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
|
||||||
@@ -2013,24 +2018,131 @@ qla2x00_tmf_iocb_timeout(void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qla_marker_sp_done(srb_t *sp, int res)
|
||||||
|
{
|
||||||
|
struct srb_iocb *tmf = &sp->u.iocb_cmd;
|
||||||
|
|
||||||
|
if (res != QLA_SUCCESS)
|
||||||
|
ql_dbg(ql_dbg_taskm, sp->vha, 0x8004,
|
||||||
|
"Async-marker fail hdl=%x portid=%06x ctrl=%x lun=%lld qp=%d.\n",
|
||||||
|
sp->handle, sp->fcport->d_id.b24, sp->u.iocb_cmd.u.tmf.flags,
|
||||||
|
sp->u.iocb_cmd.u.tmf.lun, sp->qpair->id);
|
||||||
|
|
||||||
|
sp->u.iocb_cmd.u.tmf.data = res;
|
||||||
|
complete(&tmf->u.tmf.comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define START_SP_W_RETRIES(_sp, _rval) \
|
||||||
|
{\
|
||||||
|
int cnt = 5; \
|
||||||
|
do { \
|
||||||
|
_rval = qla2x00_start_sp(_sp); \
|
||||||
|
if (_rval == EAGAIN) \
|
||||||
|
msleep(1); \
|
||||||
|
else \
|
||||||
|
break; \
|
||||||
|
cnt--; \
|
||||||
|
} while (cnt); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qla26xx_marker: send marker IOCB and wait for the completion of it.
|
||||||
|
* @arg: pointer to argument list.
|
||||||
|
* It is assume caller will provide an fcport pointer and modifier
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
qla26xx_marker(struct tmf_arg *arg)
|
||||||
|
{
|
||||||
|
struct scsi_qla_host *vha = arg->vha;
|
||||||
|
struct srb_iocb *tm_iocb;
|
||||||
|
srb_t *sp;
|
||||||
|
int rval = QLA_FUNCTION_FAILED;
|
||||||
|
fc_port_t *fcport = arg->fcport;
|
||||||
|
|
||||||
|
if (TMF_NOT_READY(arg->fcport)) {
|
||||||
|
ql_dbg(ql_dbg_taskm, vha, 0x8039,
|
||||||
|
"FC port not ready for marker loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
|
||||||
|
fcport->loop_id, fcport->d_id.b24,
|
||||||
|
arg->modifier, arg->lun, arg->qpair->id);
|
||||||
|
return QLA_SUSPENDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ref: INIT */
|
||||||
|
sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
|
||||||
|
if (!sp)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
sp->type = SRB_MARKER;
|
||||||
|
sp->name = "marker";
|
||||||
|
qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha), qla_marker_sp_done);
|
||||||
|
sp->u.iocb_cmd.timeout = qla2x00_tmf_iocb_timeout;
|
||||||
|
|
||||||
|
tm_iocb = &sp->u.iocb_cmd;
|
||||||
|
init_completion(&tm_iocb->u.tmf.comp);
|
||||||
|
tm_iocb->u.tmf.modifier = arg->modifier;
|
||||||
|
tm_iocb->u.tmf.lun = arg->lun;
|
||||||
|
tm_iocb->u.tmf.loop_id = fcport->loop_id;
|
||||||
|
tm_iocb->u.tmf.vp_index = vha->vp_idx;
|
||||||
|
|
||||||
|
START_SP_W_RETRIES(sp, rval);
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_taskm, vha, 0x8006,
|
||||||
|
"Async-marker hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
|
||||||
|
sp->handle, fcport->loop_id, fcport->d_id.b24,
|
||||||
|
arg->modifier, arg->lun, sp->qpair->id, rval);
|
||||||
|
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x8031,
|
||||||
|
"Marker IOCB send failure (%x).\n", rval);
|
||||||
|
goto done_free_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_completion(&tm_iocb->u.tmf.comp);
|
||||||
|
rval = tm_iocb->u.tmf.data;
|
||||||
|
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x8019,
|
||||||
|
"Marker failed hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
|
||||||
|
sp->handle, fcport->loop_id, fcport->d_id.b24,
|
||||||
|
arg->modifier, arg->lun, sp->qpair->id, rval);
|
||||||
|
}
|
||||||
|
|
||||||
|
done_free_sp:
|
||||||
|
/* ref: INIT */
|
||||||
|
kref_put(&sp->cmd_kref, qla2x00_sp_release);
|
||||||
|
done:
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
static void qla2x00_tmf_sp_done(srb_t *sp, int res)
|
static void qla2x00_tmf_sp_done(srb_t *sp, int res)
|
||||||
{
|
{
|
||||||
struct srb_iocb *tmf = &sp->u.iocb_cmd;
|
struct srb_iocb *tmf = &sp->u.iocb_cmd;
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
tmf->u.tmf.data = res;
|
||||||
complete(&tmf->u.tmf.comp);
|
complete(&tmf->u.tmf.comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
|
__qla2x00_async_tm_cmd(struct tmf_arg *arg)
|
||||||
uint32_t tag)
|
|
||||||
{
|
{
|
||||||
struct scsi_qla_host *vha = fcport->vha;
|
struct scsi_qla_host *vha = arg->vha;
|
||||||
struct srb_iocb *tm_iocb;
|
struct srb_iocb *tm_iocb;
|
||||||
srb_t *sp;
|
srb_t *sp;
|
||||||
int rval = QLA_FUNCTION_FAILED;
|
int rval = QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
fc_port_t *fcport = arg->fcport;
|
||||||
|
|
||||||
|
if (TMF_NOT_READY(arg->fcport)) {
|
||||||
|
ql_dbg(ql_dbg_taskm, vha, 0x8032,
|
||||||
|
"FC port not ready for TM command loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
|
||||||
|
fcport->loop_id, fcport->d_id.b24,
|
||||||
|
arg->modifier, arg->lun, arg->qpair->id);
|
||||||
|
return QLA_SUSPENDED;
|
||||||
|
}
|
||||||
|
|
||||||
/* ref: INIT */
|
/* ref: INIT */
|
||||||
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
|
sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
|
||||||
if (!sp)
|
if (!sp)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
@@ -2043,15 +2155,16 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
|
|||||||
|
|
||||||
tm_iocb = &sp->u.iocb_cmd;
|
tm_iocb = &sp->u.iocb_cmd;
|
||||||
init_completion(&tm_iocb->u.tmf.comp);
|
init_completion(&tm_iocb->u.tmf.comp);
|
||||||
tm_iocb->u.tmf.flags = flags;
|
tm_iocb->u.tmf.flags = arg->flags;
|
||||||
tm_iocb->u.tmf.lun = lun;
|
tm_iocb->u.tmf.lun = arg->lun;
|
||||||
|
|
||||||
|
START_SP_W_RETRIES(sp, rval);
|
||||||
|
|
||||||
ql_dbg(ql_dbg_taskm, vha, 0x802f,
|
ql_dbg(ql_dbg_taskm, vha, 0x802f,
|
||||||
"Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
|
"Async-tmf hdl=%x loop-id=%x portid=%06x ctrl=%x lun=%lld qp=%d rval=%x.\n",
|
||||||
sp->handle, fcport->loop_id, fcport->d_id.b.domain,
|
sp->handle, fcport->loop_id, fcport->d_id.b24,
|
||||||
fcport->d_id.b.area, fcport->d_id.b.al_pa);
|
arg->flags, arg->lun, sp->qpair->id, rval);
|
||||||
|
|
||||||
rval = qla2x00_start_sp(sp);
|
|
||||||
if (rval != QLA_SUCCESS)
|
if (rval != QLA_SUCCESS)
|
||||||
goto done_free_sp;
|
goto done_free_sp;
|
||||||
wait_for_completion(&tm_iocb->u.tmf.comp);
|
wait_for_completion(&tm_iocb->u.tmf.comp);
|
||||||
@@ -2063,15 +2176,8 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
|
|||||||
"TM IOCB failed (%x).\n", rval);
|
"TM IOCB failed (%x).\n", rval);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
|
if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw))
|
||||||
flags = tm_iocb->u.tmf.flags;
|
rval = qla26xx_marker(arg);
|
||||||
lun = (uint16_t)tm_iocb->u.tmf.lun;
|
|
||||||
|
|
||||||
/* Issue Marker IOCB */
|
|
||||||
qla2x00_marker(vha, vha->hw->base_qpair,
|
|
||||||
fcport->loop_id, lun,
|
|
||||||
flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
done_free_sp:
|
done_free_sp:
|
||||||
/* ref: INIT */
|
/* ref: INIT */
|
||||||
@@ -2080,6 +2186,115 @@ done:
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qla_put_tmf(fc_port_t *fcport)
|
||||||
|
{
|
||||||
|
struct scsi_qla_host *vha = fcport->vha;
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
|
||||||
|
fcport->active_tmf--;
|
||||||
|
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int qla_get_tmf(fc_port_t *fcport)
|
||||||
|
{
|
||||||
|
struct scsi_qla_host *vha = fcport->vha;
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
unsigned long flags;
|
||||||
|
int rc = 0;
|
||||||
|
LIST_HEAD(tmf_elem);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
|
||||||
|
list_add_tail(&tmf_elem, &fcport->tmf_pending);
|
||||||
|
|
||||||
|
while (fcport->active_tmf >= MAX_ACTIVE_TMF) {
|
||||||
|
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
|
||||||
|
|
||||||
|
msleep(1);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
|
||||||
|
if (TMF_NOT_READY(fcport)) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x802c,
|
||||||
|
"Unable to acquire TM resource due to disruption.\n");
|
||||||
|
rc = EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fcport->active_tmf < MAX_ACTIVE_TMF &&
|
||||||
|
list_is_first(&tmf_elem, &fcport->tmf_pending))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&tmf_elem);
|
||||||
|
|
||||||
|
if (!rc)
|
||||||
|
fcport->active_tmf++;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
|
||||||
|
uint32_t tag)
|
||||||
|
{
|
||||||
|
struct scsi_qla_host *vha = fcport->vha;
|
||||||
|
struct qla_qpair *qpair;
|
||||||
|
struct tmf_arg a;
|
||||||
|
int i, rval = QLA_SUCCESS;
|
||||||
|
|
||||||
|
if (TMF_NOT_READY(fcport))
|
||||||
|
return QLA_SUSPENDED;
|
||||||
|
|
||||||
|
a.vha = fcport->vha;
|
||||||
|
a.fcport = fcport;
|
||||||
|
a.lun = lun;
|
||||||
|
if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
|
||||||
|
a.modifier = MK_SYNC_ID_LUN;
|
||||||
|
|
||||||
|
if (qla_get_tmf(fcport))
|
||||||
|
return QLA_FUNCTION_FAILED;
|
||||||
|
} else {
|
||||||
|
a.modifier = MK_SYNC_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vha->hw->mqenable) {
|
||||||
|
for (i = 0; i < vha->hw->num_qpairs; i++) {
|
||||||
|
qpair = vha->hw->queue_pair_map[i];
|
||||||
|
if (!qpair)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TMF_NOT_READY(fcport)) {
|
||||||
|
ql_log(ql_log_warn, vha, 0x8026,
|
||||||
|
"Unable to send TM due to disruption.\n");
|
||||||
|
rval = QLA_SUSPENDED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.qpair = qpair;
|
||||||
|
a.flags = flags|TCF_NOTMCMD_TO_TARGET;
|
||||||
|
rval = __qla2x00_async_tm_cmd(&a);
|
||||||
|
if (rval)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rval)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
a.qpair = vha->hw->base_qpair;
|
||||||
|
a.flags = flags;
|
||||||
|
rval = __qla2x00_async_tm_cmd(&a);
|
||||||
|
|
||||||
|
bailout:
|
||||||
|
if (a.modifier == MK_SYNC_ID_LUN)
|
||||||
|
qla_put_tmf(fcport);
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
qla24xx_async_abort_command(srb_t *sp)
|
qla24xx_async_abort_command(srb_t *sp)
|
||||||
{
|
{
|
||||||
@@ -4861,7 +5076,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
|
|||||||
if (use_tbl &&
|
if (use_tbl &&
|
||||||
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
||||||
index < QLA_MODEL_NAMES)
|
index < QLA_MODEL_NAMES)
|
||||||
strlcpy(ha->model_desc,
|
strscpy(ha->model_desc,
|
||||||
qla2x00_model_name[index * 2 + 1],
|
qla2x00_model_name[index * 2 + 1],
|
||||||
sizeof(ha->model_desc));
|
sizeof(ha->model_desc));
|
||||||
} else {
|
} else {
|
||||||
@@ -4869,14 +5084,14 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
|
|||||||
if (use_tbl &&
|
if (use_tbl &&
|
||||||
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
||||||
index < QLA_MODEL_NAMES) {
|
index < QLA_MODEL_NAMES) {
|
||||||
strlcpy(ha->model_number,
|
strscpy(ha->model_number,
|
||||||
qla2x00_model_name[index * 2],
|
qla2x00_model_name[index * 2],
|
||||||
sizeof(ha->model_number));
|
sizeof(ha->model_number));
|
||||||
strlcpy(ha->model_desc,
|
strscpy(ha->model_desc,
|
||||||
qla2x00_model_name[index * 2 + 1],
|
qla2x00_model_name[index * 2 + 1],
|
||||||
sizeof(ha->model_desc));
|
sizeof(ha->model_desc));
|
||||||
} else {
|
} else {
|
||||||
strlcpy(ha->model_number, def,
|
strscpy(ha->model_number, def,
|
||||||
sizeof(ha->model_number));
|
sizeof(ha->model_number));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5291,6 +5506,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
|
|||||||
INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
|
INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
|
||||||
INIT_LIST_HEAD(&fcport->gnl_entry);
|
INIT_LIST_HEAD(&fcport->gnl_entry);
|
||||||
INIT_LIST_HEAD(&fcport->list);
|
INIT_LIST_HEAD(&fcport->list);
|
||||||
|
INIT_LIST_HEAD(&fcport->tmf_pending);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&fcport->sess_cmd_list);
|
INIT_LIST_HEAD(&fcport->sess_cmd_list);
|
||||||
spin_lock_init(&fcport->sess_cmd_lock);
|
spin_lock_init(&fcport->sess_cmd_lock);
|
||||||
@@ -5333,7 +5549,7 @@ static void qla_get_login_template(scsi_qla_host_t *vha)
|
|||||||
__be32 *q;
|
__be32 *q;
|
||||||
|
|
||||||
memset(ha->init_cb, 0, ha->init_cb_size);
|
memset(ha->init_cb, 0, ha->init_cb_size);
|
||||||
sz = min_t(int, sizeof(struct fc_els_flogi), ha->init_cb_size);
|
sz = min_t(int, sizeof(struct fc_els_csp), ha->init_cb_size);
|
||||||
rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma,
|
rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma,
|
||||||
ha->init_cb, sz);
|
ha->init_cb, sz);
|
||||||
if (rval != QLA_SUCCESS) {
|
if (rval != QLA_SUCCESS) {
|
||||||
@@ -6004,7 +6220,6 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
|
|||||||
fc_port_t *fcport;
|
fc_port_t *fcport;
|
||||||
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
||||||
uint16_t loop_id;
|
uint16_t loop_id;
|
||||||
LIST_HEAD(new_fcports);
|
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
int discovery_gen;
|
int discovery_gen;
|
||||||
|
|
||||||
|
|||||||
@@ -109,11 +109,13 @@ qla2x00_set_fcport_disc_state(fc_port_t *fcport, int state)
|
|||||||
{
|
{
|
||||||
int old_val;
|
int old_val;
|
||||||
uint8_t shiftbits, mask;
|
uint8_t shiftbits, mask;
|
||||||
|
uint8_t port_dstate_str_sz;
|
||||||
|
|
||||||
/* This will have to change when the max no. of states > 16 */
|
/* This will have to change when the max no. of states > 16 */
|
||||||
shiftbits = 4;
|
shiftbits = 4;
|
||||||
mask = (1 << shiftbits) - 1;
|
mask = (1 << shiftbits) - 1;
|
||||||
|
|
||||||
|
port_dstate_str_sz = sizeof(port_dstate_str) / sizeof(char *);
|
||||||
fcport->disc_state = state;
|
fcport->disc_state = state;
|
||||||
while (1) {
|
while (1) {
|
||||||
old_val = atomic_read(&fcport->shadow_disc_state);
|
old_val = atomic_read(&fcport->shadow_disc_state);
|
||||||
@@ -121,7 +123,8 @@ qla2x00_set_fcport_disc_state(fc_port_t *fcport, int state)
|
|||||||
old_val, (old_val << shiftbits) | state)) {
|
old_val, (old_val << shiftbits) | state)) {
|
||||||
ql_dbg(ql_dbg_disc, fcport->vha, 0x2134,
|
ql_dbg(ql_dbg_disc, fcport->vha, 0x2134,
|
||||||
"FCPort %8phC disc_state transition: %s to %s - portid=%06x.\n",
|
"FCPort %8phC disc_state transition: %s to %s - portid=%06x.\n",
|
||||||
fcport->port_name, port_dstate_str[old_val & mask],
|
fcport->port_name, (old_val & mask) < port_dstate_str_sz ?
|
||||||
|
port_dstate_str[old_val & mask] : "Unknown",
|
||||||
port_dstate_str[state], fcport->d_id.b24);
|
port_dstate_str[state], fcport->d_id.b24);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -522,21 +522,25 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
|
|||||||
return (QLA_FUNCTION_FAILED);
|
return (QLA_FUNCTION_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mrk24 = (struct mrk_entry_24xx *)mrk;
|
||||||
|
|
||||||
mrk->entry_type = MARKER_TYPE;
|
mrk->entry_type = MARKER_TYPE;
|
||||||
mrk->modifier = type;
|
mrk->modifier = type;
|
||||||
if (type != MK_SYNC_ALL) {
|
if (type != MK_SYNC_ALL) {
|
||||||
if (IS_FWI2_CAPABLE(ha)) {
|
if (IS_FWI2_CAPABLE(ha)) {
|
||||||
mrk24 = (struct mrk_entry_24xx *) mrk;
|
|
||||||
mrk24->nport_handle = cpu_to_le16(loop_id);
|
mrk24->nport_handle = cpu_to_le16(loop_id);
|
||||||
int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun);
|
int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun);
|
||||||
host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
|
host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
|
||||||
mrk24->vp_index = vha->vp_idx;
|
mrk24->vp_index = vha->vp_idx;
|
||||||
mrk24->handle = make_handle(req->id, mrk24->handle);
|
|
||||||
} else {
|
} else {
|
||||||
SET_TARGET_ID(ha, mrk->target, loop_id);
|
SET_TARGET_ID(ha, mrk->target, loop_id);
|
||||||
mrk->lun = cpu_to_le16((uint16_t)lun);
|
mrk->lun = cpu_to_le16((uint16_t)lun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_FWI2_CAPABLE(ha))
|
||||||
|
mrk24->handle = QLA_SKIP_HANDLE;
|
||||||
|
|
||||||
wmb();
|
wmb();
|
||||||
|
|
||||||
qla2x00_start_iocbs(vha, req);
|
qla2x00_start_iocbs(vha, req);
|
||||||
@@ -603,7 +607,8 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
|
|||||||
put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type);
|
put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type);
|
||||||
|
|
||||||
/* No data transfer */
|
/* No data transfer */
|
||||||
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
|
if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE ||
|
||||||
|
tot_dsds == 0) {
|
||||||
cmd_pkt->byte_count = cpu_to_le32(0);
|
cmd_pkt->byte_count = cpu_to_le32(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2541,7 +2546,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
|
|||||||
scsi_qla_host_t *vha = fcport->vha;
|
scsi_qla_host_t *vha = fcport->vha;
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
struct srb_iocb *iocb = &sp->u.iocb_cmd;
|
struct srb_iocb *iocb = &sp->u.iocb_cmd;
|
||||||
struct req_que *req = vha->req;
|
struct req_que *req = sp->qpair->req;
|
||||||
|
|
||||||
flags = iocb->u.tmf.flags;
|
flags = iocb->u.tmf.flags;
|
||||||
lun = iocb->u.tmf.lun;
|
lun = iocb->u.tmf.lun;
|
||||||
@@ -2557,7 +2562,8 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
|
|||||||
tsk->port_id[2] = fcport->d_id.b.domain;
|
tsk->port_id[2] = fcport->d_id.b.domain;
|
||||||
tsk->vp_index = fcport->vha->vp_idx;
|
tsk->vp_index = fcport->vha->vp_idx;
|
||||||
|
|
||||||
if (flags == TCF_LUN_RESET) {
|
if (flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET|
|
||||||
|
TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
|
||||||
int_to_scsilun(lun, &tsk->lun);
|
int_to_scsilun(lun, &tsk->lun);
|
||||||
host_to_fcp_swap((uint8_t *)&tsk->lun,
|
host_to_fcp_swap((uint8_t *)&tsk->lun,
|
||||||
sizeof(tsk->lun));
|
sizeof(tsk->lun));
|
||||||
@@ -3852,9 +3858,9 @@ static int qla_get_iocbs_resource(struct srb *sp)
|
|||||||
case SRB_NACK_LOGO:
|
case SRB_NACK_LOGO:
|
||||||
case SRB_LOGOUT_CMD:
|
case SRB_LOGOUT_CMD:
|
||||||
case SRB_CTRL_VP:
|
case SRB_CTRL_VP:
|
||||||
push_it_through = true;
|
case SRB_MARKER:
|
||||||
fallthrough;
|
|
||||||
default:
|
default:
|
||||||
|
push_it_through = true;
|
||||||
get_exch = false;
|
get_exch = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3870,6 +3876,19 @@ static int qla_get_iocbs_resource(struct srb *sp)
|
|||||||
return qla_get_fw_resources(sp->qpair, &sp->iores);
|
return qla_get_fw_resources(sp->qpair, &sp->iores);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
|
||||||
|
{
|
||||||
|
mrk->entry_type = MARKER_TYPE;
|
||||||
|
mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier;
|
||||||
|
if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) {
|
||||||
|
mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id);
|
||||||
|
int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun);
|
||||||
|
host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
|
||||||
|
mrk->vp_index = sp->u.iocb_cmd.u.tmf.vp_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
qla2x00_start_sp(srb_t *sp)
|
qla2x00_start_sp(srb_t *sp)
|
||||||
{
|
{
|
||||||
@@ -3973,6 +3992,9 @@ qla2x00_start_sp(srb_t *sp)
|
|||||||
case SRB_SA_REPLACE:
|
case SRB_SA_REPLACE:
|
||||||
qla24xx_sa_replace_iocb(sp, pkt);
|
qla24xx_sa_replace_iocb(sp, pkt);
|
||||||
break;
|
break;
|
||||||
|
case SRB_MARKER:
|
||||||
|
qla_marker_iocb(sp, pkt);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1862,9 +1862,9 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
srb_t *
|
static srb_t *
|
||||||
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
qla_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
||||||
struct req_que *req, void *iocb)
|
struct req_que *req, void *iocb, u16 *ret_index)
|
||||||
{
|
{
|
||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
sts_entry_t *pkt = iocb;
|
sts_entry_t *pkt = iocb;
|
||||||
@@ -1899,12 +1899,25 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
req->outstanding_cmds[index] = NULL;
|
*ret_index = index;
|
||||||
|
|
||||||
qla_put_fw_resources(sp->qpair, &sp->iores);
|
qla_put_fw_resources(sp->qpair, &sp->iores);
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srb_t *
|
||||||
|
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
||||||
|
struct req_que *req, void *iocb)
|
||||||
|
{
|
||||||
|
uint16_t index;
|
||||||
|
srb_t *sp;
|
||||||
|
|
||||||
|
sp = qla_get_sp_from_handle(vha, func, req, iocb, &index);
|
||||||
|
if (sp)
|
||||||
|
req->outstanding_cmds[index] = NULL;
|
||||||
|
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
||||||
struct mbx_entry *mbx)
|
struct mbx_entry *mbx)
|
||||||
@@ -3237,13 +3250,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
req->outstanding_cmds[handle] = NULL;
|
|
||||||
cp = GET_CMD_SP(sp);
|
cp = GET_CMD_SP(sp);
|
||||||
if (cp == NULL) {
|
if (cp == NULL) {
|
||||||
ql_dbg(ql_dbg_io, vha, 0x3018,
|
ql_dbg(ql_dbg_io, vha, 0x3018,
|
||||||
"Command already returned (0x%x/%p).\n",
|
"Command already returned (0x%x/%p).\n",
|
||||||
sts->handle, sp);
|
sts->handle, sp);
|
||||||
|
|
||||||
|
req->outstanding_cmds[handle] = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3514,6 +3527,9 @@ out:
|
|||||||
|
|
||||||
if (rsp->status_srb == NULL)
|
if (rsp->status_srb == NULL)
|
||||||
sp->done(sp, res);
|
sp->done(sp, res);
|
||||||
|
|
||||||
|
/* for io's, clearing of outstanding_cmds[handle] means scsi_done was called */
|
||||||
|
req->outstanding_cmds[handle] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3590,6 +3606,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
|
|||||||
uint16_t que = MSW(pkt->handle);
|
uint16_t que = MSW(pkt->handle);
|
||||||
struct req_que *req = NULL;
|
struct req_que *req = NULL;
|
||||||
int res = DID_ERROR << 16;
|
int res = DID_ERROR << 16;
|
||||||
|
u16 index;
|
||||||
|
|
||||||
ql_dbg(ql_dbg_async, vha, 0x502a,
|
ql_dbg(ql_dbg_async, vha, 0x502a,
|
||||||
"iocb type %xh with error status %xh, handle %xh, rspq id %d\n",
|
"iocb type %xh with error status %xh, handle %xh, rspq id %d\n",
|
||||||
@@ -3608,7 +3625,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
|
|||||||
|
|
||||||
switch (pkt->entry_type) {
|
switch (pkt->entry_type) {
|
||||||
case NOTIFY_ACK_TYPE:
|
case NOTIFY_ACK_TYPE:
|
||||||
case STATUS_TYPE:
|
|
||||||
case STATUS_CONT_TYPE:
|
case STATUS_CONT_TYPE:
|
||||||
case LOGINOUT_PORT_IOCB_TYPE:
|
case LOGINOUT_PORT_IOCB_TYPE:
|
||||||
case CT_IOCB_TYPE:
|
case CT_IOCB_TYPE:
|
||||||
@@ -3628,6 +3644,14 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
|
|||||||
case CTIO_TYPE7:
|
case CTIO_TYPE7:
|
||||||
case CTIO_CRC2:
|
case CTIO_CRC2:
|
||||||
return 1;
|
return 1;
|
||||||
|
case STATUS_TYPE:
|
||||||
|
sp = qla_get_sp_from_handle(vha, func, req, pkt, &index);
|
||||||
|
if (sp) {
|
||||||
|
sp->done(sp, res);
|
||||||
|
req->outstanding_cmds[index] = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
fatal:
|
fatal:
|
||||||
ql_log(ql_log_warn, vha, 0x5030,
|
ql_log(ql_log_warn, vha, 0x5030,
|
||||||
@@ -3750,6 +3774,28 @@ static int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
||||||
|
struct mrk_entry_24xx *pkt)
|
||||||
|
{
|
||||||
|
const char func[] = "MRK-IOCB";
|
||||||
|
srb_t *sp;
|
||||||
|
int res = QLA_SUCCESS;
|
||||||
|
|
||||||
|
if (!IS_FWI2_CAPABLE(vha->hw))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
|
||||||
|
if (!sp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pkt->entry_status) {
|
||||||
|
ql_dbg(ql_dbg_taskm, vha, 0x8025, "marker failure.\n");
|
||||||
|
res = QLA_COMMAND_ERROR;
|
||||||
|
}
|
||||||
|
sp->u.iocb_cmd.u.tmf.data = res;
|
||||||
|
sp->done(sp, res);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qla24xx_process_response_queue() - Process response queue entries.
|
* qla24xx_process_response_queue() - Process response queue entries.
|
||||||
* @vha: SCSI driver HA context
|
* @vha: SCSI driver HA context
|
||||||
@@ -3866,9 +3912,7 @@ process_err:
|
|||||||
(struct nack_to_isp *)pkt);
|
(struct nack_to_isp *)pkt);
|
||||||
break;
|
break;
|
||||||
case MARKER_TYPE:
|
case MARKER_TYPE:
|
||||||
/* Do nothing in this case, this check is to prevent it
|
qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt);
|
||||||
* from falling into default case
|
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
case ABORT_IOCB_TYPE:
|
case ABORT_IOCB_TYPE:
|
||||||
qla24xx_abort_iocb_entry(vha, rsp->req,
|
qla24xx_abort_iocb_entry(vha, rsp->req,
|
||||||
|
|||||||
@@ -691,7 +691,7 @@ qlafx00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len)
|
|||||||
struct qla_hw_data *ha = vha->hw;
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
|
||||||
if (pci_is_pcie(ha->pdev))
|
if (pci_is_pcie(ha->pdev))
|
||||||
strlcpy(str, "PCIe iSA", str_len);
|
strscpy(str, "PCIe iSA", str_len);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1850,21 +1850,21 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
|
|||||||
phost_info = &preg_hsi->hsi;
|
phost_info = &preg_hsi->hsi;
|
||||||
memset(preg_hsi, 0, sizeof(struct register_host_info));
|
memset(preg_hsi, 0, sizeof(struct register_host_info));
|
||||||
phost_info->os_type = OS_TYPE_LINUX;
|
phost_info->os_type = OS_TYPE_LINUX;
|
||||||
strlcpy(phost_info->sysname, p_sysid->sysname,
|
strscpy(phost_info->sysname, p_sysid->sysname,
|
||||||
sizeof(phost_info->sysname));
|
sizeof(phost_info->sysname));
|
||||||
strlcpy(phost_info->nodename, p_sysid->nodename,
|
strscpy(phost_info->nodename, p_sysid->nodename,
|
||||||
sizeof(phost_info->nodename));
|
sizeof(phost_info->nodename));
|
||||||
if (!strcmp(phost_info->nodename, "(none)"))
|
if (!strcmp(phost_info->nodename, "(none)"))
|
||||||
ha->mr.host_info_resend = true;
|
ha->mr.host_info_resend = true;
|
||||||
strlcpy(phost_info->release, p_sysid->release,
|
strscpy(phost_info->release, p_sysid->release,
|
||||||
sizeof(phost_info->release));
|
sizeof(phost_info->release));
|
||||||
strlcpy(phost_info->version, p_sysid->version,
|
strscpy(phost_info->version, p_sysid->version,
|
||||||
sizeof(phost_info->version));
|
sizeof(phost_info->version));
|
||||||
strlcpy(phost_info->machine, p_sysid->machine,
|
strscpy(phost_info->machine, p_sysid->machine,
|
||||||
sizeof(phost_info->machine));
|
sizeof(phost_info->machine));
|
||||||
strlcpy(phost_info->domainname, p_sysid->domainname,
|
strscpy(phost_info->domainname, p_sysid->domainname,
|
||||||
sizeof(phost_info->domainname));
|
sizeof(phost_info->domainname));
|
||||||
strlcpy(phost_info->hostdriver, QLA2XXX_VERSION,
|
strscpy(phost_info->hostdriver, QLA2XXX_VERSION,
|
||||||
sizeof(phost_info->hostdriver));
|
sizeof(phost_info->hostdriver));
|
||||||
preg_hsi->utc = (uint64_t)ktime_get_real_seconds();
|
preg_hsi->utc = (uint64_t)ktime_get_real_seconds();
|
||||||
ql_dbg(ql_dbg_init, vha, 0x0149,
|
ql_dbg(ql_dbg_init, vha, 0x0149,
|
||||||
@@ -1909,9 +1909,9 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
|
|||||||
if (fx_type == FXDISC_GET_CONFIG_INFO) {
|
if (fx_type == FXDISC_GET_CONFIG_INFO) {
|
||||||
struct config_info_data *pinfo =
|
struct config_info_data *pinfo =
|
||||||
(struct config_info_data *) fdisc->u.fxiocb.rsp_addr;
|
(struct config_info_data *) fdisc->u.fxiocb.rsp_addr;
|
||||||
strlcpy(vha->hw->model_number, pinfo->model_num,
|
strscpy(vha->hw->model_number, pinfo->model_num,
|
||||||
ARRAY_SIZE(vha->hw->model_number));
|
ARRAY_SIZE(vha->hw->model_number));
|
||||||
strlcpy(vha->hw->model_desc, pinfo->model_description,
|
strscpy(vha->hw->model_desc, pinfo->model_description,
|
||||||
ARRAY_SIZE(vha->hw->model_desc));
|
ARRAY_SIZE(vha->hw->model_desc));
|
||||||
memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name,
|
memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name,
|
||||||
sizeof(vha->hw->mr.symbolic_name));
|
sizeof(vha->hw->mr.symbolic_name));
|
||||||
|
|||||||
@@ -360,7 +360,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
|
|||||||
if (rval != QLA_SUCCESS) {
|
if (rval != QLA_SUCCESS) {
|
||||||
ql_log(ql_log_warn, vha, 0x700e,
|
ql_log(ql_log_warn, vha, 0x700e,
|
||||||
"qla2x00_start_sp failed = %d\n", rval);
|
"qla2x00_start_sp failed = %d\n", rval);
|
||||||
wake_up(&sp->nvme_ls_waitq);
|
|
||||||
sp->priv = NULL;
|
sp->priv = NULL;
|
||||||
priv->sp = NULL;
|
priv->sp = NULL;
|
||||||
qla2x00_rel_sp(sp);
|
qla2x00_rel_sp(sp);
|
||||||
@@ -652,7 +651,6 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
|
|||||||
if (!sp)
|
if (!sp)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
init_waitqueue_head(&sp->nvme_ls_waitq);
|
|
||||||
kref_init(&sp->cmd_kref);
|
kref_init(&sp->cmd_kref);
|
||||||
spin_lock_init(&priv->cmd_lock);
|
spin_lock_init(&priv->cmd_lock);
|
||||||
sp->priv = priv;
|
sp->priv = priv;
|
||||||
@@ -671,7 +669,6 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
|
|||||||
if (rval != QLA_SUCCESS) {
|
if (rval != QLA_SUCCESS) {
|
||||||
ql_log(ql_log_warn, vha, 0x212d,
|
ql_log(ql_log_warn, vha, 0x212d,
|
||||||
"qla2x00_start_nvme_mq failed = %d\n", rval);
|
"qla2x00_start_nvme_mq failed = %d\n", rval);
|
||||||
wake_up(&sp->nvme_ls_waitq);
|
|
||||||
sp->priv = NULL;
|
sp->priv = NULL;
|
||||||
priv->sp = NULL;
|
priv->sp = NULL;
|
||||||
qla2xxx_rel_qpair_sp(sp->qpair, sp);
|
qla2xxx_rel_qpair_sp(sp->qpair, sp);
|
||||||
|
|||||||
@@ -1078,43 +1078,6 @@ qc24_fail_command:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* qla2x00_eh_wait_on_command
|
|
||||||
* Waits for the command to be returned by the Firmware for some
|
|
||||||
* max time.
|
|
||||||
*
|
|
||||||
* Input:
|
|
||||||
* cmd = Scsi Command to wait on.
|
|
||||||
*
|
|
||||||
* Return:
|
|
||||||
* Completed in time : QLA_SUCCESS
|
|
||||||
* Did not complete in time : QLA_FUNCTION_FAILED
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd)
|
|
||||||
{
|
|
||||||
#define ABORT_POLLING_PERIOD 1000
|
|
||||||
#define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD))
|
|
||||||
unsigned long wait_iter = ABORT_WAIT_ITER;
|
|
||||||
scsi_qla_host_t *vha = shost_priv(cmd->device->host);
|
|
||||||
struct qla_hw_data *ha = vha->hw;
|
|
||||||
srb_t *sp = scsi_cmd_priv(cmd);
|
|
||||||
int ret = QLA_SUCCESS;
|
|
||||||
|
|
||||||
if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) {
|
|
||||||
ql_dbg(ql_dbg_taskm, vha, 0x8005,
|
|
||||||
"Return:eh_wait.\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (sp->type && wait_iter--)
|
|
||||||
msleep(ABORT_POLLING_PERIOD);
|
|
||||||
if (sp->type)
|
|
||||||
ret = QLA_FUNCTION_FAILED;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* qla2x00_wait_for_hba_online
|
* qla2x00_wait_for_hba_online
|
||||||
* Wait till the HBA is online after going through
|
* Wait till the HBA is online after going through
|
||||||
@@ -1365,6 +1328,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ABORT_POLLING_PERIOD 1000
|
||||||
|
#define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns: QLA_SUCCESS or QLA_FUNCTION_FAILED.
|
* Returns: QLA_SUCCESS or QLA_FUNCTION_FAILED.
|
||||||
*/
|
*/
|
||||||
@@ -1378,41 +1344,73 @@ __qla2x00_eh_wait_for_pending_commands(struct qla_qpair *qpair, unsigned int t,
|
|||||||
struct req_que *req = qpair->req;
|
struct req_que *req = qpair->req;
|
||||||
srb_t *sp;
|
srb_t *sp;
|
||||||
struct scsi_cmnd *cmd;
|
struct scsi_cmnd *cmd;
|
||||||
|
unsigned long wait_iter = ABORT_WAIT_ITER;
|
||||||
|
bool found;
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
|
||||||
status = QLA_SUCCESS;
|
status = QLA_SUCCESS;
|
||||||
|
|
||||||
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
|
while (wait_iter--) {
|
||||||
for (cnt = 1; status == QLA_SUCCESS &&
|
found = false;
|
||||||
cnt < req->num_outstanding_cmds; cnt++) {
|
|
||||||
sp = req->outstanding_cmds[cnt];
|
|
||||||
if (!sp)
|
|
||||||
continue;
|
|
||||||
if (sp->type != SRB_SCSI_CMD)
|
|
||||||
continue;
|
|
||||||
if (vha->vp_idx != sp->vha->vp_idx)
|
|
||||||
continue;
|
|
||||||
match = 0;
|
|
||||||
cmd = GET_CMD_SP(sp);
|
|
||||||
switch (type) {
|
|
||||||
case WAIT_HOST:
|
|
||||||
match = 1;
|
|
||||||
break;
|
|
||||||
case WAIT_TARGET:
|
|
||||||
match = cmd->device->id == t;
|
|
||||||
break;
|
|
||||||
case WAIT_LUN:
|
|
||||||
match = (cmd->device->id == t &&
|
|
||||||
cmd->device->lun == l);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!match)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
|
|
||||||
status = qla2x00_eh_wait_on_command(cmd);
|
|
||||||
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
|
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
|
||||||
|
for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
|
||||||
|
sp = req->outstanding_cmds[cnt];
|
||||||
|
if (!sp)
|
||||||
|
continue;
|
||||||
|
if (sp->type != SRB_SCSI_CMD)
|
||||||
|
continue;
|
||||||
|
if (vha->vp_idx != sp->vha->vp_idx)
|
||||||
|
continue;
|
||||||
|
match = 0;
|
||||||
|
cmd = GET_CMD_SP(sp);
|
||||||
|
switch (type) {
|
||||||
|
case WAIT_HOST:
|
||||||
|
match = 1;
|
||||||
|
break;
|
||||||
|
case WAIT_TARGET:
|
||||||
|
if (sp->fcport)
|
||||||
|
match = sp->fcport->d_id.b24 == t;
|
||||||
|
else
|
||||||
|
match = 0;
|
||||||
|
break;
|
||||||
|
case WAIT_LUN:
|
||||||
|
if (sp->fcport)
|
||||||
|
match = (sp->fcport->d_id.b24 == t &&
|
||||||
|
cmd->device->lun == l);
|
||||||
|
else
|
||||||
|
match = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!match)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
|
||||||
|
|
||||||
|
if (unlikely(pci_channel_offline(ha->pdev)) ||
|
||||||
|
ha->flags.eeh_busy) {
|
||||||
|
ql_dbg(ql_dbg_taskm, vha, 0x8005,
|
||||||
|
"Return:eh_wait.\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SRB_SCSI_CMD is still in the outstanding_cmds array.
|
||||||
|
* it means scsi_done has not called. Wait for it to
|
||||||
|
* clear from outstanding_cmds.
|
||||||
|
*/
|
||||||
|
msleep(ABORT_POLLING_PERIOD);
|
||||||
|
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
|
|
||||||
|
if (wait_iter == -1)
|
||||||
|
status = QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -5090,7 +5088,8 @@ struct scsi_qla_host *qla2x00_create_host(const struct scsi_host_template *sht,
|
|||||||
}
|
}
|
||||||
INIT_DELAYED_WORK(&vha->scan.scan_work, qla_scan_work_fn);
|
INIT_DELAYED_WORK(&vha->scan.scan_work, qla_scan_work_fn);
|
||||||
|
|
||||||
sprintf(vha->host_str, "%s_%lu", QLA2XXX_DRIVER_NAME, vha->host_no);
|
snprintf(vha->host_str, sizeof(vha->host_str), "%s_%lu",
|
||||||
|
QLA2XXX_DRIVER_NAME, vha->host_no);
|
||||||
ql_dbg(ql_dbg_init, vha, 0x0041,
|
ql_dbg(ql_dbg_init, vha, 0x0041,
|
||||||
"Allocated the host=%p hw=%p vha=%p dev_name=%s",
|
"Allocated the host=%p hw=%p vha=%p dev_name=%s",
|
||||||
vha->host, vha->hw, vha,
|
vha->host, vha->hw, vha,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user