SCSI misc on 20230629
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 and block level Persistent Reservation Operations, which touches block, nvme, target and dm (both of which are added with merge commits containing a cover letter explaining what's going on). Signed-off-by: James E.J. Bottomley <jejb@linux.ibm.com> -----BEGIN PGP SIGNATURE----- iJwEABMIAEQWIQTnYEDbdso9F2cI+arnQslM7pishQUCZJ19cSYcamFtZXMuYm90 dG9tbGV5QGhhbnNlbnBhcnRuZXJzaGlwLmNvbQAKCRDnQslM7pishfZpAQCQBuWR ELcOhsaG5KzO6xLWcH8mjsOoxffKvazZjTKXlAD5ATEv7++E250oKS3t+yfjae5I Lc195MlDju85ItUQgfk= =U9ik -----END PGP SIGNATURE----- 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:
commit
ca7ce08d6a
@ -95,3 +95,25 @@ Description:
|
||||
This file does not exist if the HBA driver does not implement
|
||||
support for the SATA NCQ priority feature, regardless of the
|
||||
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
|
||||
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/devices/*.ufs/device_descriptor/hpb_version
|
||||
Date: June 2021
|
||||
|
@ -26,6 +26,7 @@ properties:
|
||||
- qcom,msm8994-ufshc
|
||||
- qcom,msm8996-ufshc
|
||||
- qcom,msm8998-ufshc
|
||||
- qcom,sa8775p-ufshc
|
||||
- qcom,sc8280xp-ufshc
|
||||
- qcom,sdm845-ufshc
|
||||
- qcom,sm6350-ufshc
|
||||
@ -70,6 +71,10 @@ properties:
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
qcom,ice:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: phandle to the Inline Crypto Engine node
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
@ -105,6 +110,7 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,msm8998-ufshc
|
||||
- qcom,sa8775p-ufshc
|
||||
- qcom,sc8280xp-ufshc
|
||||
- qcom,sm8250-ufshc
|
||||
- qcom,sm8350-ufshc
|
||||
@ -187,6 +193,26 @@ allOf:
|
||||
|
||||
# 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
|
||||
|
||||
examples:
|
||||
|
@ -54,7 +54,7 @@ properties:
|
||||
const: ufs-phy
|
||||
|
||||
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
|
||||
which indicates the FSYSx sysreg interface and the offset of
|
||||
the control register for UFS io coherency setting.
|
||||
|
@ -1,3 +1,4 @@
|
||||
===================
|
||||
ARECA FIRMWARE SPEC
|
||||
===================
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
======================================
|
||||
README file for the dc395x SCSI driver
|
||||
======================================
|
||||
==================
|
||||
dc395x SCSI driver
|
||||
==================
|
||||
|
||||
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
|
||||
to use this driver with hard disks.
|
||||
|
||||
This is a 2.5 only driver. For a 2.4 driver please see the original
|
||||
driver (which this driver started from) at
|
||||
http://www.garloff.de/kurt/linux/dc395/
|
||||
|
||||
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/
|
||||
This driver is evolved from `the original 2.4 driver
|
||||
<https://web.archive.org/web/20140129181343/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>`_.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -1,9 +1,9 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
.. include:: <isonum.txt>
|
||||
|
||||
==========================================
|
||||
README file for the Linux g_NCR5380 driver
|
||||
==========================================
|
||||
================
|
||||
g_NCR5380 driver
|
||||
================
|
||||
|
||||
Copyright |copy| 1993 Drew Eckhard
|
||||
|
||||
|
@ -4,6 +4,38 @@
|
||||
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::
|
||||
:maxdepth: 1
|
||||
|
||||
@ -25,7 +57,6 @@ SCSI Subsystem
|
||||
hpsa
|
||||
hptiop
|
||||
libsas
|
||||
link_power_management_policy
|
||||
lpfc
|
||||
megaraid
|
||||
ncr53c8xx
|
||||
@ -33,12 +64,8 @@ SCSI Subsystem
|
||||
ppa
|
||||
qlogicfas
|
||||
scsi-changer
|
||||
scsi_eh
|
||||
scsi_fc_transport
|
||||
scsi-generic
|
||||
scsi_mid_low_api
|
||||
scsi-parameters
|
||||
scsi
|
||||
sd-parameters
|
||||
smartpqi
|
||||
st
|
||||
|
@ -1,8 +1,8 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
==========================
|
||||
Notes on Management Module
|
||||
==========================
|
||||
=================================
|
||||
Megaraid Common Management Module
|
||||
=================================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
@ -1,8 +1,8 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=================================================
|
||||
The Linux NCR53C8XX/SYM53C8XX drivers README file
|
||||
=================================================
|
||||
===========================
|
||||
NCR53C8XX/SYM53C8XX drivers
|
||||
===========================
|
||||
|
||||
Written by Gerard Roudier <groudier@free.fr>
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
.. 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
|
||||
with "Type: Medium Changer" in /proc/scsi/scsi.
|
||||
|
@ -1,15 +1,15 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=======================================
|
||||
Notes on Linux SCSI Generic (sg) driver
|
||||
=======================================
|
||||
========================
|
||||
SCSI Generic (sg) driver
|
||||
========================
|
||||
|
||||
20020126
|
||||
|
||||
Introduction
|
||||
============
|
||||
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
|
||||
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
|
||||
@ -22,7 +22,7 @@ and examples.
|
||||
|
||||
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) .
|
||||
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
|
||||
@ -33,34 +33,24 @@ There are three major versions of sg found in the linux kernel (lk):
|
||||
|
||||
Sg driver documentation
|
||||
=======================
|
||||
The most recent documentation of the sg driver is kept at the Linux
|
||||
Documentation Project's (LDP) site:
|
||||
The most recent documentation of the sg driver is kept at
|
||||
|
||||
- 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.
|
||||
|
||||
The LDP renders documents in single and multiple page HTML, postscript
|
||||
and pdf. This document can also be found at:
|
||||
Documentation (large version) for the version 2 sg driver found in the
|
||||
lk 2.2 series can be found at
|
||||
|
||||
- http://sg.danny.cz/sg/p/sg_v3_ho.html
|
||||
|
||||
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.
|
||||
- https://sg.danny.cz/sg/p/scsi-generic_long.txt.
|
||||
|
||||
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
|
||||
and in the LDP archives.
|
||||
found in the LDP archives at
|
||||
|
||||
A changelog with brief notes can be found in the
|
||||
/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.
|
||||
- https://tldp.org/HOWTO/archived/SCSI-Programming-HOWTO/index.html
|
||||
|
||||
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
|
||||
@ -73,8 +63,8 @@ There are two packages of sg utilities:
|
||||
and earlier
|
||||
========= ==========================================================
|
||||
|
||||
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
|
||||
Both packages will work in the lk 2.4 series. However, sg3_utils offers more
|
||||
capabilities. They can be found at: https://sg.danny.cz/sg/sg3_utils.html and
|
||||
freecode.com
|
||||
|
||||
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
|
||||
======================================================
|
||||
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:
|
||||
|
||||
- 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
|
||||
|
||||
.. [#] 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
|
||||
new version of the sg driver:
|
||||
For reference here is a list of Linux kernels in the 2.2 series that had
|
||||
the new version of the sg driver:
|
||||
|
||||
- lk 2.2.0 : original sg version [with no version number]
|
||||
- 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.20 : sg version 2.1.40
|
||||
|
||||
The lk 2.5 development series has recently commenced and it currently
|
||||
contains sg version 3.5.23 which is functionally equivalent to sg
|
||||
version 3.1.22 found in lk 2.4.17.
|
||||
The lk 2.5 development series currently contains sg version 3.5.23
|
||||
which is functionally equivalent to sg version 3.1.22 found in lk 2.4.17.
|
||||
|
||||
|
||||
Douglas Gilbert
|
||||
|
@ -6,30 +6,28 @@ SCSI subsystem documentation
|
||||
|
||||
The Linux Documentation Project (LDP) maintains a document describing
|
||||
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.
|
||||
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
|
||||
============================================
|
||||
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
|
||||
your options, we should first define a few terms.
|
||||
|
||||
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.
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
the SCSI subsystem.
|
||||
|
||||
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
|
||||
as a module). The disk driver (sd_mod.o), cdrom driver (sr_mod.o),
|
||||
tape driver [1]_ (st.o) and scsi generics driver (sg.o) represent the upper
|
||||
once the SCSI core is present in the kernel (either compiled in or loaded
|
||||
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
|
||||
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,
|
||||
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
|
||||
devices. Its module name is osst.o .
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
================
|
||||
SCSI FC Tansport
|
||||
================
|
||||
=================
|
||||
SCSI FC Transport
|
||||
=================
|
||||
|
||||
Date: 11/18/2008
|
||||
|
||||
@ -556,5 +556,5 @@ The following people have contributed to this document:
|
||||
|
||||
|
||||
James Smart
|
||||
james.smart@emulex.com
|
||||
james.smart@broadcom.com
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================================
|
||||
The Linux SYM-2 driver documentation file
|
||||
=========================================
|
||||
============
|
||||
SYM-2 driver
|
||||
============
|
||||
|
||||
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: Ali Akcaagac <aliakc@web.de>
|
||||
M: Jamie Lenehan <lenehan@twibble.org>
|
||||
L: dc395x@twibble.org
|
||||
S: Maintained
|
||||
W: http://twibble.org/dist/dc395x/
|
||||
W: http://lists.twibble.org/mailman/listinfo/dc395x/
|
||||
F: Documentation/scsi/dc395x.rst
|
||||
F: drivers/scsi/dc395x.*
|
||||
|
||||
@ -18918,6 +18915,16 @@ F: include/linux/wait.h
|
||||
F: include/uapi/linux/sched.h
|
||||
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
|
||||
M: Bart Van Assche <bvanassche@acm.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);
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
case IOPRIO_CLASS_IDLE:
|
||||
bfqq->new_ioprio_class = IOPRIO_CLASS_IDLE;
|
||||
bfqq->new_ioprio = 7;
|
||||
bfqq->new_ioprio = IOPRIO_NR_LEVELS - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5834,7 +5834,7 @@ static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd,
|
||||
struct bfq_io_cq *bic,
|
||||
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);
|
||||
struct bfq_queue **async_bfqq = NULL;
|
||||
struct bfq_queue *bfqq;
|
||||
|
@ -155,7 +155,7 @@ static const struct {
|
||||
[BLK_STS_NOSPC] = { -ENOSPC, "critical space allocation" },
|
||||
[BLK_STS_TRANSPORT] = { -ENOLINK, "recoverable transport" },
|
||||
[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_PROTECTION] = { -EILSEQ, "protection" },
|
||||
[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_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: */
|
||||
[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_MAX_DEVS 32768
|
||||
#define BSG_MAX_DEVS (1 << MINORBITS)
|
||||
|
||||
static DEFINE_IDA(bsg_minor_ida);
|
||||
static const struct class bsg_class;
|
||||
|
@ -33,7 +33,7 @@
|
||||
int ioprio_check_cap(int ioprio)
|
||||
{
|
||||
int class = IOPRIO_PRIO_CLASS(ioprio);
|
||||
int data = IOPRIO_PRIO_DATA(ioprio);
|
||||
int level = IOPRIO_PRIO_LEVEL(ioprio);
|
||||
|
||||
switch (class) {
|
||||
case IOPRIO_CLASS_RT:
|
||||
@ -49,15 +49,16 @@ int ioprio_check_cap(int ioprio)
|
||||
fallthrough;
|
||||
/* rt has prio field too */
|
||||
case IOPRIO_CLASS_BE:
|
||||
if (data >= IOPRIO_NR_LEVELS || data < 0)
|
||||
if (level >= IOPRIO_NR_LEVELS)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case IOPRIO_CLASS_IDLE:
|
||||
break;
|
||||
case IOPRIO_CLASS_NONE:
|
||||
if (data)
|
||||
if (level)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case IOPRIO_CLASS_INVALID:
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -665,12 +665,33 @@ u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
|
||||
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
|
||||
* @qc: Metadata associated with the taskfile to build
|
||||
* @block: Block address
|
||||
* @n_block: Number of blocks
|
||||
* @tf_flags: RW/FUA etc...
|
||||
* @cdl: Command duration limit index
|
||||
* @class: IO priority class
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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_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 &&
|
||||
class == IOPRIO_CLASS_RT)
|
||||
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) {
|
||||
tf->flags |= ATA_TFLAG_LBA;
|
||||
|
||||
/* We need LBA48 for FUA writes */
|
||||
if (!(tf->flags & ATA_TFLAG_FUA) && lba_28_ok(block, n_block)) {
|
||||
if ((dev->flags & ATA_DFLAG_CDL_ENABLED) && cdl)
|
||||
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 */
|
||||
tf->device |= (block >> 24) & 0xf;
|
||||
} 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const u16 *id = dev->id;
|
||||
@ -2534,13 +2697,14 @@ static void ata_dev_print_features(struct ata_device *dev)
|
||||
return;
|
||||
|
||||
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_TRUSTED ? " Trust" : "",
|
||||
dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "",
|
||||
dev->flags & ATA_DFLAG_DEVSLP ? " Dev-Sleep" : "",
|
||||
dev->flags & ATA_DFLAG_NCQ_SEND_RECV ? " NCQ-sndrcv" : "",
|
||||
dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : "",
|
||||
dev->flags & ATA_DFLAG_CDL ? " CDL" : "",
|
||||
dev->cpr_log ? " CPR" : "");
|
||||
}
|
||||
|
||||
@ -2702,6 +2866,7 @@ int ata_dev_configure(struct ata_device *dev)
|
||||
ata_dev_config_zac(dev);
|
||||
ata_dev_config_trusted(dev);
|
||||
ata_dev_config_cpr(dev);
|
||||
ata_dev_config_cdl(dev);
|
||||
dev->cdb_len = 32;
|
||||
|
||||
if (print_info)
|
||||
@ -4762,6 +4927,36 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
|
||||
fill_result_tf(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
|
||||
* completion.
|
||||
*/
|
||||
@ -5394,6 +5589,7 @@ static void ata_host_release(struct kref *kref)
|
||||
|
||||
kfree(ap->pmp_link);
|
||||
kfree(ap->slave_link);
|
||||
kfree(ap->ncq_sense_buf);
|
||||
kfree(ap);
|
||||
host->ports[i] = NULL;
|
||||
}
|
||||
|
@ -1401,8 +1401,11 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
|
||||
*
|
||||
* LOCKING:
|
||||
* 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 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)) {
|
||||
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)) {
|
||||
ata_dev_warn(qc->dev, "sense data reporting disabled\n");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
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 */
|
||||
if (tf.status & ATA_SENSE) {
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
|
||||
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
|
||||
* (i.e. NCQ autosense is not supported by the device).
|
||||
*/
|
||||
if (!(qc->flags & ATA_QCFLAG_SENSE_VALID) && (stat & ATA_SENSE))
|
||||
ata_eh_request_sense(qc);
|
||||
if (!(qc->flags & ATA_QCFLAG_SENSE_VALID) &&
|
||||
(stat & ATA_SENSE) && ata_eh_request_sense(qc))
|
||||
set_status_byte(qc->scsicmd, SAM_STAT_CHECK_CONDITION);
|
||||
if (err & ATA_ICRC)
|
||||
qc->err_mask |= AC_ERR_ATA_BUS;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
* @link: host link to perform autopsy on
|
||||
@ -1948,6 +2048,14 @@ static void ata_eh_link_autopsy(struct ata_link *link)
|
||||
/* analyze NCQ failure */
|
||||
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 */
|
||||
if (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) {
|
||||
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
||||
qc->flags & ATA_QCFLAG_RETRY ||
|
||||
qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD ||
|
||||
ata_dev_phys_link(qc->dev) != link)
|
||||
continue;
|
||||
|
||||
@ -3823,7 +3932,8 @@ void ata_eh_finish(struct ata_port *ap)
|
||||
ata_eh_qc_complete(qc);
|
||||
}
|
||||
} 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);
|
||||
} else {
|
||||
/* feed zero TF to sense generation */
|
||||
|
@ -11,7 +11,9 @@
|
||||
#include <linux/module.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_eh.h>
|
||||
#include <linux/libata.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "libata.h"
|
||||
#include "libata-transport.h"
|
||||
@ -907,10 +909,17 @@ static ssize_t ata_ncq_prio_enable_store(struct device *device,
|
||||
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;
|
||||
else
|
||||
} else {
|
||||
dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLED;
|
||||
}
|
||||
|
||||
unlock:
|
||||
spin_unlock_irq(ap->lock);
|
||||
@ -1413,6 +1422,95 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
|
||||
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
|
||||
* @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) {
|
||||
if (!(qc->flags & ATA_QCFLAG_EH) ||
|
||||
qc->flags & ATA_QCFLAG_EH_SUCCESS_CMD ||
|
||||
ata_dev_phys_link(qc->dev) != link)
|
||||
continue;
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "libata.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 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,
|
||||
const struct scsi_device *scsidev);
|
||||
|
||||
#define RW_RECOVERY_MPAGE 0x1
|
||||
#define RW_RECOVERY_MPAGE_LEN 12
|
||||
#define CACHE_MPAGE 0x8
|
||||
#define CACHE_MPAGE_LEN 20
|
||||
#define CONTROL_MPAGE 0xa
|
||||
#define CONTROL_MPAGE_LEN 12
|
||||
#define ALL_MPAGES 0x3f
|
||||
#define ALL_SUB_MPAGES 0xff
|
||||
|
||||
#define RW_RECOVERY_MPAGE 0x1
|
||||
#define RW_RECOVERY_MPAGE_LEN 12
|
||||
#define CACHE_MPAGE 0x8
|
||||
#define CACHE_MPAGE_LEN 20
|
||||
#define CONTROL_MPAGE 0xa
|
||||
#define CONTROL_MPAGE_LEN 12
|
||||
#define ALL_MPAGES 0x3f
|
||||
#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] = {
|
||||
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);
|
||||
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
information = ata_tf_read_block(tf, dev);
|
||||
if (information == U64_MAX)
|
||||
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]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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);
|
||||
int class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq));
|
||||
unsigned int tf_flags = 0;
|
||||
int dld = 0;
|
||||
u64 block;
|
||||
u32 n_block;
|
||||
int rc;
|
||||
@ -1600,6 +1611,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
|
||||
goto invalid_fld;
|
||||
}
|
||||
scsi_16_lba_len(cdb, &block, &n_block);
|
||||
dld = scsi_dld(cdb);
|
||||
if (cdb[1] & (1 << 3))
|
||||
tf_flags |= ATA_TFLAG_FUA;
|
||||
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->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))
|
||||
return 0;
|
||||
|
||||
@ -2203,10 +2215,123 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
|
||||
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
|
||||
* @dev: ATA device of interest
|
||||
* @buf: output buffer
|
||||
* @spg: sub-page code
|
||||
* @changeable: whether changeable parameters are requested
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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);
|
||||
if (changeable) {
|
||||
buf[2] |= (1 << 2); /* ata_mselect_control() */
|
||||
} else {
|
||||
bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
|
||||
unsigned int n;
|
||||
|
||||
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;
|
||||
spg = scsicmd[3];
|
||||
|
||||
/*
|
||||
* No mode subpages supported (yet) but asking for _all_
|
||||
* subpages may be valid
|
||||
* Supported subpages: all subpages and sub-pages 07h, 08h and f2h of
|
||||
* the control page.
|
||||
*/
|
||||
if (spg && (spg != ALL_SUB_MPAGES)) {
|
||||
fp = 3;
|
||||
goto invalid_fld;
|
||||
if (spg) {
|
||||
switch (spg) {
|
||||
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) {
|
||||
@ -2317,13 +2464,13 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case ALL_MPAGES:
|
||||
p += ata_msense_rw_recovery(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;
|
||||
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
unsigned int output_len = p - rbuf - 2;
|
||||
|
||||
rbuf[0] = output_len >> 8;
|
||||
rbuf[1] = output_len;
|
||||
put_unaligned_be16(p - rbuf - 2, &rbuf[0]);
|
||||
rbuf[3] |= dpofua;
|
||||
if (ebd) {
|
||||
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;
|
||||
u8 *cdb = args->cmd->cmnd;
|
||||
u8 supported = 0;
|
||||
u8 supported = 0, cdlp = 0, rwcdlp = 0;
|
||||
unsigned int err = 0;
|
||||
|
||||
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 READ_6:
|
||||
case READ_10:
|
||||
case READ_16:
|
||||
case WRITE_6:
|
||||
case WRITE_10:
|
||||
case WRITE_16:
|
||||
case ATA_12:
|
||||
case ATA_16:
|
||||
case VERIFY:
|
||||
@ -3300,6 +3442,28 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
|
||||
case START_STOP:
|
||||
supported = 3;
|
||||
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_OUT:
|
||||
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;
|
||||
}
|
||||
out:
|
||||
rbuf[1] = supported; /* supported */
|
||||
/* One command format */
|
||||
rbuf[0] = rwcdlp;
|
||||
rbuf[1] = cdlp | supported;
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3605,20 +3771,11 @@ static int ata_mselect_caching(struct ata_queued_cmd *qc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_mselect_control - Simulate MODE SELECT for control page
|
||||
* @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.
|
||||
/*
|
||||
* Simulate MODE SELECT control mode page, sub-page 0.
|
||||
*/
|
||||
static int ata_mselect_control(struct ata_queued_cmd *qc,
|
||||
const u8 *buf, int len, u16 *fp)
|
||||
static int ata_mselect_control_spg0(struct ata_queued_cmd *qc,
|
||||
const u8 *buf, int len, u16 *fp)
|
||||
{
|
||||
struct ata_device *dev = qc->dev;
|
||||
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.
|
||||
*/
|
||||
ata_msense_control(dev, mpage, false);
|
||||
ata_msense_control_spg0(dev, mpage, false);
|
||||
for (i = 0; i < CONTROL_MPAGE_LEN - 2; i++) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
@ -3656,6 +3813,84 @@ static int ata_mselect_control(struct ata_queued_cmd *qc,
|
||||
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
|
||||
* @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;
|
||||
u8 pg, spg;
|
||||
unsigned six_byte, pg_len, hdr_len, bd_len;
|
||||
int len;
|
||||
int len, ret;
|
||||
u16 fp = (u16)-1;
|
||||
u8 bp = 0xff;
|
||||
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_
|
||||
* subpages may be valid
|
||||
* Supported subpages: all subpages and ATA feature sub-page f2h of
|
||||
* the control page.
|
||||
*/
|
||||
if (spg && (spg != ALL_SUB_MPAGES)) {
|
||||
fp = (p[0] & 0x40) ? 1 : 0;
|
||||
fp += hdr_len + bd_len;
|
||||
goto invalid_param;
|
||||
if (spg) {
|
||||
switch (spg) {
|
||||
case ALL_SUB_MPAGES:
|
||||
/* 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)
|
||||
goto invalid_param_len;
|
||||
@ -3777,14 +4028,16 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
|
||||
}
|
||||
break;
|
||||
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;
|
||||
goto invalid_param;
|
||||
} else {
|
||||
goto skip; /* No ATA command to send */
|
||||
}
|
||||
if (!ret)
|
||||
goto skip; /* No ATA command to send */
|
||||
break;
|
||||
default: /* invalid page code */
|
||||
default:
|
||||
/* Invalid page code */
|
||||
fp = bd_len + hdr_len;
|
||||
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_lba48(const struct ata_taskfile *tf);
|
||||
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,
|
||||
struct ata_device *dev);
|
||||
extern unsigned ata_exec_internal(struct ata_device *dev,
|
||||
|
@ -3143,6 +3143,8 @@ struct dm_pr {
|
||||
bool fail_early;
|
||||
int ret;
|
||||
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,
|
||||
@ -3375,12 +3377,79 @@ out:
|
||||
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 = {
|
||||
.pr_register = dm_pr_register,
|
||||
.pr_reserve = dm_pr_reserve,
|
||||
.pr_release = dm_pr_release,
|
||||
.pr_preempt = dm_pr_preempt,
|
||||
.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 = {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
menuconfig FUSION
|
||||
bool "Fusion MPT device support"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
help
|
||||
Say Y here to get to see options for Fusion Message
|
||||
Passing Technology (MPT) drivers.
|
||||
|
@ -712,7 +712,7 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
|
||||
MptDriverClass[cb_idx] = dclass;
|
||||
MptEvHandlers[cb_idx] = NULL;
|
||||
last_drv_idx = cb_idx;
|
||||
strlcpy(MptCallbacksName[cb_idx], func_name,
|
||||
strscpy(MptCallbacksName[cb_idx], func_name,
|
||||
MPT_MAX_CALLBACKNAME_LEN+1);
|
||||
break;
|
||||
}
|
||||
@ -7666,7 +7666,7 @@ mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
|
||||
break;
|
||||
}
|
||||
if (ds)
|
||||
strlcpy(evStr, ds, EVENT_DESCR_STR_SZ);
|
||||
strscpy(evStr, ds, EVENT_DESCR_STR_SZ);
|
||||
|
||||
|
||||
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) {
|
||||
ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
|
||||
if (strlen(pdata->BoardTracerNumber) > 1) {
|
||||
strlcpy(karg.serial_number,
|
||||
strscpy(karg.serial_number,
|
||||
pdata->BoardTracerNumber, 24);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ obj-$(CONFIG_NVME_FC) += nvme-fc.o
|
||||
obj-$(CONFIG_NVME_TCP) += nvme-tcp.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_TRACING) += trace.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:
|
||||
return BLK_STS_PROTECTION;
|
||||
case NVME_SC_RESERVATION_CONFLICT:
|
||||
return BLK_STS_NEXUS;
|
||||
return BLK_STS_RESV_CONFLICT;
|
||||
case NVME_SC_HOST_PATH_ERROR:
|
||||
return BLK_STS_TRANSPORT;
|
||||
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
|
||||
static int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
|
||||
bool send)
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
#include <trace/events/block.h>
|
||||
|
||||
extern const struct pr_ops nvme_pr_ops;
|
||||
|
||||
extern unsigned int nvme_io_timeout;
|
||||
#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) {
|
||||
switch (cqr->intrc) {
|
||||
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;
|
||||
case -ENOLINK:
|
||||
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);
|
||||
|
||||
/* Initialize the card */
|
||||
if (tw_reset_sequence(tw_dev))
|
||||
if (tw_reset_sequence(tw_dev)) {
|
||||
retval = -EINVAL;
|
||||
goto out_release_mem_region;
|
||||
}
|
||||
|
||||
/* Set host specific parameters */
|
||||
host->max_id = TW_MAX_UNITS;
|
||||
|
@ -334,7 +334,7 @@ config SGIWD93_SCSI
|
||||
|
||||
config BLK_DEV_3W_XXXX_RAID
|
||||
tristate "3ware 5/6/7/8xxx ATA-RAID support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
help
|
||||
3ware is the only hardware ATA-Raid product in Linux to date.
|
||||
This card is 2,4, or 8 channel master mode support only.
|
||||
@ -381,7 +381,7 @@ config SCSI_3W_SAS
|
||||
|
||||
config SCSI_ACARD
|
||||
tristate "ACARD SCSI support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
help
|
||||
This driver supports the ACARD SCSI host adapter.
|
||||
Support Chip <ATP870 ATP876 ATP880 ATP885>
|
||||
@ -462,7 +462,7 @@ config SCSI_MVUMI
|
||||
config SCSI_ADVANSYS
|
||||
tristate "AdvanSys SCSI support"
|
||||
depends on SCSI
|
||||
depends on ISA || EISA || PCI
|
||||
depends on (ISA || EISA || PCI) && HAS_IOPORT
|
||||
depends on ISA_DMA_API || !ISA
|
||||
help
|
||||
This is a driver for all SCSI host adapters manufactured by
|
||||
@ -503,7 +503,7 @@ config SCSI_HPTIOP
|
||||
|
||||
config SCSI_BUSLOGIC
|
||||
tristate "BusLogic SCSI support"
|
||||
depends on PCI && SCSI
|
||||
depends on SCSI && PCI && HAS_IOPORT
|
||||
help
|
||||
This is support for BusLogic MultiMaster and FlashPoint SCSI Host
|
||||
Adapters. Consult the SCSI-HOWTO, available from
|
||||
@ -518,7 +518,7 @@ config SCSI_BUSLOGIC
|
||||
|
||||
config SCSI_FLASHPOINT
|
||||
bool "FlashPoint support"
|
||||
depends on SCSI_BUSLOGIC && PCI
|
||||
depends on SCSI_BUSLOGIC && PCI && HAS_IOPORT
|
||||
help
|
||||
This option allows you to add FlashPoint support to the
|
||||
BusLogic SCSI driver. The FlashPoint SCCB Manager code is
|
||||
@ -632,7 +632,7 @@ config SCSI_SNIC_DEBUG_FS
|
||||
|
||||
config SCSI_DMX3191D
|
||||
tristate "DMX3191D SCSI support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
select SCSI_SPI_ATTRS
|
||||
help
|
||||
This is support for Domex DMX3191D SCSI Host Adapters.
|
||||
@ -646,7 +646,7 @@ config SCSI_FDOMAIN
|
||||
|
||||
config SCSI_FDOMAIN_PCI
|
||||
tristate "Future Domain TMC-3260/AHA-2920A PCI SCSI support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
select SCSI_FDOMAIN
|
||||
help
|
||||
This is support for Future Domain's PCI SCSI host adapters (TMC-3260)
|
||||
@ -699,7 +699,7 @@ config SCSI_GENERIC_NCR5380
|
||||
|
||||
config SCSI_IPS
|
||||
tristate "IBM ServeRAID support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
help
|
||||
This is support for the IBM ServeRAID hardware RAID controllers.
|
||||
See <http://www.developer.ibm.com/welcome/netfinity/serveraid.html>
|
||||
@ -759,7 +759,7 @@ config SCSI_IBMVFC_TRACE
|
||||
|
||||
config SCSI_INITIO
|
||||
tristate "Initio 9100U(W) support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
help
|
||||
This is support for the Initio 91XXU(W) SCSI host adapter. Please
|
||||
read the SCSI-HOWTO, available from
|
||||
@ -770,7 +770,7 @@ config SCSI_INITIO
|
||||
|
||||
config SCSI_INIA100
|
||||
tristate "Initio INI-A100U2W support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
help
|
||||
This is support for the Initio INI-A100U2W SCSI host adapter.
|
||||
Please read the SCSI-HOWTO, available from
|
||||
@ -782,6 +782,7 @@ config SCSI_INIA100
|
||||
config SCSI_PPA
|
||||
tristate "IOMEGA parallel port (ppa - older drives)"
|
||||
depends on SCSI && PARPORT_PC
|
||||
depends on HAS_IOPORT
|
||||
help
|
||||
This driver supports older versions of IOMEGA's parallel port ZIP
|
||||
drive (a 100 MB removable media device).
|
||||
@ -1175,7 +1176,7 @@ config SCSI_SIM710
|
||||
|
||||
config SCSI_DC395x
|
||||
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
|
||||
help
|
||||
This driver supports PCI SCSI host adapters based on the ASIC
|
||||
@ -1207,7 +1208,7 @@ config SCSI_AM53C974
|
||||
|
||||
config SCSI_NSP32
|
||||
tristate "Workbit NinjaSCSI-32Bi/UDE support"
|
||||
depends on PCI && SCSI && !64BIT
|
||||
depends on PCI && SCSI && !64BIT && HAS_IOPORT
|
||||
help
|
||||
This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
|
||||
SCSI host adapter. Please read the SCSI-HOWTO, available from
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
config SCSI_AIC79XX
|
||||
tristate "Adaptec AIC79xx U320 support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
select SCSI_SPI_ATTRS
|
||||
help
|
||||
This driver supports all of Adaptec's Ultra 320 PCI-X
|
||||
|
@ -5,7 +5,7 @@
|
||||
#
|
||||
config SCSI_AIC7XXX
|
||||
tristate "Adaptec AIC7xxx Fast -> U160 support"
|
||||
depends on (PCI || EISA) && SCSI
|
||||
depends on (PCI || EISA) && HAS_IOPORT && SCSI
|
||||
select SCSI_SPI_ATTRS
|
||||
help
|
||||
This driver supports all of Adaptec's Fast through Ultra 160 PCI
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
config SCSI_AIC94XX
|
||||
tristate "Adaptec AIC94xx SAS/SATA support"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
select SCSI_SAS_LIBSAS
|
||||
select FW_LOADER
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
/* Model name/number */
|
||||
strlcpy(port_cfg->sym_name.symname, model,
|
||||
strscpy(port_cfg->sym_name.symname, model,
|
||||
BFA_SYMNAME_MAXLEN);
|
||||
strlcat(port_cfg->sym_name.symname, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
|
||||
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);
|
||||
|
||||
/* Model name/number */
|
||||
strlcpy(port_cfg->node_sym_name.symname, model,
|
||||
strscpy(port_cfg->node_sym_name.symname, model,
|
||||
BFA_SYMNAME_MAXLEN);
|
||||
strlcat(port_cfg->node_sym_name.symname,
|
||||
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,
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
/*
|
||||
@ -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);
|
||||
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);
|
||||
strcpy(hba_attr->vendor_info, "QLogic");
|
||||
hba_attr->num_ports =
|
||||
cpu_to_be32(bfa_ioc_get_nports(&port->fcs->bfa->ioc));
|
||||
hba_attr->fabric_name = port->fabric->lps->pr_nwwn;
|
||||
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
|
||||
*/
|
||||
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));
|
||||
|
||||
/*
|
||||
* 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));
|
||||
|
||||
port_attr->node_name = bfa_fcs_lport_get_nwwn(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_attr(port, &lport_attr);
|
||||
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;
|
||||
|
||||
/* 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,
|
||||
BFA_FCS_FABRIC_IPADDR_SZ);
|
||||
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.
|
||||
*/
|
||||
|
||||
strlcpy(symbl,
|
||||
strscpy(symbl,
|
||||
(char *)&(bfa_fcs_lport_get_psym_name
|
||||
(bfa_fcs_get_base_port(port->fcs))),
|
||||
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
|
||||
* 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))),
|
||||
sizeof(symbl));
|
||||
|
||||
|
@ -2788,7 +2788,7 @@ void
|
||||
bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)
|
||||
{
|
||||
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
|
||||
|
@ -330,7 +330,7 @@ bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
|
||||
lp.eid = event;
|
||||
lp.log_type = BFA_PL_LOG_TYPE_STRING;
|
||||
lp.misc = misc;
|
||||
strlcpy(lp.log_entry.string_log, log_str,
|
||||
strscpy(lp.log_entry.string_log, log_str,
|
||||
BFA_PL_STRING_LOG_SZ);
|
||||
lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0';
|
||||
bfa_plog_add(plog, &lp);
|
||||
|
@ -965,19 +965,19 @@ bfad_start_ops(struct bfad_s *bfad) {
|
||||
|
||||
/* Fill the driver_info info to fcs*/
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
|
||||
strlcpy(driver_info.os_device_name, bfad->pci_name,
|
||||
strscpy(driver_info.os_device_name, bfad->pci_name,
|
||||
sizeof(driver_info.os_device_name));
|
||||
|
||||
/* 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];
|
||||
|
||||
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);
|
||||
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 */
|
||||
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);
|
||||
strcpy(iocmd->ioc_attr.driver_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.loopback = port_attr.loopback;
|
||||
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,
|
||||
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 */
|
||||
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);
|
||||
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];
|
||||
|
||||
if (buffer) {
|
||||
strlcpy(ifname, buffer, IFNAMSIZ);
|
||||
strscpy(ifname, buffer, IFNAMSIZ);
|
||||
cp = ifname + strlen(ifname);
|
||||
while (--cp >= ifname && *cp == '\n')
|
||||
*cp = '\0';
|
||||
|
@ -201,25 +201,21 @@ static int fnic_trace_debugfs_open(struct inode *inode,
|
||||
return -ENOMEM;
|
||||
|
||||
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));
|
||||
if (!fnic_dbg_prt->buffer) {
|
||||
kfree(fnic_dbg_prt);
|
||||
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);
|
||||
} else {
|
||||
fnic_dbg_prt->buffer =
|
||||
vmalloc(array3_size(3, fnic_fc_trace_max_pages,
|
||||
vzalloc(array3_size(3, fnic_fc_trace_max_pages,
|
||||
PAGE_SIZE));
|
||||
if (!fnic_dbg_prt->buffer) {
|
||||
kfree(fnic_dbg_prt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset((void *)fnic_dbg_prt->buffer, 0,
|
||||
3 * (fnic_fc_trace_max_pages * PAGE_SIZE));
|
||||
fnic_dbg_prt->buffer_len =
|
||||
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_probe(struct platform_device *pdev,
|
||||
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_alloc(struct scsi_device *sdev);
|
||||
|
@ -2560,7 +2560,7 @@ err_out_ha:
|
||||
}
|
||||
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 hisi_hba *hisi_hba = sha->lldd_ha;
|
||||
@ -2573,7 +2573,6 @@ int hisi_sas_remove(struct platform_device *pdev)
|
||||
|
||||
hisi_sas_free(hisi_hba);
|
||||
scsi_host_put(shost);
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
static int hisi_sas_v1_remove(struct platform_device *pdev)
|
||||
{
|
||||
return hisi_sas_remove(pdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id sas_v1_of_match[] = {
|
||||
{ .compatible = "hisilicon,hip05-sas-v1",},
|
||||
{},
|
||||
@ -1810,7 +1805,7 @@ MODULE_DEVICE_TABLE(acpi, sas_v1_acpi_match);
|
||||
|
||||
static struct platform_driver hisi_sas_v1_driver = {
|
||||
.probe = hisi_sas_v1_probe,
|
||||
.remove = hisi_sas_v1_remove,
|
||||
.remove_new = hisi_sas_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.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);
|
||||
}
|
||||
|
||||
static int hisi_sas_v2_remove(struct platform_device *pdev)
|
||||
{
|
||||
return hisi_sas_remove(pdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id sas_v2_of_match[] = {
|
||||
{ .compatible = "hisilicon,hip06-sas-v2",},
|
||||
{ .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 = {
|
||||
.probe = hisi_sas_v2_probe,
|
||||
.remove = hisi_sas_v2_remove,
|
||||
.remove_new = hisi_sas_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.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_HI 0x64
|
||||
#define CFG_MAX_TAG 0x68
|
||||
#define TRANS_LOCK_ICT_TIME 0X70
|
||||
#define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL 0x84
|
||||
#define HGC_SAS_TXFAIL_RETRY_CTRL 0x88
|
||||
#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)
|
||||
{
|
||||
struct pci_dev *pdev = hisi_hba->pci_dev;
|
||||
int i, j;
|
||||
|
||||
/* Global registers init */
|
||||
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
|
||||
(u32)((1ULL << hisi_hba->queue_count) - 1));
|
||||
hisi_sas_write32(hisi_hba, SAS_AXI_USER3, 0);
|
||||
hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400);
|
||||
/* 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, CFG_AGING_TIME, 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, 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);
|
||||
for (i = 0; i < hisi_hba->n_phy; i++) {
|
||||
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);
|
||||
hisi_sas_phy_write32(hisi_hba, i, 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, CHL_INT0, 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, STP_LINK_TIMER, 0x7f7a120);
|
||||
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,
|
||||
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);
|
||||
|
||||
/* 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 */
|
||||
for (j = 0; j < FFE_CFG_MAX; j++) {
|
||||
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);
|
||||
u16 sipc_rx_err_type = le16_to_cpu(record->sipc_rx_err_type);
|
||||
u32 dw3 = le32_to_cpu(complete_hdr->dw3);
|
||||
u32 dw0 = le32_to_cpu(complete_hdr->dw0);
|
||||
|
||||
switch (task->task_proto) {
|
||||
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
|
||||
* response IU.
|
||||
*/
|
||||
if (!(complete_hdr->dw0 & CMPLT_HDR_RSPNS_GOOD_MSK) &&
|
||||
(complete_hdr->dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))
|
||||
if (!(dw0 & CMPLT_HDR_RSPNS_GOOD_MSK) &&
|
||||
(dw0 & CMPLT_HDR_RSPNS_XFRD_MSK))
|
||||
return false;
|
||||
|
||||
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_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)) {
|
||||
ts->stat = SAS_PROTO_RESPONSE;
|
||||
} 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_HI),
|
||||
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_TXFAIL_RETRY_CTRL),
|
||||
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->no_write_same = sht->no_write_same;
|
||||
shost->host_tagset = sht->host_tagset;
|
||||
shost->queuecommand_may_block = sht->queuecommand_may_block;
|
||||
|
||||
if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler)
|
||||
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));
|
||||
}
|
||||
|
||||
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,
|
||||
struct ex_phy *parent_phy,
|
||||
struct ex_phy *child_phy)
|
||||
struct ex_phy *parent_phy,
|
||||
struct ex_phy *child_phy)
|
||||
{
|
||||
int res = 0;
|
||||
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;
|
||||
pr_warn("edge ex %016llx phy S:%02d <--> edge ex %016llx phy S:%02d, while there is a fanout ex %016llx\n",
|
||||
SAS_ADDR(parent->sas_addr),
|
||||
parent_phy->phy_id,
|
||||
SAS_ADDR(child->sas_addr),
|
||||
child_phy->phy_id,
|
||||
SAS_ADDR(parent->port->disc.fanout_sas_addr));
|
||||
} else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) {
|
||||
memcpy(parent->port->disc.eeds_a, parent->sas_addr,
|
||||
SAS_ADDR_SIZE);
|
||||
memcpy(parent->port->disc.eeds_b, child->sas_addr,
|
||||
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 {
|
||||
SAS_ADDR(disc->fanout_sas_addr));
|
||||
} else if (SAS_ADDR(disc->eeds_a) == 0) {
|
||||
memcpy(disc->eeds_a, parent->sas_addr, SAS_ADDR_SIZE);
|
||||
memcpy(disc->eeds_b, child->sas_addr, SAS_ADDR_SIZE);
|
||||
} else if (!sas_eeds_valid(parent, child)) {
|
||||
res = -ENODEV;
|
||||
pr_warn("edge ex %016llx phy%02d <--> edge ex %016llx phy%02d link forms a third EEDS!\n",
|
||||
SAS_ADDR(parent->sas_addr),
|
||||
@ -1240,11 +1240,56 @@ static int sas_check_eeds(struct domain_device *child,
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Here we spill over 80 columns. It is intentional.
|
||||
*/
|
||||
static int sas_check_parent_topology(struct domain_device *child)
|
||||
static int sas_check_edge_expander_topo(struct domain_device *child,
|
||||
struct ex_phy *parent_phy)
|
||||
{
|
||||
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;
|
||||
int i;
|
||||
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++) {
|
||||
struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
|
||||
struct ex_phy *child_phy;
|
||||
|
||||
if (parent_phy->phy_state == PHY_VACANT ||
|
||||
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))
|
||||
continue;
|
||||
|
||||
child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
|
||||
|
||||
switch (child->parent->dev_type) {
|
||||
case SAS_EDGE_EXPANDER_DEVICE:
|
||||
if (child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
|
||||
if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (sas_check_edge_expander_topo(child, parent_phy))
|
||||
res = -ENODEV;
|
||||
break;
|
||||
case SAS_FANOUT_EXPANDER_DEVICE:
|
||||
if (parent_phy->routing_attr != TABLE_ROUTING ||
|
||||
child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
|
||||
sas_print_parent_topology_bug(child, parent_phy, child_phy);
|
||||
if (sas_check_fanout_expander_topo(child, parent_phy))
|
||||
res = -ENODEV;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -429,6 +429,15 @@ struct lpfc_cgn_param {
|
||||
/* Max number of days of congestion data */
|
||||
#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
|
||||
* This structure defines memory thats allocated and registered with
|
||||
* 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_V2 2
|
||||
#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_detect;
|
||||
uint8_t cgn_info_action;
|
||||
@ -450,12 +460,7 @@ struct lpfc_cgn_info {
|
||||
uint8_t cgn_info_level2;
|
||||
|
||||
/* Start Time */
|
||||
uint8_t cgn_info_month;
|
||||
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;
|
||||
struct lpfc_cgn_ts base_time;
|
||||
|
||||
/* minute / hours / daily indices */
|
||||
uint8_t cgn_index_minute;
|
||||
@ -496,45 +501,17 @@ struct lpfc_cgn_info {
|
||||
uint8_t cgn_stat_npm; /* Notifications per minute */
|
||||
|
||||
/* Start Time */
|
||||
uint8_t cgn_stat_month;
|
||||
uint8_t cgn_stat_day;
|
||||
uint8_t cgn_stat_year;
|
||||
uint8_t cgn_stat_hour;
|
||||
uint8_t cgn_stat_minute;
|
||||
uint8_t cgn_pad2[2];
|
||||
struct lpfc_cgn_ts stat_start; /* Base time */
|
||||
uint8_t cgn_pad2;
|
||||
|
||||
__le32 cgn_notification;
|
||||
__le32 cgn_peer_notification;
|
||||
__le32 link_integ_notification;
|
||||
__le32 delivery_notification;
|
||||
|
||||
uint8_t cgn_stat_cgn_month; /* Last congestion notification FPIN */
|
||||
uint8_t cgn_stat_cgn_day;
|
||||
uint8_t cgn_stat_cgn_year;
|
||||
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;
|
||||
struct lpfc_cgn_ts stat_fpin; /* Last congestion notification FPIN */
|
||||
struct lpfc_cgn_ts stat_peer; /* Last peer congestion FPIN */
|
||||
struct lpfc_cgn_ts stat_lnk; /* Last link integrity FPIN */
|
||||
struct lpfc_cgn_ts stat_delivery; /* Last delivery notification FPIN */
|
||||
);
|
||||
|
||||
__le32 cgn_info_crc;
|
||||
@ -932,8 +909,6 @@ struct lpfc_hba {
|
||||
void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *,
|
||||
struct lpfc_iocbq *);
|
||||
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 */
|
||||
int (*lpfc_sli_issue_mbox)
|
||||
@ -1045,8 +1020,6 @@ struct lpfc_hba {
|
||||
* capability
|
||||
*/
|
||||
#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_SETUP 0x1000000 /* Signifies HBA setup is completed */
|
||||
#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;
|
||||
#define LPFC_CMF_BLK_SIZE 512
|
||||
struct hrtimer cmf_timer;
|
||||
struct hrtimer cmf_stats_timer; /* 1 minute stats timer */
|
||||
atomic_t cmf_bw_wait;
|
||||
atomic_t cmf_busy;
|
||||
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_driver_evt_cnt; /* Total driver cgn events for fmw */
|
||||
atomic_t cgn_latency_evt_cnt;
|
||||
struct timespec64 cgn_daily_ts;
|
||||
atomic64_t cgn_latency_evt; /* Avg latency per minute */
|
||||
unsigned long cgn_evt_timestamp;
|
||||
#define LPFC_CGN_TIMER_TO_MIN 60000 /* ms in a minute */
|
||||
uint32_t cgn_evt_minute;
|
||||
#define LPFC_SEC_MIN 60
|
||||
#define LPFC_SEC_MIN 60UL
|
||||
#define LPFC_MIN_HOUR 60
|
||||
#define LPFC_HOUR_DAY 24
|
||||
#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_PARM_DESC(lpfc_fabric_cgn_frequency, "Congestion signaling fabric freq");
|
||||
|
||||
int lpfc_acqe_cgn_frequency = 10; /* 10 sec default */
|
||||
module_param(lpfc_acqe_cgn_frequency, int, 0444);
|
||||
unsigned char lpfc_acqe_cgn_frequency = 10; /* 10 sec default */
|
||||
module_param(lpfc_acqe_cgn_frequency, byte, 0444);
|
||||
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 */
|
||||
|
@ -134,7 +134,6 @@ void lpfc_check_nlp_post_devloss(struct lpfc_vport *vport,
|
||||
struct lpfc_nodelist *ndlp);
|
||||
void lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
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);
|
||||
void lpfc_disc_list_loopmap(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_sli4_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,
|
||||
uint32_t len);
|
||||
@ -664,7 +664,7 @@ extern int lpfc_enable_nvmet_cnt;
|
||||
extern unsigned long long lpfc_enable_nvmet[];
|
||||
extern int lpfc_no_hba_reset_cnt;
|
||||
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_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_word4 = get_job_word4(phba, ctiocbq);
|
||||
u32 did;
|
||||
u32 mi_cmd;
|
||||
u16 mi_cmd;
|
||||
|
||||
did = bf_get(els_rsp64_sid, &ctiocbq->wqe.xmit_els_rsp);
|
||||
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;
|
||||
|
||||
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,
|
||||
"6442 : MI Cmd : x%x Not Supported\n", mi_cmd);
|
||||
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 *
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) ||
|
||||
cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID))
|
||||
if (be16_to_cpu(cmdcode) == SLI_CTNS_GID_FT ||
|
||||
be16_to_cpu(cmdcode) == SLI_CTNS_GFF_ID)
|
||||
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
|
||||
else
|
||||
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 lpfc_dmabuf *outmp;
|
||||
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;
|
||||
|
||||
bpl++; /* Skip past ct request */
|
||||
@ -1043,8 +1043,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
outp,
|
||||
CTreq->un.gid.Fc4Type,
|
||||
get_job_data_placed(phba, rspiocb));
|
||||
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
|
||||
} else if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_RJT) {
|
||||
/* NameServer Rsp Error */
|
||||
if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
|
||||
&& (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,
|
||||
"0269 No NameServer Entries "
|
||||
"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->Explanation,
|
||||
vport->fc_flag);
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"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->Explanation);
|
||||
} else {
|
||||
@ -1067,14 +1067,14 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
LOG_DISCOVERY,
|
||||
"0240 NameServer Rsp Error "
|
||||
"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->Explanation,
|
||||
vport->fc_flag);
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"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->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,
|
||||
"0241 NameServer Rsp Error "
|
||||
"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->Explanation,
|
||||
vport->fc_flag);
|
||||
|
||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
||||
"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->Explanation);
|
||||
}
|
||||
@ -1247,8 +1247,8 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
/* Good status, continue checking */
|
||||
CTreq = (struct lpfc_sli_ct_request *)inp->virt;
|
||||
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) {
|
||||
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_ACC) {
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
||||
"4105 NameServer Rsp Data: x%x x%x "
|
||||
"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,
|
||||
CTreq->un.gid.Fc4Type,
|
||||
get_job_data_placed(phba, rspiocb));
|
||||
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
|
||||
} else if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_RJT) {
|
||||
/* NameServer Rsp Error */
|
||||
if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
|
||||
&& (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,
|
||||
"4106 No NameServer Entries "
|
||||
"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->Explanation,
|
||||
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(
|
||||
vport, LPFC_DISC_TRC_CT,
|
||||
"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->Explanation);
|
||||
} else {
|
||||
@ -1287,7 +1287,7 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
vport, KERN_INFO, LOG_DISCOVERY,
|
||||
"4107 NameServer Rsp Error "
|
||||
"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->Explanation,
|
||||
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(
|
||||
vport, LPFC_DISC_TRC_CT,
|
||||
"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->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,
|
||||
"4109 NameServer Rsp Error "
|
||||
"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->Explanation,
|
||||
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(
|
||||
vport, LPFC_DISC_TRC_CT,
|
||||
"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->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_TARGET) ? "Target" : " ");
|
||||
|
||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
|
||||
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_ACC) {
|
||||
if ((fbits & FC4_FEATURE_INIT) &&
|
||||
!(fbits & FC4_FEATURE_TARGET)) {
|
||||
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, "
|
||||
"ulp_status x%x CmdRsp x%x, Context x%x, Tag x%x\n",
|
||||
latt, ulp_status,
|
||||
CTrsp->CommandResponse.bits.CmdRsp,
|
||||
be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp),
|
||||
get_job_ulpcontext(phba, cmdiocb), cmdiocb->iotag);
|
||||
|
||||
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;
|
||||
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
||||
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_ACC)
|
||||
vport->ct_flags |= FC_CT_RFT_ID;
|
||||
}
|
||||
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;
|
||||
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
||||
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_ACC)
|
||||
vport->ct_flags |= FC_CT_RNN_ID;
|
||||
}
|
||||
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;
|
||||
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
||||
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_ACC)
|
||||
vport->ct_flags |= FC_CT_RSPN_ID;
|
||||
}
|
||||
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;
|
||||
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
||||
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_ACC)
|
||||
vport->ct_flags |= FC_CT_RSNN_NN;
|
||||
}
|
||||
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;
|
||||
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
||||
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
||||
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
||||
if (be16_to_cpu(CTrsp->CommandResponse.bits.CmdRsp) ==
|
||||
SLI_CT_RESPONSE_FS_ACC)
|
||||
vport->ct_flags |= FC_CT_RFF_ID;
|
||||
}
|
||||
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_sli_ct_request *CTcmd = inp->virt;
|
||||
struct lpfc_sli_ct_request *CTrsp = outp->virt;
|
||||
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
|
||||
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
|
||||
__be16 fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
|
||||
__be16 fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
|
||||
struct lpfc_nodelist *ndlp, *free_ndlp = NULL;
|
||||
uint32_t latt, cmd, err;
|
||||
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 */
|
||||
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 */
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_ELS,
|
||||
"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 */
|
||||
int (*lpfc_fdmi_hba_action[])
|
||||
static int (*lpfc_fdmi_hba_action[])
|
||||
(struct lpfc_vport *vport, void *attrbuf) = {
|
||||
/* Action routine Mask bit Attribute type */
|
||||
lpfc_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */
|
||||
@ -3134,7 +3134,7 @@ int (*lpfc_fdmi_hba_action[])
|
||||
};
|
||||
|
||||
/* RPA / RPRT attribute jump table */
|
||||
int (*lpfc_fdmi_port_action[])
|
||||
static int (*lpfc_fdmi_port_action[])
|
||||
(struct lpfc_vport *vport, void *attrbuf) = {
|
||||
/* Action routine Mask bit Attribute type */
|
||||
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_sli_ct_request *ctcmd = inp->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 lpfc_nodelist *ndlp = cmdiocb->ndlp;
|
||||
u32 cmd, hash, bucket;
|
||||
@ -3587,7 +3587,7 @@ lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
goto free_res;
|
||||
}
|
||||
/* 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)
|
||||
lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
|
||||
"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;
|
||||
memcpy(rap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
|
||||
size = RAPP_IDENT_OFFSET +
|
||||
sizeof(struct lpfc_vmid_rapp_ident_list);
|
||||
struct_size(rap, obj, be32_to_cpu(rap->no_of_objects));
|
||||
retry = 1;
|
||||
break;
|
||||
|
||||
@ -3767,7 +3767,7 @@ lpfc_vmid_cmd(struct lpfc_vport *vport,
|
||||
dap->obj[0].entity_id_len = vmid->vmid_len;
|
||||
memcpy(dap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
|
||||
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);
|
||||
vmid->flag &= ~LPFC_VMID_REGISTERED;
|
||||
write_unlock(&vport->vmid_lock);
|
||||
|
@ -2259,11 +2259,15 @@ lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file)
|
||||
goto out;
|
||||
}
|
||||
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)
|
||||
goto out;
|
||||
|
||||
size = LPFC_RAS_MIN_BUFF_POST_SIZE * phba->cfg_ras_fwlog_buffsize;
|
||||
debug->buffer = vmalloc(size);
|
||||
if (!debug->buffer)
|
||||
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)
|
||||
* 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
|
||||
* release the ndlp if it has the last reference remaining (reference count
|
||||
* is 1). If succeeded (meaning ndlp released), it sets the iocb ndlp
|
||||
* 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.
|
||||
* the completion of the LOGO process. If the node has transitioned to NPR,
|
||||
* this routine unregisters the RPI if it is still registered. The
|
||||
* lpfc_els_free_iocb() is invoked to release the IOCB data structure.
|
||||
**/
|
||||
static void
|
||||
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))
|
||||
goto out;
|
||||
|
||||
/* NPort Recovery mode or node is just allocated */
|
||||
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.
|
||||
*/
|
||||
if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
|
||||
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:
|
||||
/*
|
||||
@ -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
|
||||
* the associated lpfc Direct Memory Access (DMA) buffer back to the pool and
|
||||
* decrements the ndlp reference count held for this completion callback
|
||||
* function. After that, it invokes the lpfc_nlp_not_used() to check
|
||||
* whether there is only one reference left on the ndlp. If so, it will
|
||||
* perform one more decrement and trigger the release of the ndlp.
|
||||
* function. After that, it invokes the lpfc_drop_node to check
|
||||
* whether it is appropriate to release the node.
|
||||
**/
|
||||
void
|
||||
lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
||||
@ -5468,9 +5452,19 @@ out:
|
||||
ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
|
||||
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. */
|
||||
|
@ -458,11 +458,9 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
|
||||
if (ndlp->nlp_type & NLP_FABRIC) {
|
||||
spin_lock_irqsave(&ndlp->lock, iflags);
|
||||
|
||||
/* In massive vport configuration settings or when the FLOGI
|
||||
* completes with a sequence timeout, it's possible
|
||||
* dev_loss_tmo fired during node recovery. The driver has to
|
||||
* account for this race to allow for recovery and keep
|
||||
* the reference counting correct.
|
||||
/* The driver has to account for a race between any fabric
|
||||
* node that's in recovery when dev_loss_tmo expires. When this
|
||||
* happens, the driver has to allow node recovery.
|
||||
*/
|
||||
switch (ndlp->nlp_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)
|
||||
recovering = true;
|
||||
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);
|
||||
|
||||
@ -556,6 +565,9 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
|
||||
ndlp->nlp_DID, ndlp->nlp_flag,
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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))
|
||||
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
|
||||
* 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))) {
|
||||
spin_lock_irq(&ndlp->lock);
|
||||
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
|
||||
spin_unlock_irq(&ndlp->lock);
|
||||
lpfc_nlp_not_used(ndlp);
|
||||
lpfc_nlp_put(ndlp);
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
if (!rport) {
|
||||
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])
|
||||
strlcpy(buffer, states[state], size);
|
||||
strscpy(buffer, states[state], size);
|
||||
else
|
||||
snprintf(buffer, size, "unknown (%d)", state);
|
||||
return buffer;
|
||||
@ -6704,25 +6706,6 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp)
|
||||
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.
|
||||
* @phba: Pointer to hba context object.
|
||||
|
@ -86,8 +86,8 @@ union CtRevisionId {
|
||||
union CtCommandResponse {
|
||||
/* Structure is in Big Endian format */
|
||||
struct {
|
||||
uint32_t CmdRsp:16;
|
||||
uint32_t Size:16;
|
||||
__be16 CmdRsp;
|
||||
__be16 Size;
|
||||
} bits;
|
||||
uint32_t word;
|
||||
};
|
||||
@ -124,7 +124,7 @@ struct lpfc_sli_ct_request {
|
||||
#define LPFC_CT_PREAMBLE 20 /* Size of CTReq + 4 up to here */
|
||||
|
||||
union {
|
||||
uint32_t PortID;
|
||||
__be32 PortID;
|
||||
struct gid {
|
||||
uint8_t PortType; /* for GID_PT requests */
|
||||
#define GID_PT_N_PORT 1
|
||||
@ -1408,19 +1408,19 @@ struct entity_id_object {
|
||||
};
|
||||
|
||||
struct app_id_object {
|
||||
uint32_t port_id;
|
||||
uint32_t app_id;
|
||||
__be32 port_id;
|
||||
__be32 app_id;
|
||||
struct entity_id_object obj;
|
||||
};
|
||||
|
||||
struct lpfc_vmid_rapp_ident_list {
|
||||
uint32_t no_of_objects;
|
||||
struct entity_id_object obj[1];
|
||||
__be32 no_of_objects;
|
||||
struct entity_id_object obj[];
|
||||
};
|
||||
|
||||
struct lpfc_vmid_dapp_ident_list {
|
||||
uint32_t no_of_objects;
|
||||
struct entity_id_object obj[1];
|
||||
__be32 no_of_objects;
|
||||
struct entity_id_object obj[];
|
||||
};
|
||||
|
||||
#define GALLAPPIA_ID_LAST 0x80
|
||||
@ -1512,7 +1512,7 @@ struct lpfc_fdmi_hba_ident {
|
||||
* Registered Port List Format
|
||||
*/
|
||||
struct lpfc_fdmi_reg_port_list {
|
||||
uint32_t EntryCnt;
|
||||
__be32 EntryCnt;
|
||||
struct lpfc_fdmi_port_entry pe;
|
||||
} __packed;
|
||||
|
||||
|
@ -395,9 +395,6 @@ struct lpfc_cqe {
|
||||
#define CQE_STATUS_NEED_BUFF_ENTRY 0xf
|
||||
#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). */
|
||||
#define CQE_HW_STATUS_NO_ERR 0x0
|
||||
#define CQE_HW_STATUS_UNDERRUN 0x1
|
||||
@ -536,9 +533,9 @@ struct sli4_wcqe_xri_aborted {
|
||||
/* completion queue entry structure for rqe completion */
|
||||
struct lpfc_rcqe {
|
||||
uint32_t word0;
|
||||
#define lpfc_rcqe_bindex_SHIFT 16
|
||||
#define lpfc_rcqe_bindex_MASK 0x0000FFF
|
||||
#define lpfc_rcqe_bindex_WORD word0
|
||||
#define lpfc_rcqe_iv_SHIFT 31
|
||||
#define lpfc_rcqe_iv_MASK 0x00000001
|
||||
#define lpfc_rcqe_iv_WORD word0
|
||||
#define lpfc_rcqe_status_SHIFT 8
|
||||
#define lpfc_rcqe_status_MASK 0x000000FF
|
||||
#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_INSUFF_BUF_NEED_BUF 0x12 /* Insufficient buffers */
|
||||
#define FC_STATUS_INSUFF_BUF_FRM_DISC 0x13 /* Frame Discard */
|
||||
#define FC_STATUS_RQ_DMA_FAILURE 0x14 /* DMA failure */
|
||||
uint32_t word1;
|
||||
#define lpfc_rcqe_fcf_id_v1_SHIFT 0
|
||||
#define lpfc_rcqe_fcf_id_v1_MASK 0x0000003F
|
||||
@ -4813,8 +4811,8 @@ struct cmf_sync_wqe {
|
||||
#define cmf_sync_cqid_WORD word11
|
||||
uint32_t read_bytes;
|
||||
uint32_t word13;
|
||||
#define cmf_sync_period_SHIFT 16
|
||||
#define cmf_sync_period_MASK 0x0000ffff
|
||||
#define cmf_sync_period_SHIFT 24
|
||||
#define cmf_sync_period_MASK 0x000000ff
|
||||
#define cmf_sync_period_WORD word13
|
||||
uint32_t word14;
|
||||
uint32_t word15;
|
||||
|
@ -101,6 +101,7 @@ static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
|
||||
static DEFINE_IDR(lpfc_hba_index);
|
||||
#define LPFC_NVMET_BUF_POST 254
|
||||
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
|
||||
@ -1279,7 +1280,7 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
|
||||
/*
|
||||
* 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:
|
||||
* 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,
|
||||
idle_stat_delay_work);
|
||||
struct lpfc_queue *cq;
|
||||
struct lpfc_queue *eq;
|
||||
struct lpfc_sli4_hdw_queue *hdwq;
|
||||
struct lpfc_idle_stat *idle_stat;
|
||||
u32 i, idle_percent;
|
||||
@ -1306,10 +1307,10 @@ lpfc_idle_stat_delay_work(struct work_struct *work)
|
||||
|
||||
for_each_present_cpu(i) {
|
||||
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 */
|
||||
if (cq->chann != i)
|
||||
/* Skip if we've already handled this eq's primary CPU */
|
||||
if (eq->chann != i)
|
||||
continue;
|
||||
|
||||
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;
|
||||
|
||||
if (idle_percent < 15)
|
||||
cq->poll_mode = LPFC_QUEUE_WORK;
|
||||
eq->poll_mode = LPFC_QUEUE_WORK;
|
||||
else
|
||||
cq->poll_mode = LPFC_IRQ_POLL;
|
||||
eq->poll_mode = LPFC_THREADED_IRQ;
|
||||
|
||||
idle_stat->prev_idle = wall_idle;
|
||||
idle_stat->prev_wall = wall;
|
||||
@ -3197,6 +3198,7 @@ lpfc_cmf_stop(struct lpfc_hba *phba)
|
||||
"6221 Stop CMF / Cancel Timer\n");
|
||||
|
||||
/* Cancel the CMF timer */
|
||||
hrtimer_cancel(&phba->cmf_stats_timer);
|
||||
hrtimer_cancel(&phba->cmf_timer);
|
||||
|
||||
/* Zero CMF counters */
|
||||
@ -3283,7 +3285,10 @@ lpfc_cmf_start(struct lpfc_hba *phba)
|
||||
|
||||
phba->cmf_timer_cnt = 0;
|
||||
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);
|
||||
/* Setup for latency check in IO cmpl routines */
|
||||
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_io_buf *lpfc_cmd;
|
||||
int idx, cnt;
|
||||
unsigned long iflags;
|
||||
|
||||
qp = phba->sli4_hba.hdwq;
|
||||
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 = qp;
|
||||
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,
|
||||
&qp->lpfc_io_buf_list_put);
|
||||
qp->put_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;
|
||||
@ -5593,81 +5600,74 @@ void
|
||||
lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag)
|
||||
{
|
||||
struct lpfc_cgn_info *cp;
|
||||
struct tm broken;
|
||||
struct timespec64 cur_time;
|
||||
u32 cnt;
|
||||
u32 value;
|
||||
|
||||
/* Make sure we have a congestion info buffer */
|
||||
if (!phba->cgn_i)
|
||||
return;
|
||||
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 */
|
||||
switch (dtag) {
|
||||
case ELS_DTAG_LNK_INTEGRITY:
|
||||
cnt = le32_to_cpu(cp->link_integ_notification);
|
||||
cnt++;
|
||||
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;
|
||||
le32_add_cpu(&cp->link_integ_notification, 1);
|
||||
lpfc_cgn_update_tstamp(phba, &cp->stat_lnk);
|
||||
break;
|
||||
case ELS_DTAG_DELIVERY:
|
||||
cnt = le32_to_cpu(cp->delivery_notification);
|
||||
cnt++;
|
||||
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;
|
||||
le32_add_cpu(&cp->delivery_notification, 1);
|
||||
lpfc_cgn_update_tstamp(phba, &cp->stat_delivery);
|
||||
break;
|
||||
case ELS_DTAG_PEER_CONGEST:
|
||||
cnt = le32_to_cpu(cp->cgn_peer_notification);
|
||||
cnt++;
|
||||
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;
|
||||
le32_add_cpu(&cp->cgn_peer_notification, 1);
|
||||
lpfc_cgn_update_tstamp(phba, &cp->stat_peer);
|
||||
break;
|
||||
case ELS_DTAG_CONGESTION:
|
||||
cnt = le32_to_cpu(cp->cgn_notification);
|
||||
cnt++;
|
||||
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;
|
||||
le32_add_cpu(&cp->cgn_notification, 1);
|
||||
lpfc_cgn_update_tstamp(phba, &cp->stat_fpin);
|
||||
}
|
||||
if (phba->cgn_fpin_frequency &&
|
||||
phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) {
|
||||
value = LPFC_CGN_TIMER_TO_MIN / phba->cgn_fpin_frequency;
|
||||
cp->cgn_stat_npm = value;
|
||||
}
|
||||
|
||||
value = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ,
|
||||
LPFC_CGN_CRC32_SEED);
|
||||
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.
|
||||
* @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.
|
||||
* 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
|
||||
* to the registered congestion buffer every minute.
|
||||
*/
|
||||
static void
|
||||
lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
||||
static enum hrtimer_restart
|
||||
lpfc_cmf_stats_timer(struct hrtimer *timer)
|
||||
{
|
||||
struct lpfc_hba *phba;
|
||||
struct lpfc_cgn_info *cp;
|
||||
struct tm broken;
|
||||
struct timespec64 cur_time;
|
||||
uint32_t i, index;
|
||||
uint16_t value, mvalue;
|
||||
uint64_t bps;
|
||||
@ -5691,21 +5690,18 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
||||
__le32 *lptr;
|
||||
__le16 *mptr;
|
||||
|
||||
phba = container_of(timer, struct lpfc_hba, cmf_stats_timer);
|
||||
/* Make sure we have a congestion info buffer */
|
||||
if (!phba->cgn_i)
|
||||
return;
|
||||
return HRTIMER_NORESTART;
|
||||
cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;
|
||||
|
||||
if (time_before(jiffies, phba->cgn_evt_timestamp))
|
||||
return;
|
||||
phba->cgn_evt_timestamp = jiffies +
|
||||
msecs_to_jiffies(LPFC_CGN_TIMER_TO_MIN);
|
||||
phba->cgn_evt_minute++;
|
||||
|
||||
/* We should get to this point in the routine on 1 minute intervals */
|
||||
|
||||
ktime_get_real_ts64(&cur_time);
|
||||
time64_to_tm(cur_time.tv_sec, 0, &broken);
|
||||
lpfc_cgn_update_tstamp(phba, &cp->base_time);
|
||||
|
||||
if (phba->cgn_fpin_frequency &&
|
||||
phba->cgn_fpin_frequency != LPFC_FPIN_INIT_FREQ) {
|
||||
@ -5858,31 +5854,6 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
||||
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;
|
||||
wvalue = 0;
|
||||
lvalue = 0;
|
||||
@ -5916,15 +5887,6 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
||||
"2420 Congestion Info - daily (%d): "
|
||||
"%d %d %d %d %d\n",
|
||||
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 */
|
||||
@ -5935,6 +5897,10 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
|
||||
lvalue = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ,
|
||||
LPFC_CGN_CRC32_SEED);
|
||||
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) {
|
||||
cnt = div_u64(total, ms); /* bytes per ms */
|
||||
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;
|
||||
}
|
||||
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 */
|
||||
|
||||
/* 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
|
||||
* after max_bytes_per_interval is setup.
|
||||
*/
|
||||
@ -8014,6 +7945,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
||||
/* CMF congestion timer */
|
||||
hrtimer_init(&phba->cmf_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
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
|
||||
@ -13117,8 +13051,10 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
|
||||
}
|
||||
eqhdl->irq = rc;
|
||||
|
||||
rc = request_irq(eqhdl->irq, &lpfc_sli4_hba_intr_handler, 0,
|
||||
name, eqhdl);
|
||||
rc = request_threaded_irq(eqhdl->irq,
|
||||
&lpfc_sli4_hba_intr_handler,
|
||||
&lpfc_sli4_hba_intr_handler_th,
|
||||
IRQF_ONESHOT, name, eqhdl);
|
||||
if (rc) {
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
||||
"0486 MSI-X fast-path (%d) "
|
||||
@ -13521,6 +13457,7 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
|
||||
struct pci_dev *pdev = phba->pcidev;
|
||||
|
||||
lpfc_stop_hba_timers(phba);
|
||||
hrtimer_cancel(&phba->cmf_stats_timer);
|
||||
hrtimer_cancel(&phba->cmf_timer);
|
||||
|
||||
if (phba->pport)
|
||||
@ -13645,8 +13582,6 @@ void
|
||||
lpfc_init_congestion_buf(struct lpfc_hba *phba)
|
||||
{
|
||||
struct lpfc_cgn_info *cp;
|
||||
struct timespec64 cmpl_time;
|
||||
struct tm broken;
|
||||
uint16_t size;
|
||||
uint32_t crc;
|
||||
|
||||
@ -13666,11 +13601,10 @@ lpfc_init_congestion_buf(struct lpfc_hba *phba)
|
||||
atomic_set(&phba->cgn_latency_evt_cnt, 0);
|
||||
atomic64_set(&phba->cgn_latency_evt, 0);
|
||||
phba->cgn_evt_minute = 0;
|
||||
phba->hba_flag &= ~HBA_CGN_DAY_WRAP;
|
||||
|
||||
memset(cp, 0xff, offsetof(struct lpfc_cgn_info, cgn_stat));
|
||||
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 */
|
||||
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_level2 = phba->cgn_p.cgn_param_level2;
|
||||
|
||||
ktime_get_real_ts64(&cmpl_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);
|
||||
lpfc_cgn_update_tstamp(phba, &cp->base_time);
|
||||
|
||||
/* Fill in default LUN qdepth */
|
||||
if (phba->pport) {
|
||||
@ -13716,8 +13635,6 @@ void
|
||||
lpfc_init_congestion_stat(struct lpfc_hba *phba)
|
||||
{
|
||||
struct lpfc_cgn_info *cp;
|
||||
struct timespec64 cmpl_time;
|
||||
struct tm broken;
|
||||
uint32_t crc;
|
||||
|
||||
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;
|
||||
memset(&cp->cgn_stat, 0, sizeof(cp->cgn_stat));
|
||||
|
||||
ktime_get_real_ts64(&cmpl_time);
|
||||
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);
|
||||
|
||||
lpfc_cgn_update_tstamp(phba, &cp->stat_start);
|
||||
crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED);
|
||||
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);
|
||||
lpfc_decode_firmware_rev(phba, fwrev, 1);
|
||||
if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||
"3023 Updating Firmware, Current Version:%s "
|
||||
"New Version:%s\n",
|
||||
fwrev, image->revision);
|
||||
lpfc_log_msg(phba, KERN_NOTICE, LOG_INIT | LOG_SLI,
|
||||
"3023 Updating Firmware, Current Version:%s "
|
||||
"New Version:%s\n",
|
||||
fwrev, image->revision);
|
||||
for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {
|
||||
dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
|
||||
GFP_KERNEL);
|
||||
@ -14793,10 +14695,10 @@ lpfc_write_firmware(const struct firmware *fw, void *context)
|
||||
}
|
||||
rc = offset;
|
||||
} else
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||
"3029 Skipped Firmware update, Current "
|
||||
"Version:%s New Version:%s\n",
|
||||
fwrev, image->revision);
|
||||
lpfc_log_msg(phba, KERN_NOTICE, LOG_INIT | LOG_SLI,
|
||||
"3029 Skipped Firmware update, Current "
|
||||
"Version:%s New Version:%s\n",
|
||||
fwrev, image->revision);
|
||||
|
||||
release_out:
|
||||
list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) {
|
||||
@ -14808,11 +14710,11 @@ release_out:
|
||||
release_firmware(fw);
|
||||
out:
|
||||
if (rc < 0)
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||
"3062 Firmware update error, status %d.\n", rc);
|
||||
lpfc_log_msg(phba, KERN_ERR, LOG_INIT | LOG_SLI,
|
||||
"3062 Firmware update error, status %d.\n", rc);
|
||||
else
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||
"3024 Firmware update success: size %d.\n", rc);
|
||||
lpfc_log_msg(phba, KERN_NOTICE, LOG_INIT | LOG_SLI,
|
||||
"3024 Firmware update success: size %d.\n", rc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*******************************************************************
|
||||
* This file is part of the Emulex Linux Device Driver for *
|
||||
* 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. *
|
||||
* Copyright (C) 2004-2009 Emulex. All rights reserved. *
|
||||
* 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 */
|
||||
#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):" \
|
||||
fmt, (vport)->phba->brd_no, vport->vpi, ##arg); }
|
||||
|
||||
@ -64,7 +64,7 @@ do { \
|
||||
{ uint32_t log_verbose = (phba)->pport ? \
|
||||
(phba)->pport->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:" \
|
||||
fmt, phba->brd_no, ##arg); \
|
||||
} \
|
||||
|
@ -310,20 +310,20 @@ lpfc_nvme_handle_lsreq(struct lpfc_hba *phba,
|
||||
* for the LS request.
|
||||
**/
|
||||
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_wcqe_complete *wcqe)
|
||||
{
|
||||
struct nvmefc_ls_req *pnvme_lsreq;
|
||||
struct lpfc_dmabuf *buf_ptr;
|
||||
struct lpfc_nodelist *ndlp;
|
||||
uint32_t status;
|
||||
int status;
|
||||
|
||||
pnvme_lsreq = cmdwqe->context_un.nvme_lsreq;
|
||||
ndlp = cmdwqe->ndlp;
|
||||
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,
|
||||
"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);
|
||||
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);
|
||||
else
|
||||
} else {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
|
||||
"6046 NVMEx cmpl without done call back? "
|
||||
"Data x%px DID %x Xri: %x status %x\n",
|
||||
pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0,
|
||||
cmdwqe->sli4_xritag, status);
|
||||
}
|
||||
if (ndlp) {
|
||||
lpfc_nlp_put(ndlp);
|
||||
cmdwqe->ndlp = NULL;
|
||||
@ -367,7 +370,7 @@ lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
|
||||
uint32_t status;
|
||||
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) {
|
||||
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->transferred_length = nCmd->payload_length;
|
||||
} else {
|
||||
lpfc_ncmd->status = (status & LPFC_IOCB_STATUS_MASK);
|
||||
lpfc_ncmd->status = status;
|
||||
lpfc_ncmd->result = (wcqe->parameter & IOERR_PARAM_MASK);
|
||||
|
||||
/* 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_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
|
||||
* 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 */
|
||||
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,
|
||||
"6139 Driver in reset cleanup - flushing "
|
||||
"NVME Req now. hba_flag x%x\n",
|
||||
@ -1907,25 +1927,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
|
||||
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;
|
||||
|
||||
/* 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
|
||||
* 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,
|
||||
lpfc_nvme_abort_fcreq_cmpl);
|
||||
|
||||
spin_unlock(&lpfc_nbuf->buf_lock);
|
||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||
spin_unlock(&phba->hbalock);
|
||||
spin_unlock_irqrestore(&lpfc_nbuf->buf_lock, flags);
|
||||
|
||||
/* Make sure HBA is alive */
|
||||
lpfc_issue_hb_tmo(phba);
|
||||
@ -1998,8 +2001,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport,
|
||||
return;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&lpfc_nbuf->buf_lock);
|
||||
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||
spin_unlock(&phba->hbalock);
|
||||
spin_unlock_irqrestore(&lpfc_nbuf->buf_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*******************************************************************
|
||||
* This file is part of the Emulex Linux Device Driver for *
|
||||
* 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. *
|
||||
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
|
||||
* 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;
|
||||
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;
|
||||
|
||||
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)
|
||||
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;
|
||||
|
||||
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 Scsi_Host *shost;
|
||||
u32 logit = LOG_FCP;
|
||||
u32 status, idx;
|
||||
u32 idx;
|
||||
u32 lat;
|
||||
u8 wait_xb_clr = 0;
|
||||
|
||||
@ -4061,8 +4061,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
|
||||
#endif
|
||||
shost = cmd->device->host;
|
||||
|
||||
status = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||
lpfc_cmd->status = (status & LPFC_IOCB_STATUS_MASK);
|
||||
lpfc_cmd->status = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||
lpfc_cmd->result = (wcqe->parameter & IOERR_PARAM_MASK);
|
||||
|
||||
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
|
||||
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 &&
|
||||
!lpfc_cmd->fcp_rsp->rspStatus3 &&
|
||||
(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) {
|
||||
case IOSTAT_SUCCESS:
|
||||
case CQE_STATUS_SUCCESS:
|
||||
cmd->result = DID_OK << 16;
|
||||
break;
|
||||
case IOSTAT_FCP_RSP_ERROR:
|
||||
case CQE_STATUS_FCP_RSP_FAILURE:
|
||||
lpfc_handle_fcp_err(vport, lpfc_cmd,
|
||||
pwqeIn->wqe.fcp_iread.total_xfer_len -
|
||||
wcqe->total_data_placed);
|
||||
break;
|
||||
case IOSTAT_NPORT_BSY:
|
||||
case IOSTAT_FABRIC_BSY:
|
||||
case CQE_STATUS_NPORT_BSY:
|
||||
case CQE_STATUS_FABRIC_BSY:
|
||||
cmd->result = DID_TRANSPORT_DISRUPTED << 16;
|
||||
fast_path_evt = lpfc_alloc_fast_evt(phba);
|
||||
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,
|
||||
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
|
||||
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) {
|
||||
/* This I/O was aborted by the target, we don't
|
||||
* 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);
|
||||
}
|
||||
fallthrough;
|
||||
case IOSTAT_LOCAL_REJECT:
|
||||
case CQE_STATUS_LOCAL_REJECT:
|
||||
if (lpfc_cmd->result & IOERR_DRVR_MASK)
|
||||
lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
|
||||
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;
|
||||
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,
|
||||
"9036 Local Reject FCP cmd x%x failed"
|
||||
" <%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);
|
||||
fallthrough;
|
||||
default:
|
||||
if (lpfc_cmd->status >= IOSTAT_CNT)
|
||||
lpfc_cmd->status = IOSTAT_DEFAULT;
|
||||
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 "
|
||||
"status x%x result x%x [x%x] "
|
||||
"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",
|
||||
cmd->device->id, cmd->device->lun, cmd,
|
||||
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));
|
||||
}
|
||||
|
||||
@ -5009,7 +5004,6 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
|
||||
return -ENODEV;
|
||||
}
|
||||
phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth;
|
||||
phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,8 @@ static int lpfc_sli4_post_sgl_list(struct lpfc_hba *, struct list_head *,
|
||||
int);
|
||||
static void 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);
|
||||
static bool lpfc_sli4_mbox_completions_pending(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);
|
||||
@ -629,7 +630,7 @@ lpfc_sli4_eqcq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq)
|
||||
|
||||
static int
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
|
||||
consumed++;
|
||||
@ -1931,7 +1932,7 @@ lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total)
|
||||
unsigned long iflags;
|
||||
u32 ret_val;
|
||||
u32 atot, wtot, max;
|
||||
u16 warn_sync_period = 0;
|
||||
u8 warn_sync_period = 0;
|
||||
|
||||
/* First address any alarm / warning activity */
|
||||
atot = atomic_xchg(&phba->cgn_sync_alarm_cnt, 0);
|
||||
@ -7957,7 +7958,7 @@ out_rdf:
|
||||
* lpfc_init_idle_stat_hb - Initialize idle_stat tracking
|
||||
* @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.
|
||||
*
|
||||
* Return codes:
|
||||
@ -7967,16 +7968,16 @@ static void lpfc_init_idle_stat_hb(struct lpfc_hba *phba)
|
||||
{
|
||||
int i;
|
||||
struct lpfc_sli4_hdw_queue *hdwq;
|
||||
struct lpfc_queue *cq;
|
||||
struct lpfc_queue *eq;
|
||||
struct lpfc_idle_stat *idle_stat;
|
||||
u64 wall;
|
||||
|
||||
for_each_present_cpu(i) {
|
||||
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 */
|
||||
if (cq->chann != i)
|
||||
/* Skip if we've already handled this eq's primary CPU */
|
||||
if (eq->chann != i)
|
||||
continue;
|
||||
|
||||
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;
|
||||
|
||||
if (phba->nvmet_support ||
|
||||
phba->cmf_active_mode != LPFC_CFG_OFF)
|
||||
cq->poll_mode = LPFC_QUEUE_WORK;
|
||||
phba->cmf_active_mode != LPFC_CFG_OFF ||
|
||||
phba->intr_type != MSIX)
|
||||
eq->poll_mode = LPFC_QUEUE_WORK;
|
||||
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,
|
||||
msecs_to_jiffies(LPFC_IDLE_STAT_DELAY));
|
||||
}
|
||||
@ -9218,7 +9220,8 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
|
||||
|
||||
if (mbox_pending)
|
||||
/* 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
|
||||
/* Always clear and re-arm the EQ */
|
||||
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
|
||||
* 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);
|
||||
workposted = true;
|
||||
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:
|
||||
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
|
||||
* @handler: Routine to process each cqe
|
||||
* @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
|
||||
* 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
|
||||
__lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
||||
bool (*handler)(struct lpfc_hba *, struct lpfc_queue *,
|
||||
struct lpfc_cqe *), unsigned long *delay,
|
||||
enum lpfc_poll_mode poll_mode)
|
||||
struct lpfc_cqe *), unsigned long *delay)
|
||||
{
|
||||
struct lpfc_cqe *cqe;
|
||||
bool workposted = false;
|
||||
@ -14863,10 +14897,6 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq,
|
||||
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 */
|
||||
if (count > cq->CQ_max_cqe)
|
||||
cq->CQ_max_cqe = count;
|
||||
@ -14916,17 +14946,17 @@ __lpfc_sli4_sp_process_cq(struct lpfc_queue *cq)
|
||||
case LPFC_MCQ:
|
||||
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
||||
lpfc_sli4_sp_handle_mcqe,
|
||||
&delay, LPFC_QUEUE_WORK);
|
||||
&delay);
|
||||
break;
|
||||
case LPFC_WCQ:
|
||||
if (cq->subtype == LPFC_IO)
|
||||
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
||||
lpfc_sli4_fp_handle_cqe,
|
||||
&delay, LPFC_QUEUE_WORK);
|
||||
&delay);
|
||||
else
|
||||
workposted |= __lpfc_sli4_process_cq(phba, cq,
|
||||
lpfc_sli4_sp_handle_cqe,
|
||||
&delay, LPFC_QUEUE_WORK);
|
||||
&delay);
|
||||
break;
|
||||
default:
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||
@ -15203,6 +15233,38 @@ drop:
|
||||
hrq->RQ_no_posted_buf++;
|
||||
/* Post more buffers if possible */
|
||||
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:
|
||||
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
|
||||
* @phba: Pointer to HBA context object.
|
||||
* @cq: Pointer to CQ
|
||||
* @cqid: CQ ID
|
||||
* __lpfc_sli4_hba_process_cq - Process a fast-path event queue entry
|
||||
* @cq: Pointer to CQ to be processed
|
||||
*
|
||||
* This routine checks the poll mode of the CQ corresponding to
|
||||
* cq->chann, then either schedules a softirq or queue_work to complete
|
||||
* 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.
|
||||
* This routine calls the cq processing routine with the handler for
|
||||
* 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_sched_cq_work(struct lpfc_hba *phba,
|
||||
struct lpfc_queue *cq, uint16_t cqid)
|
||||
static void
|
||||
__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) {
|
||||
case LPFC_IRQ_POLL:
|
||||
/* CGN mgmt is mutually exclusive from softirq processing */
|
||||
if (phba->cmf_active_mode == LPFC_CFG_OFF) {
|
||||
irq_poll_sched(&cq->iop);
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
case LPFC_QUEUE_WORK:
|
||||
default:
|
||||
/* process and rearm the CQ */
|
||||
workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe,
|
||||
&delay);
|
||||
|
||||
if (delay) {
|
||||
if (is_kdump_kernel())
|
||||
ret = queue_work(phba->wq, &cq->irqwork);
|
||||
ret = queue_delayed_work(phba->wq, &cq->sched_irqwork,
|
||||
delay);
|
||||
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)
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||
"0383 Cannot schedule queue work "
|
||||
"for CQ eqcqid=%d, cqid=%d on CPU %d\n",
|
||||
cqid, cq->queue_id,
|
||||
raw_smp_processor_id());
|
||||
"0367 Cannot schedule queue work "
|
||||
"for cqid=%d on CPU %d\n",
|
||||
cq->queue_id, cq->chann);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
* @eq: Pointer to the queue structure.
|
||||
* @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.
|
||||
* 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
|
||||
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;
|
||||
uint32_t qidx = eq->hdwq;
|
||||
uint16_t cqid, id;
|
||||
int ret;
|
||||
|
||||
if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||
@ -15391,70 +15474,25 @@ work_cq:
|
||||
else
|
||||
cq->isr_timestamp = 0;
|
||||
#endif
|
||||
lpfc_sli4_sched_cq_work(phba, cq, cqid);
|
||||
}
|
||||
|
||||
/**
|
||||
* __lpfc_sli4_hba_process_cq - Process a fast-path event queue entry
|
||||
* @cq: Pointer to CQ to be processed
|
||||
* @poll_mode: Enum lpfc_poll_state to determine poll mode
|
||||
*
|
||||
* This routine calls the cq processing routine with the handler for
|
||||
* 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) {
|
||||
switch (poll_mode) {
|
||||
case LPFC_THREADED_IRQ:
|
||||
__lpfc_sli4_hba_process_cq(cq);
|
||||
break;
|
||||
case LPFC_QUEUE_WORK:
|
||||
default:
|
||||
if (is_kdump_kernel())
|
||||
ret = queue_delayed_work(phba->wq, &cq->sched_irqwork,
|
||||
delay);
|
||||
ret = queue_work(phba->wq, &cq->irqwork);
|
||||
else
|
||||
ret = queue_delayed_work_on(cq->chann, phba->wq,
|
||||
&cq->sched_irqwork, delay);
|
||||
ret = queue_work_on(cq->chann, phba->wq, &cq->irqwork);
|
||||
if (!ret)
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
|
||||
"0367 Cannot schedule queue work "
|
||||
"for cqid=%d on CPU %d\n",
|
||||
cq->queue_id, cq->chann);
|
||||
"0383 Cannot schedule queue work "
|
||||
"for CQ eqcqid=%d, cqid=%d on CPU %d\n",
|
||||
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, 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
|
||||
* held. It gets the hbalock to access and update SLI data structures.
|
||||
*
|
||||
* This function returns IRQ_HANDLED when interrupt is handled else it
|
||||
* returns IRQ_NONE.
|
||||
* This function returns IRQ_HANDLED when interrupt is handled, IRQ_WAKE_THREAD
|
||||
* when interrupt is scheduled to be handled from a threaded irq context, or
|
||||
* else returns IRQ_NONE.
|
||||
**/
|
||||
irqreturn_t
|
||||
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_queue *fpeq;
|
||||
unsigned long iflag;
|
||||
int ecount = 0;
|
||||
int hba_eqidx;
|
||||
int ecount = 0;
|
||||
struct lpfc_eq_intr_info *eqi;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
eqi = this_cpu_ptr(phba->sli4_hba.eq_info);
|
||||
eqi->icnt++;
|
||||
switch (fpeq->poll_mode) {
|
||||
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 &&
|
||||
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);
|
||||
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);
|
||||
/* process and rearm the EQ */
|
||||
ecount = lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM,
|
||||
LPFC_QUEUE_WORK);
|
||||
|
||||
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,
|
||||
"0358 MSI-X interrupt with no EQE\n");
|
||||
else
|
||||
/* Non MSI-X treated on interrupt as EQ share INT */
|
||||
return IRQ_NONE;
|
||||
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,
|
||||
"0358 MSI-X interrupt with no EQE\n");
|
||||
else
|
||||
/* Non MSI-X treated on interrupt as EQ share INT */
|
||||
return IRQ_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@ -16115,13 +16165,69 @@ out:
|
||||
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)
|
||||
phba->sli4_hba.cq_max = cq->queue_id;
|
||||
|
||||
irq_poll_init(&cq->iop, LPFC_IRQ_POLL_WEIGHT, lpfc_cq_poll_hdler);
|
||||
out:
|
||||
mempool_free(mbox, phba->mbox_mem_pool);
|
||||
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) {
|
||||
switch (shdr_add_status_2) {
|
||||
case LPFC_ADD_STATUS_2_INCOMPAT_FLASH:
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||
"4199 Firmware write failed: "
|
||||
"image incompatible with flash x%02x\n",
|
||||
phba->sli4_hba.flash_id);
|
||||
lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||
"4199 Firmware write failed: "
|
||||
"image incompatible with flash x%02x\n",
|
||||
phba->sli4_hba.flash_id);
|
||||
break;
|
||||
case LPFC_ADD_STATUS_2_INCORRECT_ASIC:
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||
"4200 Firmware write failed: "
|
||||
"image incompatible with ASIC "
|
||||
"architecture x%02x\n",
|
||||
phba->sli4_hba.asic_rev);
|
||||
lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||
"4200 Firmware write failed: "
|
||||
"image incompatible with ASIC "
|
||||
"architecture x%02x\n",
|
||||
phba->sli4_hba.asic_rev);
|
||||
break;
|
||||
default:
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||
"4210 Firmware write failed: "
|
||||
"add_status_2 x%02x\n",
|
||||
shdr_add_status_2);
|
||||
lpfc_log_msg(phba, KERN_WARNING, LOG_MBOX | LOG_SLI,
|
||||
"4210 Firmware write failed: "
|
||||
"add_status_2 x%02x\n",
|
||||
shdr_add_status_2);
|
||||
break;
|
||||
}
|
||||
} 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) {
|
||||
case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET):
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
|
||||
"3198 Firmware write complete: System "
|
||||
"reboot required to instantiate\n");
|
||||
lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
|
||||
"3198 Firmware write complete: System "
|
||||
"reboot required to instantiate\n");
|
||||
break;
|
||||
case (LPFC_CHANGE_STATUS_FW_RESET):
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
|
||||
"3199 Firmware write complete: "
|
||||
"Firmware reset required to "
|
||||
"instantiate\n");
|
||||
lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
|
||||
"3199 Firmware write complete: "
|
||||
"Firmware reset required to "
|
||||
"instantiate\n");
|
||||
break;
|
||||
case (LPFC_CHANGE_STATUS_PORT_MIGRATION):
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
|
||||
"3200 Firmware write complete: Port "
|
||||
"Migration or PCI Reset required to "
|
||||
"instantiate\n");
|
||||
lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
|
||||
"3200 Firmware write complete: Port "
|
||||
"Migration or PCI Reset required to "
|
||||
"instantiate\n");
|
||||
break;
|
||||
case (LPFC_CHANGE_STATUS_PCI_RESET):
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
|
||||
"3201 Firmware write complete: PCI "
|
||||
"Reset required to instantiate\n");
|
||||
lpfc_log_msg(phba, KERN_NOTICE, LOG_MBOX | LOG_SLI,
|
||||
"3201 Firmware write complete: PCI "
|
||||
"Reset required to instantiate\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -140,7 +140,7 @@ struct lpfc_rqb {
|
||||
|
||||
enum lpfc_poll_mode {
|
||||
LPFC_QUEUE_WORK,
|
||||
LPFC_IRQ_POLL
|
||||
LPFC_THREADED_IRQ,
|
||||
};
|
||||
|
||||
struct lpfc_idle_stat {
|
||||
@ -279,8 +279,6 @@ struct lpfc_queue {
|
||||
struct list_head _poll_list;
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
* 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"
|
||||
|
||||
/* Used for SLI 2/3 */
|
||||
|
@ -1,13 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config MEGARAID_NEWGEN
|
||||
bool "LSI Logic New Generation RAID Device Drivers"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
help
|
||||
LSI Logic RAID Device Drivers
|
||||
|
||||
config MEGARAID_MM
|
||||
tristate "LSI Logic Management Module (New Driver)"
|
||||
depends on PCI && SCSI && MEGARAID_NEWGEN
|
||||
depends on PCI && HAS_IOPORT && SCSI && MEGARAID_NEWGEN
|
||||
help
|
||||
Management Module provides ioctl, sysfs support for LSI Logic
|
||||
RAID controllers.
|
||||
@ -67,7 +67,7 @@ config MEGARAID_MAILBOX
|
||||
|
||||
config MEGARAID_LEGACY
|
||||
tristate "LSI Logic Legacy MegaRAID Driver"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
help
|
||||
This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490
|
||||
and 467 SCSI host adapters. This driver also support the all U320
|
||||
|
@ -1722,11 +1722,9 @@ struct megasas_sge_skinny {
|
||||
} __packed;
|
||||
|
||||
union megasas_sgl {
|
||||
|
||||
struct megasas_sge32 sge32[1];
|
||||
struct megasas_sge64 sge64[1];
|
||||
struct megasas_sge_skinny sge_skinny[1];
|
||||
|
||||
DECLARE_FLEX_ARRAY(struct megasas_sge32, sge32);
|
||||
DECLARE_FLEX_ARRAY(struct megasas_sge64, sge64);
|
||||
DECLARE_FLEX_ARRAY(struct megasas_sge_skinny, sge_skinny);
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct megasas_header {
|
||||
|
@ -1133,18 +1133,18 @@ struct mpi3mr_ioc {
|
||||
u32 chain_buf_count;
|
||||
struct dma_pool *chain_buf_pool;
|
||||
struct chain_element *chain_sgl_list;
|
||||
void *chain_bitmap;
|
||||
unsigned long *chain_bitmap;
|
||||
spinlock_t chain_buf_lock;
|
||||
|
||||
struct mpi3mr_drv_cmd bsg_cmds;
|
||||
struct mpi3mr_drv_cmd host_tm_cmds;
|
||||
struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD];
|
||||
struct mpi3mr_drv_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD];
|
||||
void *devrem_bitmap;
|
||||
unsigned long *devrem_bitmap;
|
||||
u16 dev_handle_bitmap_bits;
|
||||
void *removepend_bitmap;
|
||||
unsigned long *removepend_bitmap;
|
||||
struct list_head delayed_rmhs_list;
|
||||
void *evtack_cmds_bitmap;
|
||||
unsigned long *evtack_cmds_bitmap;
|
||||
struct list_head delayed_evtack_cmds_list;
|
||||
|
||||
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,
|
||||
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) {
|
||||
complete(&cmdptr->done);
|
||||
cmdptr->is_waiting = 0;
|
||||
@ -1134,7 +1139,7 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
|
||||
static int
|
||||
mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
|
||||
{
|
||||
void *removepend_bitmap;
|
||||
unsigned long *removepend_bitmap;
|
||||
|
||||
if (mrioc->facts.reply_sz > mrioc->reply_sz) {
|
||||
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),
|
||||
GFP_KERNEL);
|
||||
if (!sas_expander)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
sas_expander->handle = handle;
|
||||
sas_expander->num_phys = expander_pg0.num_phys;
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
config SCSI_MVSAS
|
||||
tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support"
|
||||
depends on PCI
|
||||
depends on PCI && HAS_IOPORT
|
||||
select SCSI_SAS_LIBSAS
|
||||
select FW_LOADER
|
||||
help
|
||||
|
@ -12,6 +12,7 @@ if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m
|
||||
|
||||
config PCMCIA_AHA152X
|
||||
tristate "Adaptec AHA152X PCMCIA support"
|
||||
depends on HAS_IOPORT
|
||||
select SCSI_SPI_ATTRS
|
||||
help
|
||||
Say Y here if you intend to attach this type of PCMCIA SCSI host
|
||||
@ -22,6 +23,7 @@ config PCMCIA_AHA152X
|
||||
|
||||
config PCMCIA_FDOMAIN
|
||||
tristate "Future Domain PCMCIA support"
|
||||
depends on HAS_IOPORT
|
||||
select SCSI_FDOMAIN
|
||||
help
|
||||
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
|
||||
tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
|
||||
depends on !64BIT || COMPILE_TEST
|
||||
depends on (!64BIT || COMPILE_TEST) && HAS_IOPORT
|
||||
help
|
||||
If you intend to attach this type of PCMCIA SCSI host adapter to
|
||||
your computer, say Y here and read
|
||||
@ -66,6 +68,7 @@ config PCMCIA_NINJA_SCSI
|
||||
|
||||
config PCMCIA_QLOGIC
|
||||
tristate "Qlogic PCMCIA support"
|
||||
depends on HAS_IOPORT
|
||||
help
|
||||
Say Y here if you intend to attach this type of PCMCIA SCSI host
|
||||
adapter to your computer.
|
||||
@ -75,6 +78,7 @@ config PCMCIA_QLOGIC
|
||||
|
||||
config PCMCIA_SYM53C500
|
||||
tristate "Symbios 53c500 PCMCIA support"
|
||||
depends on HAS_IOPORT
|
||||
help
|
||||
Say Y here if you have a New Media Bus Toaster or other PCMCIA
|
||||
SCSI adapter based on the Symbios 53c500 controller.
|
||||
|
@ -43,7 +43,8 @@
|
||||
#include "pm8001_chips.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_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,
|
||||
* 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 sas_add[8];
|
||||
@ -679,6 +680,12 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
|
||||
struct pm8001_ioctl_payload payload;
|
||||
u16 deviceid;
|
||||
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);
|
||||
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.func_specific = kzalloc(payload.rd_length, GFP_KERNEL);
|
||||
if (!payload.func_specific) {
|
||||
pm8001_dbg(pm8001_ha, INIT, "mem alloc fail\n");
|
||||
return;
|
||||
pm8001_dbg(pm8001_ha, FAIL, "mem alloc fail\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
rc = PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload);
|
||||
if (rc) {
|
||||
kfree(payload.func_specific);
|
||||
pm8001_dbg(pm8001_ha, INIT, "nvmd failed\n");
|
||||
return;
|
||||
pm8001_dbg(pm8001_ha, FAIL, "nvmd failed\n");
|
||||
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++) {
|
||||
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,
|
||||
SAS_ADDR_SIZE);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1166,7 +1181,8 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
|
||||
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 */
|
||||
rc = pm8001_configure_phy_settings(pm8001_ha);
|
||||
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;
|
||||
phy = &pm8001_ha->phy[phy_id];
|
||||
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) {
|
||||
case PHY_FUNC_SET_LINK_RATE:
|
||||
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_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
|
||||
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)) {
|
||||
struct sas_phy *phy = sas_get_local_phy(dev);
|
||||
sas_execute_internal_abort_dev(dev, 0, NULL);
|
||||
|
@ -71,6 +71,7 @@
|
||||
#define PM8001_DEV_LOGGING 0x80 /* development message logging */
|
||||
#define PM8001_DEVIO_LOGGING 0x100 /* development io 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, ...) \
|
||||
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_phy *phy = &pm8001_ha->phy[phy_id];
|
||||
unsigned long flags;
|
||||
pm8001_dbg(pm8001_ha, DEVIO,
|
||||
"port id %d, phy id %d link_rate %d portstate 0x%x\n",
|
||||
port_id, phy_id, link_rate, portstate);
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_SATA_PHY_UP phyid:%#x port_id:%#x link_rate:%d portstate:%#x\n",
|
||||
phy_id, port_id, link_rate, portstate);
|
||||
|
||||
phy->port = port;
|
||||
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;
|
||||
switch (portstate) {
|
||||
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;
|
||||
case PORT_INVALID:
|
||||
pm8001_dbg(pm8001_ha, MSG, " PortInvalid portID %d\n",
|
||||
port_id);
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_INVALID\n",
|
||||
phy_id, port_id);
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
" Last phy Down and port invalid\n");
|
||||
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);
|
||||
break;
|
||||
case PORT_IN_RESET:
|
||||
pm8001_dbg(pm8001_ha, MSG, " Port In Reset portID %d\n",
|
||||
port_id);
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_IN_RESET\n",
|
||||
phy_id, port_id);
|
||||
break;
|
||||
case PORT_NOT_ESTABLISHED:
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
" Phy Down and PORT_NOT_ESTABLISHED\n");
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_NOT_ESTABLISHED\n",
|
||||
phy_id, port_id);
|
||||
port->port_attached = 0;
|
||||
break;
|
||||
case PORT_LOSTCOMM:
|
||||
pm8001_dbg(pm8001_ha, MSG, " Phy Down and PORT_LOSTCOMM\n");
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
" Last phy Down and port invalid\n");
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_LOSTCOMM\n",
|
||||
phy_id, port_id);
|
||||
pm8001_dbg(pm8001_ha, MSG, " Last phy Down and port invalid\n");
|
||||
if (port_sata) {
|
||||
port->port_attached = 0;
|
||||
phy->phy_type = 0;
|
||||
@ -3328,9 +3335,9 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
break;
|
||||
default:
|
||||
port->port_attached = 0;
|
||||
pm8001_dbg(pm8001_ha, DEVIO,
|
||||
" Phy Down and(default) = 0x%x\n",
|
||||
portstate);
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate:%#x\n",
|
||||
phy_id, port_id, portstate);
|
||||
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 phy_id =
|
||||
(u8)((phyid_npip_portstate & 0xFF0000) >> 16);
|
||||
u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F);
|
||||
u16 eventType =
|
||||
(u16)((lr_status_evt_portid & 0x00FFFF00) >> 8);
|
||||
u8 status =
|
||||
@ -3425,26 +3433,29 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
switch (eventType) {
|
||||
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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,
|
||||
GFP_ATOMIC);
|
||||
break;
|
||||
case HW_EVENT_PHY_DOWN:
|
||||
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_DOWN\n");
|
||||
hw_event_phy_down(pm8001_ha, piomb);
|
||||
phy->phy_attached = 0;
|
||||
phy->phy_state = PHY_LINK_DISABLE;
|
||||
break;
|
||||
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);
|
||||
phy->phy_attached = 0;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
phy->phy_attached = 0;
|
||||
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);
|
||||
break;
|
||||
case HW_EVENT_LINK_ERR_INVALID_DWORD:
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
"HW_EVENT_LINK_ERR_INVALID_DWORD\n");
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_LINK_ERR_INVALID_DWORD phyid:%#x port_id:%#x\n",
|
||||
phy_id, port_id);
|
||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||
HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0);
|
||||
break;
|
||||
case HW_EVENT_LINK_ERR_DISPARITY_ERROR:
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
"HW_EVENT_LINK_ERR_DISPARITY_ERROR\n");
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_LINK_ERR_DISPARITY_ERROR phyid:%#x port_id:%#x\n",
|
||||
phy_id, port_id);
|
||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||
HW_EVENT_LINK_ERR_DISPARITY_ERROR,
|
||||
port_id, phy_id, 0, 0);
|
||||
break;
|
||||
case HW_EVENT_LINK_ERR_CODE_VIOLATION:
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
"HW_EVENT_LINK_ERR_CODE_VIOLATION\n");
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_LINK_ERR_CODE_VIOLATION phyid:%#x port_id:%#x\n",
|
||||
phy_id, port_id);
|
||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||
HW_EVENT_LINK_ERR_CODE_VIOLATION,
|
||||
port_id, phy_id, 0, 0);
|
||||
break;
|
||||
case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH:
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
"HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n");
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"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,
|
||||
HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH,
|
||||
port_id, phy_id, 0, 0);
|
||||
break;
|
||||
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;
|
||||
case HW_EVENT_BROADCAST_SES:
|
||||
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);
|
||||
break;
|
||||
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,
|
||||
HW_EVENT_INBOUND_CRC_ERROR,
|
||||
port_id, phy_id, 0, 0);
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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);
|
||||
phy->phy_attached = 0;
|
||||
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
|
||||
GFP_ATOMIC);
|
||||
break;
|
||||
case HW_EVENT_LINK_ERR_PHY_RESET_FAILED:
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
"HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n");
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"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,
|
||||
HW_EVENT_LINK_ERR_PHY_RESET_FAILED,
|
||||
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);
|
||||
break;
|
||||
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) {
|
||||
pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
|
||||
port_id, phy_id, 0, 0);
|
||||
}
|
||||
sas_phy_disconnected(sas_phy);
|
||||
phy->phy_attached = 0;
|
||||
port->port_state = portstate;
|
||||
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
|
||||
GFP_ATOMIC);
|
||||
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;
|
||||
case HW_EVENT_PORT_RECOVERY_TIMER_TMO:
|
||||
pm8001_dbg(pm8001_ha, MSG,
|
||||
"HW_EVENT_PORT_RECOVERY_TIMER_TMO\n");
|
||||
pm8001_dbg(pm8001_ha, EVENT,
|
||||
"HW_EVENT_PORT_RECOVERY_TIMER_TMO phyid:%#x port_id:%#x\n",
|
||||
phy_id, port_id);
|
||||
pm80xx_hw_event_ack_req(pm8001_ha, 0,
|
||||
HW_EVENT_PORT_RECOVERY_TIMER_TMO,
|
||||
port_id, phy_id, 0, 0);
|
||||
@ -3575,24 +3602,32 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
}
|
||||
break;
|
||||
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);
|
||||
break;
|
||||
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) {
|
||||
pm8001_ha->phy[phy_id].port_reset_status =
|
||||
PORT_RESET_SUCCESS;
|
||||
complete(pm8001_ha->phy[phy_id].reset_completion);
|
||||
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;
|
||||
case EVENT_BROADCAST_ASYNCH_EVENT:
|
||||
pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n");
|
||||
break;
|
||||
default:
|
||||
pm8001_dbg(pm8001_ha, DEVIO, "Unknown event type 0x%x\n",
|
||||
eventType);
|
||||
pm8001_dbg(pm8001_ha, DEVIO,
|
||||
"Unknown event portid:%d phyid:%d event:0x%x status:0x%x\n",
|
||||
port_id, phy_id, eventType, status);
|
||||
break;
|
||||
}
|
||||
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,
|
||||
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,
|
||||
sizeof(payload), 0);
|
||||
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.ppc_phyid =
|
||||
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",
|
||||
le32_to_cpu(payload.ppc_phyid), length);
|
||||
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
|
||||
*/
|
||||
if (!qedf->p_cpuq) {
|
||||
status = -EINVAL;
|
||||
QEDF_ERR(&qedf->dbg_ctx, "p_cpuq is NULL.\n");
|
||||
goto mem_alloc_failure;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qedf->global_queues = kzalloc((sizeof(struct global_queue *)
|
||||
|
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config SCSI_QLA_FC
|
||||
tristate "QLogic QLA2XXX Fibre Channel Support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && HAS_IOPORT && SCSI
|
||||
depends on SCSI_FC_ATTRS
|
||||
depends on NVME_FC || !NVME_FC
|
||||
select FW_LOADER
|
||||
|
@ -2750,6 +2750,7 @@ static void
|
||||
qla2x00_terminate_rport_io(struct fc_rport *rport)
|
||||
{
|
||||
fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
|
||||
scsi_qla_host_t *vha;
|
||||
|
||||
if (!fcport)
|
||||
return;
|
||||
@ -2759,9 +2760,12 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
|
||||
|
||||
if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
|
||||
return;
|
||||
vha = fcport->vha;
|
||||
|
||||
if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) {
|
||||
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;
|
||||
}
|
||||
/*
|
||||
@ -2786,6 +2790,15 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
|
||||
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
|
||||
|
@ -283,6 +283,10 @@ qla2x00_process_els(struct bsg_job *bsg_job)
|
||||
|
||||
if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
|
||||
rport = fc_bsg_to_rport(bsg_job);
|
||||
if (!rport) {
|
||||
rval = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
fcport = *(fc_port_t **) rport->dd_data;
|
||||
host = rport_to_shost(rport);
|
||||
vha = shost_priv(host);
|
||||
@ -2992,6 +2996,8 @@ qla24xx_bsg_request(struct bsg_job *bsg_job)
|
||||
|
||||
if (bsg_request->msgcode == FC_BSG_RPT_ELS) {
|
||||
rport = fc_bsg_to_rport(bsg_job);
|
||||
if (!rport)
|
||||
return ret;
|
||||
host = rport_to_shost(rport);
|
||||
vha = shost_priv(host);
|
||||
} else {
|
||||
|
@ -465,6 +465,15 @@ static inline be_id_t port_id_to_be_id(port_id_t port_id)
|
||||
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 {
|
||||
uint8_t opcode;
|
||||
uint8_t rsvd[3];
|
||||
@ -544,6 +553,10 @@ struct srb_iocb {
|
||||
uint32_t data;
|
||||
struct completion comp;
|
||||
__le16 comp_status;
|
||||
|
||||
uint8_t modifier;
|
||||
uint8_t vp_index;
|
||||
uint16_t loop_id;
|
||||
} tmf;
|
||||
struct {
|
||||
#define SRB_FXDISC_REQ_DMA_VALID BIT_0
|
||||
@ -647,6 +660,7 @@ struct srb_iocb {
|
||||
#define SRB_SA_UPDATE 25
|
||||
#define SRB_ELS_CMD_HST_NOLOGIN 26
|
||||
#define SRB_SA_REPLACE 27
|
||||
#define SRB_MARKER 28
|
||||
|
||||
struct qla_els_pt_arg {
|
||||
u8 els_opcode;
|
||||
@ -689,7 +703,6 @@ typedef struct srb {
|
||||
struct iocb_resource iores;
|
||||
struct kref cmd_kref; /* need to migrate ref_count over to this */
|
||||
void *priv;
|
||||
wait_queue_head_t nvme_ls_waitq;
|
||||
struct fc_port *fcport;
|
||||
struct scsi_qla_host *vha;
|
||||
unsigned int start_timer:1;
|
||||
@ -2528,6 +2541,7 @@ enum rscn_addr_format {
|
||||
typedef struct fc_port {
|
||||
struct list_head list;
|
||||
struct scsi_qla_host *vha;
|
||||
struct list_head tmf_pending;
|
||||
|
||||
unsigned int conf_compl_supported:1;
|
||||
unsigned int deleted:2;
|
||||
@ -2548,6 +2562,8 @@ typedef struct fc_port {
|
||||
unsigned int do_prli_nvme:1;
|
||||
|
||||
uint8_t nvme_flag;
|
||||
uint8_t active_tmf;
|
||||
#define MAX_ACTIVE_TMF 8
|
||||
|
||||
uint8_t node_name[WWN_SIZE];
|
||||
uint8_t port_name[WWN_SIZE];
|
||||
@ -3157,12 +3173,12 @@ struct ct_sns_gpnft_rsp {
|
||||
uint8_t vendor_unique;
|
||||
};
|
||||
/* 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 port_id[3];
|
||||
u32 reserved;
|
||||
u8 port_name[8];
|
||||
} entries[1];
|
||||
}, entries);
|
||||
};
|
||||
|
||||
/* 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->flags
|
||||
|
||||
#define TMF_NOT_READY(_fcport) \
|
||||
(!_fcport || IS_SESSION_DELETED(_fcport) || atomic_read(&_fcport->state) != FCS_ONLINE || \
|
||||
!_fcport->vha->hw->flags.fw_started)
|
||||
|
||||
#endif
|
||||
|
@ -2361,8 +2361,8 @@ qla24xx_issue_sa_replace_iocb(scsi_qla_host_t *vha, struct qla_work_evt *e)
|
||||
if (!sa_ctl) {
|
||||
ql_dbg(ql_dbg_edif, vha, 0x70e6,
|
||||
"sa_ctl allocation failed\n");
|
||||
rval = -ENOMEM;
|
||||
goto done;
|
||||
rval = -ENOMEM;
|
||||
return rval;
|
||||
}
|
||||
|
||||
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_adisc(struct scsi_qla_host *, fc_port_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 *,
|
||||
enum qla_work_type);
|
||||
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;
|
||||
|
||||
rspsz = sizeof(struct ct_sns_gpnft_rsp) +
|
||||
((vha->hw->max_fibre_devices - 1) *
|
||||
sizeof(struct ct_sns_gpn_ft_data));
|
||||
vha->hw->max_fibre_devices *
|
||||
sizeof(struct ct_sns_gpn_ft_data);
|
||||
|
||||
sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev,
|
||||
rspsz,
|
||||
|
@ -1996,6 +1996,11 @@ qla2x00_tmf_iocb_timeout(void *data)
|
||||
int rc, h;
|
||||
unsigned long flags;
|
||||
|
||||
if (sp->type == SRB_MARKER) {
|
||||
complete(&tmf->u.tmf.comp);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = qla24xx_async_abort_cmd(sp, false);
|
||||
if (rc) {
|
||||
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)
|
||||
{
|
||||
struct srb_iocb *tmf = &sp->u.iocb_cmd;
|
||||
|
||||
if (res)
|
||||
tmf->u.tmf.data = res;
|
||||
complete(&tmf->u.tmf.comp);
|
||||
}
|
||||
|
||||
int
|
||||
qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
|
||||
uint32_t tag)
|
||||
static int
|
||||
__qla2x00_async_tm_cmd(struct tmf_arg *arg)
|
||||
{
|
||||
struct scsi_qla_host *vha = fcport->vha;
|
||||
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, 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 */
|
||||
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
|
||||
sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
|
||||
if (!sp)
|
||||
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;
|
||||
init_completion(&tm_iocb->u.tmf.comp);
|
||||
tm_iocb->u.tmf.flags = flags;
|
||||
tm_iocb->u.tmf.lun = lun;
|
||||
tm_iocb->u.tmf.flags = arg->flags;
|
||||
tm_iocb->u.tmf.lun = arg->lun;
|
||||
|
||||
START_SP_W_RETRIES(sp, rval);
|
||||
|
||||
ql_dbg(ql_dbg_taskm, vha, 0x802f,
|
||||
"Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
|
||||
sp->handle, fcport->loop_id, fcport->d_id.b.domain,
|
||||
fcport->d_id.b.area, fcport->d_id.b.al_pa);
|
||||
"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.b24,
|
||||
arg->flags, arg->lun, sp->qpair->id, rval);
|
||||
|
||||
rval = qla2x00_start_sp(sp);
|
||||
if (rval != QLA_SUCCESS)
|
||||
goto done_free_sp;
|
||||
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);
|
||||
}
|
||||
|
||||
if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
|
||||
flags = tm_iocb->u.tmf.flags;
|
||||
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);
|
||||
}
|
||||
if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw))
|
||||
rval = qla26xx_marker(arg);
|
||||
|
||||
done_free_sp:
|
||||
/* ref: INIT */
|
||||
@ -2080,6 +2186,115 @@ done:
|
||||
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
|
||||
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 &&
|
||||
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
||||
index < QLA_MODEL_NAMES)
|
||||
strlcpy(ha->model_desc,
|
||||
strscpy(ha->model_desc,
|
||||
qla2x00_model_name[index * 2 + 1],
|
||||
sizeof(ha->model_desc));
|
||||
} else {
|
||||
@ -4869,14 +5084,14 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
|
||||
if (use_tbl &&
|
||||
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
||||
index < QLA_MODEL_NAMES) {
|
||||
strlcpy(ha->model_number,
|
||||
strscpy(ha->model_number,
|
||||
qla2x00_model_name[index * 2],
|
||||
sizeof(ha->model_number));
|
||||
strlcpy(ha->model_desc,
|
||||
strscpy(ha->model_desc,
|
||||
qla2x00_model_name[index * 2 + 1],
|
||||
sizeof(ha->model_desc));
|
||||
} else {
|
||||
strlcpy(ha->model_number, def,
|
||||
strscpy(ha->model_number, def,
|
||||
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_LIST_HEAD(&fcport->gnl_entry);
|
||||
INIT_LIST_HEAD(&fcport->list);
|
||||
INIT_LIST_HEAD(&fcport->tmf_pending);
|
||||
|
||||
INIT_LIST_HEAD(&fcport->sess_cmd_list);
|
||||
spin_lock_init(&fcport->sess_cmd_lock);
|
||||
@ -5333,7 +5549,7 @@ static void qla_get_login_template(scsi_qla_host_t *vha)
|
||||
__be32 *q;
|
||||
|
||||
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,
|
||||
ha->init_cb, sz);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
@ -6004,7 +6220,6 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
|
||||
fc_port_t *fcport;
|
||||
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
||||
uint16_t loop_id;
|
||||
LIST_HEAD(new_fcports);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int discovery_gen;
|
||||
|
||||
|
@ -109,11 +109,13 @@ qla2x00_set_fcport_disc_state(fc_port_t *fcport, int state)
|
||||
{
|
||||
int old_val;
|
||||
uint8_t shiftbits, mask;
|
||||
uint8_t port_dstate_str_sz;
|
||||
|
||||
/* This will have to change when the max no. of states > 16 */
|
||||
shiftbits = 4;
|
||||
mask = (1 << shiftbits) - 1;
|
||||
|
||||
port_dstate_str_sz = sizeof(port_dstate_str) / sizeof(char *);
|
||||
fcport->disc_state = state;
|
||||
while (1) {
|
||||
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)) {
|
||||
ql_dbg(ql_dbg_disc, fcport->vha, 0x2134,
|
||||
"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);
|
||||
return;
|
||||
}
|
||||
|
@ -522,21 +522,25 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
|
||||
return (QLA_FUNCTION_FAILED);
|
||||
}
|
||||
|
||||
mrk24 = (struct mrk_entry_24xx *)mrk;
|
||||
|
||||
mrk->entry_type = MARKER_TYPE;
|
||||
mrk->modifier = type;
|
||||
if (type != MK_SYNC_ALL) {
|
||||
if (IS_FWI2_CAPABLE(ha)) {
|
||||
mrk24 = (struct mrk_entry_24xx *) mrk;
|
||||
mrk24->nport_handle = cpu_to_le16(loop_id);
|
||||
int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun);
|
||||
host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
|
||||
mrk24->vp_index = vha->vp_idx;
|
||||
mrk24->handle = make_handle(req->id, mrk24->handle);
|
||||
} else {
|
||||
SET_TARGET_ID(ha, mrk->target, loop_id);
|
||||
mrk->lun = cpu_to_le16((uint16_t)lun);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_FWI2_CAPABLE(ha))
|
||||
mrk24->handle = QLA_SKIP_HANDLE;
|
||||
|
||||
wmb();
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
return 0;
|
||||
}
|
||||
@ -2541,7 +2546,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
|
||||
scsi_qla_host_t *vha = fcport->vha;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
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;
|
||||
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->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);
|
||||
host_to_fcp_swap((uint8_t *)&tsk->lun,
|
||||
sizeof(tsk->lun));
|
||||
@ -3852,9 +3858,9 @@ static int qla_get_iocbs_resource(struct srb *sp)
|
||||
case SRB_NACK_LOGO:
|
||||
case SRB_LOGOUT_CMD:
|
||||
case SRB_CTRL_VP:
|
||||
push_it_through = true;
|
||||
fallthrough;
|
||||
case SRB_MARKER:
|
||||
default:
|
||||
push_it_through = true;
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
qla2x00_start_sp(srb_t *sp)
|
||||
{
|
||||
@ -3973,6 +3992,9 @@ qla2x00_start_sp(srb_t *sp)
|
||||
case SRB_SA_REPLACE:
|
||||
qla24xx_sa_replace_iocb(sp, pkt);
|
||||
break;
|
||||
case SRB_MARKER:
|
||||
qla_marker_iocb(sp, pkt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1862,9 +1862,9 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
|
||||
}
|
||||
}
|
||||
|
||||
srb_t *
|
||||
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
||||
struct req_que *req, void *iocb)
|
||||
static srb_t *
|
||||
qla_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
||||
struct req_que *req, void *iocb, u16 *ret_index)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
sts_entry_t *pkt = iocb;
|
||||
@ -1899,12 +1899,25 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req->outstanding_cmds[index] = NULL;
|
||||
|
||||
*ret_index = index;
|
||||
qla_put_fw_resources(sp->qpair, &sp->iores);
|
||||
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
|
||||
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
|
||||
struct mbx_entry *mbx)
|
||||
@ -3237,13 +3250,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
|
||||
return;
|
||||
}
|
||||
|
||||
req->outstanding_cmds[handle] = NULL;
|
||||
cp = GET_CMD_SP(sp);
|
||||
if (cp == NULL) {
|
||||
ql_dbg(ql_dbg_io, vha, 0x3018,
|
||||
"Command already returned (0x%x/%p).\n",
|
||||
sts->handle, sp);
|
||||
|
||||
req->outstanding_cmds[handle] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3514,6 +3527,9 @@ out:
|
||||
|
||||
if (rsp->status_srb == NULL)
|
||||
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);
|
||||
struct req_que *req = NULL;
|
||||
int res = DID_ERROR << 16;
|
||||
u16 index;
|
||||
|
||||
ql_dbg(ql_dbg_async, vha, 0x502a,
|
||||
"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) {
|
||||
case NOTIFY_ACK_TYPE:
|
||||
case STATUS_TYPE:
|
||||
case STATUS_CONT_TYPE:
|
||||
case LOGINOUT_PORT_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_CRC2:
|
||||
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:
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
* @vha: SCSI driver HA context
|
||||
@ -3866,9 +3912,7 @@ process_err:
|
||||
(struct nack_to_isp *)pkt);
|
||||
break;
|
||||
case MARKER_TYPE:
|
||||
/* Do nothing in this case, this check is to prevent it
|
||||
* from falling into default case
|
||||
*/
|
||||
qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt);
|
||||
break;
|
||||
case ABORT_IOCB_TYPE:
|
||||
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;
|
||||
|
||||
if (pci_is_pcie(ha->pdev))
|
||||
strlcpy(str, "PCIe iSA", str_len);
|
||||
strscpy(str, "PCIe iSA", str_len);
|
||||
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;
|
||||
memset(preg_hsi, 0, sizeof(struct register_host_info));
|
||||
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));
|
||||
strlcpy(phost_info->nodename, p_sysid->nodename,
|
||||
strscpy(phost_info->nodename, p_sysid->nodename,
|
||||
sizeof(phost_info->nodename));
|
||||
if (!strcmp(phost_info->nodename, "(none)"))
|
||||
ha->mr.host_info_resend = true;
|
||||
strlcpy(phost_info->release, p_sysid->release,
|
||||
strscpy(phost_info->release, p_sysid->release,
|
||||
sizeof(phost_info->release));
|
||||
strlcpy(phost_info->version, p_sysid->version,
|
||||
strscpy(phost_info->version, p_sysid->version,
|
||||
sizeof(phost_info->version));
|
||||
strlcpy(phost_info->machine, p_sysid->machine,
|
||||
strscpy(phost_info->machine, p_sysid->machine,
|
||||
sizeof(phost_info->machine));
|
||||
strlcpy(phost_info->domainname, p_sysid->domainname,
|
||||
strscpy(phost_info->domainname, p_sysid->domainname,
|
||||
sizeof(phost_info->domainname));
|
||||
strlcpy(phost_info->hostdriver, QLA2XXX_VERSION,
|
||||
strscpy(phost_info->hostdriver, QLA2XXX_VERSION,
|
||||
sizeof(phost_info->hostdriver));
|
||||
preg_hsi->utc = (uint64_t)ktime_get_real_seconds();
|
||||
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) {
|
||||
struct config_info_data *pinfo =
|
||||
(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));
|
||||
strlcpy(vha->hw->model_desc, pinfo->model_description,
|
||||
strscpy(vha->hw->model_desc, pinfo->model_description,
|
||||
ARRAY_SIZE(vha->hw->model_desc));
|
||||
memcpy(&vha->hw->mr.symbolic_name, pinfo->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) {
|
||||
ql_log(ql_log_warn, vha, 0x700e,
|
||||
"qla2x00_start_sp failed = %d\n", rval);
|
||||
wake_up(&sp->nvme_ls_waitq);
|
||||
sp->priv = NULL;
|
||||
priv->sp = NULL;
|
||||
qla2x00_rel_sp(sp);
|
||||
@ -652,7 +651,6 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
|
||||
if (!sp)
|
||||
return -EBUSY;
|
||||
|
||||
init_waitqueue_head(&sp->nvme_ls_waitq);
|
||||
kref_init(&sp->cmd_kref);
|
||||
spin_lock_init(&priv->cmd_lock);
|
||||
sp->priv = priv;
|
||||
@ -671,7 +669,6 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x212d,
|
||||
"qla2x00_start_nvme_mq failed = %d\n", rval);
|
||||
wake_up(&sp->nvme_ls_waitq);
|
||||
sp->priv = NULL;
|
||||
priv->sp = NULL;
|
||||
qla2xxx_rel_qpair_sp(sp->qpair, sp);
|
||||
|
@ -1078,43 +1078,6 @@ qc24_fail_command:
|
||||
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
|
||||
* Wait till the HBA is online after going through
|
||||
@ -1365,6 +1328,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define ABORT_POLLING_PERIOD 1000
|
||||
#define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD))
|
||||
|
||||
/*
|
||||
* 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;
|
||||
srb_t *sp;
|
||||
struct scsi_cmnd *cmd;
|
||||
unsigned long wait_iter = ABORT_WAIT_ITER;
|
||||
bool found;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
status = QLA_SUCCESS;
|
||||
|
||||
spin_lock_irqsave(qpair->qp_lock_ptr, flags);
|
||||
for (cnt = 1; status == QLA_SUCCESS &&
|
||||
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;
|
||||
while (wait_iter--) {
|
||||
found = false;
|
||||
|
||||
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
|
||||
status = qla2x00_eh_wait_on_command(cmd);
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
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,
|
||||
"Allocated the host=%p hw=%p vha=%p dev_name=%s",
|
||||
vha->host, vha->hw, vha,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user