diff --git a/kernel/kernel-rt/centos/build_srpm.data b/kernel/kernel-rt/centos/build_srpm.data index 2ed119b61..b0daa29a3 100644 --- a/kernel/kernel-rt/centos/build_srpm.data +++ b/kernel/kernel-rt/centos/build_srpm.data @@ -1,4 +1,4 @@ COPY_LIST="files/*" -TIS_PATCH_VER=3 +TIS_PATCH_VER=4 BUILD_IS_BIG=11 BUILD_IS_SLOW=12 diff --git a/kernel/kernel-rt/centos/meta_patches/Compile-issues.patch b/kernel/kernel-rt/centos/meta_patches/Compile-issues.patch index ea9896594..c7988ad28 100644 --- a/kernel/kernel-rt/centos/meta_patches/Compile-issues.patch +++ b/kernel/kernel-rt/centos/meta_patches/Compile-issues.patch @@ -1,22 +1,21 @@ -From d85ae09a0e333ba2c0b2630a1d4768655cacf481 Mon Sep 17 00:00:00 2001 -Message-Id: -In-Reply-To: <5d869ea9407975726a95d046391cd640b726ca93.1566591106.git.Jim.Somerville@windriver.com> -References: <5d869ea9407975726a95d046391cd640b726ca93.1566591106.git.Jim.Somerville@windriver.com> -From: Bin Yang -Date: Wed, 31 Jul 2019 14:23:20 +0800 +From fd3288457759c51746ad1c6cf26c883be36da86e Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <212f8edf21d8053d99c37d2ebfe3d723fb166bf7.1584131446.git.Jim.Somerville@windriver.com> +References: <212f8edf21d8053d99c37d2ebfe3d723fb166bf7.1584131446.git.Jim.Somerville@windriver.com> +From: Jim Somerville +Date: Fri, 13 Mar 2020 16:15:29 -0400 Subject: [PATCH 2/2] Compile issues -Signed-off-by: Bin Yang Signed-off-by: Jim Somerville --- SPECS/kernel-rt.spec | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SPECS/kernel-rt.spec b/SPECS/kernel-rt.spec -index f7aad95..29d3878 100644 +index 5660f0b..c37c238 100644 --- a/SPECS/kernel-rt.spec +++ b/SPECS/kernel-rt.spec -@@ -425,6 +425,11 @@ Patch1031: epoll-fix-use-after-free-in-eventpoll_release_file.patch +@@ -424,6 +424,11 @@ Patch1031: epoll-fix-use-after-free-in-eventpoll_release_file.patch Patch1032: ipvs-fix-memory-leak-in-ip_vs_ctl.c.patch Patch1033: rh-ext4-release-leaked-posix-acl-in-ext4_acl_chmod.patch Patch1034: rh-ext4-release-leaked-posix-acl-in-ext4_xattr_set_a.patch @@ -28,7 +27,7 @@ index f7aad95..29d3878 100644 BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root -@@ -798,6 +803,9 @@ ApplyPatch epoll-fix-use-after-free-in-eventpoll_release_file.patch +@@ -796,6 +801,9 @@ ApplyPatch epoll-fix-use-after-free-in-eventpoll_release_file.patch ApplyPatch ipvs-fix-memory-leak-in-ip_vs_ctl.c.patch ApplyPatch rh-ext4-release-leaked-posix-acl-in-ext4_acl_chmod.patch ApplyPatch rh-ext4-release-leaked-posix-acl-in-ext4_xattr_set_a.patch diff --git a/kernel/kernel-rt/centos/meta_patches/Kernel-source-patches-for-TiC.patch b/kernel/kernel-rt/centos/meta_patches/Kernel-source-patches-for-TiC.patch index 830af1e10..5ace23efe 100644 --- a/kernel/kernel-rt/centos/meta_patches/Kernel-source-patches-for-TiC.patch +++ b/kernel/kernel-rt/centos/meta_patches/Kernel-source-patches-for-TiC.patch @@ -1,21 +1,19 @@ -From 5d869ea9407975726a95d046391cd640b726ca93 Mon Sep 17 00:00:00 2001 -Message-Id: <5d869ea9407975726a95d046391cd640b726ca93.1566591106.git.Jim.Somerville@windriver.com> -From: Bin Yang -Date: Mon, 29 Jul 2019 11:48:49 -0400 +From 212f8edf21d8053d99c37d2ebfe3d723fb166bf7 Mon Sep 17 00:00:00 2001 +Message-Id: <212f8edf21d8053d99c37d2ebfe3d723fb166bf7.1584131446.git.Jim.Somerville@windriver.com> +From: Jim Somerville +Date: Fri, 13 Mar 2020 16:15:29 -0400 Subject: [PATCH 1/2] Kernel source patches for TiC -Signed-off-by: Bin Yang Signed-off-by: Jim Somerville -Signed-off-by: Robin Lu --- - SPECS/kernel-rt.spec | 71 ++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 71 insertions(+) + SPECS/kernel-rt.spec | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 69 insertions(+) diff --git a/SPECS/kernel-rt.spec b/SPECS/kernel-rt.spec -index adffde2..f7aad95 100644 +index c48b73e..5660f0b 100644 --- a/SPECS/kernel-rt.spec +++ b/SPECS/kernel-rt.spec -@@ -388,6 +388,43 @@ Source30002: kernel-3.10.0-x86_64-rt-trace.config.tis_extra +@@ -388,6 +388,42 @@ Source30002: kernel-3.10.0-x86_64-rt-trace.config.tis_extra # Empty final patch file to facilitate testing of kernel patches Patch999999: linux-kernel-test.patch @@ -33,7 +31,6 @@ index adffde2..f7aad95 100644 +Patch1011: PCI-Add-ACS-quirk-for-Intel-Fortville-NICs.patch +Patch1012: x86-enable-DMA-CMA-with-swiotlb.patch +Patch1013: Add-missing-ifdef-around-max-latency-variable.patch -+Patch1014: Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch +Patch1015: Enable-building-kernel-with-CONFIG_BLK_DEV_NBD.patch +Patch1016: x86-make-dma_alloc_coherent-return-zeroed-memory-if-.patch +Patch1018: Porting-Cacheinfo-from-Kernel-4.10.17.patch @@ -59,7 +56,7 @@ index adffde2..f7aad95 100644 BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root -@@ -727,6 +764,40 @@ cp %{SOURCE38} . +@@ -727,6 +763,39 @@ cp %{SOURCE38} . ## Apply Patches here ApplyPatch linux-kernel-test.patch @@ -77,7 +74,6 @@ index adffde2..f7aad95 100644 +ApplyPatch Notification-of-death-of-arbitrary-processes.patch +ApplyPatch x86-enable-DMA-CMA-with-swiotlb.patch +ApplyPatch Add-missing-ifdef-around-max-latency-variable.patch -+ApplyPatch Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch +ApplyPatch Enable-building-kernel-with-CONFIG_BLK_DEV_NBD.patch +ApplyPatch x86-make-dma_alloc_coherent-return-zeroed-memory-if-.patch +ApplyPatch Porting-Cacheinfo-from-Kernel-4.10.17.patch diff --git a/kernel/kernel-rt/centos/patches/Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch b/kernel/kernel-rt/centos/patches/Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch deleted file mode 100644 index 49c237eea..000000000 --- a/kernel/kernel-rt/centos/patches/Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch +++ /dev/null @@ -1,34236 +0,0 @@ -From a1917d52235bec6b7a7d9758e9b0311e24e810de Mon Sep 17 00:00:00 2001 -Message-Id: -In-Reply-To: -References: -From: Chris Friesen -Date: Mon, 9 Jan 2017 15:03:00 -0500 -Subject: [PATCH 15/32] Enable building mpt2sas and mpt3sas as builtin for - CentOS 7.3 - -In CentOS 7.3 the upstream mpt2sas/mpt3sas drivers are built from -essentially the same codebase with a flag defined to give the mpt2sas -behaviour. This is purely a problem in 7.3 due to how they have mangled -the drivers. More recently in the Linux kernel these have been merged -into a single driver, while previously in 7.2 they were two totally -separate drivers. - -The 7.3 code works fine when building as modules, but when building as -builtin it gives problems because KBUILD_MODNAME is not defined for files -that are included in multiple drivers. - -The workaround is to move the mpt2sas driver into its own directory, -copying the whole mpt3sas codebase into it. This required a number of -changes after duplicating the codebase: - -1) Add knowledge of the new "mpt2sas" directory to from drivers/scsi/Kconfig -and drivers/scsi/Makefile. - -2) Remove mention of mpt2sas from drivers/scsi/mpt3sas/Kconfig and -drivers/scsi/mpt3sas/Makefile. - -3) Remove mention of mpt3sas from drivers/scsi/mpt2sas/Kconfig and -drivers/scsi/mpt2sas/Makefile. - -4) In the mpt2sas directory, all functions/variables with "mpt3sas" in -the name which did not already have an mpt2sas equivalent were renamed -to instead use "mpt2sas". Thus "_mpt3sas_init" became "_mpt2sas_init". - -5) All other symbols that collided between the two modules were renamed -in the mpt2sas driver by appending "_mpt2sas". This included ones with -"mpt2sas" already in the name, so "mpt2sas_raid_template" became -"mpt2sas_raid_template_mpt2sas". (While the version in the mpt3sas -driver remained "mpt2sas_raid_template".) - -Signed-off-by: Jim Somerville ---- - drivers/scsi/Kconfig | 1 + - drivers/scsi/Makefile | 1 + - drivers/scsi/mpt2sas/Kconfig | 61 + - drivers/scsi/mpt2sas/Makefile | 12 + - drivers/scsi/mpt2sas/mpi/mpi2.h | 1243 ++++ - drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 3493 ++++++++++ - drivers/scsi/mpt2sas/mpi/mpi2_init.h | 581 ++ - drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 1860 +++++ - drivers/scsi/mpt2sas/mpi/mpi2_raid.h | 355 + - drivers/scsi/mpt2sas/mpi/mpi2_sas.h | 303 + - drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 483 ++ - drivers/scsi/mpt2sas/mpi/mpi2_type.h | 57 + - drivers/scsi/mpt2sas/mpt3sas_base.c | 5713 ++++++++++++++++ - drivers/scsi/mpt2sas/mpt3sas_base.h | 1462 ++++ - drivers/scsi/mpt2sas/mpt3sas_config.c | 1716 +++++ - drivers/scsi/mpt2sas/mpt3sas_ctl.c | 3483 ++++++++++ - drivers/scsi/mpt2sas/mpt3sas_ctl.h | 423 ++ - drivers/scsi/mpt2sas/mpt3sas_debug.h | 206 + - drivers/scsi/mpt2sas/mpt3sas_scsih.c | 9356 ++++++++++++++++++++++++++ - drivers/scsi/mpt2sas/mpt3sas_transport.c | 2138 ++++++ - drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c | 434 ++ - drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h | 194 + - drivers/scsi/mpt2sas/mpt3sas_warpdrive.c | 344 + - drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c | 4 + - drivers/scsi/mpt3sas/Kconfig | 20 - - drivers/scsi/mpt3sas/Makefile | 9 - - 26 files changed, 33923 insertions(+), 29 deletions(-) - create mode 100644 drivers/scsi/mpt2sas/Kconfig - create mode 100644 drivers/scsi/mpt2sas/Makefile - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_init.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_ioc.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_raid.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_sas.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_tool.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_type.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_base.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_base.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_config.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_ctl.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_ctl.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_debug.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_scsih.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_transport.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_warpdrive.c - create mode 100644 drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c - -diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig -index 4cb0e23..4d79408 100644 ---- a/drivers/scsi/Kconfig -+++ b/drivers/scsi/Kconfig -@@ -599,6 +599,7 @@ config SCSI_ARCMSR - module will be called arcmsr (modprobe arcmsr). - - source "drivers/scsi/megaraid/Kconfig.megaraid" -+source "drivers/scsi/mpt2sas/Kconfig" - source "drivers/scsi/mpt3sas/Kconfig" - source "drivers/scsi/smartpqi/Kconfig" - source "drivers/scsi/ufs/Kconfig" -diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile -index 95aed68..1a08fca 100644 ---- a/drivers/scsi/Makefile -+++ b/drivers/scsi/Makefile -@@ -109,6 +109,7 @@ obj-$(CONFIG_CXLFLASH) += cxlflash/ - obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o - obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ - obj-$(CONFIG_MEGARAID_SAS) += megaraid/ -+obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/ - obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas/ - obj-$(CONFIG_SCSI_UFSHCD) += ufs/ - obj-$(CONFIG_SCSI_ACARD) += atp870u.o -diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig -new file mode 100644 -index 0000000..a53ee73 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/Kconfig -@@ -0,0 +1,61 @@ -+# -+# Kernel configuration file for the MPT2SAS -+# -+# This code is based on drivers/scsi/mpt3sas/Kconfig -+# Copyright (C) 2012-2014 LSI Corporation -+# (mailto:DL-MPTFusionLinux@lsi.com) -+ -+# This program is free software; you can redistribute it and/or -+# modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation; either version 2 -+# of the License, or (at your option) any later version. -+ -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+ -+# NO WARRANTY -+# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+# solely responsible for determining the appropriateness of using and -+# distributing the Program and assumes all risks associated with its -+# exercise of rights under this Agreement, including but not limited to -+# the risks and costs of program errors, damage to or loss of data, -+# programs or equipment, and unavailability or interruption of operations. -+ -+# DISCLAIMER OF LIABILITY -+# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+# USA. -+ -+config SCSI_MPT2SAS -+ tristate "LSI MPT Fusion SAS 2.0 Device Driver" -+ depends on PCI && SCSI -+ select SCSI_SAS_ATTRS -+ select RAID_ATTRS -+ ---help--- -+ This driver supports PCI-Express SAS 6Gb/s Host Adapters. -+ -+config SCSI_MPT2SAS_MAX_SGE -+ int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)" -+ depends on PCI && SCSI && SCSI_MPT2SAS -+ default "128" -+ range 16 256 -+ ---help--- -+ This option allows you to specify the maximum number of scatter- -+ gather entries per I/O. The driver default is 128, which matches -+ MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this -+ can be 256. However, it may decreased down to 16. Decreasing this -+ parameter will reduce memory requirements on a per controller instance. -diff --git a/drivers/scsi/mpt2sas/Makefile b/drivers/scsi/mpt2sas/Makefile -new file mode 100644 -index 0000000..5706ea4 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/Makefile -@@ -0,0 +1,12 @@ -+# mpt2-3sas makefile -+ -+obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o -+ -+obj-m += mpt2sas.o -+mpt2sas-y += mpt3sas_base.o \ -+ mpt3sas_config.o \ -+ wrapper_mpt3sas_scsih.o \ -+ mpt3sas_transport.o \ -+ mpt3sas_ctl.o \ -+ mpt3sas_trigger_diag.o \ -+ mpt3sas_warpdrive.o -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h -new file mode 100644 -index 0000000..a9a659f ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h -@@ -0,0 +1,1243 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2.h -+ * Title: MPI Message independent structures and definitions -+ * including System Interface Register Set and -+ * scatter/gather formats. -+ * Creation Date: June 21, 2006 -+ * -+ * mpi2.h Version: 02.00.42 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Moved ReplyPostHostIndex register to offset 0x6C of the -+ * MPI2_SYSTEM_INTERFACE_REGS and modified the define for -+ * MPI2_REPLY_POST_HOST_INDEX_OFFSET. -+ * Added union of request descriptors. -+ * Added union of reply descriptors. -+ * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added define for MPI2_VERSION_02_00. -+ * Fixed the size of the FunctionDependent5 field in the -+ * MPI2_DEFAULT_REPLY structure. -+ * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Removed the MPI-defined Fault Codes and extended the -+ * product specific codes up to 0xEFFF. -+ * Added a sixth key value for the WriteSequence register -+ * and changed the flush value to 0x0. -+ * Added message function codes for Diagnostic Buffer Post -+ * and Diagnsotic Release. -+ * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED -+ * Moved MPI2_VERSION_UNION from mpi2_ioc.h. -+ * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added #defines for marking a reply descriptor as unused. -+ * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Moved LUN field defines from mpi2_init.h. -+ * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. -+ * In all request and reply descriptors, replaced VF_ID -+ * field with MSIxIndex field. -+ * Removed DevHandle field from -+ * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those -+ * bytes reserved. -+ * Added RAID Accelerator functionality. -+ * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added MSI-x index mask and shift for Reply Post Host -+ * Index register. -+ * Added function code for Host Based Discovery Action. -+ * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. -+ * Added defines for product-specific range of message -+ * function codes, 0xF0 to 0xFF. -+ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added alternative defines for the SGE Direction bit. -+ * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. -+ * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. -+ * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Incorporating additions for MPI v2.5. -+ * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added Hard Reset delay timings. -+ * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET. -+ * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT -+ * 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 11-18-14 02.00.36 Updated copyright information. -+ * Bumped MPI2_HEADER_VERSION_UNIT. -+ * 03-16-15 02.00.37 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added Scratchpad registers to -+ * MPI2_SYSTEM_INTERFACE_REGS. -+ * Added MPI2_DIAG_SBR_RELOAD. -+ * 03-19-15 02.00.38 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 05-25-15 02.00.39 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 08-25-15 02.00.40 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 12-15-15 02.00.41 Bumped MPI_HEADER_VERSION_UNIT -+ * 01-01-16 02.00.42 Bumped MPI_HEADER_VERSION_UNIT -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_H -+#define MPI2_H -+ -+/***************************************************************************** -+* -+* MPI Version Definitions -+* -+*****************************************************************************/ -+ -+#define MPI2_VERSION_MAJOR_MASK (0xFF00) -+#define MPI2_VERSION_MAJOR_SHIFT (8) -+#define MPI2_VERSION_MINOR_MASK (0x00FF) -+#define MPI2_VERSION_MINOR_SHIFT (0) -+ -+/*major version for all MPI v2.x */ -+#define MPI2_VERSION_MAJOR (0x02) -+ -+/*minor version for MPI v2.0 compatible products */ -+#define MPI2_VERSION_MINOR (0x00) -+#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ -+ MPI2_VERSION_MINOR) -+#define MPI2_VERSION_02_00 (0x0200) -+ -+/*minor version for MPI v2.5 compatible products */ -+#define MPI25_VERSION_MINOR (0x05) -+#define MPI25_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ -+ MPI25_VERSION_MINOR) -+#define MPI2_VERSION_02_05 (0x0205) -+ -+/*minor version for MPI v2.6 compatible products */ -+#define MPI26_VERSION_MINOR (0x06) -+#define MPI26_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ -+ MPI26_VERSION_MINOR) -+#define MPI2_VERSION_02_06 (0x0206) -+ -+/*Unit and Dev versioning for this MPI header set */ -+#define MPI2_HEADER_VERSION_UNIT (0x2A) -+#define MPI2_HEADER_VERSION_DEV (0x00) -+#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) -+#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) -+#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) -+#define MPI2_HEADER_VERSION_DEV_SHIFT (0) -+#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \ -+ MPI2_HEADER_VERSION_DEV) -+ -+/***************************************************************************** -+* -+* IOC State Definitions -+* -+*****************************************************************************/ -+ -+#define MPI2_IOC_STATE_RESET (0x00000000) -+#define MPI2_IOC_STATE_READY (0x10000000) -+#define MPI2_IOC_STATE_OPERATIONAL (0x20000000) -+#define MPI2_IOC_STATE_FAULT (0x40000000) -+ -+#define MPI2_IOC_STATE_MASK (0xF0000000) -+#define MPI2_IOC_STATE_SHIFT (28) -+ -+/*Fault state range for prodcut specific codes */ -+#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000) -+#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF) -+ -+/***************************************************************************** -+* -+* System Interface Register Definitions -+* -+*****************************************************************************/ -+ -+typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS { -+ U32 Doorbell; /*0x00 */ -+ U32 WriteSequence; /*0x04 */ -+ U32 HostDiagnostic; /*0x08 */ -+ U32 Reserved1; /*0x0C */ -+ U32 DiagRWData; /*0x10 */ -+ U32 DiagRWAddressLow; /*0x14 */ -+ U32 DiagRWAddressHigh; /*0x18 */ -+ U32 Reserved2[5]; /*0x1C */ -+ U32 HostInterruptStatus; /*0x30 */ -+ U32 HostInterruptMask; /*0x34 */ -+ U32 DCRData; /*0x38 */ -+ U32 DCRAddress; /*0x3C */ -+ U32 Reserved3[2]; /*0x40 */ -+ U32 ReplyFreeHostIndex; /*0x48 */ -+ U32 Reserved4[8]; /*0x4C */ -+ U32 ReplyPostHostIndex; /*0x6C */ -+ U32 Reserved5; /*0x70 */ -+ U32 HCBSize; /*0x74 */ -+ U32 HCBAddressLow; /*0x78 */ -+ U32 HCBAddressHigh; /*0x7C */ -+ U32 Reserved6[12]; /*0x80 */ -+ U32 Scratchpad[4]; /*0xB0 */ -+ U32 RequestDescriptorPostLow; /*0xC0 */ -+ U32 RequestDescriptorPostHigh; /*0xC4 */ -+ U32 AtomicRequestDescriptorPost;/*0xC8 */ -+ U32 Reserved7[13]; /*0xCC */ -+} MPI2_SYSTEM_INTERFACE_REGS, -+ *PTR_MPI2_SYSTEM_INTERFACE_REGS, -+ Mpi2SystemInterfaceRegs_t, -+ *pMpi2SystemInterfaceRegs_t; -+ -+/* -+ *Defines for working with the Doorbell register. -+ */ -+#define MPI2_DOORBELL_OFFSET (0x00000000) -+ -+/*IOC --> System values */ -+#define MPI2_DOORBELL_USED (0x08000000) -+#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000) -+#define MPI2_DOORBELL_WHO_INIT_SHIFT (24) -+#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF) -+#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF) -+ -+/*System --> IOC values */ -+#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000) -+#define MPI2_DOORBELL_FUNCTION_SHIFT (24) -+#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) -+#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16) -+ -+/* -+ *Defines for the WriteSequence register -+ */ -+#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) -+#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F) -+#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) -+#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) -+#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) -+#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) -+#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) -+#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) -+#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) -+ -+/* -+ *Defines for the HostDiagnostic register -+ */ -+#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008) -+ -+#define MPI2_DIAG_SBR_RELOAD (0x00002000) -+ -+#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800) -+#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000) -+#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800) -+ -+#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) -+#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200) -+#define MPI2_DIAG_HCB_MODE (0x00000100) -+#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080) -+#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040) -+#define MPI2_DIAG_RESET_HISTORY (0x00000020) -+#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010) -+#define MPI2_DIAG_RESET_ADAPTER (0x00000004) -+#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002) -+ -+/* -+ *Offsets for DiagRWData and address -+ */ -+#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010) -+#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014) -+#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018) -+ -+/* -+ *Defines for the HostInterruptStatus register -+ */ -+#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) -+#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000) -+#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS -+#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000) -+#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008) -+#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001) -+#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS -+ -+/* -+ *Defines for the HostInterruptMask register -+ */ -+#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034) -+#define MPI2_HIM_RESET_IRQ_MASK (0x40000000) -+#define MPI2_HIM_REPLY_INT_MASK (0x00000008) -+#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK -+#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001) -+#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK -+ -+/* -+ *Offsets for DCRData and address -+ */ -+#define MPI2_DCR_DATA_OFFSET (0x00000038) -+#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C) -+ -+/* -+ *Offset for the Reply Free Queue -+ */ -+#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) -+ -+/* -+ *Defines for the Reply Descriptor Post Queue -+ */ -+#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) -+#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) -+#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) -+#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) -+#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /*MPI v2.5 only*/ -+ -+ -+/* -+ *Defines for the HCBSize and address -+ */ -+#define MPI2_HCB_SIZE_OFFSET (0x00000074) -+#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000) -+#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001) -+ -+#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078) -+#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C) -+ -+/* -+ *Offsets for the Scratchpad registers -+ */ -+#define MPI26_SCRATCHPAD0_OFFSET (0x000000B0) -+#define MPI26_SCRATCHPAD1_OFFSET (0x000000B4) -+#define MPI26_SCRATCHPAD2_OFFSET (0x000000B8) -+#define MPI26_SCRATCHPAD3_OFFSET (0x000000BC) -+ -+/* -+ *Offsets for the Request Descriptor Post Queue -+ */ -+#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0) -+#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4) -+#define MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET (0x000000C8) -+ -+/*Hard Reset delay timings */ -+#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000) -+#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC (255000) -+#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC (256000) -+ -+/***************************************************************************** -+* -+* Message Descriptors -+* -+*****************************************************************************/ -+ -+/*Request Descriptors */ -+ -+/*Default Request Descriptor */ -+typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 DescriptorTypeDependent; /*0x06 */ -+} MPI2_DEFAULT_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR, -+ Mpi2DefaultRequestDescriptor_t, -+ *pMpi2DefaultRequestDescriptor_t; -+ -+/*defines for the RequestFlags field */ -+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x1E) -+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_RSHIFT (1) -+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) -+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) -+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) -+#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) -+#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A) -+#define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO (0x0C) -+ -+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) -+ -+/*High Priority Request Descriptor */ -+typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 Reserved1; /*0x06 */ -+} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, -+ Mpi2HighPriorityRequestDescriptor_t, -+ *pMpi2HighPriorityRequestDescriptor_t; -+ -+/*SCSI IO Request Descriptor */ -+typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 DevHandle; /*0x06 */ -+} MPI2_SCSI_IO_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR, -+ Mpi2SCSIIORequestDescriptor_t, -+ *pMpi2SCSIIORequestDescriptor_t; -+ -+/*SCSI Target Request Descriptor */ -+typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 IoIndex; /*0x06 */ -+} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, -+ Mpi2SCSITargetRequestDescriptor_t, -+ *pMpi2SCSITargetRequestDescriptor_t; -+ -+/*RAID Accelerator Request Descriptor */ -+typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 Reserved; /*0x06 */ -+} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, -+ Mpi2RAIDAcceleratorRequestDescriptor_t, -+ *pMpi2RAIDAcceleratorRequestDescriptor_t; -+ -+/*Fast Path SCSI IO Request Descriptor */ -+typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR -+ MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR, -+ *PTR_MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR, -+ Mpi25FastPathSCSIIORequestDescriptor_t, -+ *pMpi25FastPathSCSIIORequestDescriptor_t; -+ -+/*union of Request Descriptors */ -+typedef union _MPI2_REQUEST_DESCRIPTOR_UNION { -+ MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; -+ MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; -+ MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; -+ MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; -+ MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; -+ MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR FastPathSCSIIO; -+ U64 Words; -+} MPI2_REQUEST_DESCRIPTOR_UNION, -+ *PTR_MPI2_REQUEST_DESCRIPTOR_UNION, -+ Mpi2RequestDescriptorUnion_t, -+ *pMpi2RequestDescriptorUnion_t; -+ -+/*Atomic Request Descriptors */ -+ -+/* -+ * All Atomic Request Descriptors have the same format, so the following -+ * structure is used for all Atomic Request Descriptors: -+ * Atomic Default Request Descriptor -+ * Atomic High Priority Request Descriptor -+ * Atomic SCSI IO Request Descriptor -+ * Atomic SCSI Target Request Descriptor -+ * Atomic RAID Accelerator Request Descriptor -+ * Atomic Fast Path SCSI IO Request Descriptor -+ */ -+ -+/*Atomic Request Descriptor */ -+typedef struct _MPI26_ATOMIC_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /* 0x00 */ -+ U8 MSIxIndex; /* 0x01 */ -+ U16 SMID; /* 0x02 */ -+} MPI26_ATOMIC_REQUEST_DESCRIPTOR, -+ *PTR_MPI26_ATOMIC_REQUEST_DESCRIPTOR, -+ Mpi26AtomicRequestDescriptor_t, -+ *pMpi26AtomicRequestDescriptor_t; -+ -+/*for the RequestFlags field, use the same -+ *defines as MPI2_DEFAULT_REQUEST_DESCRIPTOR -+ */ -+ -+/*Reply Descriptors */ -+ -+/*Default Reply Descriptor */ -+typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 DescriptorTypeDependent1; /*0x02 */ -+ U32 DescriptorTypeDependent2; /*0x04 */ -+} MPI2_DEFAULT_REPLY_DESCRIPTOR, -+ *PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR, -+ Mpi2DefaultReplyDescriptor_t, -+ *pMpi2DefaultReplyDescriptor_t; -+ -+/*defines for the ReplyFlags field */ -+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) -+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) -+#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) -+#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) -+#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) -+#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05) -+#define MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS (0x06) -+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) -+ -+/*values for marking a reply descriptor as unused */ -+#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) -+#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF) -+ -+/*Address Reply Descriptor */ -+typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U32 ReplyFrameAddress; /*0x04 */ -+} MPI2_ADDRESS_REPLY_DESCRIPTOR, -+ *PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, -+ Mpi2AddressReplyDescriptor_t, -+ *pMpi2AddressReplyDescriptor_t; -+ -+#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00) -+ -+/*SCSI IO Success Reply Descriptor */ -+typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 TaskTag; /*0x04 */ -+ U16 Reserved1; /*0x06 */ -+} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, -+ *PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, -+ Mpi2SCSIIOSuccessReplyDescriptor_t, -+ *pMpi2SCSIIOSuccessReplyDescriptor_t; -+ -+/*TargetAssist Success Reply Descriptor */ -+typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U8 SequenceNumber; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 IoIndex; /*0x06 */ -+} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, -+ *PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, -+ Mpi2TargetAssistSuccessReplyDescriptor_t, -+ *pMpi2TargetAssistSuccessReplyDescriptor_t; -+ -+/*Target Command Buffer Reply Descriptor */ -+typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U8 VP_ID; /*0x02 */ -+ U8 Flags; /*0x03 */ -+ U16 InitiatorDevHandle; /*0x04 */ -+ U16 IoIndex; /*0x06 */ -+} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, -+ *PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, -+ Mpi2TargetCommandBufferReplyDescriptor_t, -+ *pMpi2TargetCommandBufferReplyDescriptor_t; -+ -+/*defines for Flags field */ -+#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F) -+ -+/*RAID Accelerator Success Reply Descriptor */ -+typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U32 Reserved; /*0x04 */ -+} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, -+ *PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, -+ Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, -+ *pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; -+ -+/*Fast Path SCSI IO Success Reply Descriptor */ -+typedef MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR -+ MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, -+ *PTR_MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, -+ Mpi25FastPathSCSIIOSuccessReplyDescriptor_t, -+ *pMpi25FastPathSCSIIOSuccessReplyDescriptor_t; -+ -+/*union of Reply Descriptors */ -+typedef union _MPI2_REPLY_DESCRIPTORS_UNION { -+ MPI2_DEFAULT_REPLY_DESCRIPTOR Default; -+ MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; -+ MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; -+ MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; -+ MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; -+ MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; -+ MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR FastPathSCSIIOSuccess; -+ U64 Words; -+} MPI2_REPLY_DESCRIPTORS_UNION, -+ *PTR_MPI2_REPLY_DESCRIPTORS_UNION, -+ Mpi2ReplyDescriptorsUnion_t, -+ *pMpi2ReplyDescriptorsUnion_t; -+ -+/***************************************************************************** -+* -+* Message Functions -+* -+*****************************************************************************/ -+ -+#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) -+#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) -+#define MPI2_FUNCTION_IOC_INIT (0x02) -+#define MPI2_FUNCTION_IOC_FACTS (0x03) -+#define MPI2_FUNCTION_CONFIG (0x04) -+#define MPI2_FUNCTION_PORT_FACTS (0x05) -+#define MPI2_FUNCTION_PORT_ENABLE (0x06) -+#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) -+#define MPI2_FUNCTION_EVENT_ACK (0x08) -+#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) -+#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) -+#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) -+#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) -+#define MPI2_FUNCTION_FW_UPLOAD (0x12) -+#define MPI2_FUNCTION_RAID_ACTION (0x15) -+#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) -+#define MPI2_FUNCTION_TOOLBOX (0x17) -+#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) -+#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) -+#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) -+#define MPI2_FUNCTION_IO_UNIT_CONTROL (0x1B) -+#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) -+#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) -+#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) -+#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) -+#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) -+#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) -+#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) -+#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) -+#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) -+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) -+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) -+ -+/*Doorbell functions */ -+#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) -+#define MPI2_FUNCTION_HANDSHAKE (0x42) -+ -+/***************************************************************************** -+* -+* IOC Status Values -+* -+*****************************************************************************/ -+ -+/*mask for IOCStatus status value */ -+#define MPI2_IOCSTATUS_MASK (0x7FFF) -+ -+/**************************************************************************** -+* Common IOCStatus values for all replies -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_SUCCESS (0x0000) -+#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001) -+#define MPI2_IOCSTATUS_BUSY (0x0002) -+#define MPI2_IOCSTATUS_INVALID_SGL (0x0003) -+#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004) -+#define MPI2_IOCSTATUS_INVALID_VPID (0x0005) -+#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) -+#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007) -+#define MPI2_IOCSTATUS_INVALID_STATE (0x0008) -+#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) -+#define MPI2_IOCSTATUS_INSUFFICIENT_POWER (0x000A) -+ -+/**************************************************************************** -+* Config IOCStatus values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) -+#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) -+#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) -+#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) -+#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) -+#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) -+ -+/**************************************************************************** -+* SCSI IO Reply -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) -+#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) -+#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) -+#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) -+#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) -+#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) -+#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) -+#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) -+#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) -+#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) -+#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) -+#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) -+ -+/**************************************************************************** -+* For use by SCSI Initiator and SCSI Target end-to-end data protection -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) -+#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) -+#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) -+ -+/**************************************************************************** -+* SCSI Target values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) -+#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063) -+#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) -+#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) -+#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) -+#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) -+#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) -+#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) -+#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) -+#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) -+ -+/**************************************************************************** -+* Serial Attached SCSI values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) -+#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) -+ -+/**************************************************************************** -+* Diagnostic Buffer Post / Diagnostic Release values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) -+ -+/**************************************************************************** -+* RAID Accelerator values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0) -+ -+/**************************************************************************** -+* IOCStatus flag to indicate that log info is available -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) -+ -+/**************************************************************************** -+* IOCLogInfo Types -+****************************************************************************/ -+ -+#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000) -+#define MPI2_IOCLOGINFO_TYPE_SHIFT (28) -+#define MPI2_IOCLOGINFO_TYPE_NONE (0x0) -+#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1) -+#define MPI2_IOCLOGINFO_TYPE_FC (0x2) -+#define MPI2_IOCLOGINFO_TYPE_SAS (0x3) -+#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4) -+#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) -+ -+/***************************************************************************** -+* -+* Standard Message Structures -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+*Request Message Header for all request messages -+****************************************************************************/ -+ -+typedef struct _MPI2_REQUEST_HEADER { -+ U16 FunctionDependent1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 FunctionDependent2; /*0x04 */ -+ U8 FunctionDependent3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+} MPI2_REQUEST_HEADER, *PTR_MPI2_REQUEST_HEADER, -+ MPI2RequestHeader_t, *pMPI2RequestHeader_t; -+ -+/**************************************************************************** -+* Default Reply -+****************************************************************************/ -+ -+typedef struct _MPI2_DEFAULT_REPLY { -+ U16 FunctionDependent1; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 FunctionDependent2; /*0x04 */ -+ U8 FunctionDependent3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U16 FunctionDependent5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_DEFAULT_REPLY, *PTR_MPI2_DEFAULT_REPLY, -+ MPI2DefaultReply_t, *pMPI2DefaultReply_t; -+ -+/*common version structure/union used in messages and configuration pages */ -+ -+typedef struct _MPI2_VERSION_STRUCT { -+ U8 Dev; /*0x00 */ -+ U8 Unit; /*0x01 */ -+ U8 Minor; /*0x02 */ -+ U8 Major; /*0x03 */ -+} MPI2_VERSION_STRUCT; -+ -+typedef union _MPI2_VERSION_UNION { -+ MPI2_VERSION_STRUCT Struct; -+ U32 Word; -+} MPI2_VERSION_UNION; -+ -+/*LUN field defines, common to many structures */ -+#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) -+#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) -+#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) -+#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) -+#define MPI2_LUN_LEVEL_1_WORD (0xFF00) -+#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00) -+ -+/***************************************************************************** -+* -+* Fusion-MPT MPI Scatter Gather Elements -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* MPI Simple Element structures -+****************************************************************************/ -+ -+typedef struct _MPI2_SGE_SIMPLE32 { -+ U32 FlagsLength; -+ U32 Address; -+} MPI2_SGE_SIMPLE32, *PTR_MPI2_SGE_SIMPLE32, -+ Mpi2SGESimple32_t, *pMpi2SGESimple32_t; -+ -+typedef struct _MPI2_SGE_SIMPLE64 { -+ U32 FlagsLength; -+ U64 Address; -+} MPI2_SGE_SIMPLE64, *PTR_MPI2_SGE_SIMPLE64, -+ Mpi2SGESimple64_t, *pMpi2SGESimple64_t; -+ -+typedef struct _MPI2_SGE_SIMPLE_UNION { -+ U32 FlagsLength; -+ union { -+ U32 Address32; -+ U64 Address64; -+ } u; -+} MPI2_SGE_SIMPLE_UNION, -+ *PTR_MPI2_SGE_SIMPLE_UNION, -+ Mpi2SGESimpleUnion_t, -+ *pMpi2SGESimpleUnion_t; -+ -+/**************************************************************************** -+* MPI Chain Element structures - for MPI v2.0 products only -+****************************************************************************/ -+ -+typedef struct _MPI2_SGE_CHAIN32 { -+ U16 Length; -+ U8 NextChainOffset; -+ U8 Flags; -+ U32 Address; -+} MPI2_SGE_CHAIN32, *PTR_MPI2_SGE_CHAIN32, -+ Mpi2SGEChain32_t, *pMpi2SGEChain32_t; -+ -+typedef struct _MPI2_SGE_CHAIN64 { -+ U16 Length; -+ U8 NextChainOffset; -+ U8 Flags; -+ U64 Address; -+} MPI2_SGE_CHAIN64, *PTR_MPI2_SGE_CHAIN64, -+ Mpi2SGEChain64_t, *pMpi2SGEChain64_t; -+ -+typedef struct _MPI2_SGE_CHAIN_UNION { -+ U16 Length; -+ U8 NextChainOffset; -+ U8 Flags; -+ union { -+ U32 Address32; -+ U64 Address64; -+ } u; -+} MPI2_SGE_CHAIN_UNION, -+ *PTR_MPI2_SGE_CHAIN_UNION, -+ Mpi2SGEChainUnion_t, -+ *pMpi2SGEChainUnion_t; -+ -+/**************************************************************************** -+* MPI Transaction Context Element structures - for MPI v2.0 products only -+****************************************************************************/ -+ -+typedef struct _MPI2_SGE_TRANSACTION32 { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ U32 TransactionContext[1]; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION32, -+ *PTR_MPI2_SGE_TRANSACTION32, -+ Mpi2SGETransaction32_t, -+ *pMpi2SGETransaction32_t; -+ -+typedef struct _MPI2_SGE_TRANSACTION64 { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ U32 TransactionContext[2]; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION64, -+ *PTR_MPI2_SGE_TRANSACTION64, -+ Mpi2SGETransaction64_t, -+ *pMpi2SGETransaction64_t; -+ -+typedef struct _MPI2_SGE_TRANSACTION96 { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ U32 TransactionContext[3]; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION96, *PTR_MPI2_SGE_TRANSACTION96, -+ Mpi2SGETransaction96_t, *pMpi2SGETransaction96_t; -+ -+typedef struct _MPI2_SGE_TRANSACTION128 { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ U32 TransactionContext[4]; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION128, *PTR_MPI2_SGE_TRANSACTION128, -+ Mpi2SGETransaction_t128, *pMpi2SGETransaction_t128; -+ -+typedef struct _MPI2_SGE_TRANSACTION_UNION { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ union { -+ U32 TransactionContext32[1]; -+ U32 TransactionContext64[2]; -+ U32 TransactionContext96[3]; -+ U32 TransactionContext128[4]; -+ } u; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION_UNION, -+ *PTR_MPI2_SGE_TRANSACTION_UNION, -+ Mpi2SGETransactionUnion_t, -+ *pMpi2SGETransactionUnion_t; -+ -+/**************************************************************************** -+* MPI SGE union for IO SGL's - for MPI v2.0 products only -+****************************************************************************/ -+ -+typedef struct _MPI2_MPI_SGE_IO_UNION { -+ union { -+ MPI2_SGE_SIMPLE_UNION Simple; -+ MPI2_SGE_CHAIN_UNION Chain; -+ } u; -+} MPI2_MPI_SGE_IO_UNION, *PTR_MPI2_MPI_SGE_IO_UNION, -+ Mpi2MpiSGEIOUnion_t, *pMpi2MpiSGEIOUnion_t; -+ -+/**************************************************************************** -+* MPI SGE union for SGL's with Simple and Transaction elements - for MPI v2.0 products only -+****************************************************************************/ -+ -+typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION { -+ union { -+ MPI2_SGE_SIMPLE_UNION Simple; -+ MPI2_SGE_TRANSACTION_UNION Transaction; -+ } u; -+} MPI2_SGE_TRANS_SIMPLE_UNION, -+ *PTR_MPI2_SGE_TRANS_SIMPLE_UNION, -+ Mpi2SGETransSimpleUnion_t, -+ *pMpi2SGETransSimpleUnion_t; -+ -+/**************************************************************************** -+* All MPI SGE types union -+****************************************************************************/ -+ -+typedef struct _MPI2_MPI_SGE_UNION { -+ union { -+ MPI2_SGE_SIMPLE_UNION Simple; -+ MPI2_SGE_CHAIN_UNION Chain; -+ MPI2_SGE_TRANSACTION_UNION Transaction; -+ } u; -+} MPI2_MPI_SGE_UNION, *PTR_MPI2_MPI_SGE_UNION, -+ Mpi2MpiSgeUnion_t, *pMpi2MpiSgeUnion_t; -+ -+/**************************************************************************** -+* MPI SGE field definition and masks -+****************************************************************************/ -+ -+/*Flags field bit definitions */ -+ -+#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80) -+#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40) -+#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) -+#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08) -+#define MPI2_SGE_FLAGS_DIRECTION (0x04) -+#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02) -+#define MPI2_SGE_FLAGS_END_OF_LIST (0x01) -+ -+#define MPI2_SGE_FLAGS_SHIFT (24) -+ -+#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF) -+#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) -+ -+/*Element Type */ -+ -+#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) -+#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10) -+#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30) -+#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30) -+ -+/*Address location */ -+ -+#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00) -+ -+/*Direction */ -+ -+#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) -+#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) -+ -+#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST) -+#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC) -+ -+/*Address Size */ -+ -+#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) -+#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) -+ -+/*Context Size */ -+ -+#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00) -+#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02) -+#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04) -+#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06) -+ -+#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000) -+#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16) -+ -+/**************************************************************************** -+* MPI SGE operation Macros -+****************************************************************************/ -+ -+/*SIMPLE FlagsLength manipulations... */ -+#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT) -+#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> \ -+ MPI2_SGE_FLAGS_SHIFT) -+#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK) -+#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK) -+ -+#define MPI2_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_SGE_SET_FLAGS(f) | \ -+ MPI2_SGE_LENGTH(l)) -+ -+#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength) -+#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength) -+#define MPI2_pSGE_SET_FLAGS_LENGTH(psg, f, l) ((psg)->FlagsLength = \ -+ MPI2_SGE_SET_FLAGS_LENGTH(f, l)) -+ -+/*CAUTION - The following are READ-MODIFY-WRITE! */ -+#define MPI2_pSGE_SET_FLAGS(psg, f) ((psg)->FlagsLength |= \ -+ MPI2_SGE_SET_FLAGS(f)) -+#define MPI2_pSGE_SET_LENGTH(psg, l) ((psg)->FlagsLength |= \ -+ MPI2_SGE_LENGTH(l)) -+ -+#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> \ -+ MPI2_SGE_CHAIN_OFFSET_SHIFT) -+ -+/***************************************************************************** -+* -+* Fusion-MPT IEEE Scatter Gather Elements -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* IEEE Simple Element structures -+****************************************************************************/ -+ -+/*MPI2_IEEE_SGE_SIMPLE32 is for MPI v2.0 products only */ -+typedef struct _MPI2_IEEE_SGE_SIMPLE32 { -+ U32 Address; -+ U32 FlagsLength; -+} MPI2_IEEE_SGE_SIMPLE32, *PTR_MPI2_IEEE_SGE_SIMPLE32, -+ Mpi2IeeeSgeSimple32_t, *pMpi2IeeeSgeSimple32_t; -+ -+typedef struct _MPI2_IEEE_SGE_SIMPLE64 { -+ U64 Address; -+ U32 Length; -+ U16 Reserved1; -+ U8 Reserved2; -+ U8 Flags; -+} MPI2_IEEE_SGE_SIMPLE64, *PTR_MPI2_IEEE_SGE_SIMPLE64, -+ Mpi2IeeeSgeSimple64_t, *pMpi2IeeeSgeSimple64_t; -+ -+typedef union _MPI2_IEEE_SGE_SIMPLE_UNION { -+ MPI2_IEEE_SGE_SIMPLE32 Simple32; -+ MPI2_IEEE_SGE_SIMPLE64 Simple64; -+} MPI2_IEEE_SGE_SIMPLE_UNION, -+ *PTR_MPI2_IEEE_SGE_SIMPLE_UNION, -+ Mpi2IeeeSgeSimpleUnion_t, -+ *pMpi2IeeeSgeSimpleUnion_t; -+ -+/**************************************************************************** -+* IEEE Chain Element structures -+****************************************************************************/ -+ -+/*MPI2_IEEE_SGE_CHAIN32 is for MPI v2.0 products only */ -+typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32; -+ -+/*MPI2_IEEE_SGE_CHAIN64 is for MPI v2.0 products only */ -+typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64; -+ -+typedef union _MPI2_IEEE_SGE_CHAIN_UNION { -+ MPI2_IEEE_SGE_CHAIN32 Chain32; -+ MPI2_IEEE_SGE_CHAIN64 Chain64; -+} MPI2_IEEE_SGE_CHAIN_UNION, -+ *PTR_MPI2_IEEE_SGE_CHAIN_UNION, -+ Mpi2IeeeSgeChainUnion_t, -+ *pMpi2IeeeSgeChainUnion_t; -+ -+/*MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 and later */ -+typedef struct _MPI25_IEEE_SGE_CHAIN64 { -+ U64 Address; -+ U32 Length; -+ U16 Reserved1; -+ U8 NextChainOffset; -+ U8 Flags; -+} MPI25_IEEE_SGE_CHAIN64, -+ *PTR_MPI25_IEEE_SGE_CHAIN64, -+ Mpi25IeeeSgeChain64_t, -+ *pMpi25IeeeSgeChain64_t; -+ -+/**************************************************************************** -+* All IEEE SGE types union -+****************************************************************************/ -+ -+/*MPI2_IEEE_SGE_UNION is for MPI v2.0 products only */ -+typedef struct _MPI2_IEEE_SGE_UNION { -+ union { -+ MPI2_IEEE_SGE_SIMPLE_UNION Simple; -+ MPI2_IEEE_SGE_CHAIN_UNION Chain; -+ } u; -+} MPI2_IEEE_SGE_UNION, *PTR_MPI2_IEEE_SGE_UNION, -+ Mpi2IeeeSgeUnion_t, *pMpi2IeeeSgeUnion_t; -+ -+/**************************************************************************** -+* IEEE SGE union for IO SGL's -+****************************************************************************/ -+ -+typedef union _MPI25_SGE_IO_UNION { -+ MPI2_IEEE_SGE_SIMPLE64 IeeeSimple; -+ MPI25_IEEE_SGE_CHAIN64 IeeeChain; -+} MPI25_SGE_IO_UNION, *PTR_MPI25_SGE_IO_UNION, -+ Mpi25SGEIOUnion_t, *pMpi25SGEIOUnion_t; -+ -+/**************************************************************************** -+* IEEE SGE field definitions and masks -+****************************************************************************/ -+ -+/*Flags field bit definitions */ -+ -+#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80) -+#define MPI25_IEEE_SGE_FLAGS_END_OF_LIST (0x40) -+ -+#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24) -+ -+#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF) -+ -+/*Element Type */ -+ -+#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00) -+#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) -+ -+/*Next Segment Format */ -+ -+#define MPI26_IEEE_SGE_FLAGS_NSF_MASK (0x1C) -+#define MPI26_IEEE_SGE_FLAGS_NSF_MPI_IEEE (0x00) -+ -+/*Data Location Address Space */ -+ -+#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) -+#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) -+#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) -+#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) -+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) -+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03) -+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \ -+ (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) -+#define MPI26_IEEE_SGE_FLAGS_IOCCTL_ADDR (0x02) -+ -+/**************************************************************************** -+* IEEE SGE operation Macros -+****************************************************************************/ -+ -+/*SIMPLE FlagsLength manipulations... */ -+#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT) -+#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) \ -+ >> MPI2_IEEE32_SGE_FLAGS_SHIFT) -+#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK) -+ -+#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) |\ -+ MPI2_IEEE32_SGE_LENGTH(l)) -+ -+#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) \ -+ MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength) -+#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) \ -+ MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength) -+#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg, f, l) ((psg)->FlagsLength = \ -+ MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l)) -+ -+/*CAUTION - The following are READ-MODIFY-WRITE! */ -+#define MPI2_IEEE32_pSGE_SET_FLAGS(psg, f) ((psg)->FlagsLength |= \ -+ MPI2_IEEE32_SGE_SET_FLAGS(f)) -+#define MPI2_IEEE32_pSGE_SET_LENGTH(psg, l) ((psg)->FlagsLength |= \ -+ MPI2_IEEE32_SGE_LENGTH(l)) -+ -+/***************************************************************************** -+* -+* Fusion-MPT MPI/IEEE Scatter Gather Unions -+* -+*****************************************************************************/ -+ -+typedef union _MPI2_SIMPLE_SGE_UNION { -+ MPI2_SGE_SIMPLE_UNION MpiSimple; -+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; -+} MPI2_SIMPLE_SGE_UNION, *PTR_MPI2_SIMPLE_SGE_UNION, -+ Mpi2SimpleSgeUntion_t, *pMpi2SimpleSgeUntion_t; -+ -+typedef union _MPI2_SGE_IO_UNION { -+ MPI2_SGE_SIMPLE_UNION MpiSimple; -+ MPI2_SGE_CHAIN_UNION MpiChain; -+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; -+ MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; -+} MPI2_SGE_IO_UNION, *PTR_MPI2_SGE_IO_UNION, -+ Mpi2SGEIOUnion_t, *pMpi2SGEIOUnion_t; -+ -+/**************************************************************************** -+* -+* Values for SGLFlags field, used in many request messages with an SGL -+* -+****************************************************************************/ -+ -+/*values for MPI SGL Data Location Address Space subfield */ -+#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C) -+#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00) -+#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04) -+#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) -+#define MPI26_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) -+#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C) -+/*values for SGL Type subfield */ -+#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03) -+#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00) -+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01) -+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02) -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -new file mode 100644 -index 0000000..95356a8 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -@@ -0,0 +1,3493 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_cnfg.h -+ * Title: MPI Configuration messages and pages -+ * Creation Date: November 10, 2006 -+ * -+ * mpi2_cnfg.h Version: 02.00.35 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. -+ * Added Manufacturing Page 11. -+ * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE -+ * define. -+ * 06-26-07 02.00.02 Adding generic structure for product-specific -+ * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. -+ * Rework of BIOS Page 2 configuration page. -+ * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the -+ * forms. -+ * Added configuration pages IOC Page 8 and Driver -+ * Persistent Mapping Page 0. -+ * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated -+ * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, -+ * RAID Physical Disk Pages 0 and 1, RAID Configuration -+ * Page 0). -+ * Added new value for AccessStatus field of SAS Device -+ * Page 0 (_SATA_NEEDS_INITIALIZATION). -+ * 10-31-07 02.00.04 Added missing SEPDevHandle field to -+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. -+ * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for -+ * NVDATA. -+ * Modified IOC Page 7 to use masks and added field for -+ * SASBroadcastPrimitiveMasks. -+ * Added MPI2_CONFIG_PAGE_BIOS_4. -+ * Added MPI2_CONFIG_PAGE_LOG_0. -+ * 02-29-08 02.00.06 Modified various names to make them 32-character unique. -+ * Added SAS Device IDs. -+ * Updated Integrated RAID configuration pages including -+ * Manufacturing Page 4, IOC Page 6, and RAID Configuration -+ * Page 0. -+ * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. -+ * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. -+ * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. -+ * Added missing MaxNumRoutedSasAddresses field to -+ * MPI2_CONFIG_PAGE_EXPANDER_0. -+ * Added SAS Port Page 0. -+ * Modified structure layout for -+ * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. -+ * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use -+ * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. -+ * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF -+ * to 0x000000FF. -+ * Added two new values for the Physical Disk Coercion Size -+ * bits in the Flags field of Manufacturing Page 4. -+ * Added product-specific Manufacturing pages 16 to 31. -+ * Modified Flags bits for controlling write cache on SATA -+ * drives in IO Unit Page 1. -+ * Added new bit to AdditionalControlFlags of SAS IO Unit -+ * Page 1 to control Invalid Topology Correction. -+ * Added additional defines for RAID Volume Page 0 -+ * VolumeStatusFlags field. -+ * Modified meaning of RAID Volume Page 0 VolumeSettings -+ * define for auto-configure of hot-swap drives. -+ * Added SupportedPhysDisks field to RAID Volume Page 1 and -+ * added related defines. -+ * Added PhysDiskAttributes field (and related defines) to -+ * RAID Physical Disk Page 0. -+ * Added MPI2_SAS_PHYINFO_PHY_VACANT define. -+ * Added three new DiscoveryStatus bits for SAS IO Unit -+ * Page 0 and SAS Expander Page 0. -+ * Removed multiplexing information from SAS IO Unit pages. -+ * Added BootDeviceWaitTime field to SAS IO Unit Page 4. -+ * Removed Zone Address Resolved bit from PhyInfo and from -+ * Expander Page 0 Flags field. -+ * Added two new AccessStatus values to SAS Device Page 0 -+ * for indicating routing problems. Added 3 reserved words -+ * to this page. -+ * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. -+ * Inserted missing reserved field into structure for IOC -+ * Page 6. -+ * Added more pending task bits to RAID Volume Page 0 -+ * VolumeStatusFlags defines. -+ * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. -+ * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 -+ * and SAS Expander Page 0 to flag a downstream initiator -+ * when in simplified routing mode. -+ * Removed SATA Init Failure defines for DiscoveryStatus -+ * fields of SAS IO Unit Page 0 and SAS Expander Page 0. -+ * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. -+ * Added PortGroups, DmaGroup, and ControlGroup fields to -+ * SAS Device Page 0. -+ * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO -+ * Unit Page 6. -+ * Added expander reduced functionality data to SAS -+ * Expander Page 0. -+ * Added SAS PHY Page 2 and SAS PHY Page 3. -+ * 07-30-09 02.00.12 Added IO Unit Page 7. -+ * Added new device ids. -+ * Added SAS IO Unit Page 5. -+ * Added partial and slumber power management capable flags -+ * to SAS Device Page 0 Flags field. -+ * Added PhyInfo defines for power condition. -+ * Added Ethernet configuration pages. -+ * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. -+ * Added SAS PHY Page 4 structure and defines. -+ * 02-10-10 02.00.14 Modified the comments for the configuration page -+ * structures that contain an array of data. The host -+ * should use the "count" field in the page data (e.g. the -+ * NumPhys field) to determine the number of valid elements -+ * in the array. -+ * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. -+ * Added PowerManagementCapabilities to IO Unit Page 7. -+ * Added PortWidthModGroup field to -+ * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. -+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. -+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. -+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. -+ * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT -+ * define. -+ * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. -+ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. -+ * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) -+ * defines. -+ * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to -+ * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for -+ * the Pinout field. -+ * Added BoardTemperature and BoardTemperatureUnits fields -+ * to MPI2_CONFIG_PAGE_IO_UNIT_7. -+ * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define -+ * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. -+ * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. -+ * Added IO Unit Page 8, IO Unit Page 9, -+ * and IO Unit Page 10. -+ * Added SASNotifyPrimitiveMasks field to -+ * MPI2_CONFIG_PAGE_IOC_7. -+ * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). -+ * 05-25-11 02.00.20 Cleaned up a few comments. -+ * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities -+ * for PCIe link as obsolete. -+ * Added SpinupFlags field containing a Disable Spin-up bit -+ * to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of SAS IO -+ * Unit Page 4. -+ * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT. -+ * Added UEFIVersion field to BIOS Page 1 and defined new -+ * BiosOptions bits. -+ * Incorporating additions for MPI v2.5. -+ * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER. -+ * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID. -+ * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as -+ * obsolete for MPI v2.5 and later. -+ * Added some defines for 12G SAS speeds. -+ * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK. -+ * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to -+ * match the specification. -+ * 08-19-13 02.00.26 Added reserved words to MPI2_CONFIG_PAGE_IO_UNIT_7 for -+ * future use. -+ * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for -+ * MPI2_CONFIG_PAGE_MAN_7. -+ * Added EnclosureLevel and ConnectorName fields to -+ * MPI2_CONFIG_PAGE_SAS_DEV_0. -+ * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for -+ * MPI2_CONFIG_PAGE_SAS_DEV_0. -+ * Added EnclosureLevel field to -+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. -+ * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for -+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. -+ * 01-08-14 02.00.28 Added more defines for the BiosOptions field of -+ * MPI2_CONFIG_PAGE_BIOS_1. -+ * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and -+ * more defines for the BiosOptions field. -+ * 11-18-14 02.00.30 Updated copyright information. -+ * Added MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG. -+ * Added AdapterOrderAux fields to BIOS Page 3. -+ * 03-16-15 02.00.31 Updated for MPI v2.6. -+ * Added Flags field to IO Unit Page 7. -+ * Added new SAS Phy Event codes -+ * 05-25-15 02.00.33 Added more defines for the BiosOptions field of -+ * MPI2_CONFIG_PAGE_BIOS_1. -+ * 08-25-15 02.00.34 Bumped Header Version. -+ * 12-18-15 02.00.35 Added SATADeviceWaitTime to SAS IO Unit Page 4. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_CNFG_H -+#define MPI2_CNFG_H -+ -+/***************************************************************************** -+* Configuration Page Header and defines -+*****************************************************************************/ -+ -+/*Config Page Header */ -+typedef struct _MPI2_CONFIG_PAGE_HEADER { -+ U8 PageVersion; /*0x00 */ -+ U8 PageLength; /*0x01 */ -+ U8 PageNumber; /*0x02 */ -+ U8 PageType; /*0x03 */ -+} MPI2_CONFIG_PAGE_HEADER, *PTR_MPI2_CONFIG_PAGE_HEADER, -+ Mpi2ConfigPageHeader_t, *pMpi2ConfigPageHeader_t; -+ -+typedef union _MPI2_CONFIG_PAGE_HEADER_UNION { -+ MPI2_CONFIG_PAGE_HEADER Struct; -+ U8 Bytes[4]; -+ U16 Word16[2]; -+ U32 Word32; -+} MPI2_CONFIG_PAGE_HEADER_UNION, *PTR_MPI2_CONFIG_PAGE_HEADER_UNION, -+ Mpi2ConfigPageHeaderUnion, *pMpi2ConfigPageHeaderUnion; -+ -+/*Extended Config Page Header */ -+typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER { -+ U8 PageVersion; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 PageNumber; /*0x02 */ -+ U8 PageType; /*0x03 */ -+ U16 ExtPageLength; /*0x04 */ -+ U8 ExtPageType; /*0x06 */ -+ U8 Reserved2; /*0x07 */ -+} MPI2_CONFIG_EXTENDED_PAGE_HEADER, -+ *PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER, -+ Mpi2ConfigExtendedPageHeader_t, -+ *pMpi2ConfigExtendedPageHeader_t; -+ -+typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION { -+ MPI2_CONFIG_PAGE_HEADER Struct; -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext; -+ U8 Bytes[8]; -+ U16 Word16[4]; -+ U32 Word32[2]; -+} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, -+ *PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION, -+ Mpi2ConfigPageExtendedHeaderUnion, -+ *pMpi2ConfigPageExtendedHeaderUnion; -+ -+ -+/*PageType field values */ -+#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) -+#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) -+#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) -+#define MPI2_CONFIG_PAGEATTR_MASK (0xF0) -+ -+#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00) -+#define MPI2_CONFIG_PAGETYPE_IOC (0x01) -+#define MPI2_CONFIG_PAGETYPE_BIOS (0x02) -+#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08) -+#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09) -+#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) -+#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F) -+#define MPI2_CONFIG_PAGETYPE_MASK (0x0F) -+ -+#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF) -+ -+ -+/*ExtPageType field values */ -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) -+#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14) -+#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) -+#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) -+#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) -+#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) -+#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) -+ -+ -+/***************************************************************************** -+* PageAddress defines -+*****************************************************************************/ -+ -+/*RAID Volume PageAddress format */ -+#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -+#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000) -+ -+#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF) -+ -+ -+/*RAID Physical Disk PageAddress format */ -+#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000) -+#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000) -+#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000) -+ -+#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) -+#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF) -+ -+ -+/*SAS Expander PageAddress format */ -+#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000) -+#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000) -+#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000) -+ -+#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF) -+#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000) -+#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16) -+ -+ -+/*SAS Device PageAddress format */ -+#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -+#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000) -+ -+#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF) -+ -+ -+/*SAS PHY PageAddress format */ -+#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000) -+#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000) -+ -+#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) -+#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF) -+ -+ -+/*SAS Port PageAddress format */ -+#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000) -+#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000) -+ -+#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF) -+ -+ -+/*SAS Enclosure PageAddress format */ -+#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -+#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000) -+ -+#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF) -+ -+ -+/*RAID Configuration PageAddress format */ -+#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000) -+#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000) -+#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000) -+ -+#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF) -+ -+ -+/*Driver Persistent Mapping PageAddress format */ -+#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000) -+ -+#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000) -+#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16) -+#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) -+ -+ -+/*Ethernet PageAddress format */ -+#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) -+ -+#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) -+ -+ -+/**************************************************************************** -+* Configuration messages -+****************************************************************************/ -+ -+/*Configuration Request Message */ -+typedef struct _MPI2_CONFIG_REQUEST { -+ U8 Action; /*0x00 */ -+ U8 SGLFlags; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 ExtPageLength; /*0x04 */ -+ U8 ExtPageType; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U8 Reserved2; /*0x0C */ -+ U8 ProxyVF_ID; /*0x0D */ -+ U16 Reserved4; /*0x0E */ -+ U32 Reserved3; /*0x10 */ -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x14 */ -+ U32 PageAddress; /*0x18 */ -+ MPI2_SGE_IO_UNION PageBufferSGE; /*0x1C */ -+} MPI2_CONFIG_REQUEST, *PTR_MPI2_CONFIG_REQUEST, -+ Mpi2ConfigRequest_t, *pMpi2ConfigRequest_t; -+ -+/*values for the Action field */ -+#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00) -+#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) -+#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) -+#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03) -+#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) -+#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) -+#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) -+#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) -+ -+/*use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+ -+/*Config Reply Message */ -+typedef struct _MPI2_CONFIG_REPLY { -+ U8 Action; /*0x00 */ -+ U8 SGLFlags; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 ExtPageLength; /*0x04 */ -+ U8 ExtPageType; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U16 Reserved2; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x14 */ -+} MPI2_CONFIG_REPLY, *PTR_MPI2_CONFIG_REPLY, -+ Mpi2ConfigReply_t, *pMpi2ConfigReply_t; -+ -+ -+ -+/***************************************************************************** -+* -+* C o n f i g u r a t i o n P a g e s -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* Manufacturing Config pages -+****************************************************************************/ -+ -+#define MPI2_MFGPAGE_VENDORID_LSI (0x1000) -+ -+/*MPI v2.0 SAS products */ -+#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070) -+#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072) -+#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074) -+#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076) -+#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) -+#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) -+#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) -+ -+#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E) -+ -+#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) -+#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) -+#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) -+#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) -+#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) -+#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) -+#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) -+#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) -+#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) -+ -+/*MPI v2.5 SAS products */ -+#define MPI25_MFGPAGE_DEVID_SAS3004 (0x0096) -+#define MPI25_MFGPAGE_DEVID_SAS3008 (0x0097) -+#define MPI25_MFGPAGE_DEVID_SAS3108_1 (0x0090) -+#define MPI25_MFGPAGE_DEVID_SAS3108_2 (0x0091) -+#define MPI25_MFGPAGE_DEVID_SAS3108_5 (0x0094) -+#define MPI25_MFGPAGE_DEVID_SAS3108_6 (0x0095) -+ -+/* MPI v2.6 SAS Products */ -+#define MPI26_MFGPAGE_DEVID_SAS3216 (0x00C9) -+#define MPI26_MFGPAGE_DEVID_SAS3224 (0x00C4) -+#define MPI26_MFGPAGE_DEVID_SAS3316_1 (0x00C5) -+#define MPI26_MFGPAGE_DEVID_SAS3316_2 (0x00C6) -+#define MPI26_MFGPAGE_DEVID_SAS3316_3 (0x00C7) -+#define MPI26_MFGPAGE_DEVID_SAS3316_4 (0x00C8) -+#define MPI26_MFGPAGE_DEVID_SAS3324_1 (0x00C0) -+#define MPI26_MFGPAGE_DEVID_SAS3324_2 (0x00C1) -+#define MPI26_MFGPAGE_DEVID_SAS3324_3 (0x00C2) -+#define MPI26_MFGPAGE_DEVID_SAS3324_4 (0x00C3) -+ -+/*Manufacturing Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 ChipName[16]; /*0x04 */ -+ U8 ChipRevision[8]; /*0x14 */ -+ U8 BoardName[16]; /*0x1C */ -+ U8 BoardAssembly[16]; /*0x2C */ -+ U8 BoardTracerNumber[16]; /*0x3C */ -+} MPI2_CONFIG_PAGE_MAN_0, -+ *PTR_MPI2_CONFIG_PAGE_MAN_0, -+ Mpi2ManufacturingPage0_t, -+ *pMpi2ManufacturingPage0_t; -+ -+#define MPI2_MANUFACTURING0_PAGEVERSION (0x00) -+ -+ -+/*Manufacturing Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 VPD[256]; /*0x04 */ -+} MPI2_CONFIG_PAGE_MAN_1, -+ *PTR_MPI2_CONFIG_PAGE_MAN_1, -+ Mpi2ManufacturingPage1_t, -+ *pMpi2ManufacturingPage1_t; -+ -+#define MPI2_MANUFACTURING1_PAGEVERSION (0x00) -+ -+ -+typedef struct _MPI2_CHIP_REVISION_ID { -+ U16 DeviceID; /*0x00 */ -+ U8 PCIRevisionID; /*0x02 */ -+ U8 Reserved; /*0x03 */ -+} MPI2_CHIP_REVISION_ID, *PTR_MPI2_CHIP_REVISION_ID, -+ Mpi2ChipRevisionId_t, *pMpi2ChipRevisionId_t; -+ -+ -+/*Manufacturing Page 2 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check Header.PageLength at runtime. -+ */ -+#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS -+#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_2 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ MPI2_CHIP_REVISION_ID ChipId; /*0x04 */ -+ U32 -+ HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/*0x08 */ -+} MPI2_CONFIG_PAGE_MAN_2, -+ *PTR_MPI2_CONFIG_PAGE_MAN_2, -+ Mpi2ManufacturingPage2_t, -+ *pMpi2ManufacturingPage2_t; -+ -+#define MPI2_MANUFACTURING2_PAGEVERSION (0x00) -+ -+ -+/*Manufacturing Page 3 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check Header.PageLength at runtime. -+ */ -+#ifndef MPI2_MAN_PAGE_3_INFO_WORDS -+#define MPI2_MAN_PAGE_3_INFO_WORDS (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_3 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ MPI2_CHIP_REVISION_ID ChipId; /*0x04 */ -+ U32 -+ Info[MPI2_MAN_PAGE_3_INFO_WORDS];/*0x08 */ -+} MPI2_CONFIG_PAGE_MAN_3, -+ *PTR_MPI2_CONFIG_PAGE_MAN_3, -+ Mpi2ManufacturingPage3_t, -+ *pMpi2ManufacturingPage3_t; -+ -+#define MPI2_MANUFACTURING3_PAGEVERSION (0x00) -+ -+ -+/*Manufacturing Page 4 */ -+ -+typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS { -+ U8 PowerSaveFlags; /*0x00 */ -+ U8 InternalOperationsSleepTime; /*0x01 */ -+ U8 InternalOperationsRunTime; /*0x02 */ -+ U8 HostIdleTime; /*0x03 */ -+} MPI2_MANPAGE4_PWR_SAVE_SETTINGS, -+ *PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS, -+ Mpi2ManPage4PwrSaveSettings_t, -+ *pMpi2ManPage4PwrSaveSettings_t; -+ -+/*defines for the PowerSaveFlags field */ -+#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03) -+#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00) -+#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01) -+#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02) -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_4 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Flags; /*0x08 */ -+ U8 InquirySize; /*0x0C */ -+ U8 Reserved2; /*0x0D */ -+ U16 Reserved3; /*0x0E */ -+ U8 InquiryData[56]; /*0x10 */ -+ U32 RAID0VolumeSettings; /*0x48 */ -+ U32 RAID1EVolumeSettings; /*0x4C */ -+ U32 RAID1VolumeSettings; /*0x50 */ -+ U32 RAID10VolumeSettings; /*0x54 */ -+ U32 Reserved4; /*0x58 */ -+ U32 Reserved5; /*0x5C */ -+ MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /*0x60 */ -+ U8 MaxOCEDisks; /*0x64 */ -+ U8 ResyncRate; /*0x65 */ -+ U16 DataScrubDuration; /*0x66 */ -+ U8 MaxHotSpares; /*0x68 */ -+ U8 MaxPhysDisksPerVol; /*0x69 */ -+ U8 MaxPhysDisks; /*0x6A */ -+ U8 MaxVolumes; /*0x6B */ -+} MPI2_CONFIG_PAGE_MAN_4, -+ *PTR_MPI2_CONFIG_PAGE_MAN_4, -+ Mpi2ManufacturingPage4_t, -+ *pMpi2ManufacturingPage4_t; -+ -+#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A) -+ -+/*Manufacturing Page 4 Flags field */ -+#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000) -+#define MPI2_MANPAGE4_METADATA_512MB (0x00000000) -+ -+#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000) -+#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000) -+#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000) -+ -+#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00) -+#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000) -+#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400) -+#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800) -+#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00) -+ -+#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300) -+#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000) -+#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100) -+#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200) -+ -+#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080) -+#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040) -+#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020) -+#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010) -+#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008) -+#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004) -+#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002) -+#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001) -+ -+ -+/*Manufacturing Page 5 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES -+#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_MANUFACTURING5_ENTRY { -+ U64 WWID; /*0x00 */ -+ U64 DeviceName; /*0x08 */ -+} MPI2_MANUFACTURING5_ENTRY, -+ *PTR_MPI2_MANUFACTURING5_ENTRY, -+ Mpi2Manufacturing5Entry_t, -+ *pMpi2Manufacturing5Entry_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_5 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumPhys; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U32 Reserved3; /*0x08 */ -+ U32 Reserved4; /*0x0C */ -+ MPI2_MANUFACTURING5_ENTRY -+ Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/*0x08 */ -+} MPI2_CONFIG_PAGE_MAN_5, -+ *PTR_MPI2_CONFIG_PAGE_MAN_5, -+ Mpi2ManufacturingPage5_t, -+ *pMpi2ManufacturingPage5_t; -+ -+#define MPI2_MANUFACTURING5_PAGEVERSION (0x03) -+ -+ -+/*Manufacturing Page 6 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_6 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 ProductSpecificInfo;/*0x04 */ -+} MPI2_CONFIG_PAGE_MAN_6, -+ *PTR_MPI2_CONFIG_PAGE_MAN_6, -+ Mpi2ManufacturingPage6_t, -+ *pMpi2ManufacturingPage6_t; -+ -+#define MPI2_MANUFACTURING6_PAGEVERSION (0x00) -+ -+ -+/*Manufacturing Page 7 */ -+ -+typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO { -+ U32 Pinout; /*0x00 */ -+ U8 Connector[16]; /*0x04 */ -+ U8 Location; /*0x14 */ -+ U8 ReceptacleID; /*0x15 */ -+ U16 Slot; /*0x16 */ -+ U32 Reserved2; /*0x18 */ -+} MPI2_MANPAGE7_CONNECTOR_INFO, -+ *PTR_MPI2_MANPAGE7_CONNECTOR_INFO, -+ Mpi2ManPage7ConnectorInfo_t, -+ *pMpi2ManPage7ConnectorInfo_t; -+ -+/*defines for the Pinout field */ -+#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00) -+#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) -+ -+#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) -+#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) -+#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) -+#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) -+#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) -+#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) -+#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) -+#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) -+#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) -+#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) -+#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) -+#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) -+#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) -+#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) -+#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) -+ -+/*defines for the Location field */ -+#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) -+#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02) -+#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04) -+#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08) -+#define MPI2_MANPAGE7_LOCATION_AUTO (0x10) -+#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20) -+#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX -+#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_7 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U32 Flags; /*0x0C */ -+ U8 EnclosureName[16]; /*0x10 */ -+ U8 NumPhys; /*0x20 */ -+ U8 Reserved3; /*0x21 */ -+ U16 Reserved4; /*0x22 */ -+ MPI2_MANPAGE7_CONNECTOR_INFO -+ ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /*0x24 */ -+} MPI2_CONFIG_PAGE_MAN_7, -+ *PTR_MPI2_CONFIG_PAGE_MAN_7, -+ Mpi2ManufacturingPage7_t, -+ *pMpi2ManufacturingPage7_t; -+ -+#define MPI2_MANUFACTURING7_PAGEVERSION (0x01) -+ -+/*defines for the Flags field */ -+#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008) -+#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002) -+#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) -+ -+ -+/* -+ *Generic structure to use for product-specific manufacturing pages -+ *(currently Manufacturing Page 8 through Manufacturing Page 31). -+ */ -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_PS { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 ProductSpecificInfo;/*0x04 */ -+} MPI2_CONFIG_PAGE_MAN_PS, -+ *PTR_MPI2_CONFIG_PAGE_MAN_PS, -+ Mpi2ManufacturingPagePS_t, -+ *pMpi2ManufacturingPagePS_t; -+ -+#define MPI2_MANUFACTURING8_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING9_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING10_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING11_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING12_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING13_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING14_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING15_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING16_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING17_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING18_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING19_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING20_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING21_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING22_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING23_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING24_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING25_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING26_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING27_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING28_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING29_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING30_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING31_PAGEVERSION (0x00) -+ -+ -+/**************************************************************************** -+* IO Unit Config Pages -+****************************************************************************/ -+ -+/*IO Unit Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U64 UniqueValue; /*0x04 */ -+ MPI2_VERSION_UNION NvdataVersionDefault; /*0x08 */ -+ MPI2_VERSION_UNION NvdataVersionPersistent; /*0x0A */ -+} MPI2_CONFIG_PAGE_IO_UNIT_0, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_0, -+ Mpi2IOUnitPage0_t, *pMpi2IOUnitPage0_t; -+ -+#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02) -+ -+ -+/*IO Unit Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Flags; /*0x04 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_1, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_1, -+ Mpi2IOUnitPage1_t, *pMpi2IOUnitPage1_t; -+ -+#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) -+ -+/*IO Unit Page 1 Flags defines */ -+#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000) -+#define MPI25_IOUNITPAGE1_NEW_DEVICE_FAST_PATH_DISABLE (0x00002000) -+#define MPI25_IOUNITPAGE1_DISABLE_FAST_PATH (0x00001000) -+#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) -+#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) -+#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9) -+#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) -+#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) -+#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) -+#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) -+#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) -+#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) -+#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) -+ -+ -+/*IO Unit Page 3 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for GPIOCount at runtime. -+ */ -+#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX -+#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 GPIOCount; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U16 -+ GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/*0x08 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_3, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_3, -+ Mpi2IOUnitPage3_t, *pMpi2IOUnitPage3_t; -+ -+#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01) -+ -+/*defines for IO Unit Page 3 GPIOVal field */ -+#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC) -+#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2) -+#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000) -+#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001) -+ -+ -+/*IO Unit Page 5 */ -+ -+/* -+ *Upper layer code (drivers, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumDmaEngines at runtime. -+ */ -+#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES -+#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U64 -+ RaidAcceleratorBufferBaseAddress; /*0x04 */ -+ U64 -+ RaidAcceleratorBufferSize; /*0x0C */ -+ U64 -+ RaidAcceleratorControlBaseAddress; /*0x14 */ -+ U8 RAControlSize; /*0x1C */ -+ U8 NumDmaEngines; /*0x1D */ -+ U8 RAMinControlSize; /*0x1E */ -+ U8 RAMaxControlSize; /*0x1F */ -+ U32 Reserved1; /*0x20 */ -+ U32 Reserved2; /*0x24 */ -+ U32 Reserved3; /*0x28 */ -+ U32 -+ DmaEngineCapabilities[MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /*0x2C */ -+} MPI2_CONFIG_PAGE_IO_UNIT_5, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, -+ Mpi2IOUnitPage5_t, *pMpi2IOUnitPage5_t; -+ -+#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00) -+ -+/*defines for IO Unit Page 5 DmaEngineCapabilities field */ -+#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFFFF0000) -+#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16) -+ -+#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008) -+#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004) -+#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002) -+#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001) -+ -+ -+/*IO Unit Page 6 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U16 Flags; /*0x04 */ -+ U8 RAHostControlSize; /*0x06 */ -+ U8 Reserved0; /*0x07 */ -+ U64 -+ RaidAcceleratorHostControlBaseAddress; /*0x08 */ -+ U32 Reserved1; /*0x10 */ -+ U32 Reserved2; /*0x14 */ -+ U32 Reserved3; /*0x18 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_6, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, -+ Mpi2IOUnitPage6_t, *pMpi2IOUnitPage6_t; -+ -+#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00) -+ -+/*defines for IO Unit Page 6 Flags field */ -+#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) -+ -+ -+/*IO Unit Page 7 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 CurrentPowerMode; /*0x04 */ -+ U8 PreviousPowerMode; /*0x05 */ -+ U8 PCIeWidth; /*0x06 */ -+ U8 PCIeSpeed; /*0x07 */ -+ U32 ProcessorState; /*0x08 */ -+ U32 -+ PowerManagementCapabilities; /*0x0C */ -+ U16 IOCTemperature; /*0x10 */ -+ U8 -+ IOCTemperatureUnits; /*0x12 */ -+ U8 IOCSpeed; /*0x13 */ -+ U16 BoardTemperature; /*0x14 */ -+ U8 -+ BoardTemperatureUnits; /*0x16 */ -+ U8 Reserved3; /*0x17 */ -+ U32 BoardPowerRequirement; /*0x18 */ -+ U32 PCISlotPowerAllocation; /*0x1C */ -+/* reserved prior to MPI v2.6 */ -+ U8 Flags; /* 0x20 */ -+ U8 Reserved6; /* 0x21 */ -+ U16 Reserved7; /* 0x22 */ -+ U32 Reserved8; /* 0x24 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_7, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, -+ Mpi2IOUnitPage7_t, *pMpi2IOUnitPage7_t; -+ -+#define MPI2_IOUNITPAGE7_PAGEVERSION (0x05) -+ -+/*defines for IO Unit Page 7 CurrentPowerMode and PreviousPowerMode fields */ -+#define MPI25_IOUNITPAGE7_PM_INIT_MASK (0xC0) -+#define MPI25_IOUNITPAGE7_PM_INIT_UNAVAILABLE (0x00) -+#define MPI25_IOUNITPAGE7_PM_INIT_HOST (0x40) -+#define MPI25_IOUNITPAGE7_PM_INIT_IO_UNIT (0x80) -+#define MPI25_IOUNITPAGE7_PM_INIT_PCIE_DPA (0xC0) -+ -+#define MPI25_IOUNITPAGE7_PM_MODE_MASK (0x07) -+#define MPI25_IOUNITPAGE7_PM_MODE_UNAVAILABLE (0x00) -+#define MPI25_IOUNITPAGE7_PM_MODE_UNKNOWN (0x01) -+#define MPI25_IOUNITPAGE7_PM_MODE_FULL_POWER (0x04) -+#define MPI25_IOUNITPAGE7_PM_MODE_REDUCED_POWER (0x05) -+#define MPI25_IOUNITPAGE7_PM_MODE_STANDBY (0x06) -+ -+ -+/*defines for IO Unit Page 7 PCIeWidth field */ -+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) -+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) -+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) -+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) -+ -+/*defines for IO Unit Page 7 PCIeSpeed field */ -+#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) -+#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) -+#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) -+ -+/*defines for IO Unit Page 7 ProcessorState field */ -+#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) -+#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) -+ -+#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) -+#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) -+#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) -+ -+/*defines for IO Unit Page 7 PowerManagementCapabilities field */ -+#define MPI25_IOUNITPAGE7_PMCAP_DPA_FULL_PWR_MODE (0x00400000) -+#define MPI25_IOUNITPAGE7_PMCAP_DPA_REDUCED_PWR_MODE (0x00200000) -+#define MPI25_IOUNITPAGE7_PMCAP_DPA_STANDBY_MODE (0x00100000) -+#define MPI25_IOUNITPAGE7_PMCAP_HOST_FULL_PWR_MODE (0x00040000) -+#define MPI25_IOUNITPAGE7_PMCAP_HOST_REDUCED_PWR_MODE (0x00020000) -+#define MPI25_IOUNITPAGE7_PMCAP_HOST_STANDBY_MODE (0x00010000) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_FULL_PWR_MODE (0x00004000) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_REDUCED_PWR_MODE (0x00002000) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_STANDBY_MODE (0x00001000) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_12_5_PCT_IOCSPEED (0x00000400) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_25_0_PCT_IOCSPEED (0x00000200) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_50_0_PCT_IOCSPEED (0x00000100) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_12_5_PCT_IOCSPEED (0x00000040) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_25_0_PCT_IOCSPEED (0x00000020) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_50_0_PCT_IOCSPEED (0x00000010) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_WIDTH_CHANGE_PCIE (0x00000008) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_SPEED_CHANGE_PCIE (0x00000004) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_WIDTH_CHANGE_PCIE (0x00000002) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_SPEED_CHANGE_PCIE (0x00000001) -+ -+/*obsolete names for the PowerManagementCapabilities bits (above) */ -+#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) -+#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) -+#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) -+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /*obsolete */ -+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /*obsolete */ -+ -+ -+/*defines for IO Unit Page 7 IOCTemperatureUnits field */ -+#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) -+#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) -+#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) -+ -+/*defines for IO Unit Page 7 IOCSpeed field */ -+#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) -+#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) -+#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) -+#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) -+ -+/*defines for IO Unit Page 7 BoardTemperatureUnits field */ -+#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) -+#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) -+#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) -+ -+/* defines for IO Unit Page 7 Flags field */ -+#define MPI2_IOUNITPAGE7_FLAG_CABLE_POWER_EXC (0x01) -+ -+/*IO Unit Page 8 */ -+ -+#define MPI2_IOUNIT8_NUM_THRESHOLDS (4) -+ -+typedef struct _MPI2_IOUNIT8_SENSOR { -+ U16 Flags; /*0x00 */ -+ U16 Reserved1; /*0x02 */ -+ U16 -+ Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /*0x04 */ -+ U32 Reserved2; /*0x0C */ -+ U32 Reserved3; /*0x10 */ -+ U32 Reserved4; /*0x14 */ -+} MPI2_IOUNIT8_SENSOR, *PTR_MPI2_IOUNIT8_SENSOR, -+ Mpi2IOUnit8Sensor_t, *pMpi2IOUnit8Sensor_t; -+ -+/*defines for IO Unit Page 8 Sensor Flags field */ -+#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008) -+#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004) -+#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002) -+#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumSensors at runtime. -+ */ -+#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES -+#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U8 NumSensors; /*0x0C */ -+ U8 PollingInterval; /*0x0D */ -+ U16 Reserved3; /*0x0E */ -+ MPI2_IOUNIT8_SENSOR -+ Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/*0x10 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_8, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, -+ Mpi2IOUnitPage8_t, *pMpi2IOUnitPage8_t; -+ -+#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00) -+ -+ -+/*IO Unit Page 9 */ -+ -+typedef struct _MPI2_IOUNIT9_SENSOR { -+ U16 CurrentTemperature; /*0x00 */ -+ U16 Reserved1; /*0x02 */ -+ U8 Flags; /*0x04 */ -+ U8 Reserved2; /*0x05 */ -+ U16 Reserved3; /*0x06 */ -+ U32 Reserved4; /*0x08 */ -+ U32 Reserved5; /*0x0C */ -+} MPI2_IOUNIT9_SENSOR, *PTR_MPI2_IOUNIT9_SENSOR, -+ Mpi2IOUnit9Sensor_t, *pMpi2IOUnit9Sensor_t; -+ -+/*defines for IO Unit Page 9 Sensor Flags field */ -+#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumSensors at runtime. -+ */ -+#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES -+#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U8 NumSensors; /*0x0C */ -+ U8 Reserved4; /*0x0D */ -+ U16 Reserved3; /*0x0E */ -+ MPI2_IOUNIT9_SENSOR -+ Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/*0x10 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_9, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, -+ Mpi2IOUnitPage9_t, *pMpi2IOUnitPage9_t; -+ -+#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00) -+ -+ -+/*IO Unit Page 10 */ -+ -+typedef struct _MPI2_IOUNIT10_FUNCTION { -+ U8 CreditPercent; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+} MPI2_IOUNIT10_FUNCTION, -+ *PTR_MPI2_IOUNIT10_FUNCTION, -+ Mpi2IOUnit10Function_t, -+ *pMpi2IOUnit10Function_t; -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumFunctions at runtime. -+ */ -+#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES -+#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumFunctions; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U32 Reserved3; /*0x08 */ -+ U32 Reserved4; /*0x0C */ -+ MPI2_IOUNIT10_FUNCTION -+ Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/*0x10 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_10, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, -+ Mpi2IOUnitPage10_t, *pMpi2IOUnitPage10_t; -+ -+#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01) -+ -+ -+/* IO Unit Page 11 (for MPI v2.6 and later) */ -+ -+typedef struct _MPI26_IOUNIT11_SPINUP_GROUP { -+ U8 MaxTargetSpinup; /* 0x00 */ -+ U8 SpinupDelay; /* 0x01 */ -+ U8 SpinupFlags; /* 0x02 */ -+ U8 Reserved1; /* 0x03 */ -+} MPI26_IOUNIT11_SPINUP_GROUP, -+ *PTR_MPI26_IOUNIT11_SPINUP_GROUP, -+ Mpi26IOUnit11SpinupGroup_t, -+ *pMpi26IOUnit11SpinupGroup_t; -+ -+/* defines for IO Unit Page 11 SpinupFlags */ -+#define MPI26_IOUNITPAGE11_SPINUP_DISABLE_FLAG (0x01) -+ -+ -+/* -+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ * four and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI26_IOUNITPAGE11_PHY_MAX -+#define MPI26_IOUNITPAGE11_PHY_MAX (4) -+#endif -+ -+typedef struct _MPI26_CONFIG_PAGE_IO_UNIT_11 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ MPI26_IOUNIT11_SPINUP_GROUP SpinupGroupParameters[4]; /*0x08 */ -+ U32 Reserved2; /*0x18 */ -+ U32 Reserved3; /*0x1C */ -+ U32 Reserved4; /*0x20 */ -+ U8 BootDeviceWaitTime; /*0x24 */ -+ U8 Reserved5; /*0x25 */ -+ U16 Reserved6; /*0x26 */ -+ U8 NumPhys; /*0x28 */ -+ U8 PEInitialSpinupDelay; /*0x29 */ -+ U8 PEReplyDelay; /*0x2A */ -+ U8 Flags; /*0x2B */ -+ U8 PHY[MPI26_IOUNITPAGE11_PHY_MAX];/*0x2C */ -+} MPI26_CONFIG_PAGE_IO_UNIT_11, -+ *PTR_MPI26_CONFIG_PAGE_IO_UNIT_11, -+ Mpi26IOUnitPage11_t, -+ *pMpi26IOUnitPage11_t; -+ -+#define MPI26_IOUNITPAGE11_PAGEVERSION (0x00) -+ -+/* defines for Flags field */ -+#define MPI26_IOUNITPAGE11_FLAGS_AUTO_PORTENABLE (0x01) -+ -+/* defines for PHY field */ -+#define MPI26_IOUNITPAGE11_PHY_SPINUP_GROUP_MASK (0x03) -+ -+ -+ -+ -+ -+ -+/**************************************************************************** -+* IOC Config Pages -+****************************************************************************/ -+ -+/*IOC Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U16 VendorID; /*0x0C */ -+ U16 DeviceID; /*0x0E */ -+ U8 RevisionID; /*0x10 */ -+ U8 Reserved3; /*0x11 */ -+ U16 Reserved4; /*0x12 */ -+ U32 ClassCode; /*0x14 */ -+ U16 SubsystemVendorID; /*0x18 */ -+ U16 SubsystemID; /*0x1A */ -+} MPI2_CONFIG_PAGE_IOC_0, -+ *PTR_MPI2_CONFIG_PAGE_IOC_0, -+ Mpi2IOCPage0_t, *pMpi2IOCPage0_t; -+ -+#define MPI2_IOCPAGE0_PAGEVERSION (0x02) -+ -+ -+/*IOC Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Flags; /*0x04 */ -+ U32 CoalescingTimeout; /*0x08 */ -+ U8 CoalescingDepth; /*0x0C */ -+ U8 PCISlotNum; /*0x0D */ -+ U8 PCIBusNum; /*0x0E */ -+ U8 PCIDomainSegment; /*0x0F */ -+ U32 Reserved1; /*0x10 */ -+ U32 Reserved2; /*0x14 */ -+} MPI2_CONFIG_PAGE_IOC_1, -+ *PTR_MPI2_CONFIG_PAGE_IOC_1, -+ Mpi2IOCPage1_t, *pMpi2IOCPage1_t; -+ -+#define MPI2_IOCPAGE1_PAGEVERSION (0x05) -+ -+/*defines for IOC Page 1 Flags field */ -+#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001) -+ -+#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) -+#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF) -+#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF) -+ -+/*IOC Page 6 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_6 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 -+ CapabilitiesFlags; /*0x04 */ -+ U8 MaxDrivesRAID0; /*0x08 */ -+ U8 MaxDrivesRAID1; /*0x09 */ -+ U8 -+ MaxDrivesRAID1E; /*0x0A */ -+ U8 -+ MaxDrivesRAID10; /*0x0B */ -+ U8 MinDrivesRAID0; /*0x0C */ -+ U8 MinDrivesRAID1; /*0x0D */ -+ U8 -+ MinDrivesRAID1E; /*0x0E */ -+ U8 -+ MinDrivesRAID10; /*0x0F */ -+ U32 Reserved1; /*0x10 */ -+ U8 -+ MaxGlobalHotSpares; /*0x14 */ -+ U8 MaxPhysDisks; /*0x15 */ -+ U8 MaxVolumes; /*0x16 */ -+ U8 MaxConfigs; /*0x17 */ -+ U8 MaxOCEDisks; /*0x18 */ -+ U8 Reserved2; /*0x19 */ -+ U16 Reserved3; /*0x1A */ -+ U32 -+ SupportedStripeSizeMapRAID0; /*0x1C */ -+ U32 -+ SupportedStripeSizeMapRAID1E; /*0x20 */ -+ U32 -+ SupportedStripeSizeMapRAID10; /*0x24 */ -+ U32 Reserved4; /*0x28 */ -+ U32 Reserved5; /*0x2C */ -+ U16 -+ DefaultMetadataSize; /*0x30 */ -+ U16 Reserved6; /*0x32 */ -+ U16 -+ MaxBadBlockTableEntries; /*0x34 */ -+ U16 Reserved7; /*0x36 */ -+ U32 -+ IRNvsramVersion; /*0x38 */ -+} MPI2_CONFIG_PAGE_IOC_6, -+ *PTR_MPI2_CONFIG_PAGE_IOC_6, -+ Mpi2IOCPage6_t, *pMpi2IOCPage6_t; -+ -+#define MPI2_IOCPAGE6_PAGEVERSION (0x05) -+ -+/*defines for IOC Page 6 CapabilitiesFlags */ -+#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020) -+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010) -+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008) -+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004) -+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002) -+#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) -+ -+ -+/*IOC Page 7 */ -+ -+#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4) -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_7 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 -+ EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/*0x08 */ -+ U16 SASBroadcastPrimitiveMasks; /*0x18 */ -+ U16 SASNotifyPrimitiveMasks; /*0x1A */ -+ U32 Reserved3; /*0x1C */ -+} MPI2_CONFIG_PAGE_IOC_7, -+ *PTR_MPI2_CONFIG_PAGE_IOC_7, -+ Mpi2IOCPage7_t, *pMpi2IOCPage7_t; -+ -+#define MPI2_IOCPAGE7_PAGEVERSION (0x02) -+ -+ -+/*IOC Page 8 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_8 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumDevsPerEnclosure; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U16 MaxPersistentEntries; /*0x08 */ -+ U16 MaxNumPhysicalMappedIDs; /*0x0A */ -+ U16 Flags; /*0x0C */ -+ U16 Reserved3; /*0x0E */ -+ U16 IRVolumeMappingFlags; /*0x10 */ -+ U16 Reserved4; /*0x12 */ -+ U32 Reserved5; /*0x14 */ -+} MPI2_CONFIG_PAGE_IOC_8, -+ *PTR_MPI2_CONFIG_PAGE_IOC_8, -+ Mpi2IOCPage8_t, *pMpi2IOCPage8_t; -+ -+#define MPI2_IOCPAGE8_PAGEVERSION (0x00) -+ -+/*defines for IOC Page 8 Flags field */ -+#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020) -+#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010) -+ -+#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E) -+#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000) -+#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002) -+ -+#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001) -+#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000) -+ -+/*defines for IOC Page 8 IRVolumeMappingFlags */ -+#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003) -+#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000) -+#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001) -+ -+ -+/**************************************************************************** -+* BIOS Config Pages -+****************************************************************************/ -+ -+/*BIOS Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_BIOS_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 BiosOptions; /*0x04 */ -+ U32 IOCSettings; /*0x08 */ -+ U8 SSUTimeout; /*0x0C */ -+ U8 Reserved1; /*0x0D */ -+ U16 Reserved2; /*0x0E */ -+ U32 DeviceSettings; /*0x10 */ -+ U16 NumberOfDevices; /*0x14 */ -+ U16 UEFIVersion; /*0x16 */ -+ U16 IOTimeoutBlockDevicesNonRM; /*0x18 */ -+ U16 IOTimeoutSequential; /*0x1A */ -+ U16 IOTimeoutOther; /*0x1C */ -+ U16 IOTimeoutBlockDevicesRM; /*0x1E */ -+} MPI2_CONFIG_PAGE_BIOS_1, -+ *PTR_MPI2_CONFIG_PAGE_BIOS_1, -+ Mpi2BiosPage1_t, *pMpi2BiosPage1_t; -+ -+#define MPI2_BIOSPAGE1_PAGEVERSION (0x07) -+ -+/*values for BIOS Page 1 BiosOptions field */ -+#define MPI2_BIOSPAGE1_OPTIONS_BOOT_LIST_ADD_ALT_BOOT_DEVICE (0x00008000) -+#define MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG (0x00004000) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300) -+#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000) -+#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100) -+#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200) -+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0) -+#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006) -+#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000) -+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002) -+#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) -+ -+/*values for BIOS Page 1 IOCSettings field */ -+#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) -+#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) -+#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) -+ -+#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) -+#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) -+#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) -+#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) -+ -+#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) -+#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) -+#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) -+#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) -+#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) -+ -+#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) -+ -+/*values for BIOS Page 1 DeviceSettings field */ -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010) -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) -+ -+/*defines for BIOS Page 1 UEFIVersion field */ -+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00) -+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8) -+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF) -+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0) -+ -+ -+ -+/*BIOS Page 2 */ -+ -+typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER { -+ U32 Reserved1; /*0x00 */ -+ U32 Reserved2; /*0x04 */ -+ U32 Reserved3; /*0x08 */ -+ U32 Reserved4; /*0x0C */ -+ U32 Reserved5; /*0x10 */ -+ U32 Reserved6; /*0x14 */ -+} MPI2_BOOT_DEVICE_ADAPTER_ORDER, -+ *PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER, -+ Mpi2BootDeviceAdapterOrder_t, -+ *pMpi2BootDeviceAdapterOrder_t; -+ -+typedef struct _MPI2_BOOT_DEVICE_SAS_WWID { -+ U64 SASAddress; /*0x00 */ -+ U8 LUN[8]; /*0x08 */ -+ U32 Reserved1; /*0x10 */ -+ U32 Reserved2; /*0x14 */ -+} MPI2_BOOT_DEVICE_SAS_WWID, -+ *PTR_MPI2_BOOT_DEVICE_SAS_WWID, -+ Mpi2BootDeviceSasWwid_t, -+ *pMpi2BootDeviceSasWwid_t; -+ -+typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT { -+ U64 EnclosureLogicalID; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+ U16 SlotNumber; /*0x10 */ -+ U16 Reserved3; /*0x12 */ -+ U32 Reserved4; /*0x14 */ -+} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, -+ *PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, -+ Mpi2BootDeviceEnclosureSlot_t, -+ *pMpi2BootDeviceEnclosureSlot_t; -+ -+typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME { -+ U64 DeviceName; /*0x00 */ -+ U8 LUN[8]; /*0x08 */ -+ U32 Reserved1; /*0x10 */ -+ U32 Reserved2; /*0x14 */ -+} MPI2_BOOT_DEVICE_DEVICE_NAME, -+ *PTR_MPI2_BOOT_DEVICE_DEVICE_NAME, -+ Mpi2BootDeviceDeviceName_t, -+ *pMpi2BootDeviceDeviceName_t; -+ -+typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE { -+ MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder; -+ MPI2_BOOT_DEVICE_SAS_WWID SasWwid; -+ MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot; -+ MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName; -+} MPI2_BIOSPAGE2_BOOT_DEVICE, -+ *PTR_MPI2_BIOSPAGE2_BOOT_DEVICE, -+ Mpi2BiosPage2BootDevice_t, -+ *pMpi2BiosPage2BootDevice_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_BIOS_2 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U32 Reserved3; /*0x0C */ -+ U32 Reserved4; /*0x10 */ -+ U32 Reserved5; /*0x14 */ -+ U32 Reserved6; /*0x18 */ -+ U8 ReqBootDeviceForm; /*0x1C */ -+ U8 Reserved7; /*0x1D */ -+ U16 Reserved8; /*0x1E */ -+ MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /*0x20 */ -+ U8 ReqAltBootDeviceForm; /*0x38 */ -+ U8 Reserved9; /*0x39 */ -+ U16 Reserved10; /*0x3A */ -+ MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /*0x3C */ -+ U8 CurrentBootDeviceForm; /*0x58 */ -+ U8 Reserved11; /*0x59 */ -+ U16 Reserved12; /*0x5A */ -+ MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /*0x58 */ -+} MPI2_CONFIG_PAGE_BIOS_2, *PTR_MPI2_CONFIG_PAGE_BIOS_2, -+ Mpi2BiosPage2_t, *pMpi2BiosPage2_t; -+ -+#define MPI2_BIOSPAGE2_PAGEVERSION (0x04) -+ -+/*values for BIOS Page 2 BootDeviceForm fields */ -+#define MPI2_BIOSPAGE2_FORM_MASK (0x0F) -+#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00) -+#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05) -+#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) -+#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07) -+ -+ -+/*BIOS Page 3 */ -+ -+#define MPI2_BIOSPAGE3_NUM_ADAPTER (4) -+ -+typedef struct _MPI2_ADAPTER_INFO { -+ U8 PciBusNumber; /*0x00 */ -+ U8 PciDeviceAndFunctionNumber; /*0x01 */ -+ U16 AdapterFlags; /*0x02 */ -+} MPI2_ADAPTER_INFO, *PTR_MPI2_ADAPTER_INFO, -+ Mpi2AdapterInfo_t, *pMpi2AdapterInfo_t; -+ -+#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) -+#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) -+ -+typedef struct _MPI2_ADAPTER_ORDER_AUX { -+ U64 WWID; /* 0x00 */ -+ U32 Reserved1; /* 0x08 */ -+ U32 Reserved2; /* 0x0C */ -+} MPI2_ADAPTER_ORDER_AUX, *PTR_MPI2_ADAPTER_ORDER_AUX, -+ Mpi2AdapterOrderAux_t, *pMpi2AdapterOrderAux_t; -+ -+ -+typedef struct _MPI2_CONFIG_PAGE_BIOS_3 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 GlobalFlags; /*0x04 */ -+ U32 BiosVersion; /*0x08 */ -+ MPI2_ADAPTER_INFO AdapterOrder[MPI2_BIOSPAGE3_NUM_ADAPTER]; -+ U32 Reserved1; /*0x1C */ -+ MPI2_ADAPTER_ORDER_AUX AdapterOrderAux[MPI2_BIOSPAGE3_NUM_ADAPTER]; -+} MPI2_CONFIG_PAGE_BIOS_3, -+ *PTR_MPI2_CONFIG_PAGE_BIOS_3, -+ Mpi2BiosPage3_t, *pMpi2BiosPage3_t; -+ -+#define MPI2_BIOSPAGE3_PAGEVERSION (0x01) -+ -+/*values for BIOS Page 3 GlobalFlags */ -+#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002) -+#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004) -+#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010) -+ -+#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) -+#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) -+#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020) -+#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) -+ -+ -+/*BIOS Page 4 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES -+#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_BIOS4_ENTRY { -+ U64 ReassignmentWWID; /*0x00 */ -+ U64 ReassignmentDeviceName; /*0x08 */ -+} MPI2_BIOS4_ENTRY, *PTR_MPI2_BIOS4_ENTRY, -+ Mpi2MBios4Entry_t, *pMpi2Bios4Entry_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_BIOS_4 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumPhys; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ MPI2_BIOS4_ENTRY -+ Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /*0x08 */ -+} MPI2_CONFIG_PAGE_BIOS_4, *PTR_MPI2_CONFIG_PAGE_BIOS_4, -+ Mpi2BiosPage4_t, *pMpi2BiosPage4_t; -+ -+#define MPI2_BIOSPAGE4_PAGEVERSION (0x01) -+ -+ -+/**************************************************************************** -+* RAID Volume Config Pages -+****************************************************************************/ -+ -+/*RAID Volume Page 0 */ -+ -+typedef struct _MPI2_RAIDVOL0_PHYS_DISK { -+ U8 RAIDSetNum; /*0x00 */ -+ U8 PhysDiskMap; /*0x01 */ -+ U8 PhysDiskNum; /*0x02 */ -+ U8 Reserved; /*0x03 */ -+} MPI2_RAIDVOL0_PHYS_DISK, *PTR_MPI2_RAIDVOL0_PHYS_DISK, -+ Mpi2RaidVol0PhysDisk_t, *pMpi2RaidVol0PhysDisk_t; -+ -+/*defines for the PhysDiskMap field */ -+#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01) -+#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02) -+ -+typedef struct _MPI2_RAIDVOL0_SETTINGS { -+ U16 Settings; /*0x00 */ -+ U8 HotSparePool; /*0x01 */ -+ U8 Reserved; /*0x02 */ -+} MPI2_RAIDVOL0_SETTINGS, *PTR_MPI2_RAIDVOL0_SETTINGS, -+ Mpi2RaidVol0Settings_t, -+ *pMpi2RaidVol0Settings_t; -+ -+/*RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */ -+#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01) -+#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02) -+#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04) -+#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08) -+#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10) -+#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20) -+#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40) -+#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80) -+ -+/*RAID Volume Page 0 VolumeSettings defines */ -+#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008) -+#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004) -+ -+#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003) -+#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000) -+#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001) -+#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhysDisks at runtime. -+ */ -+#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX -+#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U16 DevHandle; /*0x04 */ -+ U8 VolumeState; /*0x06 */ -+ U8 VolumeType; /*0x07 */ -+ U32 VolumeStatusFlags; /*0x08 */ -+ MPI2_RAIDVOL0_SETTINGS VolumeSettings; /*0x0C */ -+ U64 MaxLBA; /*0x10 */ -+ U32 StripeSize; /*0x18 */ -+ U16 BlockSize; /*0x1C */ -+ U16 Reserved1; /*0x1E */ -+ U8 SupportedPhysDisks;/*0x20 */ -+ U8 ResyncRate; /*0x21 */ -+ U16 DataScrubDuration; /*0x22 */ -+ U8 NumPhysDisks; /*0x24 */ -+ U8 Reserved2; /*0x25 */ -+ U8 Reserved3; /*0x26 */ -+ U8 InactiveStatus; /*0x27 */ -+ MPI2_RAIDVOL0_PHYS_DISK -+ PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /*0x28 */ -+} MPI2_CONFIG_PAGE_RAID_VOL_0, -+ *PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, -+ Mpi2RaidVolPage0_t, *pMpi2RaidVolPage0_t; -+ -+#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A) -+ -+/*values for RAID VolumeState */ -+#define MPI2_RAID_VOL_STATE_MISSING (0x00) -+#define MPI2_RAID_VOL_STATE_FAILED (0x01) -+#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02) -+#define MPI2_RAID_VOL_STATE_ONLINE (0x03) -+#define MPI2_RAID_VOL_STATE_DEGRADED (0x04) -+#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05) -+ -+/*values for RAID VolumeType */ -+#define MPI2_RAID_VOL_TYPE_RAID0 (0x00) -+#define MPI2_RAID_VOL_TYPE_RAID1E (0x01) -+#define MPI2_RAID_VOL_TYPE_RAID1 (0x02) -+#define MPI2_RAID_VOL_TYPE_RAID10 (0x05) -+#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF) -+ -+/*values for RAID Volume Page 0 VolumeStatusFlags field */ -+#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080) -+#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) -+#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) -+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010) -+#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008) -+#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004) -+#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002) -+#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001) -+ -+/*values for RAID Volume Page 0 SupportedPhysDisks field */ -+#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08) -+#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04) -+#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02) -+#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01) -+ -+/*values for RAID Volume Page 0 InactiveStatus field */ -+#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) -+#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01) -+#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02) -+#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03) -+#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04) -+#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05) -+#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06) -+ -+ -+/*RAID Volume Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U16 DevHandle; /*0x04 */ -+ U16 Reserved0; /*0x06 */ -+ U8 GUID[24]; /*0x08 */ -+ U8 Name[16]; /*0x20 */ -+ U64 WWID; /*0x30 */ -+ U32 Reserved1; /*0x38 */ -+ U32 Reserved2; /*0x3C */ -+} MPI2_CONFIG_PAGE_RAID_VOL_1, -+ *PTR_MPI2_CONFIG_PAGE_RAID_VOL_1, -+ Mpi2RaidVolPage1_t, *pMpi2RaidVolPage1_t; -+ -+#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03) -+ -+ -+/**************************************************************************** -+* RAID Physical Disk Config Pages -+****************************************************************************/ -+ -+/*RAID Physical Disk Page 0 */ -+ -+typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS { -+ U16 Reserved1; /*0x00 */ -+ U8 HotSparePool; /*0x02 */ -+ U8 Reserved2; /*0x03 */ -+} MPI2_RAIDPHYSDISK0_SETTINGS, -+ *PTR_MPI2_RAIDPHYSDISK0_SETTINGS, -+ Mpi2RaidPhysDisk0Settings_t, -+ *pMpi2RaidPhysDisk0Settings_t; -+ -+/*use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */ -+ -+typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA { -+ U8 VendorID[8]; /*0x00 */ -+ U8 ProductID[16]; /*0x08 */ -+ U8 ProductRevLevel[4]; /*0x18 */ -+ U8 SerialNum[32]; /*0x1C */ -+} MPI2_RAIDPHYSDISK0_INQUIRY_DATA, -+ *PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA, -+ Mpi2RaidPhysDisk0InquiryData_t, -+ *pMpi2RaidPhysDisk0InquiryData_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U16 DevHandle; /*0x04 */ -+ U8 Reserved1; /*0x06 */ -+ U8 PhysDiskNum; /*0x07 */ -+ MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+ MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /*0x10 */ -+ U32 Reserved3; /*0x4C */ -+ U8 PhysDiskState; /*0x50 */ -+ U8 OfflineReason; /*0x51 */ -+ U8 IncompatibleReason; /*0x52 */ -+ U8 PhysDiskAttributes; /*0x53 */ -+ U32 PhysDiskStatusFlags;/*0x54 */ -+ U64 DeviceMaxLBA; /*0x58 */ -+ U64 HostMaxLBA; /*0x60 */ -+ U64 CoercedMaxLBA; /*0x68 */ -+ U16 BlockSize; /*0x70 */ -+ U16 Reserved5; /*0x72 */ -+ U32 Reserved6; /*0x74 */ -+} MPI2_CONFIG_PAGE_RD_PDISK_0, -+ *PTR_MPI2_CONFIG_PAGE_RD_PDISK_0, -+ Mpi2RaidPhysDiskPage0_t, -+ *pMpi2RaidPhysDiskPage0_t; -+ -+#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05) -+ -+/*PhysDiskState defines */ -+#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00) -+#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01) -+#define MPI2_RAID_PD_STATE_OFFLINE (0x02) -+#define MPI2_RAID_PD_STATE_ONLINE (0x03) -+#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04) -+#define MPI2_RAID_PD_STATE_DEGRADED (0x05) -+#define MPI2_RAID_PD_STATE_REBUILDING (0x06) -+#define MPI2_RAID_PD_STATE_OPTIMAL (0x07) -+ -+/*OfflineReason defines */ -+#define MPI2_PHYSDISK0_ONLINE (0x00) -+#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01) -+#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03) -+#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04) -+#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05) -+#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06) -+#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF) -+ -+/*IncompatibleReason defines */ -+#define MPI2_PHYSDISK0_COMPATIBLE (0x00) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) -+ -+/*PhysDiskAttributes defines */ -+#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C) -+#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) -+#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) -+ -+#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03) -+#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) -+#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) -+ -+/*PhysDiskStatusFlags defines */ -+#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040) -+#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020) -+#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010) -+#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000) -+#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008) -+#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004) -+#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002) -+#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001) -+ -+ -+/*RAID Physical Disk Page 1 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhysDiskPaths at runtime. -+ */ -+#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX -+#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) -+#endif -+ -+typedef struct _MPI2_RAIDPHYSDISK1_PATH { -+ U16 DevHandle; /*0x00 */ -+ U16 Reserved1; /*0x02 */ -+ U64 WWID; /*0x04 */ -+ U64 OwnerWWID; /*0x0C */ -+ U8 OwnerIdentifier; /*0x14 */ -+ U8 Reserved2; /*0x15 */ -+ U16 Flags; /*0x16 */ -+} MPI2_RAIDPHYSDISK1_PATH, *PTR_MPI2_RAIDPHYSDISK1_PATH, -+ Mpi2RaidPhysDisk1Path_t, -+ *pMpi2RaidPhysDisk1Path_t; -+ -+/*RAID Physical Disk Page 1 Physical Disk Path Flags field defines */ -+#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004) -+#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) -+#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001) -+ -+typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumPhysDiskPaths; /*0x04 */ -+ U8 PhysDiskNum; /*0x05 */ -+ U16 Reserved1; /*0x06 */ -+ U32 Reserved2; /*0x08 */ -+ MPI2_RAIDPHYSDISK1_PATH -+ PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/*0x0C */ -+} MPI2_CONFIG_PAGE_RD_PDISK_1, -+ *PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, -+ Mpi2RaidPhysDiskPage1_t, -+ *pMpi2RaidPhysDiskPage1_t; -+ -+#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02) -+ -+ -+/**************************************************************************** -+* values for fields used by several types of SAS Config Pages -+****************************************************************************/ -+ -+/*values for NegotiatedLinkRates fields */ -+#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0) -+#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4) -+#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F) -+/*link rates used for Negotiated Physical and Logical Link Rate */ -+#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00) -+#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01) -+#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02) -+#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) -+#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) -+#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) -+#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06) -+#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) -+#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) -+#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) -+#define MPI25_SAS_NEG_LINK_RATE_12_0 (0x0B) -+ -+ -+/*values for AttachedPhyInfo fields */ -+#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040) -+#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020) -+#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010) -+ -+#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F) -+#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000) -+#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001) -+#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002) -+#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003) -+#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004) -+#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005) -+#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006) -+#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007) -+#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008) -+ -+ -+/*values for PhyInfo fields */ -+#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) -+ -+#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) -+#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27) -+#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) -+#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) -+#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) -+ -+#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) -+#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) -+#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) -+#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000) -+#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000) -+#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000) -+ -+#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000) -+#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000) -+#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000) -+#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000) -+#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000) -+#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000) -+#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000) -+#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000) -+#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000) -+#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000) -+ -+#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000) -+#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000) -+#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000) -+#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000) -+ -+#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) -+#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) -+ -+#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) -+#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000) -+#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) -+#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020) -+ -+ -+/*values for SAS ProgrammedLinkRate fields */ -+#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0) -+#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) -+#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80) -+#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90) -+#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0) -+#define MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0) -+#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F) -+#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) -+#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08) -+#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09) -+#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A) -+#define MPI25_SAS_PRATE_MIN_RATE_12_0 (0x0B) -+ -+ -+/*values for SAS HwLinkRate fields */ -+#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0) -+#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80) -+#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90) -+#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0) -+#define MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0) -+#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F) -+#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08) -+#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09) -+#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A) -+#define MPI25_SAS_HWRATE_MIN_RATE_12_0 (0x0B) -+ -+ -+ -+/**************************************************************************** -+* SAS IO Unit Config Pages -+****************************************************************************/ -+ -+/*SAS IO Unit Page 0 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA { -+ U8 Port; /*0x00 */ -+ U8 PortFlags; /*0x01 */ -+ U8 PhyFlags; /*0x02 */ -+ U8 NegotiatedLinkRate; /*0x03 */ -+ U32 ControllerPhyDeviceInfo;/*0x04 */ -+ U16 AttachedDevHandle; /*0x08 */ -+ U16 ControllerDevHandle; /*0x0A */ -+ U32 DiscoveryStatus; /*0x0C */ -+ U32 Reserved; /*0x10 */ -+} MPI2_SAS_IO_UNIT0_PHY_DATA, -+ *PTR_MPI2_SAS_IO_UNIT0_PHY_DATA, -+ Mpi2SasIOUnit0PhyData_t, -+ *pMpi2SasIOUnit0PhyData_t; -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT0_PHY_MAX -+#define MPI2_SAS_IOUNIT0_PHY_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1;/*0x08 */ -+ U8 NumPhys; /*0x0C */ -+ U8 Reserved2;/*0x0D */ -+ U16 Reserved3;/*0x0E */ -+ MPI2_SAS_IO_UNIT0_PHY_DATA -+ PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /*0x10 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_0, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, -+ Mpi2SasIOUnitPage0_t, *pMpi2SasIOUnitPage0_t; -+ -+#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05) -+ -+/*values for SAS IO Unit Page 0 PortFlags */ -+#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08) -+#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01) -+ -+/*values for SAS IO Unit Page 0 PhyFlags */ -+#define MPI2_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT (0x40) -+#define MPI2_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT (0x20) -+#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10) -+#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) -+ -+/*use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -+ -+/*see mpi2_sas.h for values for -+ *SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ -+ -+/*values for SAS IO Unit Page 0 DiscoveryStatus */ -+#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -+#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000) -+#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000) -+#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -+#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000) -+#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -+#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -+#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000) -+#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -+#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) -+#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400) -+#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) -+#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100) -+#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080) -+#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040) -+#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020) -+#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010) -+#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004) -+#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002) -+#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001) -+ -+ -+/*SAS IO Unit Page 1 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA { -+ U8 Port; /*0x00 */ -+ U8 PortFlags; /*0x01 */ -+ U8 PhyFlags; /*0x02 */ -+ U8 MaxMinLinkRate; /*0x03 */ -+ U32 ControllerPhyDeviceInfo; /*0x04 */ -+ U16 MaxTargetPortConnectTime; /*0x08 */ -+ U16 Reserved1; /*0x0A */ -+} MPI2_SAS_IO_UNIT1_PHY_DATA, -+ *PTR_MPI2_SAS_IO_UNIT1_PHY_DATA, -+ Mpi2SasIOUnit1PhyData_t, -+ *pMpi2SasIOUnit1PhyData_t; -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT1_PHY_MAX -+#define MPI2_SAS_IOUNIT1_PHY_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U16 -+ ControlFlags; /*0x08 */ -+ U16 -+ SASNarrowMaxQueueDepth; /*0x0A */ -+ U16 -+ AdditionalControlFlags; /*0x0C */ -+ U16 -+ SASWideMaxQueueDepth; /*0x0E */ -+ U8 -+ NumPhys; /*0x10 */ -+ U8 -+ SATAMaxQDepth; /*0x11 */ -+ U8 -+ ReportDeviceMissingDelay; /*0x12 */ -+ U8 -+ IODeviceMissingDelay; /*0x13 */ -+ MPI2_SAS_IO_UNIT1_PHY_DATA -+ PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /*0x14 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_1, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, -+ Mpi2SasIOUnitPage1_t, *pMpi2SasIOUnitPage1_t; -+ -+#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09) -+ -+/*values for SAS IO Unit Page 1 ControlFlags */ -+#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) -+ -+#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600) -+#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) -+#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0) -+#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1) -+#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2) -+ -+#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) -+#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008) -+#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) -+#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) -+#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) -+ -+/*values for SAS IO Unit Page 1 AdditionalControlFlags */ -+#define MPI2_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT (0x0100) -+#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) -+#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) -+#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020) -+#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) -+#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) -+#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) -+#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) -+#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) -+ -+/*defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ -+#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) -+#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80) -+ -+/*values for SAS IO Unit Page 1 PortFlags */ -+#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) -+ -+/*values for SAS IO Unit Page 1 PhyFlags */ -+#define MPI2_SASIOUNIT1_PHYFLAGS_INIT_PERSIST_CONNECT (0x40) -+#define MPI2_SASIOUNIT1_PHYFLAGS_TARG_PERSIST_CONNECT (0x20) -+#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) -+#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) -+ -+/*values for SAS IO Unit Page 1 MaxMinLinkRate */ -+#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) -+#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) -+#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) -+#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0) -+#define MPI25_SASIOUNIT1_MAX_RATE_12_0 (0xB0) -+#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F) -+#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08) -+#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09) -+#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A) -+#define MPI25_SASIOUNIT1_MIN_RATE_12_0 (0x0B) -+ -+/*see mpi2_sas.h for values for -+ *SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ -+ -+ -+/*SAS IO Unit Page 4 (for MPI v2.5 and earlier) */ -+ -+typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP { -+ U8 MaxTargetSpinup; /*0x00 */ -+ U8 SpinupDelay; /*0x01 */ -+ U8 SpinupFlags; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+} MPI2_SAS_IOUNIT4_SPINUP_GROUP, -+ *PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, -+ Mpi2SasIOUnit4SpinupGroup_t, -+ *pMpi2SasIOUnit4SpinupGroup_t; -+/*defines for SAS IO Unit Page 4 SpinupFlags */ -+#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01) -+ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT4_PHY_MAX -+#define MPI2_SAS_IOUNIT4_PHY_MAX (4) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header;/*0x00 */ -+ MPI2_SAS_IOUNIT4_SPINUP_GROUP -+ SpinupGroupParameters[4]; /*0x08 */ -+ U32 -+ Reserved1; /*0x18 */ -+ U32 -+ Reserved2; /*0x1C */ -+ U32 -+ Reserved3; /*0x20 */ -+ U8 -+ BootDeviceWaitTime; /*0x24 */ -+ U8 -+ SATADeviceWaitTime; /*0x25 */ -+ U16 -+ Reserved5; /*0x26 */ -+ U8 -+ NumPhys; /*0x28 */ -+ U8 -+ PEInitialSpinupDelay; /*0x29 */ -+ U8 -+ PEReplyDelay; /*0x2A */ -+ U8 -+ Flags; /*0x2B */ -+ U8 -+ PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /*0x2C */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_4, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4, -+ Mpi2SasIOUnitPage4_t, *pMpi2SasIOUnitPage4_t; -+ -+#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02) -+ -+/*defines for Flags field */ -+#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01) -+ -+/*defines for PHY field */ -+#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) -+ -+ -+/*SAS IO Unit Page 5 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { -+ U8 ControlFlags; /*0x00 */ -+ U8 PortWidthModGroup; /*0x01 */ -+ U16 InactivityTimerExponent; /*0x02 */ -+ U8 SATAPartialTimeout; /*0x04 */ -+ U8 Reserved2; /*0x05 */ -+ U8 SATASlumberTimeout; /*0x06 */ -+ U8 Reserved3; /*0x07 */ -+ U8 SASPartialTimeout; /*0x08 */ -+ U8 Reserved4; /*0x09 */ -+ U8 SASSlumberTimeout; /*0x0A */ -+ U8 Reserved5; /*0x0B */ -+} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, -+ *PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, -+ Mpi2SasIOUnit5PhyPmSettings_t, -+ *pMpi2SasIOUnit5PhyPmSettings_t; -+ -+/*defines for ControlFlags field */ -+#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) -+#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) -+#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) -+#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) -+ -+/*defines for PortWidthModeGroup field */ -+#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) -+ -+/*defines for InactivityTimerExponent field */ -+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) -+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) -+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) -+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) -+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) -+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) -+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) -+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) -+ -+#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) -+#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) -+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) -+#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) -+#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) -+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) -+#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) -+#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT5_PHY_MAX -+#define MPI2_SAS_IOUNIT5_PHY_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U8 NumPhys; /*0x08 */ -+ U8 Reserved1;/*0x09 */ -+ U16 Reserved2;/*0x0A */ -+ U32 Reserved3;/*0x0C */ -+ MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS -+ SASPhyPowerManagementSettings[MPI2_SAS_IOUNIT5_PHY_MAX];/*0x10 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_5, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, -+ Mpi2SasIOUnitPage5_t, *pMpi2SasIOUnitPage5_t; -+ -+#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) -+ -+ -+/*SAS IO Unit Page 6 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { -+ U8 CurrentStatus; /*0x00 */ -+ U8 CurrentModulation; /*0x01 */ -+ U8 CurrentUtilization; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+ U32 Reserved2; /*0x04 */ -+} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, -+ *PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, -+ Mpi2SasIOUnit6PortWidthModGroupStatus_t, -+ *pMpi2SasIOUnit6PortWidthModGroupStatus_t; -+ -+/*defines for CurrentStatus field */ -+#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) -+#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) -+#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) -+#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) -+#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) -+#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) -+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) -+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) -+ -+/*defines for CurrentModulation field */ -+#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) -+#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) -+#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) -+#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumGroups at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX -+#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+ U8 NumGroups; /*0x10 */ -+ U8 Reserved3; /*0x11 */ -+ U16 Reserved4; /*0x12 */ -+ MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS -+ PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /*0x14 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_6, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, -+ Mpi2SasIOUnitPage6_t, *pMpi2SasIOUnitPage6_t; -+ -+#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) -+ -+ -+/*SAS IO Unit Page 7 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { -+ U8 Flags; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U8 Threshold75Pct; /*0x04 */ -+ U8 Threshold50Pct; /*0x05 */ -+ U8 Threshold25Pct; /*0x06 */ -+ U8 Reserved3; /*0x07 */ -+} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, -+ *PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, -+ Mpi2SasIOUnit7PortWidthModGroupSettings_t, -+ *pMpi2SasIOUnit7PortWidthModGroupSettings_t; -+ -+/*defines for Flags field */ -+#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) -+ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumGroups at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX -+#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U8 SamplingInterval; /*0x08 */ -+ U8 WindowLength; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U32 Reserved2; /*0x0C */ -+ U32 Reserved3; /*0x10 */ -+ U8 NumGroups; /*0x14 */ -+ U8 Reserved4; /*0x15 */ -+ U16 Reserved5; /*0x16 */ -+ MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS -+ PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX];/*0x18 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_7, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, -+ Mpi2SasIOUnitPage7_t, *pMpi2SasIOUnitPage7_t; -+ -+#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) -+ -+ -+/*SAS IO Unit Page 8 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U32 -+ PowerManagementCapabilities; /*0x0C */ -+ U8 -+ TxRxSleepStatus; /*0x10 */ -+ U8 -+ Reserved2; /*0x11 */ -+ U16 -+ Reserved3; /*0x12 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_8, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, -+ Mpi2SasIOUnitPage8_t, *pMpi2SasIOUnitPage8_t; -+ -+#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) -+ -+/*defines for PowerManagementCapabilities field */ -+#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000) -+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800) -+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400) -+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200) -+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001) -+ -+/*defines for TxRxSleepStatus field */ -+#define MPI25_SASIOUNIT8_TXRXSLEEP_UNSUPPORTED (0x00) -+#define MPI25_SASIOUNIT8_TXRXSLEEP_DISENGAGED (0x01) -+#define MPI25_SASIOUNIT8_TXRXSLEEP_ACTIVE (0x02) -+#define MPI25_SASIOUNIT8_TXRXSLEEP_SHUTDOWN (0x03) -+ -+ -+ -+/*SAS IO Unit Page 16 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U64 -+ TimeStamp; /*0x08 */ -+ U32 -+ Reserved1; /*0x10 */ -+ U32 -+ Reserved2; /*0x14 */ -+ U32 -+ FastPathPendedRequests; /*0x18 */ -+ U32 -+ FastPathUnPendedRequests; /*0x1C */ -+ U32 -+ FastPathHostRequestStarts; /*0x20 */ -+ U32 -+ FastPathFirmwareRequestStarts; /*0x24 */ -+ U32 -+ FastPathHostCompletions; /*0x28 */ -+ U32 -+ FastPathFirmwareCompletions; /*0x2C */ -+ U32 -+ NonFastPathRequestStarts; /*0x30 */ -+ U32 -+ NonFastPathHostCompletions; /*0x30 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT16, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT16, -+ Mpi2SasIOUnitPage16_t, *pMpi2SasIOUnitPage16_t; -+ -+#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00) -+ -+ -+/**************************************************************************** -+* SAS Expander Config Pages -+****************************************************************************/ -+ -+/*SAS Expander Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U8 -+ PhysicalPort; /*0x08 */ -+ U8 -+ ReportGenLength; /*0x09 */ -+ U16 -+ EnclosureHandle; /*0x0A */ -+ U64 -+ SASAddress; /*0x0C */ -+ U32 -+ DiscoveryStatus; /*0x14 */ -+ U16 -+ DevHandle; /*0x18 */ -+ U16 -+ ParentDevHandle; /*0x1A */ -+ U16 -+ ExpanderChangeCount; /*0x1C */ -+ U16 -+ ExpanderRouteIndexes; /*0x1E */ -+ U8 -+ NumPhys; /*0x20 */ -+ U8 -+ SASLevel; /*0x21 */ -+ U16 -+ Flags; /*0x22 */ -+ U16 -+ STPBusInactivityTimeLimit; /*0x24 */ -+ U16 -+ STPMaxConnectTimeLimit; /*0x26 */ -+ U16 -+ STP_SMP_NexusLossTime; /*0x28 */ -+ U16 -+ MaxNumRoutedSasAddresses; /*0x2A */ -+ U64 -+ ActiveZoneManagerSASAddress;/*0x2C */ -+ U16 -+ ZoneLockInactivityLimit; /*0x34 */ -+ U16 -+ Reserved1; /*0x36 */ -+ U8 -+ TimeToReducedFunc; /*0x38 */ -+ U8 -+ InitialTimeToReducedFunc; /*0x39 */ -+ U8 -+ MaxReducedFuncTime; /*0x3A */ -+ U8 -+ Reserved2; /*0x3B */ -+} MPI2_CONFIG_PAGE_EXPANDER_0, -+ *PTR_MPI2_CONFIG_PAGE_EXPANDER_0, -+ Mpi2ExpanderPage0_t, *pMpi2ExpanderPage0_t; -+ -+#define MPI2_SASEXPANDER0_PAGEVERSION (0x06) -+ -+/*values for SAS Expander Page 0 DiscoveryStatus field */ -+#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -+#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000) -+#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000) -+#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -+#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000) -+#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -+#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -+#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000) -+#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -+#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) -+#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400) -+#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200) -+#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100) -+#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080) -+#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040) -+#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020) -+#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010) -+#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004) -+#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002) -+#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) -+ -+/*values for SAS Expander Page 0 Flags field */ -+#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000) -+#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000) -+#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) -+#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) -+#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200) -+#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100) -+#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080) -+#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010) -+#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004) -+#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002) -+#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001) -+ -+ -+/*SAS Expander Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U8 -+ PhysicalPort; /*0x08 */ -+ U8 -+ Reserved1; /*0x09 */ -+ U16 -+ Reserved2; /*0x0A */ -+ U8 -+ NumPhys; /*0x0C */ -+ U8 -+ Phy; /*0x0D */ -+ U16 -+ NumTableEntriesProgrammed; /*0x0E */ -+ U8 -+ ProgrammedLinkRate; /*0x10 */ -+ U8 -+ HwLinkRate; /*0x11 */ -+ U16 -+ AttachedDevHandle; /*0x12 */ -+ U32 -+ PhyInfo; /*0x14 */ -+ U32 -+ AttachedDeviceInfo; /*0x18 */ -+ U16 -+ ExpanderDevHandle; /*0x1C */ -+ U8 -+ ChangeCount; /*0x1E */ -+ U8 -+ NegotiatedLinkRate; /*0x1F */ -+ U8 -+ PhyIdentifier; /*0x20 */ -+ U8 -+ AttachedPhyIdentifier; /*0x21 */ -+ U8 -+ Reserved3; /*0x22 */ -+ U8 -+ DiscoveryInfo; /*0x23 */ -+ U32 -+ AttachedPhyInfo; /*0x24 */ -+ U8 -+ ZoneGroup; /*0x28 */ -+ U8 -+ SelfConfigStatus; /*0x29 */ -+ U16 -+ Reserved4; /*0x2A */ -+} MPI2_CONFIG_PAGE_EXPANDER_1, -+ *PTR_MPI2_CONFIG_PAGE_EXPANDER_1, -+ Mpi2ExpanderPage1_t, *pMpi2ExpanderPage1_t; -+ -+#define MPI2_SASEXPANDER1_PAGEVERSION (0x02) -+ -+/*use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ -+ -+/*use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ -+ -+/*use MPI2_SAS_PHYINFO_ for the PhyInfo field */ -+ -+/*see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines -+ *used for the AttachedDeviceInfo field */ -+ -+/*use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -+ -+/*values for SAS Expander Page 1 DiscoveryInfo field */ -+#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) -+#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) -+#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) -+ -+/*use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ -+ -+ -+/**************************************************************************** -+* SAS Device Config Pages -+****************************************************************************/ -+ -+/*SAS Device Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U16 -+ Slot; /*0x08 */ -+ U16 -+ EnclosureHandle; /*0x0A */ -+ U64 -+ SASAddress; /*0x0C */ -+ U16 -+ ParentDevHandle; /*0x14 */ -+ U8 -+ PhyNum; /*0x16 */ -+ U8 -+ AccessStatus; /*0x17 */ -+ U16 -+ DevHandle; /*0x18 */ -+ U8 -+ AttachedPhyIdentifier; /*0x1A */ -+ U8 -+ ZoneGroup; /*0x1B */ -+ U32 -+ DeviceInfo; /*0x1C */ -+ U16 -+ Flags; /*0x20 */ -+ U8 -+ PhysicalPort; /*0x22 */ -+ U8 -+ MaxPortConnections; /*0x23 */ -+ U64 -+ DeviceName; /*0x24 */ -+ U8 -+ PortGroups; /*0x2C */ -+ U8 -+ DmaGroup; /*0x2D */ -+ U8 -+ ControlGroup; /*0x2E */ -+ U8 -+ EnclosureLevel; /*0x2F */ -+ U32 -+ ConnectorName[4]; /*0x30 */ -+ U32 -+ Reserved3; /*0x34 */ -+} MPI2_CONFIG_PAGE_SAS_DEV_0, -+ *PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, -+ Mpi2SasDevicePage0_t, -+ *pMpi2SasDevicePage0_t; -+ -+#define MPI2_SASDEVICE0_PAGEVERSION (0x09) -+ -+/*values for SAS Device Page 0 AccessStatus field */ -+#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) -+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) -+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) -+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) -+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) -+#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05) -+#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06) -+#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07) -+/*specific values for SATA Init failures */ -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) -+ -+/*see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ -+ -+/*values for SAS Device Page 0 Flags field */ -+#define MPI2_SAS_DEVICE0_FLAGS_UNAUTHORIZED_DEVICE (0x8000) -+#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH (0x4000) -+#define MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE (0x2000) -+#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) -+#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) -+#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) -+#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) -+#define MPI2_SAS_DEVICE0_FLAGS_PERSIST_CAPABLE (0x0004) -+#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002) -+#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) -+ -+ -+/*SAS Device Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U64 -+ SASAddress; /*0x0C */ -+ U32 -+ Reserved2; /*0x14 */ -+ U16 -+ DevHandle; /*0x18 */ -+ U16 -+ Reserved3; /*0x1A */ -+ U8 -+ InitialRegDeviceFIS[20];/*0x1C */ -+} MPI2_CONFIG_PAGE_SAS_DEV_1, -+ *PTR_MPI2_CONFIG_PAGE_SAS_DEV_1, -+ Mpi2SasDevicePage1_t, -+ *pMpi2SasDevicePage1_t; -+ -+#define MPI2_SASDEVICE1_PAGEVERSION (0x01) -+ -+ -+/**************************************************************************** -+* SAS PHY Config Pages -+****************************************************************************/ -+ -+/*SAS PHY Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U16 -+ OwnerDevHandle; /*0x08 */ -+ U16 -+ Reserved1; /*0x0A */ -+ U16 -+ AttachedDevHandle; /*0x0C */ -+ U8 -+ AttachedPhyIdentifier; /*0x0E */ -+ U8 -+ Reserved2; /*0x0F */ -+ U32 -+ AttachedPhyInfo; /*0x10 */ -+ U8 -+ ProgrammedLinkRate; /*0x14 */ -+ U8 -+ HwLinkRate; /*0x15 */ -+ U8 -+ ChangeCount; /*0x16 */ -+ U8 -+ Flags; /*0x17 */ -+ U32 -+ PhyInfo; /*0x18 */ -+ U8 -+ NegotiatedLinkRate; /*0x1C */ -+ U8 -+ Reserved3; /*0x1D */ -+ U16 -+ Reserved4; /*0x1E */ -+} MPI2_CONFIG_PAGE_SAS_PHY_0, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_0, -+ Mpi2SasPhyPage0_t, *pMpi2SasPhyPage0_t; -+ -+#define MPI2_SASPHY0_PAGEVERSION (0x03) -+ -+/*use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ -+ -+/*use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ -+ -+/*use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ -+ -+/*values for SAS PHY Page 0 Flags field */ -+#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) -+ -+/*use MPI2_SAS_PHYINFO_ for the PhyInfo field */ -+ -+/*use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -+ -+ -+/*SAS PHY Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U32 -+ InvalidDwordCount; /*0x0C */ -+ U32 -+ RunningDisparityErrorCount; /*0x10 */ -+ U32 -+ LossDwordSynchCount; /*0x14 */ -+ U32 -+ PhyResetProblemCount; /*0x18 */ -+} MPI2_CONFIG_PAGE_SAS_PHY_1, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_1, -+ Mpi2SasPhyPage1_t, *pMpi2SasPhyPage1_t; -+ -+#define MPI2_SASPHY1_PAGEVERSION (0x01) -+ -+ -+/*SAS PHY Page 2 */ -+ -+typedef struct _MPI2_SASPHY2_PHY_EVENT { -+ U8 PhyEventCode; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 PhyEventInfo; /*0x04 */ -+} MPI2_SASPHY2_PHY_EVENT, *PTR_MPI2_SASPHY2_PHY_EVENT, -+ Mpi2SasPhy2PhyEvent_t, *pMpi2SasPhy2PhyEvent_t; -+ -+/*use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ -+ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhyEvents at runtime. -+ */ -+#ifndef MPI2_SASPHY2_PHY_EVENT_MAX -+#define MPI2_SASPHY2_PHY_EVENT_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U8 -+ NumPhyEvents; /*0x0C */ -+ U8 -+ Reserved2; /*0x0D */ -+ U16 -+ Reserved3; /*0x0E */ -+ MPI2_SASPHY2_PHY_EVENT -+ PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; /*0x10 */ -+} MPI2_CONFIG_PAGE_SAS_PHY_2, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, -+ Mpi2SasPhyPage2_t, -+ *pMpi2SasPhyPage2_t; -+ -+#define MPI2_SASPHY2_PAGEVERSION (0x00) -+ -+ -+/*SAS PHY Page 3 */ -+ -+typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { -+ U8 PhyEventCode; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U8 CounterType; /*0x04 */ -+ U8 ThresholdWindow; /*0x05 */ -+ U8 TimeUnits; /*0x06 */ -+ U8 Reserved3; /*0x07 */ -+ U32 EventThreshold; /*0x08 */ -+ U16 ThresholdFlags; /*0x0C */ -+ U16 Reserved4; /*0x0E */ -+} MPI2_SASPHY3_PHY_EVENT_CONFIG, -+ *PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, -+ Mpi2SasPhy3PhyEventConfig_t, -+ *pMpi2SasPhy3PhyEventConfig_t; -+ -+/*values for PhyEventCode field */ -+#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00) -+#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) -+#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) -+#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) -+#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) -+#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) -+#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06) -+#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) -+#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) -+#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) -+#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) -+#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) -+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) -+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) -+#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27) -+#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28) -+#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) -+#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A) -+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) -+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) -+#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) -+#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) -+#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) -+#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) -+#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) -+#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) -+#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) -+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2) -+ -+/*Following codes are product specific and in MPI v2.6 and later */ -+#define MPI2_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME (0xD3) -+#define MPI2_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME (0xD4) -+#define MPI2_SASPHY3_EVENT_CODE_LCCONN_TIME (0xD5) -+#define MPI2_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT (0xD6) -+#define MPI2_SASPHY3_EVENT_CODE_SATA_TX_START (0xD7) -+#define MPI2_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT (0xD8) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN (0xD9) -+#define MPI2_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE (0xDA) -+#define MPI2_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xDB) -+#define MPI2_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE (0xDC) -+ -+ -+/*values for the CounterType field */ -+#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) -+#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01) -+#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) -+ -+/*values for the TimeUnits field */ -+#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) -+#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) -+#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) -+#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) -+ -+/*values for the ThresholdFlags field */ -+#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002) -+#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhyEvents at runtime. -+ */ -+#ifndef MPI2_SASPHY3_PHY_EVENT_MAX -+#define MPI2_SASPHY3_PHY_EVENT_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U8 -+ NumPhyEvents; /*0x0C */ -+ U8 -+ Reserved2; /*0x0D */ -+ U16 -+ Reserved3; /*0x0E */ -+ MPI2_SASPHY3_PHY_EVENT_CONFIG -+ PhyEventConfig[MPI2_SASPHY3_PHY_EVENT_MAX]; /*0x10 */ -+} MPI2_CONFIG_PAGE_SAS_PHY_3, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, -+ Mpi2SasPhyPage3_t, *pMpi2SasPhyPage3_t; -+ -+#define MPI2_SASPHY3_PAGEVERSION (0x00) -+ -+ -+/*SAS PHY Page 4 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U16 -+ Reserved1; /*0x08 */ -+ U8 -+ Reserved2; /*0x0A */ -+ U8 -+ Flags; /*0x0B */ -+ U8 -+ InitialFrame[28]; /*0x0C */ -+} MPI2_CONFIG_PAGE_SAS_PHY_4, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, -+ Mpi2SasPhyPage4_t, *pMpi2SasPhyPage4_t; -+ -+#define MPI2_SASPHY4_PAGEVERSION (0x00) -+ -+/*values for the Flags field */ -+#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) -+#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) -+ -+ -+ -+ -+/**************************************************************************** -+* SAS Port Config Pages -+****************************************************************************/ -+ -+/*SAS Port Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U8 -+ PortNumber; /*0x08 */ -+ U8 -+ PhysicalPort; /*0x09 */ -+ U8 -+ PortWidth; /*0x0A */ -+ U8 -+ PhysicalPortWidth; /*0x0B */ -+ U8 -+ ZoneGroup; /*0x0C */ -+ U8 -+ Reserved1; /*0x0D */ -+ U16 -+ Reserved2; /*0x0E */ -+ U64 -+ SASAddress; /*0x10 */ -+ U32 -+ DeviceInfo; /*0x18 */ -+ U32 -+ Reserved3; /*0x1C */ -+ U32 -+ Reserved4; /*0x20 */ -+} MPI2_CONFIG_PAGE_SAS_PORT_0, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PORT_0, -+ Mpi2SasPortPage0_t, *pMpi2SasPortPage0_t; -+ -+#define MPI2_SASPORT0_PAGEVERSION (0x00) -+ -+/*see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */ -+ -+ -+/**************************************************************************** -+* SAS Enclosure Config Pages -+****************************************************************************/ -+ -+/*SAS Enclosure Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U64 -+ EnclosureLogicalID; /*0x0C */ -+ U16 -+ Flags; /*0x14 */ -+ U16 -+ EnclosureHandle; /*0x16 */ -+ U16 -+ NumSlots; /*0x18 */ -+ U16 -+ StartSlot; /*0x1A */ -+ U8 -+ Reserved2; /*0x1C */ -+ U8 -+ EnclosureLevel; /*0x1D */ -+ U16 -+ SEPDevHandle; /*0x1E */ -+ U32 -+ Reserved3; /*0x20 */ -+ U32 -+ Reserved4; /*0x24 */ -+} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, -+ *PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, -+ Mpi2SasEnclosurePage0_t, *pMpi2SasEnclosurePage0_t; -+ -+#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04) -+ -+/*values for SAS Enclosure Page 0 Flags field */ -+#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) -+ -+ -+/**************************************************************************** -+* Log Config Page -+****************************************************************************/ -+ -+/*Log Page 0 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumLogEntries at runtime. -+ */ -+#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES -+#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) -+#endif -+ -+#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) -+ -+typedef struct _MPI2_LOG_0_ENTRY { -+ U64 TimeStamp; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U16 LogSequence; /*0x0C */ -+ U16 LogEntryQualifier; /*0x0E */ -+ U8 VP_ID; /*0x10 */ -+ U8 VF_ID; /*0x11 */ -+ U16 Reserved2; /*0x12 */ -+ U8 -+ LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/*0x14 */ -+} MPI2_LOG_0_ENTRY, *PTR_MPI2_LOG_0_ENTRY, -+ Mpi2Log0Entry_t, *pMpi2Log0Entry_t; -+ -+/*values for Log Page 0 LogEntry LogEntryQualifier field */ -+#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000) -+#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001) -+#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002) -+#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000) -+#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF) -+ -+typedef struct _MPI2_CONFIG_PAGE_LOG_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+ U16 NumLogEntries;/*0x10 */ -+ U16 Reserved3; /*0x12 */ -+ MPI2_LOG_0_ENTRY -+ LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /*0x14 */ -+} MPI2_CONFIG_PAGE_LOG_0, *PTR_MPI2_CONFIG_PAGE_LOG_0, -+ Mpi2LogPage0_t, *pMpi2LogPage0_t; -+ -+#define MPI2_LOG_0_PAGEVERSION (0x02) -+ -+ -+/**************************************************************************** -+* RAID Config Page -+****************************************************************************/ -+ -+/*RAID Page 0 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumElements at runtime. -+ */ -+#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS -+#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) -+#endif -+ -+typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT { -+ U16 ElementFlags; /*0x00 */ -+ U16 VolDevHandle; /*0x02 */ -+ U8 HotSparePool; /*0x04 */ -+ U8 PhysDiskNum; /*0x05 */ -+ U16 PhysDiskDevHandle; /*0x06 */ -+} MPI2_RAIDCONFIG0_CONFIG_ELEMENT, -+ *PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT, -+ Mpi2RaidConfig0ConfigElement_t, -+ *pMpi2RaidConfig0ConfigElement_t; -+ -+/*values for the ElementFlags field */ -+#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F) -+#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000) -+#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001) -+#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002) -+#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003) -+ -+ -+typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U8 NumHotSpares; /*0x08 */ -+ U8 NumPhysDisks; /*0x09 */ -+ U8 NumVolumes; /*0x0A */ -+ U8 ConfigNum; /*0x0B */ -+ U32 Flags; /*0x0C */ -+ U8 ConfigGUID[24]; /*0x10 */ -+ U32 Reserved1; /*0x28 */ -+ U8 NumElements; /*0x2C */ -+ U8 Reserved2; /*0x2D */ -+ U16 Reserved3; /*0x2E */ -+ MPI2_RAIDCONFIG0_CONFIG_ELEMENT -+ ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /*0x30 */ -+} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, -+ *PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, -+ Mpi2RaidConfigurationPage0_t, -+ *pMpi2RaidConfigurationPage0_t; -+ -+#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00) -+ -+/*values for RAID Configuration Page 0 Flags field */ -+#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001) -+ -+ -+/**************************************************************************** -+* Driver Persistent Mapping Config Pages -+****************************************************************************/ -+ -+/*Driver Persistent Mapping Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY { -+ U64 PhysicalIdentifier; /*0x00 */ -+ U16 MappingInformation; /*0x08 */ -+ U16 DeviceIndex; /*0x0A */ -+ U32 PhysicalBitsMapping; /*0x0C */ -+ U32 Reserved1; /*0x10 */ -+} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, -+ *PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, -+ Mpi2DriverMap0Entry_t, *pMpi2DriverMap0Entry_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /*0x08 */ -+} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, -+ *PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, -+ Mpi2DriverMappingPage0_t, *pMpi2DriverMappingPage0_t; -+ -+#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00) -+ -+/*values for Driver Persistent Mapping Page 0 MappingInformation field */ -+#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0) -+#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4) -+#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) -+ -+ -+/**************************************************************************** -+* Ethernet Config Pages -+****************************************************************************/ -+ -+/*Ethernet Page 0 */ -+ -+/*IP address (union of IPv4 and IPv6) */ -+typedef union _MPI2_ETHERNET_IP_ADDR { -+ U32 IPv4Addr; -+ U32 IPv6Addr[4]; -+} MPI2_ETHERNET_IP_ADDR, *PTR_MPI2_ETHERNET_IP_ADDR, -+ Mpi2EthernetIpAddr_t, *pMpi2EthernetIpAddr_t; -+ -+#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) -+ -+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U8 NumInterfaces; /*0x08 */ -+ U8 Reserved0; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U32 Status; /*0x0C */ -+ U8 MediaState; /*0x10 */ -+ U8 Reserved2; /*0x11 */ -+ U16 Reserved3; /*0x12 */ -+ U8 MacAddress[6]; /*0x14 */ -+ U8 Reserved4; /*0x1A */ -+ U8 Reserved5; /*0x1B */ -+ MPI2_ETHERNET_IP_ADDR IpAddress; /*0x1C */ -+ MPI2_ETHERNET_IP_ADDR SubnetMask; /*0x2C */ -+ MPI2_ETHERNET_IP_ADDR GatewayIpAddress;/*0x3C */ -+ MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /*0x4C */ -+ MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /*0x5C */ -+ MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /*0x6C */ -+ U8 -+ HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/*0x7C */ -+} MPI2_CONFIG_PAGE_ETHERNET_0, -+ *PTR_MPI2_CONFIG_PAGE_ETHERNET_0, -+ Mpi2EthernetPage0_t, *pMpi2EthernetPage0_t; -+ -+#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) -+ -+/*values for Ethernet Page 0 Status field */ -+#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) -+#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) -+#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) -+#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) -+#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) -+#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) -+#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) -+#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) -+#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) -+#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) -+#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) -+#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) -+ -+/*values for Ethernet Page 0 MediaState field */ -+#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) -+#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) -+#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) -+ -+#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) -+#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) -+#define MPI2_ETHPG0_MS_10MBIT (0x01) -+#define MPI2_ETHPG0_MS_100MBIT (0x02) -+#define MPI2_ETHPG0_MS_1GBIT (0x03) -+ -+ -+/*Ethernet Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved0; /*0x08 */ -+ U32 -+ Flags; /*0x0C */ -+ U8 -+ MediaState; /*0x10 */ -+ U8 -+ Reserved1; /*0x11 */ -+ U16 -+ Reserved2; /*0x12 */ -+ U8 -+ MacAddress[6]; /*0x14 */ -+ U8 -+ Reserved3; /*0x1A */ -+ U8 -+ Reserved4; /*0x1B */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticIpAddress; /*0x1C */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticSubnetMask; /*0x2C */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticGatewayIpAddress; /*0x3C */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticDNS1IpAddress; /*0x4C */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticDNS2IpAddress; /*0x5C */ -+ U32 -+ Reserved5; /*0x6C */ -+ U32 -+ Reserved6; /*0x70 */ -+ U32 -+ Reserved7; /*0x74 */ -+ U32 -+ Reserved8; /*0x78 */ -+ U8 -+ HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/*0x7C */ -+} MPI2_CONFIG_PAGE_ETHERNET_1, -+ *PTR_MPI2_CONFIG_PAGE_ETHERNET_1, -+ Mpi2EthernetPage1_t, *pMpi2EthernetPage1_t; -+ -+#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) -+ -+/*values for Ethernet Page 1 Flags field */ -+#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) -+#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) -+#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) -+#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) -+#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) -+#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) -+#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) -+#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) -+#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) -+ -+/*values for Ethernet Page 1 MediaState field */ -+#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) -+#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) -+#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) -+ -+#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) -+#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) -+#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) -+#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) -+#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) -+ -+ -+/**************************************************************************** -+* Extended Manufacturing Config Pages -+****************************************************************************/ -+ -+/* -+ *Generic structure to use for product-specific extended manufacturing pages -+ *(currently Extended Manufacturing Page 40 through Extended Manufacturing -+ *Page 60). -+ */ -+ -+typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ ProductSpecificInfo; /*0x08 */ -+} MPI2_CONFIG_PAGE_EXT_MAN_PS, -+ *PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, -+ Mpi2ExtManufacturingPagePS_t, -+ *pMpi2ExtManufacturingPagePS_t; -+ -+/*PageVersion should be provided by product-specific code */ -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h -new file mode 100644 -index 0000000..bba56b6 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h -@@ -0,0 +1,581 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_init.h -+ * Title: MPI SCSI initiator mode messages and structures -+ * Creation Date: June 23, 2006 -+ * -+ * mpi2_init.h Version: 02.00.20 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. -+ * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. -+ * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. -+ * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. -+ * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. -+ * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO -+ * Control field Task Attribute flags. -+ * Moved LUN field defines to mpi2.h becasue they are -+ * common to many structures. -+ * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to -+ * Query Asynchronous Event. -+ * Defined two new bits in the SlotStatus field of the SCSI -+ * Enclosure Processor Request and Reply. -+ * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for -+ * both SCSI IO Error Reply and SCSI Task Management Reply. -+ * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. -+ * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. -+ * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. -+ * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. -+ * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. -+ * 11-18-11 02.00.12 Incorporating additions for MPI v2.5. -+ * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command -+ * Priority to match SAM-4. -+ * Added EEDPErrorOffset to MPI2_SCSI_IO_REPLY. -+ * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION. -+ * 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY, -+ * replacing the Reserved4 field. -+ * 11-18-14 02.00.16 Updated copyright information. -+ * 03-16-15 02.00.17 Updated for MPI v2.6. -+ * Added MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH. -+ * Added MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF and -+ * MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF. -+ * 08-26-15 02.00.18 Added SCSITASKMGMT_MSGFLAGS for Target Reset. -+ * 12-18-15 02.00.19 Added EEDPObservedValue added to SCSI IO Reply message. -+ * 01-04-16 02.00.20 Modified EEDP reported values in SCSI IO Reply message. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_INIT_H -+#define MPI2_INIT_H -+ -+/***************************************************************************** -+* -+* SCSI Initiator Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* SCSI IO messages and associated structures -+****************************************************************************/ -+ -+typedef struct _MPI2_SCSI_IO_CDB_EEDP32 { -+ U8 CDB[20]; /*0x00 */ -+ U32 PrimaryReferenceTag; /*0x14 */ -+ U16 PrimaryApplicationTag; /*0x18 */ -+ U16 PrimaryApplicationTagMask; /*0x1A */ -+ U32 TransferLength; /*0x1C */ -+} MPI2_SCSI_IO_CDB_EEDP32, *PTR_MPI2_SCSI_IO_CDB_EEDP32, -+ Mpi2ScsiIoCdbEedp32_t, *pMpi2ScsiIoCdbEedp32_t; -+ -+/*MPI v2.0 CDB field */ -+typedef union _MPI2_SCSI_IO_CDB_UNION { -+ U8 CDB32[32]; -+ MPI2_SCSI_IO_CDB_EEDP32 EEDP32; -+ MPI2_SGE_SIMPLE_UNION SGE; -+} MPI2_SCSI_IO_CDB_UNION, *PTR_MPI2_SCSI_IO_CDB_UNION, -+ Mpi2ScsiIoCdb_t, *pMpi2ScsiIoCdb_t; -+ -+/*MPI v2.0 SCSI IO Request Message */ -+typedef struct _MPI2_SCSI_IO_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U32 SenseBufferLowAddress; /*0x0C */ -+ U16 SGLFlags; /*0x10 */ -+ U8 SenseBufferLength; /*0x12 */ -+ U8 Reserved4; /*0x13 */ -+ U8 SGLOffset0; /*0x14 */ -+ U8 SGLOffset1; /*0x15 */ -+ U8 SGLOffset2; /*0x16 */ -+ U8 SGLOffset3; /*0x17 */ -+ U32 SkipCount; /*0x18 */ -+ U32 DataLength; /*0x1C */ -+ U32 BidirectionalDataLength; /*0x20 */ -+ U16 IoFlags; /*0x24 */ -+ U16 EEDPFlags; /*0x26 */ -+ U32 EEDPBlockSize; /*0x28 */ -+ U32 SecondaryReferenceTag; /*0x2C */ -+ U16 SecondaryApplicationTag; /*0x30 */ -+ U16 ApplicationTagTranslationMask; /*0x32 */ -+ U8 LUN[8]; /*0x34 */ -+ U32 Control; /*0x3C */ -+ MPI2_SCSI_IO_CDB_UNION CDB; /*0x40 */ -+ -+#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /*typically this is left undefined */ -+ MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion; -+#endif -+ -+ MPI2_SGE_IO_UNION SGL; /*0x60 */ -+ -+} MPI2_SCSI_IO_REQUEST, *PTR_MPI2_SCSI_IO_REQUEST, -+ Mpi2SCSIIORequest_t, *pMpi2SCSIIORequest_t; -+ -+/*SCSI IO MsgFlags bits */ -+ -+/*MsgFlags for SenseBufferAddressSpace */ -+#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C) -+#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00) -+#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04) -+#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08) -+#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C) -+#define MPI26_SCSIIO_MSGFLAGS_IOCCTL_SENSE_ADDR (0x08) -+ -+/*SCSI IO SGLFlags bits */ -+ -+/*base values for Data Location Address Space */ -+#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C) -+#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00) -+#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04) -+#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08) -+#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) -+ -+/*base values for Type */ -+#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03) -+#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00) -+#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01) -+#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02) -+ -+/*shift values for each sub-field */ -+#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12) -+#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8) -+#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) -+#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) -+ -+/*number of SGLOffset fields */ -+#define MPI2_SCSIIO_NUM_SGLOFFSETS (4) -+ -+/*SCSI IO IoFlags bits */ -+ -+/*Large CDB Address Space */ -+#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000) -+#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000) -+#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000) -+#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000) -+#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000) -+ -+#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) -+#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) -+#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400) -+#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200) -+#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) -+ -+/*SCSI IO EEDPFlags bits */ -+ -+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) -+#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000) -+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000) -+#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000) -+ -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) -+ -+#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) -+ -+#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007) -+#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001) -+#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) -+#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) -+#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007) -+ -+/*SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */ -+ -+/*SCSI IO Control bits */ -+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000) -+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) -+ -+#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) -+#define MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION (24) -+#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) -+#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) -+#define MPI2_SCSIIO_CONTROL_READ (0x02000000) -+#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000) -+ -+#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800) -+#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11) -+/*alternate name for the previous field; called Command Priority in SAM-4 */ -+#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK (0x00007800) -+#define MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT (11) -+ -+#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) -+#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000) -+#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100) -+#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200) -+#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400) -+ -+#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0) -+#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000) -+#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040) -+#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080) -+ -+/*MPI v2.5 CDB field */ -+typedef union _MPI25_SCSI_IO_CDB_UNION { -+ U8 CDB32[32]; -+ MPI2_SCSI_IO_CDB_EEDP32 EEDP32; -+ MPI2_IEEE_SGE_SIMPLE64 SGE; -+} MPI25_SCSI_IO_CDB_UNION, *PTR_MPI25_SCSI_IO_CDB_UNION, -+ Mpi25ScsiIoCdb_t, *pMpi25ScsiIoCdb_t; -+ -+/*MPI v2.5/2.6 SCSI IO Request Message */ -+typedef struct _MPI25_SCSI_IO_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U32 SenseBufferLowAddress; /*0x0C */ -+ U8 DMAFlags; /*0x10 */ -+ U8 Reserved5; /*0x11 */ -+ U8 SenseBufferLength; /*0x12 */ -+ U8 Reserved4; /*0x13 */ -+ U8 SGLOffset0; /*0x14 */ -+ U8 SGLOffset1; /*0x15 */ -+ U8 SGLOffset2; /*0x16 */ -+ U8 SGLOffset3; /*0x17 */ -+ U32 SkipCount; /*0x18 */ -+ U32 DataLength; /*0x1C */ -+ U32 BidirectionalDataLength; /*0x20 */ -+ U16 IoFlags; /*0x24 */ -+ U16 EEDPFlags; /*0x26 */ -+ U16 EEDPBlockSize; /*0x28 */ -+ U16 Reserved6; /*0x2A */ -+ U32 SecondaryReferenceTag; /*0x2C */ -+ U16 SecondaryApplicationTag; /*0x30 */ -+ U16 ApplicationTagTranslationMask; /*0x32 */ -+ U8 LUN[8]; /*0x34 */ -+ U32 Control; /*0x3C */ -+ MPI25_SCSI_IO_CDB_UNION CDB; /*0x40 */ -+ -+#ifdef MPI25_SCSI_IO_VENDOR_UNIQUE_REGION /*typically this is left undefined */ -+ MPI25_SCSI_IO_VENDOR_UNIQUE VendorRegion; -+#endif -+ -+ MPI25_SGE_IO_UNION SGL; /*0x60 */ -+ -+} MPI25_SCSI_IO_REQUEST, *PTR_MPI25_SCSI_IO_REQUEST, -+ Mpi25SCSIIORequest_t, *pMpi25SCSIIORequest_t; -+ -+/*use MPI2_SCSIIO_MSGFLAGS_ defines for the MsgFlags field */ -+ -+/*Defines for the DMAFlags field -+ * Each setting affects 4 SGLS, from SGL0 to SGL3. -+ * D = Data -+ * C = Cache DIF -+ * I = Interleaved -+ * H = Host DIF -+ */ -+#define MPI25_SCSIIO_DMAFLAGS_OP_MASK (0x0F) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_D (0x00) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_C (0x01) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_I (0x02) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_C (0x03) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_I (0x04) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_I_I (0x05) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_C (0x06) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_I (0x07) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_I_I (0x08) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_I_I_I (0x09) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_D (0x0A) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_C (0x0B) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_I (0x0C) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_C (0x0D) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_I (0x0E) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_I_I (0x0F) -+ -+/*number of SGLOffset fields */ -+#define MPI25_SCSIIO_NUM_SGLOFFSETS (4) -+ -+/*defines for the IoFlags field */ -+#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK (0xC000) -+#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH (0x0000) -+#define MPI25_SCSIIO_IOFLAGS_FAST_PATH (0x4000) -+ -+#define MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH (0x2000) -+#define MPI25_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) -+#define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) -+#define MPI26_SCSIIO_IOFLAGS_PORT_REQUEST (0x0400) -+#define MPI25_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) -+ -+/*MPI v2.5 defines for the EEDPFlags bits */ -+/*use MPI2_SCSIIO_EEDPFLAGS_ defines for the other EEDPFlags bits */ -+#define MPI25_SCSIIO_EEDPFLAGS_ESCAPE_MODE_MASK (0x00C0) -+#define MPI25_SCSIIO_EEDPFLAGS_COMPATIBLE_MODE (0x0000) -+#define MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE (0x0040) -+#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE (0x0080) -+#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_REFTAG_DISABLE_MODE (0x00C0) -+ -+#define MPI25_SCSIIO_EEDPFLAGS_HOST_GUARD_METHOD_MASK (0x0030) -+#define MPI25_SCSIIO_EEDPFLAGS_T10_CRC_HOST_GUARD (0x0000) -+#define MPI25_SCSIIO_EEDPFLAGS_IP_CHKSUM_HOST_GUARD (0x0010) -+ -+/*use MPI2_LUN_ defines from mpi2.h for the LUN field */ -+ -+/*use MPI2_SCSIIO_CONTROL_ defines for the Control field */ -+ -+/*NOTE: The SCSI IO Reply is nearly the same for MPI 2.0 and MPI 2.5, so -+ * MPI2_SCSI_IO_REPLY is used for both. -+ */ -+ -+/*SCSI IO Error Reply Message */ -+typedef struct _MPI2_SCSI_IO_REPLY { -+ U16 DevHandle; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U8 SCSIStatus; /*0x0C */ -+ U8 SCSIState; /*0x0D */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 TransferCount; /*0x14 */ -+ U32 SenseCount; /*0x18 */ -+ U32 ResponseInfo; /*0x1C */ -+ U16 TaskTag; /*0x20 */ -+ U16 SCSIStatusQualifier; /* 0x22 */ -+ U32 BidirectionalTransferCount; /*0x24 */ -+ /* MPI 2.5+ only; Reserved in MPI 2.0 */ -+ U32 EEDPErrorOffset; /* 0x28 */ -+ /* MPI 2.5+ only; Reserved in MPI 2.0 */ -+ U16 EEDPObservedAppTag; /* 0x2C */ -+ /* MPI 2.5+ only; Reserved in MPI 2.0 */ -+ U16 EEDPObservedGuard; /* 0x2E */ -+ /* MPI 2.5+ only; Reserved in MPI 2.0 */ -+ U32 EEDPObservedRefTag; /* 0x30 */ -+} MPI2_SCSI_IO_REPLY, *PTR_MPI2_SCSI_IO_REPLY, -+ Mpi2SCSIIOReply_t, *pMpi2SCSIIOReply_t; -+ -+/*SCSI IO Reply SCSIStatus values (SAM-4 status codes) */ -+ -+#define MPI2_SCSI_STATUS_GOOD (0x00) -+#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02) -+#define MPI2_SCSI_STATUS_CONDITION_MET (0x04) -+#define MPI2_SCSI_STATUS_BUSY (0x08) -+#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10) -+#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) -+#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18) -+#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /*obsolete */ -+#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28) -+#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30) -+#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40) -+ -+/*SCSI IO Reply SCSIState flags */ -+ -+#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10) -+#define MPI2_SCSI_STATE_TERMINATED (0x08) -+#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04) -+#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) -+#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) -+ -+/*masks and shifts for the ResponseInfo field */ -+ -+#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) -+#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) -+ -+#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) -+ -+/**************************************************************************** -+* SCSI Task Management messages -+****************************************************************************/ -+ -+/*SCSI Task Management Request Message */ -+typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Reserved1; /*0x04 */ -+ U8 TaskType; /*0x05 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U8 LUN[8]; /*0x0C */ -+ U32 Reserved4[7]; /*0x14 */ -+ U16 TaskMID; /*0x30 */ -+ U16 Reserved5; /*0x32 */ -+} MPI2_SCSI_TASK_MANAGE_REQUEST, -+ *PTR_MPI2_SCSI_TASK_MANAGE_REQUEST, -+ Mpi2SCSITaskManagementRequest_t, -+ *pMpi2SCSITaskManagementRequest_t; -+ -+/*TaskType values */ -+ -+#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) -+#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) -+#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) -+#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) -+#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) -+#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) -+#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) -+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) -+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) -+ -+/*obsolete TaskType name */ -+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \ -+ (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT) -+ -+/*MsgFlags bits */ -+ -+#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18) -+#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00) -+#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08) -+#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10) -+ -+#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) -+ -+/*SCSI Task Management Reply Message */ -+typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY { -+ U16 DevHandle; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 ResponseCode; /*0x04 */ -+ U8 TaskType; /*0x05 */ -+ U8 Reserved1; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U16 Reserved3; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 TerminationCount; /*0x14 */ -+ U32 ResponseInfo; /*0x18 */ -+} MPI2_SCSI_TASK_MANAGE_REPLY, -+ *PTR_MPI2_SCSI_TASK_MANAGE_REPLY, -+ Mpi2SCSITaskManagementReply_t, *pMpi2SCSIManagementReply_t; -+ -+/*ResponseCode values */ -+ -+#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) -+#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) -+#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) -+#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) -+#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) -+#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) -+#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) -+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) -+ -+/*masks and shifts for the ResponseInfo field */ -+ -+#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) -+#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) -+#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) -+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) -+#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) -+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) -+#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) -+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) -+ -+/**************************************************************************** -+* SCSI Enclosure Processor messages -+****************************************************************************/ -+ -+/*SCSI Enclosure Processor Request Message */ -+typedef struct _MPI2_SEP_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Action; /*0x04 */ -+ U8 Flags; /*0x05 */ -+ U8 Reserved1; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U32 SlotStatus; /*0x0C */ -+ U32 Reserved3; /*0x10 */ -+ U32 Reserved4; /*0x14 */ -+ U32 Reserved5; /*0x18 */ -+ U16 Slot; /*0x1C */ -+ U16 EnclosureHandle; /*0x1E */ -+} MPI2_SEP_REQUEST, *PTR_MPI2_SEP_REQUEST, -+ Mpi2SepRequest_t, *pMpi2SepRequest_t; -+ -+/*Action defines */ -+#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00) -+#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01) -+ -+/*Flags defines */ -+#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00) -+#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01) -+ -+/*SlotStatus defines */ -+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF (0x00080000) -+#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) -+#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) -+#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) -+#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) -+#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) -+#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) -+#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) -+#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) -+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) -+#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) -+ -+/*SCSI Enclosure Processor Reply Message */ -+typedef struct _MPI2_SEP_REPLY { -+ U16 DevHandle; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Action; /*0x04 */ -+ U8 Flags; /*0x05 */ -+ U8 Reserved1; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U16 Reserved3; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 SlotStatus; /*0x14 */ -+ U32 Reserved4; /*0x18 */ -+ U16 Slot; /*0x1C */ -+ U16 EnclosureHandle; /*0x1E */ -+} MPI2_SEP_REPLY, *PTR_MPI2_SEP_REPLY, -+ Mpi2SepReply_t, *pMpi2SepReply_t; -+ -+/*SlotStatus defines */ -+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF (0x00080000) -+#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) -+#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) -+#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) -+#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) -+#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) -+#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) -+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) -+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) -+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) -+#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h -new file mode 100644 -index 0000000..8bae305 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h -@@ -0,0 +1,1860 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_ioc.h -+ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages -+ * Creation Date: October 11, 2006 -+ * -+ * mpi2_ioc.h Version: 02.00.27 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to -+ * MaxTargets. -+ * Added TotalImageSize field to FWDownload Request. -+ * Added reserved words to FWUpload Request. -+ * 06-26-07 02.00.02 Added IR Configuration Change List Event. -+ * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit -+ * request and replaced it with -+ * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. -+ * Replaced the MinReplyQueueDepth field of the IOCFacts -+ * reply with MaxReplyDescriptorPostQueueDepth. -+ * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum -+ * depth for the Reply Descriptor Post Queue. -+ * Added SASAddress field to Initiator Device Table -+ * Overflow Event data. -+ * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING -+ * for SAS Initiator Device Status Change Event data. -+ * Modified Reason Code defines for SAS Topology Change -+ * List Event data, including adding a bit for PHY Vacant -+ * status, and adding a mask for the Reason Code. -+ * Added define for -+ * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. -+ * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. -+ * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of -+ * the IOCFacts Reply. -+ * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. -+ * Moved MPI2_VERSION_UNION to mpi2.h. -+ * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks -+ * instead of enables, and added SASBroadcastPrimitiveMasks -+ * field. -+ * Added Log Entry Added Event and related structure. -+ * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. -+ * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. -+ * Added MaxVolumes and MaxPersistentEntries fields to -+ * IOCFacts reply. -+ * Added ProtocalFlags and IOCCapabilities fields to -+ * MPI2_FW_IMAGE_HEADER. -+ * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. -+ * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to -+ * a U16 (from a U32). -+ * Removed extra 's' from EventMasks name. -+ * 06-27-08 02.00.08 Fixed an offset in a comment. -+ * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. -+ * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and -+ * renamed MinReplyFrameSize to ReplyFrameSize. -+ * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. -+ * Added two new RAIDOperation values for Integrated RAID -+ * Operations Status Event data. -+ * Added four new IR Configuration Change List Event data -+ * ReasonCode values. -+ * Added two new ReasonCode defines for SAS Device Status -+ * Change Event data. -+ * Added three new DiscoveryStatus bits for the SAS -+ * Discovery event data. -+ * Added Multiplexing Status Change bit to the PhyStatus -+ * field of the SAS Topology Change List event data. -+ * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. -+ * BootFlags are now product-specific. -+ * Added defines for the indivdual signature bytes -+ * for MPI2_INIT_IMAGE_FOOTER. -+ * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. -+ * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR -+ * define. -+ * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE -+ * define. -+ * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. -+ * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. -+ * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. -+ * Added two new reason codes for SAS Device Status Change -+ * Event. -+ * Added new event: SAS PHY Counter. -+ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. -+ * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. -+ * Added new product id family for 2208. -+ * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. -+ * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. -+ * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. -+ * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. -+ * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. -+ * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. -+ * Added Host Based Discovery Phy Event data. -+ * Added defines for ProductID Product field -+ * (MPI2_FW_HEADER_PID_). -+ * Modified values for SAS ProductID Family -+ * (MPI2_FW_HEADER_PID_FAMILY_). -+ * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. -+ * Added PowerManagementControl Request structures and -+ * defines. -+ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. -+ * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. -+ * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. -+ * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added -+ * SASNotifyPrimitiveMasks field to -+ * MPI2_EVENT_NOTIFICATION_REQUEST. -+ * Added Temperature Threshold Event. -+ * Added Host Message Event. -+ * Added Send Host Message request and reply. -+ * 05-25-11 02.00.18 For Extended Image Header, added -+ * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and -+ * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. -+ * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. -+ * 08-24-11 02.00.19 Added PhysicalPort field to -+ * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. -+ * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. -+ * 11-18-11 02.00.20 Incorporating additions for MPI v2.5. -+ * 03-29-12 02.00.21 Added a product specific range to event values. -+ * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE. -+ * Added ElapsedSeconds field to -+ * MPI2_EVENT_DATA_IR_OPERATION_STATUS. -+ * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE -+ * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY. -+ * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. -+ * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. -+ * Added Encrypted Hash Extended Image. -+ * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. -+ * 11-18-14 02.00.25 Updated copyright information. -+ * 03-16-15 02.00.26 Updated for MPI v2.6. -+ * Added MPI2_EVENT_ACTIVE_CABLE_EXCEPTION and -+ * MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT. -+ * Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and -+ * MPI26_FW_HEADER_PID_FAMILY_3516_SAS. -+ * Added MPI26_CTRL_OP_SHUTDOWN. -+ * 08-25-15 02.00.27 Added IC ARCH Class based signature defines -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_IOC_H -+#define MPI2_IOC_H -+ -+/***************************************************************************** -+* -+* IOC Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* IOCInit message -+****************************************************************************/ -+ -+/*IOCInit Request message */ -+typedef struct _MPI2_IOC_INIT_REQUEST { -+ U8 WhoInit; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 MsgVersion; /*0x0C */ -+ U16 HeaderVersion; /*0x0E */ -+ U32 Reserved5; /*0x10 */ -+ U16 ConfigurationFlags; /* 0x14 */ -+ U8 HostPageSize; /*0x16 */ -+ U8 HostMSIxVectors; /*0x17 */ -+ U16 Reserved8; /*0x18 */ -+ U16 SystemRequestFrameSize; /*0x1A */ -+ U16 ReplyDescriptorPostQueueDepth; /*0x1C */ -+ U16 ReplyFreeQueueDepth; /*0x1E */ -+ U32 SenseBufferAddressHigh; /*0x20 */ -+ U32 SystemReplyAddressHigh; /*0x24 */ -+ U64 SystemRequestFrameBaseAddress; /*0x28 */ -+ U64 ReplyDescriptorPostQueueAddress; /*0x30 */ -+ U64 ReplyFreeQueueAddress; /*0x38 */ -+ U64 TimeStamp; /*0x40 */ -+} MPI2_IOC_INIT_REQUEST, *PTR_MPI2_IOC_INIT_REQUEST, -+ Mpi2IOCInitRequest_t, *pMpi2IOCInitRequest_t; -+ -+/*WhoInit values */ -+#define MPI2_WHOINIT_NOT_INITIALIZED (0x00) -+#define MPI2_WHOINIT_SYSTEM_BIOS (0x01) -+#define MPI2_WHOINIT_ROM_BIOS (0x02) -+#define MPI2_WHOINIT_PCI_PEER (0x03) -+#define MPI2_WHOINIT_HOST_DRIVER (0x04) -+#define MPI2_WHOINIT_MANUFACTURER (0x05) -+ -+/* MsgFlags */ -+#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01) -+ -+ -+/*MsgVersion */ -+#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00) -+#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8) -+#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF) -+#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0) -+ -+/*HeaderVersion */ -+#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00) -+#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8) -+#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF) -+#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0) -+ -+/*minimum depth for a Reply Descriptor Post Queue */ -+#define MPI2_RDPQ_DEPTH_MIN (16) -+ -+/* Reply Descriptor Post Queue Array Entry */ -+typedef struct _MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { -+ U64 RDPQBaseAddress; /* 0x00 */ -+ U32 Reserved1; /* 0x08 */ -+ U32 Reserved2; /* 0x0C */ -+} MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, -+*PTR_MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, -+Mpi2IOCInitRDPQArrayEntry, *pMpi2IOCInitRDPQArrayEntry; -+ -+ -+/*IOCInit Reply message */ -+typedef struct _MPI2_IOC_INIT_REPLY { -+ U8 WhoInit; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_IOC_INIT_REPLY, *PTR_MPI2_IOC_INIT_REPLY, -+ Mpi2IOCInitReply_t, *pMpi2IOCInitReply_t; -+ -+/**************************************************************************** -+* IOCFacts message -+****************************************************************************/ -+ -+/*IOCFacts Request message */ -+typedef struct _MPI2_IOC_FACTS_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+} MPI2_IOC_FACTS_REQUEST, *PTR_MPI2_IOC_FACTS_REQUEST, -+ Mpi2IOCFactsRequest_t, *pMpi2IOCFactsRequest_t; -+ -+/*IOCFacts Reply message */ -+typedef struct _MPI2_IOC_FACTS_REPLY { -+ U16 MsgVersion; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 HeaderVersion; /*0x04 */ -+ U8 IOCNumber; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U16 IOCExceptions; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U8 MaxChainDepth; /*0x14 */ -+ U8 WhoInit; /*0x15 */ -+ U8 NumberOfPorts; /*0x16 */ -+ U8 MaxMSIxVectors; /*0x17 */ -+ U16 RequestCredit; /*0x18 */ -+ U16 ProductID; /*0x1A */ -+ U32 IOCCapabilities; /*0x1C */ -+ MPI2_VERSION_UNION FWVersion; /*0x20 */ -+ U16 IOCRequestFrameSize; /*0x24 */ -+ U16 IOCMaxChainSegmentSize; /*0x26 */ -+ U16 MaxInitiators; /*0x28 */ -+ U16 MaxTargets; /*0x2A */ -+ U16 MaxSasExpanders; /*0x2C */ -+ U16 MaxEnclosures; /*0x2E */ -+ U16 ProtocolFlags; /*0x30 */ -+ U16 HighPriorityCredit; /*0x32 */ -+ U16 MaxReplyDescriptorPostQueueDepth; /*0x34 */ -+ U8 ReplyFrameSize; /*0x36 */ -+ U8 MaxVolumes; /*0x37 */ -+ U16 MaxDevHandle; /*0x38 */ -+ U16 MaxPersistentEntries; /*0x3A */ -+ U16 MinDevHandle; /*0x3C */ -+ U8 CurrentHostPageSize; /* 0x3E */ -+ U8 Reserved4; /* 0x3F */ -+} MPI2_IOC_FACTS_REPLY, *PTR_MPI2_IOC_FACTS_REPLY, -+ Mpi2IOCFactsReply_t, *pMpi2IOCFactsReply_t; -+ -+/*MsgVersion */ -+#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) -+#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8) -+#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) -+#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0) -+ -+/*HeaderVersion */ -+#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00) -+#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8) -+#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF) -+#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0) -+ -+/*IOCExceptions */ -+#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200) -+#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100) -+ -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0) -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000) -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020) -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040) -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060) -+ -+#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) -+#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008) -+#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) -+#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) -+#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) -+ -+/*defines for WhoInit field are after the IOCInit Request */ -+ -+/*ProductID field uses MPI2_FW_HEADER_PID_ */ -+ -+/*IOCCapabilities */ -+#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000) -+#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000) -+#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE (0x00020000) -+#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) -+#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) -+#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) -+#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) -+#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000) -+#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800) -+#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) -+#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) -+#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) -+#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) -+#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) -+#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) -+#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) -+ -+/*ProtocolFlags */ -+#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) -+#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) -+ -+/**************************************************************************** -+* PortFacts message -+****************************************************************************/ -+ -+/*PortFacts Request message */ -+typedef struct _MPI2_PORT_FACTS_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 PortNumber; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+} MPI2_PORT_FACTS_REQUEST, *PTR_MPI2_PORT_FACTS_REQUEST, -+ Mpi2PortFactsRequest_t, *pMpi2PortFactsRequest_t; -+ -+/*PortFacts Reply message */ -+typedef struct _MPI2_PORT_FACTS_REPLY { -+ U16 Reserved1; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 PortNumber; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U16 Reserved4; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U8 Reserved5; /*0x14 */ -+ U8 PortType; /*0x15 */ -+ U16 Reserved6; /*0x16 */ -+ U16 MaxPostedCmdBuffers; /*0x18 */ -+ U16 Reserved7; /*0x1A */ -+} MPI2_PORT_FACTS_REPLY, *PTR_MPI2_PORT_FACTS_REPLY, -+ Mpi2PortFactsReply_t, *pMpi2PortFactsReply_t; -+ -+/*PortType values */ -+#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00) -+#define MPI2_PORTFACTS_PORTTYPE_FC (0x10) -+#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20) -+#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30) -+#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31) -+ -+/**************************************************************************** -+* PortEnable message -+****************************************************************************/ -+ -+/*PortEnable Request message */ -+typedef struct _MPI2_PORT_ENABLE_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Reserved2; /*0x04 */ -+ U8 PortFlags; /*0x05 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+} MPI2_PORT_ENABLE_REQUEST, *PTR_MPI2_PORT_ENABLE_REQUEST, -+ Mpi2PortEnableRequest_t, *pMpi2PortEnableRequest_t; -+ -+/*PortEnable Reply message */ -+typedef struct _MPI2_PORT_ENABLE_REPLY { -+ U16 Reserved1; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Reserved2; /*0x04 */ -+ U8 PortFlags; /*0x05 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_PORT_ENABLE_REPLY, *PTR_MPI2_PORT_ENABLE_REPLY, -+ Mpi2PortEnableReply_t, *pMpi2PortEnableReply_t; -+ -+/**************************************************************************** -+* EventNotification message -+****************************************************************************/ -+ -+/*EventNotification Request message */ -+#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4) -+ -+typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 Reserved6; /*0x10 */ -+ U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; /*0x14 */ -+ U16 SASBroadcastPrimitiveMasks; /*0x24 */ -+ U16 SASNotifyPrimitiveMasks; /*0x26 */ -+ U32 Reserved8; /*0x28 */ -+} MPI2_EVENT_NOTIFICATION_REQUEST, -+ *PTR_MPI2_EVENT_NOTIFICATION_REQUEST, -+ Mpi2EventNotificationRequest_t, -+ *pMpi2EventNotificationRequest_t; -+ -+/*EventNotification Reply message */ -+typedef struct _MPI2_EVENT_NOTIFICATION_REPLY { -+ U16 EventDataLength; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 AckRequired; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U16 Reserved3; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U16 Event; /*0x14 */ -+ U16 Reserved4; /*0x16 */ -+ U32 EventContext; /*0x18 */ -+ U32 EventData[1]; /*0x1C */ -+} MPI2_EVENT_NOTIFICATION_REPLY, *PTR_MPI2_EVENT_NOTIFICATION_REPLY, -+ Mpi2EventNotificationReply_t, -+ *pMpi2EventNotificationReply_t; -+ -+/*AckRequired */ -+#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) -+#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) -+ -+/*Event */ -+#define MPI2_EVENT_LOG_DATA (0x0001) -+#define MPI2_EVENT_STATE_CHANGE (0x0002) -+#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) -+#define MPI2_EVENT_EVENT_CHANGE (0x000A) -+#define MPI2_EVENT_TASK_SET_FULL (0x000E) /*obsolete */ -+#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) -+#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) -+#define MPI2_EVENT_SAS_DISCOVERY (0x0016) -+#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017) -+#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018) -+#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019) -+#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C) -+#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D) -+#define MPI2_EVENT_IR_VOLUME (0x001E) -+#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) -+#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) -+#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) -+#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) -+#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) -+#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) -+#define MPI2_EVENT_SAS_QUIESCE (0x0025) -+#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026) -+#define MPI2_EVENT_TEMP_THRESHOLD (0x0027) -+#define MPI2_EVENT_HOST_MESSAGE (0x0028) -+#define MPI2_EVENT_POWER_PERFORMANCE_CHANGE (0x0029) -+#define MPI2_EVENT_ACTIVE_CABLE_EXCEPTION (0x0034) -+#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E) -+#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F) -+ -+/*Log Entry Added Event data */ -+ -+/*the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */ -+#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C) -+ -+typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED { -+ U64 TimeStamp; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U16 LogSequence; /*0x0C */ -+ U16 LogEntryQualifier; /*0x0E */ -+ U8 VP_ID; /*0x10 */ -+ U8 VF_ID; /*0x11 */ -+ U16 Reserved2; /*0x12 */ -+ U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH]; /*0x14 */ -+} MPI2_EVENT_DATA_LOG_ENTRY_ADDED, -+ *PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, -+ Mpi2EventDataLogEntryAdded_t, -+ *pMpi2EventDataLogEntryAdded_t; -+ -+/*GPIO Interrupt Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT { -+ U8 GPIONum; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+} MPI2_EVENT_DATA_GPIO_INTERRUPT, -+ *PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, -+ Mpi2EventDataGpioInterrupt_t, -+ *pMpi2EventDataGpioInterrupt_t; -+ -+/*Temperature Threshold Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_TEMPERATURE { -+ U16 Status; /*0x00 */ -+ U8 SensorNum; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+ U16 CurrentTemperature; /*0x04 */ -+ U16 Reserved2; /*0x06 */ -+ U32 Reserved3; /*0x08 */ -+ U32 Reserved4; /*0x0C */ -+} MPI2_EVENT_DATA_TEMPERATURE, -+ *PTR_MPI2_EVENT_DATA_TEMPERATURE, -+ Mpi2EventDataTemperature_t, *pMpi2EventDataTemperature_t; -+ -+/*Temperature Threshold Event data Status bits */ -+#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008) -+#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004) -+#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002) -+#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001) -+ -+/*Host Message Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE { -+ U8 SourceVF_ID; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 Reserved3; /*0x04 */ -+ U32 HostData[1]; /*0x08 */ -+} MPI2_EVENT_DATA_HOST_MESSAGE, *PTR_MPI2_EVENT_DATA_HOST_MESSAGE, -+ Mpi2EventDataHostMessage_t, *pMpi2EventDataHostMessage_t; -+ -+/*Power Performance Change Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_POWER_PERF_CHANGE { -+ U8 CurrentPowerMode; /*0x00 */ -+ U8 PreviousPowerMode; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+} MPI2_EVENT_DATA_POWER_PERF_CHANGE, -+ *PTR_MPI2_EVENT_DATA_POWER_PERF_CHANGE, -+ Mpi2EventDataPowerPerfChange_t, -+ *pMpi2EventDataPowerPerfChange_t; -+ -+/*defines for CurrentPowerMode and PreviousPowerMode fields */ -+#define MPI2_EVENT_PM_INIT_MASK (0xC0) -+#define MPI2_EVENT_PM_INIT_UNAVAILABLE (0x00) -+#define MPI2_EVENT_PM_INIT_HOST (0x40) -+#define MPI2_EVENT_PM_INIT_IO_UNIT (0x80) -+#define MPI2_EVENT_PM_INIT_PCIE_DPA (0xC0) -+ -+#define MPI2_EVENT_PM_MODE_MASK (0x07) -+#define MPI2_EVENT_PM_MODE_UNAVAILABLE (0x00) -+#define MPI2_EVENT_PM_MODE_UNKNOWN (0x01) -+#define MPI2_EVENT_PM_MODE_FULL_POWER (0x04) -+#define MPI2_EVENT_PM_MODE_REDUCED_POWER (0x05) -+#define MPI2_EVENT_PM_MODE_STANDBY (0x06) -+ -+/* Active Cable Exception Event data */ -+ -+typedef struct _MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT { -+ U32 ActiveCablePowerRequirement; /* 0x00 */ -+ U8 ReasonCode; /* 0x04 */ -+ U8 ReceptacleID; /* 0x05 */ -+ U16 Reserved1; /* 0x06 */ -+} MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT, -+ *PTR_MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT, -+ Mpi26EventDataActiveCableExcept_t, -+ *pMpi26EventDataActiveCableExcept_t; -+ -+/* defines for ReasonCode field */ -+#define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00) -+ -+/*Hard Reset Received Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED { -+ U8 Reserved1; /*0x00 */ -+ U8 Port; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+} MPI2_EVENT_DATA_HARD_RESET_RECEIVED, -+ *PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED, -+ Mpi2EventDataHardResetReceived_t, -+ *pMpi2EventDataHardResetReceived_t; -+ -+/*Task Set Full Event data */ -+/* this event is obsolete */ -+ -+typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL { -+ U16 DevHandle; /*0x00 */ -+ U16 CurrentDepth; /*0x02 */ -+} MPI2_EVENT_DATA_TASK_SET_FULL, *PTR_MPI2_EVENT_DATA_TASK_SET_FULL, -+ Mpi2EventDataTaskSetFull_t, *pMpi2EventDataTaskSetFull_t; -+ -+/*SAS Device Status Change Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE { -+ U16 TaskTag; /*0x00 */ -+ U8 ReasonCode; /*0x02 */ -+ U8 PhysicalPort; /*0x03 */ -+ U8 ASC; /*0x04 */ -+ U8 ASCQ; /*0x05 */ -+ U16 DevHandle; /*0x06 */ -+ U32 Reserved2; /*0x08 */ -+ U64 SASAddress; /*0x0C */ -+ U8 LUN[8]; /*0x14 */ -+} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, -+ *PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, -+ Mpi2EventDataSasDeviceStatusChange_t, -+ *pMpi2EventDataSasDeviceStatusChange_t; -+ -+/*SAS Device Status Change Event data ReasonCode values */ -+#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12) -+ -+/*Integrated RAID Operation Status Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS { -+ U16 VolDevHandle; /*0x00 */ -+ U16 Reserved1; /*0x02 */ -+ U8 RAIDOperation; /*0x04 */ -+ U8 PercentComplete; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U32 ElapsedSeconds; /*0x08 */ -+} MPI2_EVENT_DATA_IR_OPERATION_STATUS, -+ *PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS, -+ Mpi2EventDataIrOperationStatus_t, -+ *pMpi2EventDataIrOperationStatus_t; -+ -+/*Integrated RAID Operation Status Event data RAIDOperation values */ -+#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00) -+#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01) -+#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02) -+#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03) -+#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04) -+ -+/*Integrated RAID Volume Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_IR_VOLUME { -+ U16 VolDevHandle; /*0x00 */ -+ U8 ReasonCode; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+ U32 NewValue; /*0x04 */ -+ U32 PreviousValue; /*0x08 */ -+} MPI2_EVENT_DATA_IR_VOLUME, *PTR_MPI2_EVENT_DATA_IR_VOLUME, -+ Mpi2EventDataIrVolume_t, *pMpi2EventDataIrVolume_t; -+ -+/*Integrated RAID Volume Event data ReasonCode values */ -+#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01) -+#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02) -+#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03) -+ -+/*Integrated RAID Physical Disk Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK { -+ U16 Reserved1; /*0x00 */ -+ U8 ReasonCode; /*0x02 */ -+ U8 PhysDiskNum; /*0x03 */ -+ U16 PhysDiskDevHandle; /*0x04 */ -+ U16 Reserved2; /*0x06 */ -+ U16 Slot; /*0x08 */ -+ U16 EnclosureHandle; /*0x0A */ -+ U32 NewValue; /*0x0C */ -+ U32 PreviousValue; /*0x10 */ -+} MPI2_EVENT_DATA_IR_PHYSICAL_DISK, -+ *PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK, -+ Mpi2EventDataIrPhysicalDisk_t, -+ *pMpi2EventDataIrPhysicalDisk_t; -+ -+/*Integrated RAID Physical Disk Event data ReasonCode values */ -+#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01) -+#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02) -+#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03) -+ -+/*Integrated RAID Configuration Change List Event data */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check NumElements at runtime. -+ */ -+#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT -+#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) -+#endif -+ -+typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT { -+ U16 ElementFlags; /*0x00 */ -+ U16 VolDevHandle; /*0x02 */ -+ U8 ReasonCode; /*0x04 */ -+ U8 PhysDiskNum; /*0x05 */ -+ U16 PhysDiskDevHandle; /*0x06 */ -+} MPI2_EVENT_IR_CONFIG_ELEMENT, *PTR_MPI2_EVENT_IR_CONFIG_ELEMENT, -+ Mpi2EventIrConfigElement_t, *pMpi2EventIrConfigElement_t; -+ -+/*IR Configuration Change List Event data ElementFlags values */ -+#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F) -+#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000) -+#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001) -+#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002) -+ -+/*IR Configuration Change List Event data ReasonCode values */ -+#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01) -+#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02) -+#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03) -+#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04) -+#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05) -+#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06) -+#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07) -+#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08) -+#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09) -+ -+typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST { -+ U8 NumElements; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 Reserved2; /*0x02 */ -+ U8 ConfigNum; /*0x03 */ -+ U32 Flags; /*0x04 */ -+ MPI2_EVENT_IR_CONFIG_ELEMENT -+ ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT];/*0x08 */ -+} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, -+ *PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, -+ Mpi2EventDataIrConfigChangeList_t, -+ *pMpi2EventDataIrConfigChangeList_t; -+ -+/*IR Configuration Change List Event data Flags values */ -+#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001) -+ -+/*SAS Discovery Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY { -+ U8 Flags; /*0x00 */ -+ U8 ReasonCode; /*0x01 */ -+ U8 PhysicalPort; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+ U32 DiscoveryStatus; /*0x04 */ -+} MPI2_EVENT_DATA_SAS_DISCOVERY, -+ *PTR_MPI2_EVENT_DATA_SAS_DISCOVERY, -+ Mpi2EventDataSasDiscovery_t, *pMpi2EventDataSasDiscovery_t; -+ -+/*SAS Discovery Event data Flags values */ -+#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02) -+#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01) -+ -+/*SAS Discovery Event data ReasonCode values */ -+#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01) -+#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02) -+ -+/*SAS Discovery Event data DiscoveryStatus values */ -+#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -+#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000) -+#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000) -+#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -+#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000) -+#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -+#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -+#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000) -+#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -+#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800) -+#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400) -+#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200) -+#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100) -+#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080) -+#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040) -+#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020) -+#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010) -+#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004) -+#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002) -+#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001) -+ -+/*SAS Broadcast Primitive Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE { -+ U8 PhyNum; /*0x00 */ -+ U8 Port; /*0x01 */ -+ U8 PortWidth; /*0x02 */ -+ U8 Primitive; /*0x03 */ -+} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, -+ *PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, -+ Mpi2EventDataSasBroadcastPrimitive_t, -+ *pMpi2EventDataSasBroadcastPrimitive_t; -+ -+/*defines for the Primitive field */ -+#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01) -+#define MPI2_EVENT_PRIMITIVE_SES (0x02) -+#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03) -+#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) -+#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05) -+#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06) -+#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) -+#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) -+ -+/*SAS Notify Primitive Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE { -+ U8 PhyNum; /*0x00 */ -+ U8 Port; /*0x01 */ -+ U8 Reserved1; /*0x02 */ -+ U8 Primitive; /*0x03 */ -+} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -+ *PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -+ Mpi2EventDataSasNotifyPrimitive_t, -+ *pMpi2EventDataSasNotifyPrimitive_t; -+ -+/*defines for the Primitive field */ -+#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01) -+#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02) -+#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03) -+#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04) -+ -+/*SAS Initiator Device Status Change Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE { -+ U8 ReasonCode; /*0x00 */ -+ U8 PhysicalPort; /*0x01 */ -+ U16 DevHandle; /*0x02 */ -+ U64 SASAddress; /*0x04 */ -+} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, -+ *PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, -+ Mpi2EventDataSasInitDevStatusChange_t, -+ *pMpi2EventDataSasInitDevStatusChange_t; -+ -+/*SAS Initiator Device Status Change event ReasonCode values */ -+#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01) -+#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02) -+ -+/*SAS Initiator Device Table Overflow Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW { -+ U16 MaxInit; /*0x00 */ -+ U16 CurrentInit; /*0x02 */ -+ U64 SASAddress; /*0x04 */ -+} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, -+ *PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, -+ Mpi2EventDataSasInitTableOverflow_t, -+ *pMpi2EventDataSasInitTableOverflow_t; -+ -+/*SAS Topology Change List Event data */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check NumEntries at runtime. -+ */ -+#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT -+#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) -+#endif -+ -+typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY { -+ U16 AttachedDevHandle; /*0x00 */ -+ U8 LinkRate; /*0x02 */ -+ U8 PhyStatus; /*0x03 */ -+} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, *PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY, -+ Mpi2EventSasTopoPhyEntry_t, *pMpi2EventSasTopoPhyEntry_t; -+ -+typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST { -+ U16 EnclosureHandle; /*0x00 */ -+ U16 ExpanderDevHandle; /*0x02 */ -+ U8 NumPhys; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U8 NumEntries; /*0x08 */ -+ U8 StartPhyNum; /*0x09 */ -+ U8 ExpStatus; /*0x0A */ -+ U8 PhysicalPort; /*0x0B */ -+ MPI2_EVENT_SAS_TOPO_PHY_ENTRY -+ PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /*0x0C */ -+} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, -+ *PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, -+ Mpi2EventDataSasTopologyChangeList_t, -+ *pMpi2EventDataSasTopologyChangeList_t; -+ -+/*values for the ExpStatus field */ -+#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) -+#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) -+#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) -+#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) -+#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) -+ -+/*defines for the LinkRate field */ -+#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0) -+#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4) -+#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F) -+#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0) -+ -+#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00) -+#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01) -+#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02) -+#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) -+#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) -+#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) -+#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06) -+#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) -+#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) -+#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) -+#define MPI25_EVENT_SAS_TOPO_LR_RATE_12_0 (0x0B) -+ -+/*values for the PhyStatus field */ -+#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80) -+#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10) -+/*values for the PhyStatus ReasonCode sub-field */ -+#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F) -+#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01) -+#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02) -+#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03) -+#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04) -+#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05) -+ -+/*SAS Enclosure Device Status Change Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE { -+ U16 EnclosureHandle; /*0x00 */ -+ U8 ReasonCode; /*0x02 */ -+ U8 PhysicalPort; /*0x03 */ -+ U64 EnclosureLogicalID; /*0x04 */ -+ U16 NumSlots; /*0x0C */ -+ U16 StartSlot; /*0x0E */ -+ U32 PhyBits; /*0x10 */ -+} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, -+ *PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, -+ Mpi2EventDataSasEnclDevStatusChange_t, -+ *pMpi2EventDataSasEnclDevStatusChange_t; -+ -+/*SAS Enclosure Device Status Change event ReasonCode values */ -+#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01) -+#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02) -+ -+/*SAS PHY Counter Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { -+ U64 TimeStamp; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U8 PhyEventCode; /*0x0C */ -+ U8 PhyNum; /*0x0D */ -+ U16 Reserved2; /*0x0E */ -+ U32 PhyEventInfo; /*0x10 */ -+ U8 CounterType; /*0x14 */ -+ U8 ThresholdWindow; /*0x15 */ -+ U8 TimeUnits; /*0x16 */ -+ U8 Reserved3; /*0x17 */ -+ U32 EventThreshold; /*0x18 */ -+ U16 ThresholdFlags; /*0x1C */ -+ U16 Reserved4; /*0x1E */ -+} MPI2_EVENT_DATA_SAS_PHY_COUNTER, -+ *PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, -+ Mpi2EventDataSasPhyCounter_t, -+ *pMpi2EventDataSasPhyCounter_t; -+ -+/*use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h -+ *for the PhyEventCode field */ -+ -+/*use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h -+ *for the CounterType field */ -+ -+/*use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h -+ *for the TimeUnits field */ -+ -+/*use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h -+ *for the ThresholdFlags field */ -+ -+/*SAS Quiesce Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE { -+ U8 ReasonCode; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 Reserved3; /*0x04 */ -+} MPI2_EVENT_DATA_SAS_QUIESCE, -+ *PTR_MPI2_EVENT_DATA_SAS_QUIESCE, -+ Mpi2EventDataSasQuiesce_t, *pMpi2EventDataSasQuiesce_t; -+ -+/*SAS Quiesce Event data ReasonCode values */ -+#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) -+#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) -+ -+/*Host Based Discovery Phy Event data */ -+ -+typedef struct _MPI2_EVENT_HBD_PHY_SAS { -+ U8 Flags; /*0x00 */ -+ U8 NegotiatedLinkRate; /*0x01 */ -+ U8 PhyNum; /*0x02 */ -+ U8 PhysicalPort; /*0x03 */ -+ U32 Reserved1; /*0x04 */ -+ U8 InitialFrame[28]; /*0x08 */ -+} MPI2_EVENT_HBD_PHY_SAS, *PTR_MPI2_EVENT_HBD_PHY_SAS, -+ Mpi2EventHbdPhySas_t, *pMpi2EventHbdPhySas_t; -+ -+/*values for the Flags field */ -+#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) -+#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) -+ -+/*use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h -+ *for the NegotiatedLinkRate field */ -+ -+typedef union _MPI2_EVENT_HBD_DESCRIPTOR { -+ MPI2_EVENT_HBD_PHY_SAS Sas; -+} MPI2_EVENT_HBD_DESCRIPTOR, *PTR_MPI2_EVENT_HBD_DESCRIPTOR, -+ Mpi2EventHbdDescriptor_t, *pMpi2EventHbdDescriptor_t; -+ -+typedef struct _MPI2_EVENT_DATA_HBD_PHY { -+ U8 DescriptorType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 Reserved3; /*0x04 */ -+ MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /*0x08 */ -+} MPI2_EVENT_DATA_HBD_PHY, *PTR_MPI2_EVENT_DATA_HBD_PHY, -+ Mpi2EventDataHbdPhy_t, -+ *pMpi2EventDataMpi2EventDataHbdPhy_t; -+ -+/*values for the DescriptorType field */ -+#define MPI2_EVENT_HBD_DT_SAS (0x01) -+ -+/**************************************************************************** -+* EventAck message -+****************************************************************************/ -+ -+/*EventAck Request message */ -+typedef struct _MPI2_EVENT_ACK_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Event; /*0x0C */ -+ U16 Reserved5; /*0x0E */ -+ U32 EventContext; /*0x10 */ -+} MPI2_EVENT_ACK_REQUEST, *PTR_MPI2_EVENT_ACK_REQUEST, -+ Mpi2EventAckRequest_t, *pMpi2EventAckRequest_t; -+ -+/*EventAck Reply message */ -+typedef struct _MPI2_EVENT_ACK_REPLY { -+ U16 Reserved1; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_EVENT_ACK_REPLY, *PTR_MPI2_EVENT_ACK_REPLY, -+ Mpi2EventAckReply_t, *pMpi2EventAckReply_t; -+ -+/**************************************************************************** -+* SendHostMessage message -+****************************************************************************/ -+ -+/*SendHostMessage Request message */ -+typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST { -+ U16 HostDataLength; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U8 Reserved4; /*0x0C */ -+ U8 DestVF_ID; /*0x0D */ -+ U16 Reserved5; /*0x0E */ -+ U32 Reserved6; /*0x10 */ -+ U32 Reserved7; /*0x14 */ -+ U32 Reserved8; /*0x18 */ -+ U32 Reserved9; /*0x1C */ -+ U32 Reserved10; /*0x20 */ -+ U32 HostData[1]; /*0x24 */ -+} MPI2_SEND_HOST_MESSAGE_REQUEST, -+ *PTR_MPI2_SEND_HOST_MESSAGE_REQUEST, -+ Mpi2SendHostMessageRequest_t, -+ *pMpi2SendHostMessageRequest_t; -+ -+/*SendHostMessage Reply message */ -+typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY { -+ U16 HostDataLength; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U16 Reserved4; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_SEND_HOST_MESSAGE_REPLY, *PTR_MPI2_SEND_HOST_MESSAGE_REPLY, -+ Mpi2SendHostMessageReply_t, *pMpi2SendHostMessageReply_t; -+ -+/**************************************************************************** -+* FWDownload message -+****************************************************************************/ -+ -+/*MPI v2.0 FWDownload Request message */ -+typedef struct _MPI2_FW_DOWNLOAD_REQUEST { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 TotalImageSize; /*0x0C */ -+ U32 Reserved5; /*0x10 */ -+ MPI2_MPI_SGE_UNION SGL; /*0x14 */ -+} MPI2_FW_DOWNLOAD_REQUEST, *PTR_MPI2_FW_DOWNLOAD_REQUEST, -+ Mpi2FWDownloadRequest, *pMpi2FWDownloadRequest; -+ -+#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01) -+ -+#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01) -+#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02) -+#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) -+#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) -+#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) -+#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) -+#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) -+#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -+#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C) -+#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) -+ -+/*MPI v2.0 FWDownload TransactionContext Element */ -+typedef struct _MPI2_FW_DOWNLOAD_TCSGE { -+ U8 Reserved1; /*0x00 */ -+ U8 ContextSize; /*0x01 */ -+ U8 DetailsLength; /*0x02 */ -+ U8 Flags; /*0x03 */ -+ U32 Reserved2; /*0x04 */ -+ U32 ImageOffset; /*0x08 */ -+ U32 ImageSize; /*0x0C */ -+} MPI2_FW_DOWNLOAD_TCSGE, *PTR_MPI2_FW_DOWNLOAD_TCSGE, -+ Mpi2FWDownloadTCSGE_t, *pMpi2FWDownloadTCSGE_t; -+ -+/*MPI v2.5 FWDownload Request message */ -+typedef struct _MPI25_FW_DOWNLOAD_REQUEST { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 TotalImageSize; /*0x0C */ -+ U32 Reserved5; /*0x10 */ -+ U32 Reserved6; /*0x14 */ -+ U32 ImageOffset; /*0x18 */ -+ U32 ImageSize; /*0x1C */ -+ MPI25_SGE_IO_UNION SGL; /*0x20 */ -+} MPI25_FW_DOWNLOAD_REQUEST, *PTR_MPI25_FW_DOWNLOAD_REQUEST, -+ Mpi25FWDownloadRequest, *pMpi25FWDownloadRequest; -+ -+/*FWDownload Reply message */ -+typedef struct _MPI2_FW_DOWNLOAD_REPLY { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_FW_DOWNLOAD_REPLY, *PTR_MPI2_FW_DOWNLOAD_REPLY, -+ Mpi2FWDownloadReply_t, *pMpi2FWDownloadReply_t; -+ -+/**************************************************************************** -+* FWUpload message -+****************************************************************************/ -+ -+/*MPI v2.0 FWUpload Request message */ -+typedef struct _MPI2_FW_UPLOAD_REQUEST { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 Reserved6; /*0x10 */ -+ MPI2_MPI_SGE_UNION SGL; /*0x14 */ -+} MPI2_FW_UPLOAD_REQUEST, *PTR_MPI2_FW_UPLOAD_REQUEST, -+ Mpi2FWUploadRequest_t, *pMpi2FWUploadRequest_t; -+ -+#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00) -+#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01) -+#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) -+#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) -+#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) -+#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) -+#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) -+#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09) -+#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A) -+#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -+#define MPI2_FW_UPLOAD_ITYPE_CBB_BACKUP (0x0D) -+ -+/*MPI v2.0 FWUpload TransactionContext Element */ -+typedef struct _MPI2_FW_UPLOAD_TCSGE { -+ U8 Reserved1; /*0x00 */ -+ U8 ContextSize; /*0x01 */ -+ U8 DetailsLength; /*0x02 */ -+ U8 Flags; /*0x03 */ -+ U32 Reserved2; /*0x04 */ -+ U32 ImageOffset; /*0x08 */ -+ U32 ImageSize; /*0x0C */ -+} MPI2_FW_UPLOAD_TCSGE, *PTR_MPI2_FW_UPLOAD_TCSGE, -+ Mpi2FWUploadTCSGE_t, *pMpi2FWUploadTCSGE_t; -+ -+/*MPI v2.5 FWUpload Request message */ -+typedef struct _MPI25_FW_UPLOAD_REQUEST { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 Reserved6; /*0x10 */ -+ U32 Reserved7; /*0x14 */ -+ U32 ImageOffset; /*0x18 */ -+ U32 ImageSize; /*0x1C */ -+ MPI25_SGE_IO_UNION SGL; /*0x20 */ -+} MPI25_FW_UPLOAD_REQUEST, *PTR_MPI25_FW_UPLOAD_REQUEST, -+ Mpi25FWUploadRequest_t, *pMpi25FWUploadRequest_t; -+ -+/*FWUpload Reply message */ -+typedef struct _MPI2_FW_UPLOAD_REPLY { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 ActualImageSize; /*0x14 */ -+} MPI2_FW_UPLOAD_REPLY, *PTR_MPI2_FW_UPLOAD_REPLY, -+ Mpi2FWUploadReply_t, *pMPi2FWUploadReply_t; -+ -+/*FW Image Header */ -+typedef struct _MPI2_FW_IMAGE_HEADER { -+ U32 Signature; /*0x00 */ -+ U32 Signature0; /*0x04 */ -+ U32 Signature1; /*0x08 */ -+ U32 Signature2; /*0x0C */ -+ MPI2_VERSION_UNION MPIVersion; /*0x10 */ -+ MPI2_VERSION_UNION FWVersion; /*0x14 */ -+ MPI2_VERSION_UNION NVDATAVersion; /*0x18 */ -+ MPI2_VERSION_UNION PackageVersion; /*0x1C */ -+ U16 VendorID; /*0x20 */ -+ U16 ProductID; /*0x22 */ -+ U16 ProtocolFlags; /*0x24 */ -+ U16 Reserved26; /*0x26 */ -+ U32 IOCCapabilities; /*0x28 */ -+ U32 ImageSize; /*0x2C */ -+ U32 NextImageHeaderOffset; /*0x30 */ -+ U32 Checksum; /*0x34 */ -+ U32 Reserved38; /*0x38 */ -+ U32 Reserved3C; /*0x3C */ -+ U32 Reserved40; /*0x40 */ -+ U32 Reserved44; /*0x44 */ -+ U32 Reserved48; /*0x48 */ -+ U32 Reserved4C; /*0x4C */ -+ U32 Reserved50; /*0x50 */ -+ U32 Reserved54; /*0x54 */ -+ U32 Reserved58; /*0x58 */ -+ U32 Reserved5C; /*0x5C */ -+ U32 BootFlags; /*0x60 */ -+ U32 FirmwareVersionNameWhat; /*0x64 */ -+ U8 FirmwareVersionName[32]; /*0x68 */ -+ U32 VendorNameWhat; /*0x88 */ -+ U8 VendorName[32]; /*0x8C */ -+ U32 PackageNameWhat; /*0x88 */ -+ U8 PackageName[32]; /*0x8C */ -+ U32 ReservedD0; /*0xD0 */ -+ U32 ReservedD4; /*0xD4 */ -+ U32 ReservedD8; /*0xD8 */ -+ U32 ReservedDC; /*0xDC */ -+ U32 ReservedE0; /*0xE0 */ -+ U32 ReservedE4; /*0xE4 */ -+ U32 ReservedE8; /*0xE8 */ -+ U32 ReservedEC; /*0xEC */ -+ U32 ReservedF0; /*0xF0 */ -+ U32 ReservedF4; /*0xF4 */ -+ U32 ReservedF8; /*0xF8 */ -+ U32 ReservedFC; /*0xFC */ -+} MPI2_FW_IMAGE_HEADER, *PTR_MPI2_FW_IMAGE_HEADER, -+ Mpi2FWImageHeader_t, *pMpi2FWImageHeader_t; -+ -+/*Signature field */ -+#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00) -+#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000) -+#define MPI2_FW_HEADER_SIGNATURE (0xEA000000) -+#define MPI26_FW_HEADER_SIGNATURE (0xEB000000) -+ -+/*Signature0 field */ -+#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04) -+#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A) -+/* Last byte is defined by architecture */ -+#define MPI26_FW_HEADER_SIGNATURE0_BASE (0x5AEAA500) -+#define MPI26_FW_HEADER_SIGNATURE0_ARC_0 (0x5A) -+#define MPI26_FW_HEADER_SIGNATURE0_ARC_1 (0x00) -+#define MPI26_FW_HEADER_SIGNATURE0_ARC_2 (0x01) -+/* legacy (0x5AEAA55A) */ -+#define MPI26_FW_HEADER_SIGNATURE0 \ -+ (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_0) -+#define MPI26_FW_HEADER_SIGNATURE0_3516 \ -+ (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_1) -+ -+/*Signature1 field */ -+#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08) -+#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5) -+#define MPI26_FW_HEADER_SIGNATURE1 (0xA55AEAA5) -+ -+/*Signature2 field */ -+#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C) -+#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA) -+#define MPI26_FW_HEADER_SIGNATURE2 (0x5AA55AEA) -+ -+/*defines for using the ProductID field */ -+#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) -+#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) -+ -+#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) -+#define MPI2_FW_HEADER_PID_PROD_A (0x0000) -+#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) -+#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) -+ -+#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) -+/*SAS ProductID Family bits */ -+#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) -+#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) -+#define MPI25_FW_HEADER_PID_FAMILY_3108_SAS (0x0021) -+#define MPI26_FW_HEADER_PID_FAMILY_3324_SAS (0x0028) -+#define MPI26_FW_HEADER_PID_FAMILY_3516_SAS (0x0031) -+ -+/*use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ -+ -+/*use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */ -+ -+#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C) -+#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30) -+#define MPI26_FW_HEADER_BOOTFLAGS_OFFSET (0x60) -+#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64) -+ -+#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840) -+ -+#define MPI2_FW_HEADER_SIZE (0x100) -+ -+/*Extended Image Header */ -+typedef struct _MPI2_EXT_IMAGE_HEADER { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 Checksum; /*0x04 */ -+ U32 ImageSize; /*0x08 */ -+ U32 NextImageHeaderOffset; /*0x0C */ -+ U32 PackageVersion; /*0x10 */ -+ U32 Reserved3; /*0x14 */ -+ U32 Reserved4; /*0x18 */ -+ U32 Reserved5; /*0x1C */ -+ U8 IdentifyString[32]; /*0x20 */ -+} MPI2_EXT_IMAGE_HEADER, *PTR_MPI2_EXT_IMAGE_HEADER, -+ Mpi2ExtImageHeader_t, *pMpi2ExtImageHeader_t; -+ -+/*useful offsets */ -+#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00) -+#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08) -+#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C) -+ -+#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40) -+ -+/*defines for the ImageType field */ -+#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) -+#define MPI2_EXT_IMAGE_TYPE_FW (0x01) -+#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) -+#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) -+#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) -+#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) -+#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) -+#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) -+#define MPI2_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09) -+#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) -+#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) -+ -+#define MPI2_EXT_IMAGE_TYPE_MAX (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) -+ -+/*FLASH Layout Extended Image Data */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check RegionsPerLayout at runtime. -+ */ -+#ifndef MPI2_FLASH_NUMBER_OF_REGIONS -+#define MPI2_FLASH_NUMBER_OF_REGIONS (1) -+#endif -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check NumberOfLayouts at runtime. -+ */ -+#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS -+#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) -+#endif -+ -+typedef struct _MPI2_FLASH_REGION { -+ U8 RegionType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 RegionOffset; /*0x04 */ -+ U32 RegionSize; /*0x08 */ -+ U32 Reserved3; /*0x0C */ -+} MPI2_FLASH_REGION, *PTR_MPI2_FLASH_REGION, -+ Mpi2FlashRegion_t, *pMpi2FlashRegion_t; -+ -+typedef struct _MPI2_FLASH_LAYOUT { -+ U32 FlashSize; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U32 Reserved3; /*0x0C */ -+ MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS]; /*0x10 */ -+} MPI2_FLASH_LAYOUT, *PTR_MPI2_FLASH_LAYOUT, -+ Mpi2FlashLayout_t, *pMpi2FlashLayout_t; -+ -+typedef struct _MPI2_FLASH_LAYOUT_DATA { -+ U8 ImageRevision; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 SizeOfRegion; /*0x02 */ -+ U8 Reserved2; /*0x03 */ -+ U16 NumberOfLayouts; /*0x04 */ -+ U16 RegionsPerLayout; /*0x06 */ -+ U16 MinimumSectorAlignment; /*0x08 */ -+ U16 Reserved3; /*0x0A */ -+ U32 Reserved4; /*0x0C */ -+ MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS]; /*0x10 */ -+} MPI2_FLASH_LAYOUT_DATA, *PTR_MPI2_FLASH_LAYOUT_DATA, -+ Mpi2FlashLayoutData_t, *pMpi2FlashLayoutData_t; -+ -+/*defines for the RegionType field */ -+#define MPI2_FLASH_REGION_UNUSED (0x00) -+#define MPI2_FLASH_REGION_FIRMWARE (0x01) -+#define MPI2_FLASH_REGION_BIOS (0x02) -+#define MPI2_FLASH_REGION_NVDATA (0x03) -+#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05) -+#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06) -+#define MPI2_FLASH_REGION_CONFIG_1 (0x07) -+#define MPI2_FLASH_REGION_CONFIG_2 (0x08) -+#define MPI2_FLASH_REGION_MEGARAID (0x09) -+#define MPI2_FLASH_REGION_COMMON_BOOT_BLOCK (0x0A) -+#define MPI2_FLASH_REGION_INIT (MPI2_FLASH_REGION_COMMON_BOOT_BLOCK) -+#define MPI2_FLASH_REGION_CBB_BACKUP (0x0D) -+ -+/*ImageRevision */ -+#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00) -+ -+/*Supported Devices Extended Image Data */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check NumberOfDevices at runtime. -+ */ -+#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES -+#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) -+#endif -+ -+typedef struct _MPI2_SUPPORTED_DEVICE { -+ U16 DeviceID; /*0x00 */ -+ U16 VendorID; /*0x02 */ -+ U16 DeviceIDMask; /*0x04 */ -+ U16 Reserved1; /*0x06 */ -+ U8 LowPCIRev; /*0x08 */ -+ U8 HighPCIRev; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U32 Reserved3; /*0x0C */ -+} MPI2_SUPPORTED_DEVICE, *PTR_MPI2_SUPPORTED_DEVICE, -+ Mpi2SupportedDevice_t, *pMpi2SupportedDevice_t; -+ -+typedef struct _MPI2_SUPPORTED_DEVICES_DATA { -+ U8 ImageRevision; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 NumberOfDevices; /*0x02 */ -+ U8 Reserved2; /*0x03 */ -+ U32 Reserved3; /*0x04 */ -+ MPI2_SUPPORTED_DEVICE -+ SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES];/*0x08 */ -+} MPI2_SUPPORTED_DEVICES_DATA, *PTR_MPI2_SUPPORTED_DEVICES_DATA, -+ Mpi2SupportedDevicesData_t, *pMpi2SupportedDevicesData_t; -+ -+/*ImageRevision */ -+#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00) -+ -+/*Init Extended Image Data */ -+ -+typedef struct _MPI2_INIT_IMAGE_FOOTER { -+ U32 BootFlags; /*0x00 */ -+ U32 ImageSize; /*0x04 */ -+ U32 Signature0; /*0x08 */ -+ U32 Signature1; /*0x0C */ -+ U32 Signature2; /*0x10 */ -+ U32 ResetVector; /*0x14 */ -+} MPI2_INIT_IMAGE_FOOTER, *PTR_MPI2_INIT_IMAGE_FOOTER, -+ Mpi2InitImageFooter_t, *pMpi2InitImageFooter_t; -+ -+/*defines for the BootFlags field */ -+#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00) -+ -+/*defines for the ImageSize field */ -+#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04) -+ -+/*defines for the Signature0 field */ -+#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08) -+#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA) -+ -+/*defines for the Signature1 field */ -+#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C) -+#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5) -+ -+/*defines for the Signature2 field */ -+#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10) -+#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A) -+ -+/*Signature fields as individual bytes */ -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A) -+ -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5) -+ -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A) -+ -+/*defines for the ResetVector field */ -+#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) -+ -+ -+/* Encrypted Hash Extended Image Data */ -+ -+typedef struct _MPI25_ENCRYPTED_HASH_ENTRY { -+ U8 HashImageType; /* 0x00 */ -+ U8 HashAlgorithm; /* 0x01 */ -+ U8 EncryptionAlgorithm; /* 0x02 */ -+ U8 Reserved1; /* 0x03 */ -+ U32 Reserved2; /* 0x04 */ -+ U32 EncryptedHash[1]; /* 0x08 */ /* variable length */ -+} MPI25_ENCRYPTED_HASH_ENTRY, *PTR_MPI25_ENCRYPTED_HASH_ENTRY, -+Mpi25EncryptedHashEntry_t, *pMpi25EncryptedHashEntry_t; -+ -+/* values for HashImageType */ -+#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00) -+#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01) -+#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02) -+ -+/* values for HashAlgorithm */ -+#define MPI25_HASH_ALGORITHM_UNUSED (0x00) -+#define MPI25_HASH_ALGORITHM_SHA256 (0x01) -+ -+/* values for EncryptionAlgorithm */ -+#define MPI25_ENCRYPTION_ALG_UNUSED (0x00) -+#define MPI25_ENCRYPTION_ALG_RSA256 (0x01) -+ -+typedef struct _MPI25_ENCRYPTED_HASH_DATA { -+ U8 ImageVersion; /* 0x00 */ -+ U8 NumHash; /* 0x01 */ -+ U16 Reserved1; /* 0x02 */ -+ U32 Reserved2; /* 0x04 */ -+ MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /* 0x08 */ -+} MPI25_ENCRYPTED_HASH_DATA, *PTR_MPI25_ENCRYPTED_HASH_DATA, -+Mpi25EncryptedHashData_t, *pMpi25EncryptedHashData_t; -+ -+ -+/**************************************************************************** -+* PowerManagementControl message -+****************************************************************************/ -+ -+/*PowerManagementControl Request message */ -+typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { -+ U8 Feature; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U8 Parameter1; /*0x0C */ -+ U8 Parameter2; /*0x0D */ -+ U8 Parameter3; /*0x0E */ -+ U8 Parameter4; /*0x0F */ -+ U32 Reserved5; /*0x10 */ -+ U32 Reserved6; /*0x14 */ -+} MPI2_PWR_MGMT_CONTROL_REQUEST, *PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, -+ Mpi2PwrMgmtControlRequest_t, *pMpi2PwrMgmtControlRequest_t; -+ -+/*defines for the Feature field */ -+#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) -+#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) -+#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /*obsolete */ -+#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) -+#define MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE (0x05) -+#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) -+#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) -+ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ -+/*Parameter1 contains a PHY number */ -+/*Parameter2 indicates power condition action using these defines */ -+#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) -+#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) -+#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) -+/*Parameter3 and Parameter4 are reserved */ -+ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION -+ * Feature */ -+/*Parameter1 contains SAS port width modulation group number */ -+/*Parameter2 indicates IOC action using these defines */ -+#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) -+#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) -+#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) -+/*Parameter3 indicates desired modulation level using these defines */ -+#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) -+#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) -+#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) -+#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) -+/*Parameter4 is reserved */ -+ -+/*this next set (_PCIE_LINK) is obsolete */ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ -+/*Parameter1 indicates desired PCIe link speed using these defines */ -+#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /*obsolete */ -+/*Parameter2 indicates desired PCIe link width using these defines */ -+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /*obsolete */ -+/*Parameter3 and Parameter4 are reserved */ -+ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ -+/*Parameter1 indicates desired IOC hardware clock speed using these defines */ -+#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) -+#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) -+#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) -+#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) -+/*Parameter2, Parameter3, and Parameter4 are reserved */ -+ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE Feature*/ -+/*Parameter1 indicates host action regarding global power management mode */ -+#define MPI2_PM_CONTROL_PARAM1_TAKE_CONTROL (0x01) -+#define MPI2_PM_CONTROL_PARAM1_CHANGE_GLOBAL_MODE (0x02) -+#define MPI2_PM_CONTROL_PARAM1_RELEASE_CONTROL (0x03) -+/*Parameter2 indicates the requested global power management mode */ -+#define MPI2_PM_CONTROL_PARAM2_FULL_PWR_PERF (0x01) -+#define MPI2_PM_CONTROL_PARAM2_REDUCED_PWR_PERF (0x08) -+#define MPI2_PM_CONTROL_PARAM2_STANDBY (0x40) -+/*Parameter3 and Parameter4 are reserved */ -+ -+/*PowerManagementControl Reply message */ -+typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY { -+ U8 Feature; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_PWR_MGMT_CONTROL_REPLY, *PTR_MPI2_PWR_MGMT_CONTROL_REPLY, -+ Mpi2PwrMgmtControlReply_t, *pMpi2PwrMgmtControlReply_t; -+ -+/**************************************************************************** -+* IO Unit Control messages (MPI v2.6 and later only.) -+****************************************************************************/ -+ -+/* IO Unit Control Request Message */ -+typedef struct _MPI26_IOUNIT_CONTROL_REQUEST { -+ U8 Operation; /* 0x00 */ -+ U8 Reserved1; /* 0x01 */ -+ U8 ChainOffset; /* 0x02 */ -+ U8 Function; /* 0x03 */ -+ U16 DevHandle; /* 0x04 */ -+ U8 IOCParameter; /* 0x06 */ -+ U8 MsgFlags; /* 0x07 */ -+ U8 VP_ID; /* 0x08 */ -+ U8 VF_ID; /* 0x09 */ -+ U16 Reserved3; /* 0x0A */ -+ U16 Reserved4; /* 0x0C */ -+ U8 PhyNum; /* 0x0E */ -+ U8 PrimFlags; /* 0x0F */ -+ U32 Primitive; /* 0x10 */ -+ U8 LookupMethod; /* 0x14 */ -+ U8 Reserved5; /* 0x15 */ -+ U16 SlotNumber; /* 0x16 */ -+ U64 LookupAddress; /* 0x18 */ -+ U32 IOCParameterValue; /* 0x20 */ -+ U32 Reserved7; /* 0x24 */ -+ U32 Reserved8; /* 0x28 */ -+} MPI26_IOUNIT_CONTROL_REQUEST, -+ *PTR_MPI26_IOUNIT_CONTROL_REQUEST, -+ Mpi26IoUnitControlRequest_t, -+ *pMpi26IoUnitControlRequest_t; -+ -+/* values for the Operation field */ -+#define MPI26_CTRL_OP_CLEAR_ALL_PERSISTENT (0x02) -+#define MPI26_CTRL_OP_SAS_PHY_LINK_RESET (0x06) -+#define MPI26_CTRL_OP_SAS_PHY_HARD_RESET (0x07) -+#define MPI26_CTRL_OP_PHY_CLEAR_ERROR_LOG (0x08) -+#define MPI26_CTRL_OP_LINK_CLEAR_ERROR_LOG (0x09) -+#define MPI26_CTRL_OP_SAS_SEND_PRIMITIVE (0x0A) -+#define MPI26_CTRL_OP_FORCE_FULL_DISCOVERY (0x0B) -+#define MPI26_CTRL_OP_REMOVE_DEVICE (0x0D) -+#define MPI26_CTRL_OP_LOOKUP_MAPPING (0x0E) -+#define MPI26_CTRL_OP_SET_IOC_PARAMETER (0x0F) -+#define MPI26_CTRL_OP_ENABLE_FP_DEVICE (0x10) -+#define MPI26_CTRL_OP_DISABLE_FP_DEVICE (0x11) -+#define MPI26_CTRL_OP_ENABLE_FP_ALL (0x12) -+#define MPI26_CTRL_OP_DISABLE_FP_ALL (0x13) -+#define MPI26_CTRL_OP_DEV_ENABLE_NCQ (0x14) -+#define MPI26_CTRL_OP_DEV_DISABLE_NCQ (0x15) -+#define MPI26_CTRL_OP_SHUTDOWN (0x16) -+#define MPI26_CTRL_OP_DEV_ENABLE_PERSIST_CONNECTION (0x17) -+#define MPI26_CTRL_OP_DEV_DISABLE_PERSIST_CONNECTION (0x18) -+#define MPI26_CTRL_OP_DEV_CLOSE_PERSIST_CONNECTION (0x19) -+#define MPI26_CTRL_OP_PRODUCT_SPECIFIC_MIN (0x80) -+ -+/* values for the PrimFlags field */ -+#define MPI26_CTRL_PRIMFLAGS_SINGLE (0x08) -+#define MPI26_CTRL_PRIMFLAGS_TRIPLE (0x02) -+#define MPI26_CTRL_PRIMFLAGS_REDUNDANT (0x01) -+ -+/* values for the LookupMethod field */ -+#define MPI26_CTRL_LOOKUP_METHOD_WWID_ADDRESS (0x01) -+#define MPI26_CTRL_LOOKUP_METHOD_ENCLOSURE_SLOT (0x02) -+#define MPI26_CTRL_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) -+ -+ -+/* IO Unit Control Reply Message */ -+typedef struct _MPI26_IOUNIT_CONTROL_REPLY { -+ U8 Operation; /* 0x00 */ -+ U8 Reserved1; /* 0x01 */ -+ U8 MsgLength; /* 0x02 */ -+ U8 Function; /* 0x03 */ -+ U16 DevHandle; /* 0x04 */ -+ U8 IOCParameter; /* 0x06 */ -+ U8 MsgFlags; /* 0x07 */ -+ U8 VP_ID; /* 0x08 */ -+ U8 VF_ID; /* 0x09 */ -+ U16 Reserved3; /* 0x0A */ -+ U16 Reserved4; /* 0x0C */ -+ U16 IOCStatus; /* 0x0E */ -+ U32 IOCLogInfo; /* 0x10 */ -+} MPI26_IOUNIT_CONTROL_REPLY, -+ *PTR_MPI26_IOUNIT_CONTROL_REPLY, -+ Mpi26IoUnitControlReply_t, -+ *pMpi26IoUnitControlReply_t; -+ -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h -new file mode 100644 -index 0000000..1c0eeee ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h -@@ -0,0 +1,355 @@ -+/* -+ * Copyright 2000-2014 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_raid.h -+ * Title: MPI Integrated RAID messages and structures -+ * Creation Date: April 26, 2007 -+ * -+ * mpi2_raid.h Version: 02.00.11 -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 08-31-07 02.00.01 Modifications to RAID Action request and reply, -+ * including the Actions and ActionData. -+ * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. -+ * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that -+ * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT -+ * can be sized by the build environment. -+ * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of -+ * VolumeCreationFlags and marked the old one as obsolete. -+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. -+ * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with -+ * related structures and defines. -+ * Added product-specific range to RAID Action values. -+ * 11-18-11 02.00.07 Incorporating additions for MPI v2.5. -+ * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN. -+ * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR. -+ * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define. -+ * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI. -+ * 11-18-14 02.00.11 Updated copyright information. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_RAID_H -+#define MPI2_RAID_H -+ -+/***************************************************************************** -+* -+* Integrated RAID Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* RAID Action messages -+****************************************************************************/ -+ -+/* ActionDataWord defines for use with MPI2_RAID_ACTION_CREATE_VOLUME action */ -+#define MPI25_RAID_ACTION_ADATA_ALLOW_PI (0x80000000) -+ -+/*ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */ -+#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) -+#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001) -+ -+/*use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for -+ *MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ -+ -+/*ActionDataWord defines for use with -+ *MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */ -+#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001) -+ -+/*ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */ -+typedef struct _MPI2_RAID_ACTION_RATE_DATA { -+ U8 RateToChange; /*0x00 */ -+ U8 RateOrMode; /*0x01 */ -+ U16 DataScrubDuration; /*0x02 */ -+} MPI2_RAID_ACTION_RATE_DATA, *PTR_MPI2_RAID_ACTION_RATE_DATA, -+ Mpi2RaidActionRateData_t, *pMpi2RaidActionRateData_t; -+ -+#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00) -+#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01) -+#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02) -+ -+/*ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */ -+typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION { -+ U8 RAIDFunction; /*0x00 */ -+ U8 Flags; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+} MPI2_RAID_ACTION_START_RAID_FUNCTION, -+ *PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION, -+ Mpi2RaidActionStartRaidFunction_t, -+ *pMpi2RaidActionStartRaidFunction_t; -+ -+/*defines for the RAIDFunction field */ -+#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00) -+#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01) -+#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02) -+ -+/*defines for the Flags field */ -+#define MPI2_RAID_ACTION_START_NEW (0x00) -+#define MPI2_RAID_ACTION_START_RESUME (0x01) -+ -+/*ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */ -+typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION { -+ U8 RAIDFunction; /*0x00 */ -+ U8 Flags; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+} MPI2_RAID_ACTION_STOP_RAID_FUNCTION, -+ *PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION, -+ Mpi2RaidActionStopRaidFunction_t, -+ *pMpi2RaidActionStopRaidFunction_t; -+ -+/*defines for the RAIDFunction field */ -+#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00) -+#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01) -+#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02) -+ -+/*defines for the Flags field */ -+#define MPI2_RAID_ACTION_STOP_ABORT (0x00) -+#define MPI2_RAID_ACTION_STOP_PAUSE (0x01) -+ -+/*ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */ -+typedef struct _MPI2_RAID_ACTION_HOT_SPARE { -+ U8 HotSparePool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 DevHandle; /*0x02 */ -+} MPI2_RAID_ACTION_HOT_SPARE, *PTR_MPI2_RAID_ACTION_HOT_SPARE, -+ Mpi2RaidActionHotSpare_t, *pMpi2RaidActionHotSpare_t; -+ -+/*ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */ -+typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE { -+ U8 Flags; /*0x00 */ -+ U8 DeviceFirmwareUpdateModeTimeout; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+} MPI2_RAID_ACTION_FW_UPDATE_MODE, -+ *PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE, -+ Mpi2RaidActionFwUpdateMode_t, -+ *pMpi2RaidActionFwUpdateMode_t; -+ -+/*ActionDataWord defines for use with -+ *MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */ -+#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00) -+#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01) -+ -+typedef union _MPI2_RAID_ACTION_DATA { -+ U32 Word; -+ MPI2_RAID_ACTION_RATE_DATA Rates; -+ MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction; -+ MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction; -+ MPI2_RAID_ACTION_HOT_SPARE HotSpare; -+ MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode; -+} MPI2_RAID_ACTION_DATA, *PTR_MPI2_RAID_ACTION_DATA, -+ Mpi2RaidActionData_t, *pMpi2RaidActionData_t; -+ -+/*RAID Action Request Message */ -+typedef struct _MPI2_RAID_ACTION_REQUEST { -+ U8 Action; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 VolDevHandle; /*0x04 */ -+ U8 PhysDiskNum; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U32 Reserved3; /*0x0C */ -+ MPI2_RAID_ACTION_DATA ActionDataWord; /*0x10 */ -+ MPI2_SGE_SIMPLE_UNION ActionDataSGE; /*0x14 */ -+} MPI2_RAID_ACTION_REQUEST, *PTR_MPI2_RAID_ACTION_REQUEST, -+ Mpi2RaidActionRequest_t, *pMpi2RaidActionRequest_t; -+ -+/*RAID Action request Action values */ -+ -+#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01) -+#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02) -+#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03) -+#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04) -+#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05) -+#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A) -+#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B) -+#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F) -+#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11) -+#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) -+#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) -+#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18) -+#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19) -+#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C) -+#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D) -+#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E) -+#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20) -+#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21) -+#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22) -+#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23) -+#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN (0x24) -+#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80) -+#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF) -+ -+/*RAID Volume Creation Structure */ -+ -+/* -+ *The following define can be customized for the targeted product. -+ */ -+#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS -+#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1) -+#endif -+ -+typedef struct _MPI2_RAID_VOLUME_PHYSDISK { -+ U8 RAIDSetNum; /*0x00 */ -+ U8 PhysDiskMap; /*0x01 */ -+ U16 PhysDiskDevHandle; /*0x02 */ -+} MPI2_RAID_VOLUME_PHYSDISK, *PTR_MPI2_RAID_VOLUME_PHYSDISK, -+ Mpi2RaidVolumePhysDisk_t, *pMpi2RaidVolumePhysDisk_t; -+ -+/*defines for the PhysDiskMap field */ -+#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01) -+#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02) -+ -+typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT { -+ U8 NumPhysDisks; /*0x00 */ -+ U8 VolumeType; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+ U32 VolumeCreationFlags; /*0x04 */ -+ U32 VolumeSettings; /*0x08 */ -+ U8 Reserved2; /*0x0C */ -+ U8 ResyncRate; /*0x0D */ -+ U16 DataScrubDuration; /*0x0E */ -+ U64 VolumeMaxLBA; /*0x10 */ -+ U32 StripeSize; /*0x18 */ -+ U8 Name[16]; /*0x1C */ -+ MPI2_RAID_VOLUME_PHYSDISK -+ PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS]; /*0x2C */ -+} MPI2_RAID_VOLUME_CREATION_STRUCT, -+ *PTR_MPI2_RAID_VOLUME_CREATION_STRUCT, -+ Mpi2RaidVolumeCreationStruct_t, -+ *pMpi2RaidVolumeCreationStruct_t; -+ -+/*use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ -+ -+/*defines for the VolumeCreationFlags field */ -+#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000) -+#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) -+#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) -+#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) -+/*The following is an obsolete define. -+ *It must be shifted left 24 bits in order to set the proper bit. -+ */ -+#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) -+ -+/*RAID Online Capacity Expansion Structure */ -+ -+typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION { -+ U32 Flags; /*0x00 */ -+ U16 DevHandle0; /*0x04 */ -+ U16 Reserved1; /*0x06 */ -+ U16 DevHandle1; /*0x08 */ -+ U16 Reserved2; /*0x0A */ -+} MPI2_RAID_ONLINE_CAPACITY_EXPANSION, -+ *PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION, -+ Mpi2RaidOnlineCapacityExpansion_t, -+ *pMpi2RaidOnlineCapacityExpansion_t; -+ -+/*RAID Compatibility Input Structure */ -+ -+typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT { -+ U16 SourceDevHandle; /*0x00 */ -+ U16 CandidateDevHandle; /*0x02 */ -+ U32 Flags; /*0x04 */ -+ U32 Reserved1; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -+ *PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -+ Mpi2RaidCompatibilityInputStruct_t, -+ *pMpi2RaidCompatibilityInputStruct_t; -+ -+/*defines for RAID Compatibility Structure Flags field */ -+#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002) -+#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001) -+ -+/*RAID Volume Indicator Structure */ -+ -+typedef struct _MPI2_RAID_VOL_INDICATOR { -+ U64 TotalBlocks; /*0x00 */ -+ U64 BlocksRemaining; /*0x08 */ -+ U32 Flags; /*0x10 */ -+ U32 ElapsedSeconds; /* 0x14 */ -+} MPI2_RAID_VOL_INDICATOR, *PTR_MPI2_RAID_VOL_INDICATOR, -+ Mpi2RaidVolIndicator_t, *pMpi2RaidVolIndicator_t; -+ -+/*defines for RAID Volume Indicator Flags field */ -+#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID (0x80000000) -+#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F) -+#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000) -+#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) -+#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) -+#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) -+#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) -+ -+/*RAID Compatibility Result Structure */ -+ -+typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT { -+ U8 State; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 GenericAttributes; /*0x04 */ -+ U32 OEMSpecificAttributes; /*0x08 */ -+ U32 Reserved3; /*0x0C */ -+ U32 Reserved4; /*0x10 */ -+} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -+ *PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -+ Mpi2RaidCompatibilityResultStruct_t, -+ *pMpi2RaidCompatibilityResultStruct_t; -+ -+/*defines for RAID Compatibility Result Structure State field */ -+#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00) -+#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01) -+ -+/*defines for RAID Compatibility Result Structure GenericAttributes field */ -+#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010) -+ -+#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C) -+#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008) -+#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004) -+ -+#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003) -+#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002) -+#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001) -+ -+/*RAID Action Reply ActionData union */ -+typedef union _MPI2_RAID_ACTION_REPLY_DATA { -+ U32 Word[6]; -+ MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; -+ U16 VolDevHandle; -+ U8 VolumeState; -+ U8 PhysDiskNum; -+ MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult; -+} MPI2_RAID_ACTION_REPLY_DATA, *PTR_MPI2_RAID_ACTION_REPLY_DATA, -+ Mpi2RaidActionReplyData_t, *pMpi2RaidActionReplyData_t; -+ -+/*use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for -+ *MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ -+ -+/*RAID Action Reply Message */ -+typedef struct _MPI2_RAID_ACTION_REPLY { -+ U8 Action; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 VolDevHandle; /*0x04 */ -+ U8 PhysDiskNum; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U16 Reserved3; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ MPI2_RAID_ACTION_REPLY_DATA ActionData; /*0x14 */ -+} MPI2_RAID_ACTION_REPLY, *PTR_MPI2_RAID_ACTION_REPLY, -+ Mpi2RaidActionReply_t, *pMpi2RaidActionReply_t; -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h -new file mode 100644 -index 0000000..c10c2c0 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h -@@ -0,0 +1,303 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_sas.h -+ * Title: MPI Serial Attached SCSI structures and definitions -+ * Creation Date: February 9, 2007 -+ * -+ * mpi2_sas.h Version: 02.00.10 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit -+ * Control Request. -+ * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control -+ * Request. -+ * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST -+ * to MPI2_SGE_IO_UNION since it supports chained SGLs. -+ * 05-12-10 02.00.04 Modified some comments. -+ * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. -+ * 11-18-11 02.00.06 Incorporating additions for MPI v2.5. -+ * 07-10-12 02.00.07 Added MPI2_SATA_PT_SGE_UNION for use in the SATA -+ * Passthrough Request message. -+ * 08-19-13 02.00.08 Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete -+ * for anything newer than MPI v2.0. -+ * 11-18-14 02.00.09 Updated copyright information. -+ * 03-16-15 02.00.10 Updated for MPI v2.6. -+ * Added MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_SAS_H -+#define MPI2_SAS_H -+ -+/* -+ *Values for SASStatus. -+ */ -+#define MPI2_SASSTATUS_SUCCESS (0x00) -+#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01) -+#define MPI2_SASSTATUS_INVALID_FRAME (0x02) -+#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03) -+#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04) -+#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) -+#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) -+#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) -+#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) -+#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09) -+#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) -+#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) -+#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) -+#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) -+#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) -+#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) -+#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) -+#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11) -+#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12) -+#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) -+#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) -+ -+/* -+ *Values for the SAS DeviceInfo field used in SAS Device Status Change Event -+ *data and SAS Configuration pages. -+ */ -+#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000) -+#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) -+#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) -+#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) -+#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) -+#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200) -+#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) -+#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) -+#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) -+#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) -+#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) -+#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008) -+ -+#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) -+#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) -+#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001) -+#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) -+#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) -+ -+/***************************************************************************** -+* -+* SAS Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* SMP Passthrough messages -+****************************************************************************/ -+ -+/*SMP Passthrough Request Message */ -+typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST { -+ U8 PassthroughFlags; /*0x00 */ -+ U8 PhysicalPort; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 RequestDataLength; /*0x04 */ -+ U8 SGLFlags; /*0x06*//*MPI v2.0 only. Reserved on MPI v2.5*/ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U32 Reserved2; /*0x0C */ -+ U64 SASAddress; /*0x10 */ -+ U32 Reserved3; /*0x18 */ -+ U32 Reserved4; /*0x1C */ -+ MPI2_SIMPLE_SGE_UNION SGL;/*0x20 */ -+} MPI2_SMP_PASSTHROUGH_REQUEST, *PTR_MPI2_SMP_PASSTHROUGH_REQUEST, -+ Mpi2SmpPassthroughRequest_t, *pMpi2SmpPassthroughRequest_t; -+ -+/*values for PassthroughFlags field */ -+#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) -+ -+/*MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+/*SMP Passthrough Reply Message */ -+typedef struct _MPI2_SMP_PASSTHROUGH_REPLY { -+ U8 PassthroughFlags; /*0x00 */ -+ U8 PhysicalPort; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 ResponseDataLength; /*0x04 */ -+ U8 SGLFlags; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U8 Reserved2; /*0x0C */ -+ U8 SASStatus; /*0x0D */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 Reserved3; /*0x14 */ -+ U8 ResponseData[4]; /*0x18 */ -+} MPI2_SMP_PASSTHROUGH_REPLY, *PTR_MPI2_SMP_PASSTHROUGH_REPLY, -+ Mpi2SmpPassthroughReply_t, *pMpi2SmpPassthroughReply_t; -+ -+/*values for PassthroughFlags field */ -+#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) -+ -+/*values for SASStatus field are at the top of this file */ -+ -+/**************************************************************************** -+* SATA Passthrough messages -+****************************************************************************/ -+ -+typedef union _MPI2_SATA_PT_SGE_UNION { -+ MPI2_SGE_SIMPLE_UNION MpiSimple; /*MPI v2.0 only */ -+ MPI2_SGE_CHAIN_UNION MpiChain; /*MPI v2.0 only */ -+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; -+ MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; /*MPI v2.0 only */ -+ MPI25_IEEE_SGE_CHAIN64 IeeeChain64; /*MPI v2.5 only */ -+} MPI2_SATA_PT_SGE_UNION, *PTR_MPI2_SATA_PT_SGE_UNION, -+ Mpi2SataPTSGEUnion_t, *pMpi2SataPTSGEUnion_t; -+ -+/*SATA Passthrough Request Message */ -+typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 PassthroughFlags; /*0x04 */ -+ U8 SGLFlags; /*0x06*//*MPI v2.0 only. Reserved on MPI v2.5*/ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U32 Reserved2; /*0x0C */ -+ U32 Reserved3; /*0x10 */ -+ U32 Reserved4; /*0x14 */ -+ U32 DataLength; /*0x18 */ -+ U8 CommandFIS[20]; /*0x1C */ -+ MPI2_SATA_PT_SGE_UNION SGL;/*0x30*//*MPI v2.5: IEEE 64 elements only*/ -+} MPI2_SATA_PASSTHROUGH_REQUEST, *PTR_MPI2_SATA_PASSTHROUGH_REQUEST, -+ Mpi2SataPassthroughRequest_t, -+ *pMpi2SataPassthroughRequest_t; -+ -+/*values for PassthroughFlags field */ -+#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA (0x0040) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) -+ -+/*MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+/*SATA Passthrough Reply Message */ -+typedef struct _MPI2_SATA_PASSTHROUGH_REPLY { -+ U16 DevHandle; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 PassthroughFlags; /*0x04 */ -+ U8 SGLFlags; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U8 Reserved2; /*0x0C */ -+ U8 SASStatus; /*0x0D */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U8 StatusFIS[20]; /*0x14 */ -+ U32 StatusControlRegisters; /*0x28 */ -+ U32 TransferCount; /*0x2C */ -+} MPI2_SATA_PASSTHROUGH_REPLY, *PTR_MPI2_SATA_PASSTHROUGH_REPLY, -+ Mpi2SataPassthroughReply_t, *pMpi2SataPassthroughReply_t; -+ -+/*values for SASStatus field are at the top of this file */ -+ -+/**************************************************************************** -+* SAS IO Unit Control messages -+* (MPI v2.5 and earlier only. -+* Replaced by IO Unit Control messages in MPI v2.6 and later.) -+****************************************************************************/ -+ -+/*SAS IO Unit Control Request Message */ -+typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST { -+ U8 Operation; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 DevHandle; /*0x04 */ -+ U8 IOCParameter; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U16 Reserved4; /*0x0C */ -+ U8 PhyNum; /*0x0E */ -+ U8 PrimFlags; /*0x0F */ -+ U32 Primitive; /*0x10 */ -+ U8 LookupMethod; /*0x14 */ -+ U8 Reserved5; /*0x15 */ -+ U16 SlotNumber; /*0x16 */ -+ U64 LookupAddress; /*0x18 */ -+ U32 IOCParameterValue; /*0x20 */ -+ U32 Reserved7; /*0x24 */ -+ U32 Reserved8; /*0x28 */ -+} MPI2_SAS_IOUNIT_CONTROL_REQUEST, -+ *PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST, -+ Mpi2SasIoUnitControlRequest_t, -+ *pMpi2SasIoUnitControlRequest_t; -+ -+/*values for the Operation field */ -+#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02) -+#define MPI2_SAS_OP_PHY_LINK_RESET (0x06) -+#define MPI2_SAS_OP_PHY_HARD_RESET (0x07) -+#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) -+#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A) -+#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) -+#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) /* MPI v2.0 only */ -+#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D) -+#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E) -+#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F) -+#define MPI25_SAS_OP_ENABLE_FP_DEVICE (0x10) -+#define MPI25_SAS_OP_DISABLE_FP_DEVICE (0x11) -+#define MPI25_SAS_OP_ENABLE_FP_ALL (0x12) -+#define MPI25_SAS_OP_DISABLE_FP_ALL (0x13) -+#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14) -+#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15) -+#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) -+ -+/*values for the PrimFlags field */ -+#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08) -+#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02) -+#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01) -+ -+/*values for the LookupMethod field */ -+#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01) -+#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02) -+#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) -+ -+/*SAS IO Unit Control Reply Message */ -+typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY { -+ U8 Operation; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 DevHandle; /*0x04 */ -+ U8 IOCParameter; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U16 Reserved4; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_SAS_IOUNIT_CONTROL_REPLY, -+ *PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY, -+ Mpi2SasIoUnitControlReply_t, *pMpi2SasIoUnitControlReply_t; -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h -new file mode 100644 -index 0000000..5f9289a ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h -@@ -0,0 +1,483 @@ -+/* -+ * Copyright 2000-2014 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_tool.h -+ * Title: MPI diagnostic tool structures and definitions -+ * Creation Date: March 26, 2007 -+ * -+ * mpi2_tool.h Version: 02.00.13 -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release -+ * structures and defines. -+ * 02-29-08 02.00.02 Modified various names to make them 32-character unique. -+ * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. -+ * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request -+ * and reply messages. -+ * Added MPI2_DIAG_BUF_TYPE_EXTENDED. -+ * Incremented MPI2_DIAG_BUF_TYPE_COUNT. -+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. -+ * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer -+ * Post Request. -+ * 05-25-11 02.00.07 Added Flags field and related defines to -+ * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. -+ * 11-18-11 02.00.08 Incorporating additions for MPI v2.5. -+ * 07-10-12 02.00.09 Add MPI v2.5 Toolbox Diagnostic CLI Tool Request -+ * message. -+ * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that -+ * it uses MPI Chain SGE as well as MPI Simple SGE. -+ * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. -+ * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC. -+ * 11-18-14 02.00.13 Updated copyright information. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_TOOL_H -+#define MPI2_TOOL_H -+ -+/***************************************************************************** -+* -+* Toolbox Messages -+* -+*****************************************************************************/ -+ -+/*defines for the Tools */ -+#define MPI2_TOOLBOX_CLEAN_TOOL (0x00) -+#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) -+#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) -+#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) -+#define MPI2_TOOLBOX_BEACON_TOOL (0x05) -+#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) -+#define MPI2_TOOLBOX_TEXT_DISPLAY_TOOL (0x07) -+ -+/**************************************************************************** -+* Toolbox reply -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_REPLY { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_TOOLBOX_REPLY, *PTR_MPI2_TOOLBOX_REPLY, -+ Mpi2ToolboxReply_t, *pMpi2ToolboxReply_t; -+ -+/**************************************************************************** -+* Toolbox Clean Tool request -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Flags; /*0x0C */ -+} MPI2_TOOLBOX_CLEAN_REQUEST, *PTR_MPI2_TOOLBOX_CLEAN_REQUEST, -+ Mpi2ToolboxCleanRequest_t, *pMpi2ToolboxCleanRequest_t; -+ -+/*values for the Flags field */ -+#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) -+#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) -+#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) -+#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) -+#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) -+#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000) -+#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) -+#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) -+#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) -+#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002) -+#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001) -+ -+/**************************************************************************** -+* Toolbox Memory Move request -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ MPI2_SGE_SIMPLE_UNION SGL; /*0x0C */ -+} MPI2_TOOLBOX_MEM_MOVE_REQUEST, *PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST, -+ Mpi2ToolboxMemMoveRequest_t, *pMpi2ToolboxMemMoveRequest_t; -+ -+/**************************************************************************** -+* Toolbox Diagnostic Data Upload request -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U8 SGLFlags; /*0x0C */ -+ U8 Reserved5; /*0x0D */ -+ U16 Reserved6; /*0x0E */ -+ U32 Flags; /*0x10 */ -+ U32 DataLength; /*0x14 */ -+ MPI2_SGE_SIMPLE_UNION SGL; /*0x18 */ -+} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -+ *PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -+ Mpi2ToolboxDiagDataUploadRequest_t, -+ *pMpi2ToolboxDiagDataUploadRequest_t; -+ -+/*use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER { -+ U32 DiagDataLength; /*00h */ -+ U8 FormatCode; /*04h */ -+ U8 Reserved1; /*05h */ -+ U16 Reserved2; /*06h */ -+} MPI2_DIAG_DATA_UPLOAD_HEADER, *PTR_MPI2_DIAG_DATA_UPLOAD_HEADER, -+ Mpi2DiagDataUploadHeader_t, *pMpi2DiagDataUploadHeader_t; -+ -+/**************************************************************************** -+* Toolbox ISTWI Read Write Tool -+****************************************************************************/ -+ -+/*Toolbox ISTWI Read Write Tool request message */ -+typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 Reserved6; /*0x10 */ -+ U8 DevIndex; /*0x14 */ -+ U8 Action; /*0x15 */ -+ U8 SGLFlags; /*0x16 */ -+ U8 Flags; /*0x17 */ -+ U16 TxDataLength; /*0x18 */ -+ U16 RxDataLength; /*0x1A */ -+ U32 Reserved8; /*0x1C */ -+ U32 Reserved9; /*0x20 */ -+ U32 Reserved10; /*0x24 */ -+ U32 Reserved11; /*0x28 */ -+ U32 Reserved12; /*0x2C */ -+ MPI2_SGE_SIMPLE_UNION SGL; /*0x30 */ -+} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, -+ *PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, -+ Mpi2ToolboxIstwiReadWriteRequest_t, -+ *pMpi2ToolboxIstwiReadWriteRequest_t; -+ -+/*values for the Action field */ -+#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01) -+#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02) -+#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03) -+#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10) -+#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) -+#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) -+ -+/*use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+/*values for the Flags field */ -+#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80) -+#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07) -+ -+/*Toolbox ISTWI Read Write Tool reply message */ -+typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U8 DevIndex; /*0x14 */ -+ U8 Action; /*0x15 */ -+ U8 IstwiStatus; /*0x16 */ -+ U8 Reserved6; /*0x17 */ -+ U16 TxDataCount; /*0x18 */ -+ U16 RxDataCount; /*0x1A */ -+} MPI2_TOOLBOX_ISTWI_REPLY, *PTR_MPI2_TOOLBOX_ISTWI_REPLY, -+ Mpi2ToolboxIstwiReply_t, *pMpi2ToolboxIstwiReply_t; -+ -+/**************************************************************************** -+* Toolbox Beacon Tool request -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_BEACON_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U8 Reserved5; /*0x0C */ -+ U8 PhysicalPort; /*0x0D */ -+ U8 Reserved6; /*0x0E */ -+ U8 Flags; /*0x0F */ -+} MPI2_TOOLBOX_BEACON_REQUEST, *PTR_MPI2_TOOLBOX_BEACON_REQUEST, -+ Mpi2ToolboxBeaconRequest_t, *pMpi2ToolboxBeaconRequest_t; -+ -+/*values for the Flags field */ -+#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00) -+#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01) -+ -+/**************************************************************************** -+* Toolbox Diagnostic CLI Tool -+****************************************************************************/ -+ -+#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C) -+ -+/*MPI v2.0 Toolbox Diagnostic CLI Tool request message */ -+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U8 SGLFlags; /*0x0C */ -+ U8 Reserved5; /*0x0D */ -+ U16 Reserved6; /*0x0E */ -+ U32 DataLength; /*0x10 */ -+ U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];/*0x14 */ -+ MPI2_MPI_SGE_IO_UNION SGL; /*0x70 */ -+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, -+ *PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, -+ Mpi2ToolboxDiagnosticCliRequest_t, -+ *pMpi2ToolboxDiagnosticCliRequest_t; -+ -+/*use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+/*MPI v2.5 Toolbox Diagnostic CLI Tool request message */ -+typedef struct _MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 DataLength; /*0x10 */ -+ U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];/*0x14 */ -+ MPI25_SGE_IO_UNION SGL; /* 0x70 */ -+} MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, -+ *PTR_MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, -+ Mpi25ToolboxDiagnosticCliRequest_t, -+ *pMpi25ToolboxDiagnosticCliRequest_t; -+ -+/*Toolbox Diagnostic CLI Tool reply message */ -+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 ReturnedDataLength; /*0x14 */ -+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, -+ *PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, -+ Mpi2ToolboxDiagnosticCliReply_t, -+ *pMpi2ToolboxDiagnosticCliReply_t; -+ -+ -+/**************************************************************************** -+* Toolbox Console Text Display Tool -+****************************************************************************/ -+ -+/* Toolbox Console Text Display Tool request message */ -+typedef struct _MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST { -+ U8 Tool; /* 0x00 */ -+ U8 Reserved1; /* 0x01 */ -+ U8 ChainOffset; /* 0x02 */ -+ U8 Function; /* 0x03 */ -+ U16 Reserved2; /* 0x04 */ -+ U8 Reserved3; /* 0x06 */ -+ U8 MsgFlags; /* 0x07 */ -+ U8 VP_ID; /* 0x08 */ -+ U8 VF_ID; /* 0x09 */ -+ U16 Reserved4; /* 0x0A */ -+ U8 Console; /* 0x0C */ -+ U8 Flags; /* 0x0D */ -+ U16 Reserved6; /* 0x0E */ -+ U8 TextToDisplay[4]; /* 0x10 */ -+} MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, -+*PTR_MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, -+Mpi2ToolboxTextDisplayRequest_t, -+*pMpi2ToolboxTextDisplayRequest_t; -+ -+/* defines for the Console field */ -+#define MPI2_TOOLBOX_CONSOLE_TYPE_MASK (0xF0) -+#define MPI2_TOOLBOX_CONSOLE_TYPE_DEFAULT (0x00) -+#define MPI2_TOOLBOX_CONSOLE_TYPE_UART (0x10) -+#define MPI2_TOOLBOX_CONSOLE_TYPE_ETHERNET (0x20) -+ -+#define MPI2_TOOLBOX_CONSOLE_NUMBER_MASK (0x0F) -+ -+/* defines for the Flags field */ -+#define MPI2_TOOLBOX_CONSOLE_FLAG_TIMESTAMP (0x01) -+ -+ -+ -+/***************************************************************************** -+* -+* Diagnostic Buffer Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* Diagnostic Buffer Post request -+****************************************************************************/ -+ -+typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST { -+ U8 ExtendedType; /*0x00 */ -+ U8 BufferType; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U64 BufferAddress; /*0x0C */ -+ U32 BufferLength; /*0x14 */ -+ U32 Reserved5; /*0x18 */ -+ U32 Reserved6; /*0x1C */ -+ U32 Flags; /*0x20 */ -+ U32 ProductSpecific[23]; /*0x24 */ -+} MPI2_DIAG_BUFFER_POST_REQUEST, *PTR_MPI2_DIAG_BUFFER_POST_REQUEST, -+ Mpi2DiagBufferPostRequest_t, *pMpi2DiagBufferPostRequest_t; -+ -+/*values for the ExtendedType field */ -+#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) -+ -+/*values for the BufferType field */ -+#define MPI2_DIAG_BUF_TYPE_TRACE (0x00) -+#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) -+#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) -+/*count of the number of buffer types */ -+#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) -+ -+/*values for the Flags field */ -+#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002) -+#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001) -+ -+/**************************************************************************** -+* Diagnostic Buffer Post reply -+****************************************************************************/ -+ -+typedef struct _MPI2_DIAG_BUFFER_POST_REPLY { -+ U8 ExtendedType; /*0x00 */ -+ U8 BufferType; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 TransferLength; /*0x14 */ -+} MPI2_DIAG_BUFFER_POST_REPLY, *PTR_MPI2_DIAG_BUFFER_POST_REPLY, -+ Mpi2DiagBufferPostReply_t, *pMpi2DiagBufferPostReply_t; -+ -+/**************************************************************************** -+* Diagnostic Release request -+****************************************************************************/ -+ -+typedef struct _MPI2_DIAG_RELEASE_REQUEST { -+ U8 Reserved1; /*0x00 */ -+ U8 BufferType; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+} MPI2_DIAG_RELEASE_REQUEST, *PTR_MPI2_DIAG_RELEASE_REQUEST, -+ Mpi2DiagReleaseRequest_t, *pMpi2DiagReleaseRequest_t; -+ -+/**************************************************************************** -+* Diagnostic Buffer Post reply -+****************************************************************************/ -+ -+typedef struct _MPI2_DIAG_RELEASE_REPLY { -+ U8 Reserved1; /*0x00 */ -+ U8 BufferType; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_DIAG_RELEASE_REPLY, *PTR_MPI2_DIAG_RELEASE_REPLY, -+ Mpi2DiagReleaseReply_t, *pMpi2DiagReleaseReply_t; -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h -new file mode 100644 -index 0000000..92a81ab ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_type.h -@@ -0,0 +1,57 @@ -+/* -+ * Copyright 2000-2014 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_type.h -+ * Title: MPI basic type definitions -+ * Creation Date: August 16, 2006 -+ * -+ * mpi2_type.h Version: 02.00.01 -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 11-18-14 02.00.01 Updated copyright information. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_TYPE_H -+#define MPI2_TYPE_H -+ -+/******************************************************************************* -+ * Define * if it hasn't already been defined. By default -+ * * is defined to be a near pointer. MPI2_POINTER can be defined as -+ * a far pointer by defining * as "far *" before this header file is -+ * included. -+ */ -+ -+/* the basic types may have already been included by mpi_type.h */ -+#ifndef MPI_TYPE_H -+/***************************************************************************** -+* -+* Basic Types -+* -+*****************************************************************************/ -+ -+typedef u8 U8; -+typedef __le16 U16; -+typedef __le32 U32; -+typedef __le64 U64 __attribute__ ((aligned(4))); -+ -+/***************************************************************************** -+* -+* Pointer Types -+* -+*****************************************************************************/ -+ -+typedef U8 *PU8; -+typedef U16 *PU16; -+typedef U32 *PU32; -+typedef U64 *PU64; -+ -+#endif -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpt3sas_base.c b/drivers/scsi/mpt2sas/mpt3sas_base.c -new file mode 100644 -index 0000000..224bf9d ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_base.c -@@ -0,0 +1,5713 @@ -+/* -+ * This is the Fusion MPT base driver providing common API layer interface -+ * for access to MPT (Message Passing Technology) firmware. -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#include "mpt3sas_base.h" -+ -+static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; -+ -+ -+#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ -+ -+ /* maximum controller queue depth */ -+#define MAX_HBA_QUEUE_DEPTH 30000 -+#define MAX_CHAIN_DEPTH 100000 -+static int max_queue_depth = -1; -+module_param(max_queue_depth, int, 0); -+MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); -+ -+static int max_sgl_entries = -1; -+module_param(max_sgl_entries, int, 0); -+MODULE_PARM_DESC(max_sgl_entries, " max sg entries "); -+ -+static int msix_disable = -1; -+module_param(msix_disable, int, 0); -+MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); -+ -+static int smp_affinity_enable = 1; -+module_param(smp_affinity_enable, int, S_IRUGO); -+MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)"); -+ -+static int max_msix_vectors = -1; -+module_param(max_msix_vectors, int, 0); -+MODULE_PARM_DESC(max_msix_vectors, -+ " max msix vectors"); -+ -+static int mpt2sas_fwfault_debug; -+MODULE_PARM_DESC(mpt2sas_fwfault_debug, -+ " enable detection of firmware fault and halt firmware - (default=0)"); -+ -+static int -+_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag); -+ -+/** -+ * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. -+ * -+ */ -+static int -+_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) -+{ -+ int ret = param_set_int(val, kp); -+ struct MPT3SAS_ADAPTER *ioc; -+ -+ if (ret) -+ return ret; -+ -+ /* global ioc spinlock to protect controller list on list operations */ -+ pr_info("setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); -+ spin_lock(&gioc_lock_mpt2sas); -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) -+ ioc->fwfault_debug = mpt2sas_fwfault_debug; -+ spin_unlock(&gioc_lock_mpt2sas); -+ return 0; -+} -+module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, -+ param_get_int, &mpt2sas_fwfault_debug, 0644); -+ -+/** -+ * mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc -+ * @arg: input argument, used to derive ioc -+ * -+ * Return 0 if controller is removed from pci subsystem. -+ * Return -1 for other case. -+ */ -+static int mpt2sas_remove_dead_ioc_func(void *arg) -+{ -+ struct MPT3SAS_ADAPTER *ioc = (struct MPT3SAS_ADAPTER *)arg; -+ struct pci_dev *pdev; -+ -+ if ((ioc == NULL)) -+ return -1; -+ -+ pdev = ioc->pdev; -+ if ((pdev == NULL)) -+ return -1; -+ pci_stop_and_remove_bus_device_locked(pdev); -+ return 0; -+} -+ -+/** -+ * _base_fault_reset_work - workq handling ioc fault conditions -+ * @work: input argument, used to derive ioc -+ * Context: sleep. -+ * -+ * Return nothing. -+ */ -+static void -+_base_fault_reset_work(struct work_struct *work) -+{ -+ struct MPT3SAS_ADAPTER *ioc = -+ container_of(work, struct MPT3SAS_ADAPTER, fault_reset_work.work); -+ unsigned long flags; -+ u32 doorbell; -+ int rc; -+ struct task_struct *p; -+ -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ if (ioc->shost_recovery || ioc->pci_error_recovery) -+ goto rearm_timer; -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+ -+ doorbell = mpt2sas_base_get_iocstate(ioc, 0); -+ if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) { -+ pr_err(MPT3SAS_FMT "SAS host is non-operational !!!!\n", -+ ioc->name); -+ -+ /* It may be possible that EEH recovery can resolve some of -+ * pci bus failure issues rather removing the dead ioc function -+ * by considering controller is in a non-operational state. So -+ * here priority is given to the EEH recovery. If it doesn't -+ * not resolve this issue, mpt3sas driver will consider this -+ * controller to non-operational state and remove the dead ioc -+ * function. -+ */ -+ if (ioc->non_operational_loop++ < 5) { -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, -+ flags); -+ goto rearm_timer; -+ } -+ -+ /* -+ * Call _scsih_flush_pending_cmds callback so that we flush all -+ * pending commands back to OS. This call is required to aovid -+ * deadlock at block layer. Dead IOC will fail to do diag reset, -+ * and this call is safe since dead ioc will never return any -+ * command back from HW. -+ */ -+ ioc->schedule_dead_ioc_flush_running_cmds(ioc); -+ /* -+ * Set remove_host flag early since kernel thread will -+ * take some time to execute. -+ */ -+ ioc->remove_host = 1; -+ /*Remove the Dead Host */ -+ p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc, -+ "%s_dead_ioc_%d", ioc->driver_name, ioc->id); -+ if (IS_ERR(p)) -+ pr_err(MPT3SAS_FMT -+ "%s: Running mpt2sas_dead_ioc thread failed !!!!\n", -+ ioc->name, __func__); -+ else -+ pr_err(MPT3SAS_FMT -+ "%s: Running mpt2sas_dead_ioc thread success !!!!\n", -+ ioc->name, __func__); -+ return; /* don't rearm timer */ -+ } -+ -+ ioc->non_operational_loop = 0; -+ -+ if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) { -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ pr_warn(MPT3SAS_FMT "%s: hard reset: %s\n", ioc->name, -+ __func__, (rc == 0) ? "success" : "failed"); -+ doorbell = mpt2sas_base_get_iocstate(ioc, 0); -+ if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) -+ mpt2sas_base_fault_info(ioc, doorbell & -+ MPI2_DOORBELL_DATA_MASK); -+ if (rc && (doorbell & MPI2_IOC_STATE_MASK) != -+ MPI2_IOC_STATE_OPERATIONAL) -+ return; /* don't rearm timer */ -+ } -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ rearm_timer: -+ if (ioc->fault_reset_work_q) -+ queue_delayed_work(ioc->fault_reset_work_q, -+ &ioc->fault_reset_work, -+ msecs_to_jiffies(FAULT_POLLING_INTERVAL)); -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+} -+ -+/** -+ * mpt2sas_base_start_watchdog - start the fault_reset_work_q -+ * @ioc: per adapter object -+ * Context: sleep. -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) -+{ -+ unsigned long flags; -+ -+ if (ioc->fault_reset_work_q) -+ return; -+ -+ /* initialize fault polling */ -+ -+ INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); -+ snprintf(ioc->fault_reset_work_q_name, -+ sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", -+ ioc->driver_name, ioc->id); -+ ioc->fault_reset_work_q = -+ create_singlethread_workqueue(ioc->fault_reset_work_q_name); -+ if (!ioc->fault_reset_work_q) { -+ pr_err(MPT3SAS_FMT "%s: failed (line=%d)\n", -+ ioc->name, __func__, __LINE__); -+ return; -+ } -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ if (ioc->fault_reset_work_q) -+ queue_delayed_work(ioc->fault_reset_work_q, -+ &ioc->fault_reset_work, -+ msecs_to_jiffies(FAULT_POLLING_INTERVAL)); -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+} -+ -+/** -+ * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q -+ * @ioc: per adapter object -+ * Context: sleep. -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc) -+{ -+ unsigned long flags; -+ struct workqueue_struct *wq; -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ wq = ioc->fault_reset_work_q; -+ ioc->fault_reset_work_q = NULL; -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+ if (wq) { -+ if (!cancel_delayed_work_sync(&ioc->fault_reset_work)) -+ flush_workqueue(wq); -+ destroy_workqueue(wq); -+ } -+} -+ -+/** -+ * mpt2sas_base_fault_info - verbose translation of firmware FAULT code -+ * @ioc: per adapter object -+ * @fault_code: fault code -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code) -+{ -+ pr_err(MPT3SAS_FMT "fault_state(0x%04x)!\n", -+ ioc->name, fault_code); -+} -+ -+/** -+ * mpt2sas_halt_firmware - halt's mpt controller firmware -+ * @ioc: per adapter object -+ * -+ * For debugging timeout related issues. Writing 0xCOFFEE00 -+ * to the doorbell register will halt controller firmware. With -+ * the purpose to stop both driver and firmware, the enduser can -+ * obtain a ring buffer from controller UART. -+ */ -+void -+mpt2sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u32 doorbell; -+ -+ if (!ioc->fwfault_debug) -+ return; -+ -+ dump_stack(); -+ -+ doorbell = readl(&ioc->chip->Doorbell); -+ if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) -+ mpt2sas_base_fault_info(ioc , doorbell); -+ else { -+ writel(0xC0FFEE00, &ioc->chip->Doorbell); -+ pr_err(MPT3SAS_FMT "Firmware is halted due to command timeout\n", -+ ioc->name); -+ } -+ -+ if (ioc->fwfault_debug == 2) -+ for (;;) -+ ; -+ else -+ panic("panic in %s\n", __func__); -+} -+ -+/** -+ * _base_sas_ioc_info - verbose translation of the ioc status -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @request_hdr: request mf -+ * -+ * Return nothing. -+ */ -+static void -+_base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, -+ MPI2RequestHeader_t *request_hdr) -+{ -+ u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ char *desc = NULL; -+ u16 frame_sz; -+ char *func_str = NULL; -+ -+ /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */ -+ if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || -+ request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) -+ return; -+ -+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) -+ return; -+ -+ switch (ioc_status) { -+ -+/**************************************************************************** -+* Common IOCStatus values for all replies -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_INVALID_FUNCTION: -+ desc = "invalid function"; -+ break; -+ case MPI2_IOCSTATUS_BUSY: -+ desc = "busy"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_SGL: -+ desc = "invalid sgl"; -+ break; -+ case MPI2_IOCSTATUS_INTERNAL_ERROR: -+ desc = "internal error"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_VPID: -+ desc = "invalid vpid"; -+ break; -+ case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: -+ desc = "insufficient resources"; -+ break; -+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER: -+ desc = "insufficient power"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_FIELD: -+ desc = "invalid field"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_STATE: -+ desc = "invalid state"; -+ break; -+ case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: -+ desc = "op state not supported"; -+ break; -+ -+/**************************************************************************** -+* Config IOCStatus values -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION: -+ desc = "config invalid action"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE: -+ desc = "config invalid type"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE: -+ desc = "config invalid page"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_INVALID_DATA: -+ desc = "config invalid data"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS: -+ desc = "config no defaults"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT: -+ desc = "config cant commit"; -+ break; -+ -+/**************************************************************************** -+* SCSI IO Reply -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: -+ case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: -+ case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: -+ case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: -+ case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: -+ case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: -+ case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: -+ case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: -+ case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: -+ case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: -+ case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: -+ case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: -+ break; -+ -+/**************************************************************************** -+* For use by SCSI Initiator and SCSI Target end-to-end data protection -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: -+ desc = "eedp guard error"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: -+ desc = "eedp ref tag error"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: -+ desc = "eedp app tag error"; -+ break; -+ -+/**************************************************************************** -+* SCSI Target values -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX: -+ desc = "target invalid io index"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_ABORTED: -+ desc = "target aborted"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: -+ desc = "target no conn retryable"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_NO_CONNECTION: -+ desc = "target no connection"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: -+ desc = "target xfer count mismatch"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: -+ desc = "target data offset error"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: -+ desc = "target too much write data"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT: -+ desc = "target iu too short"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: -+ desc = "target ack nak timeout"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED: -+ desc = "target nak received"; -+ break; -+ -+/**************************************************************************** -+* Serial Attached SCSI values -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED: -+ desc = "smp request failed"; -+ break; -+ case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN: -+ desc = "smp data overrun"; -+ break; -+ -+/**************************************************************************** -+* Diagnostic Buffer Post / Diagnostic Release values -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED: -+ desc = "diagnostic released"; -+ break; -+ default: -+ break; -+ } -+ -+ if (!desc) -+ return; -+ -+ switch (request_hdr->Function) { -+ case MPI2_FUNCTION_CONFIG: -+ frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size; -+ func_str = "config_page"; -+ break; -+ case MPI2_FUNCTION_SCSI_TASK_MGMT: -+ frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t); -+ func_str = "task_mgmt"; -+ break; -+ case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: -+ frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t); -+ func_str = "sas_iounit_ctl"; -+ break; -+ case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: -+ frame_sz = sizeof(Mpi2SepRequest_t); -+ func_str = "enclosure"; -+ break; -+ case MPI2_FUNCTION_IOC_INIT: -+ frame_sz = sizeof(Mpi2IOCInitRequest_t); -+ func_str = "ioc_init"; -+ break; -+ case MPI2_FUNCTION_PORT_ENABLE: -+ frame_sz = sizeof(Mpi2PortEnableRequest_t); -+ func_str = "port_enable"; -+ break; -+ case MPI2_FUNCTION_SMP_PASSTHROUGH: -+ frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size; -+ func_str = "smp_passthru"; -+ break; -+ default: -+ frame_sz = 32; -+ func_str = "unknown"; -+ break; -+ } -+ -+ pr_warn(MPT3SAS_FMT "ioc_status: %s(0x%04x), request(0x%p),(%s)\n", -+ ioc->name, desc, ioc_status, request_hdr, func_str); -+ -+ _debug_dump_mf(request_hdr, frame_sz/4); -+} -+ -+/** -+ * _base_display_event_data - verbose translation of firmware asyn events -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * -+ * Return nothing. -+ */ -+static void -+_base_display_event_data(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventNotificationReply_t *mpi_reply) -+{ -+ char *desc = NULL; -+ u16 event; -+ -+ if (!(ioc->logging_level & MPT_DEBUG_EVENTS)) -+ return; -+ -+ event = le16_to_cpu(mpi_reply->Event); -+ -+ switch (event) { -+ case MPI2_EVENT_LOG_DATA: -+ desc = "Log Data"; -+ break; -+ case MPI2_EVENT_STATE_CHANGE: -+ desc = "Status Change"; -+ break; -+ case MPI2_EVENT_HARD_RESET_RECEIVED: -+ desc = "Hard Reset Received"; -+ break; -+ case MPI2_EVENT_EVENT_CHANGE: -+ desc = "Event Change"; -+ break; -+ case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: -+ desc = "Device Status Change"; -+ break; -+ case MPI2_EVENT_IR_OPERATION_STATUS: -+ if (!ioc->hide_ir_msg) -+ desc = "IR Operation Status"; -+ break; -+ case MPI2_EVENT_SAS_DISCOVERY: -+ { -+ Mpi2EventDataSasDiscovery_t *event_data = -+ (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; -+ pr_info(MPT3SAS_FMT "Discovery: (%s)", ioc->name, -+ (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? -+ "start" : "stop"); -+ if (event_data->DiscoveryStatus) -+ pr_info("discovery_status(0x%08x)", -+ le32_to_cpu(event_data->DiscoveryStatus)); -+ pr_info("\n"); -+ return; -+ } -+ case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: -+ desc = "SAS Broadcast Primitive"; -+ break; -+ case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: -+ desc = "SAS Init Device Status Change"; -+ break; -+ case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW: -+ desc = "SAS Init Table Overflow"; -+ break; -+ case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: -+ desc = "SAS Topology Change List"; -+ break; -+ case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: -+ desc = "SAS Enclosure Device Status Change"; -+ break; -+ case MPI2_EVENT_IR_VOLUME: -+ if (!ioc->hide_ir_msg) -+ desc = "IR Volume"; -+ break; -+ case MPI2_EVENT_IR_PHYSICAL_DISK: -+ if (!ioc->hide_ir_msg) -+ desc = "IR Physical Disk"; -+ break; -+ case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: -+ if (!ioc->hide_ir_msg) -+ desc = "IR Configuration Change List"; -+ break; -+ case MPI2_EVENT_LOG_ENTRY_ADDED: -+ if (!ioc->hide_ir_msg) -+ desc = "Log Entry Added"; -+ break; -+ case MPI2_EVENT_TEMP_THRESHOLD: -+ desc = "Temperature Threshold"; -+ break; -+ case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION: -+ desc = "Active cable exception"; -+ break; -+ } -+ -+ if (!desc) -+ return; -+ -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc); -+} -+ -+/** -+ * _base_sas_log_info - verbose translation of firmware log info -+ * @ioc: per adapter object -+ * @log_info: log info -+ * -+ * Return nothing. -+ */ -+static void -+_base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info) -+{ -+ union loginfo_type { -+ u32 loginfo; -+ struct { -+ u32 subcode:16; -+ u32 code:8; -+ u32 originator:4; -+ u32 bus_type:4; -+ } dw; -+ }; -+ union loginfo_type sas_loginfo; -+ char *originator_str = NULL; -+ -+ sas_loginfo.loginfo = log_info; -+ if (sas_loginfo.dw.bus_type != 3 /*SAS*/) -+ return; -+ -+ /* each nexus loss loginfo */ -+ if (log_info == 0x31170000) -+ return; -+ -+ /* eat the loginfos associated with task aborts */ -+ if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info == -+ 0x31140000 || log_info == 0x31130000)) -+ return; -+ -+ switch (sas_loginfo.dw.originator) { -+ case 0: -+ originator_str = "IOP"; -+ break; -+ case 1: -+ originator_str = "PL"; -+ break; -+ case 2: -+ if (!ioc->hide_ir_msg) -+ originator_str = "IR"; -+ else -+ originator_str = "WarpDrive"; -+ break; -+ } -+ -+ pr_warn(MPT3SAS_FMT -+ "log_info(0x%08x): originator(%s), code(0x%02x), sub_code(0x%04x)\n", -+ ioc->name, log_info, -+ originator_str, sas_loginfo.dw.code, -+ sas_loginfo.dw.subcode); -+} -+ -+/** -+ * _base_display_reply_info - -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Return nothing. -+ */ -+static void -+_base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ u16 ioc_status; -+ u32 loginfo = 0; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (unlikely(!mpi_reply)) { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -+ -+ if ((ioc_status & MPI2_IOCSTATUS_MASK) && -+ (ioc->logging_level & MPT_DEBUG_REPLY)) { -+ _base_sas_ioc_info(ioc , mpi_reply, -+ mpt2sas_base_get_msg_frame(ioc, smid)); -+ } -+ -+ if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { -+ loginfo = le32_to_cpu(mpi_reply->IOCLogInfo); -+ _base_sas_log_info(ioc, loginfo); -+ } -+ -+ if (ioc_status || loginfo) { -+ ioc_status &= MPI2_IOCSTATUS_MASK; -+ mpt2sas_trigger_mpi(ioc, ioc_status, loginfo); -+ } -+} -+ -+/** -+ * mpt2sas_base_done - base internal command completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) -+ return mpt2sas_check_for_pending_internal_cmds(ioc, smid); -+ -+ if (ioc->base_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ -+ ioc->base_cmds.status |= MPT3_CMD_COMPLETE; -+ if (mpi_reply) { -+ ioc->base_cmds.status |= MPT3_CMD_REPLY_VALID; -+ memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); -+ } -+ ioc->base_cmds.status &= ~MPT3_CMD_PENDING; -+ -+ complete(&ioc->base_cmds.done); -+ return 1; -+} -+ -+/** -+ * _base_async_event - main callback handler for firmware asyn events -+ * @ioc: per adapter object -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) -+{ -+ Mpi2EventNotificationReply_t *mpi_reply; -+ Mpi2EventAckRequest_t *ack_request; -+ u16 smid; -+ struct _event_ack_list *delayed_event_ack; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (!mpi_reply) -+ return 1; -+ if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) -+ return 1; -+ -+ _base_display_event_data(ioc, mpi_reply); -+ -+ if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) -+ goto out; -+ smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); -+ if (!smid) { -+ delayed_event_ack = kzalloc(sizeof(*delayed_event_ack), -+ GFP_ATOMIC); -+ if (!delayed_event_ack) -+ goto out; -+ INIT_LIST_HEAD(&delayed_event_ack->list); -+ delayed_event_ack->Event = mpi_reply->Event; -+ delayed_event_ack->EventContext = mpi_reply->EventContext; -+ list_add_tail(&delayed_event_ack->list, -+ &ioc->delayed_event_ack_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED: EVENT ACK: event (0x%04x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->Event))); -+ goto out; -+ } -+ -+ ack_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); -+ ack_request->Function = MPI2_FUNCTION_EVENT_ACK; -+ ack_request->Event = mpi_reply->Event; -+ ack_request->EventContext = mpi_reply->EventContext; -+ ack_request->VF_ID = 0; /* TODO */ -+ ack_request->VP_ID = 0; -+ mpt2sas_base_put_smid_default(ioc, smid); -+ -+ out: -+ -+ /* scsih callback handler */ -+ mpt2sas_scsih_event_callback(ioc, msix_index, reply); -+ -+ /* ctl callback handler */ -+ mpt2sas_ctl_event_callback(ioc, msix_index, reply); -+ -+ return 1; -+} -+ -+/** -+ * _base_get_cb_idx - obtain the callback index -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Return callback index. -+ */ -+static u8 -+_base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ int i; -+ u8 cb_idx; -+ -+ if (smid < ioc->hi_priority_smid) { -+ i = smid - 1; -+ cb_idx = ioc->scsi_lookup[i].cb_idx; -+ } else if (smid < ioc->internal_smid) { -+ i = smid - ioc->hi_priority_smid; -+ cb_idx = ioc->hpr_lookup[i].cb_idx; -+ } else if (smid <= ioc->hba_queue_depth) { -+ i = smid - ioc->internal_smid; -+ cb_idx = ioc->internal_lookup[i].cb_idx; -+ } else -+ cb_idx = 0xFF; -+ return cb_idx; -+} -+ -+/** -+ * _base_mask_interrupts - disable interrupts -+ * @ioc: per adapter object -+ * -+ * Disabling ResetIRQ, Reply and Doorbell Interrupts -+ * -+ * Return nothing. -+ */ -+static void -+_base_mask_interrupts(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u32 him_register; -+ -+ ioc->mask_interrupts = 1; -+ him_register = readl(&ioc->chip->HostInterruptMask); -+ him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK; -+ writel(him_register, &ioc->chip->HostInterruptMask); -+ readl(&ioc->chip->HostInterruptMask); -+} -+ -+/** -+ * _base_unmask_interrupts - enable interrupts -+ * @ioc: per adapter object -+ * -+ * Enabling only Reply Interrupts -+ * -+ * Return nothing. -+ */ -+static void -+_base_unmask_interrupts(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u32 him_register; -+ -+ him_register = readl(&ioc->chip->HostInterruptMask); -+ him_register &= ~MPI2_HIM_RIM; -+ writel(him_register, &ioc->chip->HostInterruptMask); -+ ioc->mask_interrupts = 0; -+} -+ -+union reply_descriptor { -+ u64 word; -+ struct { -+ u32 low; -+ u32 high; -+ } u; -+}; -+ -+/** -+ * _base_interrupt - MPT adapter (IOC) specific interrupt handler. -+ * @irq: irq number (not used) -+ * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure -+ * @r: pt_regs pointer (not used) -+ * -+ * Return IRQ_HANDLE if processed, else IRQ_NONE. -+ */ -+static irqreturn_t -+_base_interrupt(int irq, void *bus_id) -+{ -+ struct adapter_reply_queue *reply_q = bus_id; -+ union reply_descriptor rd; -+ u32 completed_cmds; -+ u8 request_desript_type; -+ u16 smid; -+ u8 cb_idx; -+ u32 reply; -+ u8 msix_index = reply_q->msix_index; -+ struct MPT3SAS_ADAPTER *ioc = reply_q->ioc; -+ Mpi2ReplyDescriptorsUnion_t *rpf; -+ u8 rc; -+ -+ if (ioc->mask_interrupts) -+ return IRQ_NONE; -+ -+ if (!atomic_add_unless(&reply_q->busy, 1, 1)) -+ return IRQ_NONE; -+ -+ rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index]; -+ request_desript_type = rpf->Default.ReplyFlags -+ & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; -+ if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { -+ atomic_dec(&reply_q->busy); -+ return IRQ_NONE; -+ } -+ -+ completed_cmds = 0; -+ cb_idx = 0xFF; -+ do { -+ rd.word = le64_to_cpu(rpf->Words); -+ if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) -+ goto out; -+ reply = 0; -+ smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); -+ if (request_desript_type == -+ MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS || -+ request_desript_type == -+ MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { -+ cb_idx = _base_get_cb_idx(ioc, smid); -+ if ((likely(cb_idx < MPT_MAX_CALLBACKS)) && -+ (likely(mpt_callbacks[cb_idx] != NULL))) { -+ rc = mpt_callbacks[cb_idx](ioc, smid, -+ msix_index, 0); -+ if (rc) -+ mpt2sas_base_free_smid(ioc, smid); -+ } -+ } else if (request_desript_type == -+ MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { -+ reply = le32_to_cpu( -+ rpf->AddressReply.ReplyFrameAddress); -+ if (reply > ioc->reply_dma_max_address || -+ reply < ioc->reply_dma_min_address) -+ reply = 0; -+ if (smid) { -+ cb_idx = _base_get_cb_idx(ioc, smid); -+ if ((likely(cb_idx < MPT_MAX_CALLBACKS)) && -+ (likely(mpt_callbacks[cb_idx] != NULL))) { -+ rc = mpt_callbacks[cb_idx](ioc, smid, -+ msix_index, reply); -+ if (reply) -+ _base_display_reply_info(ioc, -+ smid, msix_index, reply); -+ if (rc) -+ mpt2sas_base_free_smid(ioc, -+ smid); -+ } -+ } else { -+ _base_async_event(ioc, msix_index, reply); -+ } -+ -+ /* reply free queue handling */ -+ if (reply) { -+ ioc->reply_free_host_index = -+ (ioc->reply_free_host_index == -+ (ioc->reply_free_queue_depth - 1)) ? -+ 0 : ioc->reply_free_host_index + 1; -+ ioc->reply_free[ioc->reply_free_host_index] = -+ cpu_to_le32(reply); -+ wmb(); -+ writel(ioc->reply_free_host_index, -+ &ioc->chip->ReplyFreeHostIndex); -+ } -+ } -+ -+ rpf->Words = cpu_to_le64(ULLONG_MAX); -+ reply_q->reply_post_host_index = -+ (reply_q->reply_post_host_index == -+ (ioc->reply_post_queue_depth - 1)) ? 0 : -+ reply_q->reply_post_host_index + 1; -+ request_desript_type = -+ reply_q->reply_post_free[reply_q->reply_post_host_index]. -+ Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; -+ completed_cmds++; -+ if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) -+ goto out; -+ if (!reply_q->reply_post_host_index) -+ rpf = reply_q->reply_post_free; -+ else -+ rpf++; -+ } while (1); -+ -+ out: -+ -+ if (!completed_cmds) { -+ atomic_dec(&reply_q->busy); -+ return IRQ_NONE; -+ } -+ -+ wmb(); -+ if (ioc->is_warpdrive) { -+ writel(reply_q->reply_post_host_index, -+ ioc->reply_post_host_index[msix_index]); -+ atomic_dec(&reply_q->busy); -+ return IRQ_HANDLED; -+ } -+ -+ /* Update Reply Post Host Index. -+ * For those HBA's which support combined reply queue feature -+ * 1. Get the correct Supplemental Reply Post Host Index Register. -+ * i.e. (msix_index / 8)th entry from Supplemental Reply Post Host -+ * Index Register address bank i.e replyPostRegisterIndex[], -+ * 2. Then update this register with new reply host index value -+ * in ReplyPostIndex field and the MSIxIndex field with -+ * msix_index value reduced to a value between 0 and 7, -+ * using a modulo 8 operation. Since each Supplemental Reply Post -+ * Host Index Register supports 8 MSI-X vectors. -+ * -+ * For other HBA's just update the Reply Post Host Index register with -+ * new reply host index value in ReplyPostIndex Field and msix_index -+ * value in MSIxIndex field. -+ */ -+ if (ioc->msix96_vector) -+ writel(reply_q->reply_post_host_index | ((msix_index & 7) << -+ MPI2_RPHI_MSIX_INDEX_SHIFT), -+ ioc->replyPostRegisterIndex[msix_index/8]); -+ else -+ writel(reply_q->reply_post_host_index | (msix_index << -+ MPI2_RPHI_MSIX_INDEX_SHIFT), -+ &ioc->chip->ReplyPostHostIndex); -+ atomic_dec(&reply_q->busy); -+ return IRQ_HANDLED; -+} -+ -+/** -+ * _base_is_controller_msix_enabled - is controller support muli-reply queues -+ * @ioc: per adapter object -+ * -+ */ -+static inline int -+_base_is_controller_msix_enabled(struct MPT3SAS_ADAPTER *ioc) -+{ -+ return (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable; -+} -+ -+/** -+ * mpt2sas_base_sync_reply_irqs - flush pending MSIX interrupts -+ * @ioc: per adapter object -+ * Context: non ISR conext -+ * -+ * Called when a Task Management request has completed. -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct adapter_reply_queue *reply_q; -+ -+ /* If MSIX capability is turned off -+ * then multi-queues are not enabled -+ */ -+ if (!_base_is_controller_msix_enabled(ioc)) -+ return; -+ -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery) -+ return; -+ /* TMs are on msix_index == 0 */ -+ if (reply_q->msix_index == 0) -+ continue; -+ synchronize_irq(reply_q->vector); -+ } -+} -+ -+/** -+ * mpt2sas_base_release_callback_handler - clear interrupt callback handler -+ * @cb_idx: callback index -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_release_callback_handler(u8 cb_idx) -+{ -+ mpt_callbacks[cb_idx] = NULL; -+} -+ -+/** -+ * mpt2sas_base_register_callback_handler - obtain index for the interrupt callback handler -+ * @cb_func: callback function -+ * -+ * Returns cb_func. -+ */ -+u8 -+mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func) -+{ -+ u8 cb_idx; -+ -+ for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--) -+ if (mpt_callbacks[cb_idx] == NULL) -+ break; -+ -+ mpt_callbacks[cb_idx] = cb_func; -+ return cb_idx; -+} -+ -+/** -+ * mpt2sas_base_initialize_callback_handler - initialize the interrupt callback handler -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_initialize_callback_handler(void) -+{ -+ u8 cb_idx; -+ -+ for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++) -+ mpt2sas_base_release_callback_handler(cb_idx); -+} -+ -+ -+/** -+ * _base_build_zero_len_sge - build zero length sg entry -+ * @ioc: per adapter object -+ * @paddr: virtual address for SGE -+ * -+ * Create a zero length scatter gather entry to insure the IOCs hardware has -+ * something to use if the target device goes brain dead and tries -+ * to send data even when none is asked for. -+ * -+ * Return nothing. -+ */ -+static void -+_base_build_zero_len_sge(struct MPT3SAS_ADAPTER *ioc, void *paddr) -+{ -+ u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT | -+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST | -+ MPI2_SGE_FLAGS_SIMPLE_ELEMENT) << -+ MPI2_SGE_FLAGS_SHIFT); -+ ioc->base_add_sg_single(paddr, flags_length, -1); -+} -+ -+/** -+ * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr. -+ * @paddr: virtual address for SGE -+ * @flags_length: SGE flags and data transfer length -+ * @dma_addr: Physical address -+ * -+ * Return nothing. -+ */ -+static void -+_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr) -+{ -+ Mpi2SGESimple32_t *sgel = paddr; -+ -+ flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING | -+ MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; -+ sgel->FlagsLength = cpu_to_le32(flags_length); -+ sgel->Address = cpu_to_le32(dma_addr); -+} -+ -+ -+/** -+ * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr. -+ * @paddr: virtual address for SGE -+ * @flags_length: SGE flags and data transfer length -+ * @dma_addr: Physical address -+ * -+ * Return nothing. -+ */ -+static void -+_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr) -+{ -+ Mpi2SGESimple64_t *sgel = paddr; -+ -+ flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING | -+ MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; -+ sgel->FlagsLength = cpu_to_le32(flags_length); -+ sgel->Address = cpu_to_le64(dma_addr); -+} -+ -+/** -+ * _base_get_chain_buffer_tracker - obtain chain tracker -+ * @ioc: per adapter object -+ * @smid: smid associated to an IO request -+ * -+ * Returns chain tracker(from ioc->free_chain_list) -+ */ -+static struct chain_tracker * -+_base_get_chain_buffer_tracker(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ struct chain_tracker *chain_req; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (list_empty(&ioc->free_chain_list)) { -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "chain buffers not available\n", ioc->name)); -+ return NULL; -+ } -+ chain_req = list_entry(ioc->free_chain_list.next, -+ struct chain_tracker, tracker_list); -+ list_del_init(&chain_req->tracker_list); -+ list_add_tail(&chain_req->tracker_list, -+ &ioc->scsi_lookup[smid - 1].chain_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return chain_req; -+} -+ -+ -+/** -+ * _base_build_sg - build generic sg -+ * @ioc: per adapter object -+ * @psge: virtual address for SGE -+ * @data_out_dma: physical address for WRITES -+ * @data_out_sz: data xfer size for WRITES -+ * @data_in_dma: physical address for READS -+ * @data_in_sz: data xfer size for READS -+ * -+ * Return nothing. -+ */ -+static void -+_base_build_sg(struct MPT3SAS_ADAPTER *ioc, void *psge, -+ dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, -+ size_t data_in_sz) -+{ -+ u32 sgl_flags; -+ -+ if (!data_out_sz && !data_in_sz) { -+ _base_build_zero_len_sge(ioc, psge); -+ return; -+ } -+ -+ if (data_out_sz && data_in_sz) { -+ /* WRITE sgel first */ -+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ ioc->base_add_sg_single(psge, sgl_flags | -+ data_out_sz, data_out_dma); -+ -+ /* incr sgel */ -+ psge += ioc->sge_size; -+ -+ /* READ sgel last */ -+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | -+ MPI2_SGE_FLAGS_END_OF_LIST); -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ ioc->base_add_sg_single(psge, sgl_flags | -+ data_in_sz, data_in_dma); -+ } else if (data_out_sz) /* WRITE */ { -+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | -+ MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC); -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ ioc->base_add_sg_single(psge, sgl_flags | -+ data_out_sz, data_out_dma); -+ } else if (data_in_sz) /* READ */ { -+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | -+ MPI2_SGE_FLAGS_END_OF_LIST); -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ ioc->base_add_sg_single(psge, sgl_flags | -+ data_in_sz, data_in_dma); -+ } -+} -+ -+/* IEEE format sgls */ -+ -+/** -+ * _base_add_sg_single_ieee - add sg element for IEEE format -+ * @paddr: virtual address for SGE -+ * @flags: SGE flags -+ * @chain_offset: number of 128 byte elements from start of segment -+ * @length: data transfer length -+ * @dma_addr: Physical address -+ * -+ * Return nothing. -+ */ -+static void -+_base_add_sg_single_ieee(void *paddr, u8 flags, u8 chain_offset, u32 length, -+ dma_addr_t dma_addr) -+{ -+ Mpi25IeeeSgeChain64_t *sgel = paddr; -+ -+ sgel->Flags = flags; -+ sgel->NextChainOffset = chain_offset; -+ sgel->Length = cpu_to_le32(length); -+ sgel->Address = cpu_to_le64(dma_addr); -+} -+ -+/** -+ * _base_build_zero_len_sge_ieee - build zero length sg entry for IEEE format -+ * @ioc: per adapter object -+ * @paddr: virtual address for SGE -+ * -+ * Create a zero length scatter gather entry to insure the IOCs hardware has -+ * something to use if the target device goes brain dead and tries -+ * to send data even when none is asked for. -+ * -+ * Return nothing. -+ */ -+static void -+_base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr) -+{ -+ u8 sgl_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR | -+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST); -+ -+ _base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1); -+} -+ -+/** -+ * _base_build_sg_scmd - main sg creation routine -+ * @ioc: per adapter object -+ * @scmd: scsi command -+ * @smid: system request message index -+ * Context: none. -+ * -+ * The main routine that builds scatter gather table from a given -+ * scsi request sent via the .queuecommand main handler. -+ * -+ * Returns 0 success, anything else error -+ */ -+static int -+_base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc, -+ struct scsi_cmnd *scmd, u16 smid) -+{ -+ Mpi2SCSIIORequest_t *mpi_request; -+ dma_addr_t chain_dma; -+ struct scatterlist *sg_scmd; -+ void *sg_local, *chain; -+ u32 chain_offset; -+ u32 chain_length; -+ u32 chain_flags; -+ int sges_left; -+ u32 sges_in_segment; -+ u32 sgl_flags; -+ u32 sgl_flags_last_element; -+ u32 sgl_flags_end_buffer; -+ struct chain_tracker *chain_req; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ -+ /* init scatter gather flags */ -+ sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT; -+ if (scmd->sc_data_direction == DMA_TO_DEVICE) -+ sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC; -+ sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT) -+ << MPI2_SGE_FLAGS_SHIFT; -+ sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT | -+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST) -+ << MPI2_SGE_FLAGS_SHIFT; -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ -+ sg_scmd = scsi_sglist(scmd); -+ sges_left = scsi_dma_map(scmd); -+ if (sges_left < 0) { -+ sdev_printk(KERN_ERR, scmd->device, -+ "pci_map_sg failed: request for %d bytes!\n", -+ scsi_bufflen(scmd)); -+ return -ENOMEM; -+ } -+ -+ sg_local = &mpi_request->SGL; -+ sges_in_segment = ioc->max_sges_in_main_message; -+ if (sges_left <= sges_in_segment) -+ goto fill_in_last_segment; -+ -+ mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) + -+ (sges_in_segment * ioc->sge_size))/4; -+ -+ /* fill in main message segment when there is a chain following */ -+ while (sges_in_segment) { -+ if (sges_in_segment == 1) -+ ioc->base_add_sg_single(sg_local, -+ sgl_flags_last_element | sg_dma_len(sg_scmd), -+ sg_dma_address(sg_scmd)); -+ else -+ ioc->base_add_sg_single(sg_local, sgl_flags | -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size; -+ sges_left--; -+ sges_in_segment--; -+ } -+ -+ /* initializing the chain flags and pointers */ -+ chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; -+ chain_req = _base_get_chain_buffer_tracker(ioc, smid); -+ if (!chain_req) -+ return -1; -+ chain = chain_req->chain_buffer; -+ chain_dma = chain_req->chain_buffer_dma; -+ do { -+ sges_in_segment = (sges_left <= -+ ioc->max_sges_in_chain_message) ? sges_left : -+ ioc->max_sges_in_chain_message; -+ chain_offset = (sges_left == sges_in_segment) ? -+ 0 : (sges_in_segment * ioc->sge_size)/4; -+ chain_length = sges_in_segment * ioc->sge_size; -+ if (chain_offset) { -+ chain_offset = chain_offset << -+ MPI2_SGE_CHAIN_OFFSET_SHIFT; -+ chain_length += ioc->sge_size; -+ } -+ ioc->base_add_sg_single(sg_local, chain_flags | chain_offset | -+ chain_length, chain_dma); -+ sg_local = chain; -+ if (!chain_offset) -+ goto fill_in_last_segment; -+ -+ /* fill in chain segments */ -+ while (sges_in_segment) { -+ if (sges_in_segment == 1) -+ ioc->base_add_sg_single(sg_local, -+ sgl_flags_last_element | -+ sg_dma_len(sg_scmd), -+ sg_dma_address(sg_scmd)); -+ else -+ ioc->base_add_sg_single(sg_local, sgl_flags | -+ sg_dma_len(sg_scmd), -+ sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size; -+ sges_left--; -+ sges_in_segment--; -+ } -+ -+ chain_req = _base_get_chain_buffer_tracker(ioc, smid); -+ if (!chain_req) -+ return -1; -+ chain = chain_req->chain_buffer; -+ chain_dma = chain_req->chain_buffer_dma; -+ } while (1); -+ -+ -+ fill_in_last_segment: -+ -+ /* fill the last segment */ -+ while (sges_left) { -+ if (sges_left == 1) -+ ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer | -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ else -+ ioc->base_add_sg_single(sg_local, sgl_flags | -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size; -+ sges_left--; -+ } -+ -+ return 0; -+} -+ -+/** -+ * _base_build_sg_scmd_ieee - main sg creation routine for IEEE format -+ * @ioc: per adapter object -+ * @scmd: scsi command -+ * @smid: system request message index -+ * Context: none. -+ * -+ * The main routine that builds scatter gather table from a given -+ * scsi request sent via the .queuecommand main handler. -+ * -+ * Returns 0 success, anything else error -+ */ -+static int -+_base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, -+ struct scsi_cmnd *scmd, u16 smid) -+{ -+ Mpi2SCSIIORequest_t *mpi_request; -+ dma_addr_t chain_dma; -+ struct scatterlist *sg_scmd; -+ void *sg_local, *chain; -+ u32 chain_offset; -+ u32 chain_length; -+ int sges_left; -+ u32 sges_in_segment; -+ u8 simple_sgl_flags; -+ u8 simple_sgl_flags_last; -+ u8 chain_sgl_flags; -+ struct chain_tracker *chain_req; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ -+ /* init scatter gather flags */ -+ simple_sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ simple_sgl_flags_last = simple_sgl_flags | -+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST; -+ chain_sgl_flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ -+ sg_scmd = scsi_sglist(scmd); -+ sges_left = scsi_dma_map(scmd); -+ if (sges_left < 0) { -+ sdev_printk(KERN_ERR, scmd->device, -+ "pci_map_sg failed: request for %d bytes!\n", -+ scsi_bufflen(scmd)); -+ return -ENOMEM; -+ } -+ -+ sg_local = &mpi_request->SGL; -+ sges_in_segment = (ioc->request_sz - -+ offsetof(Mpi2SCSIIORequest_t, SGL))/ioc->sge_size_ieee; -+ if (sges_left <= sges_in_segment) -+ goto fill_in_last_segment; -+ -+ mpi_request->ChainOffset = (sges_in_segment - 1 /* chain element */) + -+ (offsetof(Mpi2SCSIIORequest_t, SGL)/ioc->sge_size_ieee); -+ -+ /* fill in main message segment when there is a chain following */ -+ while (sges_in_segment > 1) { -+ _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size_ieee; -+ sges_left--; -+ sges_in_segment--; -+ } -+ -+ /* initializing the pointers */ -+ chain_req = _base_get_chain_buffer_tracker(ioc, smid); -+ if (!chain_req) -+ return -1; -+ chain = chain_req->chain_buffer; -+ chain_dma = chain_req->chain_buffer_dma; -+ do { -+ sges_in_segment = (sges_left <= -+ ioc->max_sges_in_chain_message) ? sges_left : -+ ioc->max_sges_in_chain_message; -+ chain_offset = (sges_left == sges_in_segment) ? -+ 0 : sges_in_segment; -+ chain_length = sges_in_segment * ioc->sge_size_ieee; -+ if (chain_offset) -+ chain_length += ioc->sge_size_ieee; -+ _base_add_sg_single_ieee(sg_local, chain_sgl_flags, -+ chain_offset, chain_length, chain_dma); -+ -+ sg_local = chain; -+ if (!chain_offset) -+ goto fill_in_last_segment; -+ -+ /* fill in chain segments */ -+ while (sges_in_segment) { -+ _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size_ieee; -+ sges_left--; -+ sges_in_segment--; -+ } -+ -+ chain_req = _base_get_chain_buffer_tracker(ioc, smid); -+ if (!chain_req) -+ return -1; -+ chain = chain_req->chain_buffer; -+ chain_dma = chain_req->chain_buffer_dma; -+ } while (1); -+ -+ -+ fill_in_last_segment: -+ -+ /* fill the last segment */ -+ while (sges_left > 0) { -+ if (sges_left == 1) -+ _base_add_sg_single_ieee(sg_local, -+ simple_sgl_flags_last, 0, sg_dma_len(sg_scmd), -+ sg_dma_address(sg_scmd)); -+ else -+ _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size_ieee; -+ sges_left--; -+ } -+ -+ return 0; -+} -+ -+/** -+ * _base_build_sg_ieee - build generic sg for IEEE format -+ * @ioc: per adapter object -+ * @psge: virtual address for SGE -+ * @data_out_dma: physical address for WRITES -+ * @data_out_sz: data xfer size for WRITES -+ * @data_in_dma: physical address for READS -+ * @data_in_sz: data xfer size for READS -+ * -+ * Return nothing. -+ */ -+static void -+_base_build_sg_ieee(struct MPT3SAS_ADAPTER *ioc, void *psge, -+ dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, -+ size_t data_in_sz) -+{ -+ u8 sgl_flags; -+ -+ if (!data_out_sz && !data_in_sz) { -+ _base_build_zero_len_sge_ieee(ioc, psge); -+ return; -+ } -+ -+ if (data_out_sz && data_in_sz) { -+ /* WRITE sgel first */ -+ sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ _base_add_sg_single_ieee(psge, sgl_flags, 0, data_out_sz, -+ data_out_dma); -+ -+ /* incr sgel */ -+ psge += ioc->sge_size_ieee; -+ -+ /* READ sgel last */ -+ sgl_flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST; -+ _base_add_sg_single_ieee(psge, sgl_flags, 0, data_in_sz, -+ data_in_dma); -+ } else if (data_out_sz) /* WRITE */ { -+ sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ _base_add_sg_single_ieee(psge, sgl_flags, 0, data_out_sz, -+ data_out_dma); -+ } else if (data_in_sz) /* READ */ { -+ sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ _base_add_sg_single_ieee(psge, sgl_flags, 0, data_in_sz, -+ data_in_dma); -+ } -+} -+ -+#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10)) -+ -+/** -+ * _base_config_dma_addressing - set dma addressing -+ * @ioc: per adapter object -+ * @pdev: PCI device struct -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) -+{ -+ struct sysinfo s; -+ u64 consistent_dma_mask; -+ -+ if (ioc->dma_mask) -+ consistent_dma_mask = DMA_BIT_MASK(64); -+ else -+ consistent_dma_mask = DMA_BIT_MASK(32); -+ -+ if (sizeof(dma_addr_t) > 4) { -+ const uint64_t required_mask = -+ dma_get_required_mask(&pdev->dev); -+ if ((required_mask > DMA_BIT_MASK(32)) && -+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && -+ !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) { -+ ioc->base_add_sg_single = &_base_add_sg_single_64; -+ ioc->sge_size = sizeof(Mpi2SGESimple64_t); -+ ioc->dma_mask = 64; -+ goto out; -+ } -+ } -+ -+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) -+ && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { -+ ioc->base_add_sg_single = &_base_add_sg_single_32; -+ ioc->sge_size = sizeof(Mpi2SGESimple32_t); -+ ioc->dma_mask = 32; -+ } else -+ return -ENODEV; -+ -+ out: -+ si_meminfo(&s); -+ pr_info(MPT3SAS_FMT -+ "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", -+ ioc->name, ioc->dma_mask, convert_to_kb(s.totalram)); -+ -+ return 0; -+} -+ -+static int -+_base_change_consistent_dma_mask(struct MPT3SAS_ADAPTER *ioc, -+ struct pci_dev *pdev) -+{ -+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { -+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+/** -+ * _base_check_enable_msix - checks MSIX capabable. -+ * @ioc: per adapter object -+ * -+ * Check to see if card is capable of MSIX, and set number -+ * of available msix vectors -+ */ -+static int -+_base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int base; -+ u16 message_control; -+ -+ /* Check whether controller SAS2008 B0 controller, -+ * if it is SAS2008 B0 controller use IO-APIC instead of MSIX -+ */ -+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && -+ ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) { -+ return -EINVAL; -+ } -+ -+ base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); -+ if (!base) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n", -+ ioc->name)); -+ return -EINVAL; -+ } -+ -+ /* get msix vector count */ -+ /* NUMA_IO not supported for older controllers */ -+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) -+ ioc->msix_vector_count = 1; -+ else { -+ pci_read_config_word(ioc->pdev, base + 2, &message_control); -+ ioc->msix_vector_count = (message_control & 0x3FF) + 1; -+ } -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "msix is supported, vector_count(%d)\n", -+ ioc->name, ioc->msix_vector_count)); -+ return 0; -+} -+ -+/** -+ * _base_free_irq - free irq -+ * @ioc: per adapter object -+ * -+ * Freeing respective reply_queue from the list. -+ */ -+static void -+_base_free_irq(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct adapter_reply_queue *reply_q, *next; -+ -+ if (list_empty(&ioc->reply_queue_list)) -+ return; -+ -+ list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { -+ list_del(&reply_q->list); -+ if (smp_affinity_enable) { -+ irq_set_affinity_hint(reply_q->vector, NULL); -+ free_cpumask_var(reply_q->affinity_hint); -+ } -+ free_irq(reply_q->vector, reply_q); -+ kfree(reply_q); -+ } -+} -+ -+/** -+ * _base_request_irq - request irq -+ * @ioc: per adapter object -+ * @index: msix index into vector table -+ * @vector: irq vector -+ * -+ * Inserting respective reply_queue into the list. -+ */ -+static int -+_base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector) -+{ -+ struct adapter_reply_queue *reply_q; -+ int r; -+ -+ reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); -+ if (!reply_q) { -+ pr_err(MPT3SAS_FMT "unable to allocate memory %d!\n", -+ ioc->name, (int)sizeof(struct adapter_reply_queue)); -+ return -ENOMEM; -+ } -+ reply_q->ioc = ioc; -+ reply_q->msix_index = index; -+ reply_q->vector = vector; -+ -+ if (smp_affinity_enable) { -+ if (!zalloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) { -+ kfree(reply_q); -+ return -ENOMEM; -+ } -+ } -+ -+ atomic_set(&reply_q->busy, 0); -+ if (ioc->msix_enable) -+ snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", -+ ioc->driver_name, ioc->id, index); -+ else -+ snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", -+ ioc->driver_name, ioc->id); -+ r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, -+ reply_q); -+ if (r) { -+ pr_err(MPT3SAS_FMT "unable to allocate interrupt %d!\n", -+ reply_q->name, vector); -+ free_cpumask_var(reply_q->affinity_hint); -+ kfree(reply_q); -+ return -EBUSY; -+ } -+ -+ INIT_LIST_HEAD(&reply_q->list); -+ list_add_tail(&reply_q->list, &ioc->reply_queue_list); -+ return 0; -+} -+ -+/** -+ * _base_assign_reply_queues - assigning msix index for each cpu -+ * @ioc: per adapter object -+ * -+ * The enduser would need to set the affinity via /proc/irq/#/smp_affinity -+ * -+ * It would nice if we could call irq_set_affinity, however it is not -+ * an exported symbol -+ */ -+static void -+_base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) -+{ -+ unsigned int cpu, nr_cpus, nr_msix, index = 0; -+ struct adapter_reply_queue *reply_q; -+ -+ if (!_base_is_controller_msix_enabled(ioc)) -+ return; -+ -+ memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); -+ -+ nr_cpus = num_online_cpus(); -+ nr_msix = ioc->reply_queue_count = min(ioc->reply_queue_count, -+ ioc->facts.MaxMSIxVectors); -+ if (!nr_msix) -+ return; -+ -+ cpu = cpumask_first(cpu_online_mask); -+ -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { -+ -+ unsigned int i, group = nr_cpus / nr_msix; -+ -+ if (cpu >= nr_cpus) -+ break; -+ -+ if (index < nr_cpus % nr_msix) -+ group++; -+ -+ for (i = 0 ; i < group ; i++) { -+ ioc->cpu_msix_table[cpu] = index; -+ if (smp_affinity_enable) -+ cpumask_or(reply_q->affinity_hint, -+ reply_q->affinity_hint, get_cpu_mask(cpu)); -+ cpu = cpumask_next(cpu, cpu_online_mask); -+ } -+ if (smp_affinity_enable) -+ if (irq_set_affinity_hint(reply_q->vector, -+ reply_q->affinity_hint)) -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "Err setting affinity hint to irq vector %d\n", -+ ioc->name, reply_q->vector)); -+ index++; -+ } -+} -+ -+/** -+ * _base_disable_msix - disables msix -+ * @ioc: per adapter object -+ * -+ */ -+static void -+_base_disable_msix(struct MPT3SAS_ADAPTER *ioc) -+{ -+ if (!ioc->msix_enable) -+ return; -+ pci_disable_msix(ioc->pdev); -+ ioc->msix_enable = 0; -+} -+ -+/** -+ * _base_enable_msix - enables msix, failback to io_apic -+ * @ioc: per adapter object -+ * -+ */ -+static int -+_base_enable_msix(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct msix_entry *entries, *a; -+ int r; -+ int i; -+ u8 try_msix = 0; -+ -+ if (msix_disable == -1 || msix_disable == 0) -+ try_msix = 1; -+ -+ if (!try_msix) -+ goto try_ioapic; -+ -+ if (_base_check_enable_msix(ioc) != 0) -+ goto try_ioapic; -+ -+ ioc->reply_queue_count = min_t(int, ioc->cpu_count, -+ ioc->msix_vector_count); -+ -+ printk(MPT3SAS_FMT "MSI-X vectors supported: %d, no of cores" -+ ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count, -+ ioc->cpu_count, max_msix_vectors); -+ -+ if (!ioc->rdpq_array_enable && max_msix_vectors == -1) -+ max_msix_vectors = 8; -+ -+ if (max_msix_vectors > 0) { -+ ioc->reply_queue_count = min_t(int, max_msix_vectors, -+ ioc->reply_queue_count); -+ ioc->msix_vector_count = ioc->reply_queue_count; -+ } else if (max_msix_vectors == 0) -+ goto try_ioapic; -+ -+ if (ioc->msix_vector_count < ioc->cpu_count) -+ smp_affinity_enable = 0; -+ -+ entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry), -+ GFP_KERNEL); -+ if (!entries) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT -+ "kcalloc failed @ at %s:%d/%s() !!!\n", -+ ioc->name, __FILE__, __LINE__, __func__)); -+ goto try_ioapic; -+ } -+ -+ for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) -+ a->entry = i; -+ -+ r = pci_enable_msix_exact(ioc->pdev, entries, ioc->reply_queue_count); -+ if (r) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT -+ "pci_enable_msix_exact failed (r=%d) !!!\n", -+ ioc->name, r)); -+ kfree(entries); -+ goto try_ioapic; -+ } -+ -+ ioc->msix_enable = 1; -+ for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) { -+ r = _base_request_irq(ioc, i, a->vector); -+ if (r) { -+ _base_free_irq(ioc); -+ _base_disable_msix(ioc); -+ kfree(entries); -+ goto try_ioapic; -+ } -+ } -+ -+ kfree(entries); -+ return 0; -+ -+/* failback to io_apic interrupt routing */ -+ try_ioapic: -+ -+ ioc->reply_queue_count = 1; -+ r = _base_request_irq(ioc, 0, ioc->pdev->irq); -+ -+ return r; -+} -+ -+/** -+ * mpt2sas_base_unmap_resources - free controller resources -+ * @ioc: per adapter object -+ */ -+void -+mpt2sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct pci_dev *pdev = ioc->pdev; -+ -+ dexitprintk(ioc, printk(MPT3SAS_FMT "%s\n", -+ ioc->name, __func__)); -+ -+ _base_free_irq(ioc); -+ _base_disable_msix(ioc); -+ -+ if (ioc->msix96_vector) { -+ kfree(ioc->replyPostRegisterIndex); -+ ioc->replyPostRegisterIndex = NULL; -+ } -+ -+ if (ioc->chip_phys) { -+ iounmap(ioc->chip); -+ ioc->chip_phys = 0; -+ } -+ -+ if (pci_is_enabled(pdev)) { -+ pci_release_selected_regions(ioc->pdev, ioc->bars); -+ pci_disable_pcie_error_reporting(pdev); -+ pci_disable_device(pdev); -+ } -+} -+ -+/** -+ * mpt2sas_base_map_resources - map in controller resources (io/irq/memap) -+ * @ioc: per adapter object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct pci_dev *pdev = ioc->pdev; -+ u32 memap_sz; -+ u32 pio_sz; -+ int i, r = 0; -+ u64 pio_chip = 0; -+ u64 chip_phys = 0; -+ struct adapter_reply_queue *reply_q; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", -+ ioc->name, __func__)); -+ -+ ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); -+ if (pci_enable_device_mem(pdev)) { -+ pr_warn(MPT3SAS_FMT "pci_enable_device_mem: failed\n", -+ ioc->name); -+ ioc->bars = 0; -+ return -ENODEV; -+ } -+ -+ -+ if (pci_request_selected_regions(pdev, ioc->bars, -+ ioc->driver_name)) { -+ pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n", -+ ioc->name); -+ ioc->bars = 0; -+ r = -ENODEV; -+ goto out_fail; -+ } -+ -+/* AER (Advanced Error Reporting) hooks */ -+ pci_enable_pcie_error_reporting(pdev); -+ -+ pci_set_master(pdev); -+ -+ -+ if (_base_config_dma_addressing(ioc, pdev) != 0) { -+ pr_warn(MPT3SAS_FMT "no suitable DMA mask for %s\n", -+ ioc->name, pci_name(pdev)); -+ r = -ENODEV; -+ goto out_fail; -+ } -+ -+ for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) && -+ (!memap_sz || !pio_sz); i++) { -+ if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { -+ if (pio_sz) -+ continue; -+ pio_chip = (u64)pci_resource_start(pdev, i); -+ pio_sz = pci_resource_len(pdev, i); -+ } else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { -+ if (memap_sz) -+ continue; -+ ioc->chip_phys = pci_resource_start(pdev, i); -+ chip_phys = (u64)ioc->chip_phys; -+ memap_sz = pci_resource_len(pdev, i); -+ ioc->chip = ioremap(ioc->chip_phys, memap_sz); -+ } -+ } -+ -+ if (ioc->chip == NULL) { -+ pr_err(MPT3SAS_FMT "unable to map adapter memory! " -+ " or resource not found\n", ioc->name); -+ r = -EINVAL; -+ goto out_fail; -+ } -+ -+ _base_mask_interrupts(ioc); -+ -+ r = _base_get_ioc_facts(ioc, CAN_SLEEP); -+ if (r) -+ goto out_fail; -+ -+ if (!ioc->rdpq_array_enable_assigned) { -+ ioc->rdpq_array_enable = ioc->rdpq_array_capable; -+ ioc->rdpq_array_enable_assigned = 1; -+ } -+ -+ r = _base_enable_msix(ioc); -+ if (r) -+ goto out_fail; -+ -+ /* Use the Combined reply queue feature only for SAS3 C0 & higher -+ * revision HBAs and also only when reply queue count is greater than 8 -+ */ -+ if (ioc->msix96_vector && ioc->reply_queue_count > 8) { -+ /* Determine the Supplemental Reply Post Host Index Registers -+ * Addresse. Supplemental Reply Post Host Index Registers -+ * starts at offset MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET and -+ * each register is at offset bytes of -+ * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET from previous one. -+ */ -+ ioc->replyPostRegisterIndex = kcalloc( -+ MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT, -+ sizeof(resource_size_t *), GFP_KERNEL); -+ if (!ioc->replyPostRegisterIndex) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "allocation for reply Post Register Index failed!!!\n", -+ ioc->name)); -+ r = -ENOMEM; -+ goto out_fail; -+ } -+ -+ for (i = 0; i < MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT; i++) { -+ ioc->replyPostRegisterIndex[i] = (resource_size_t *) -+ ((u8 *)&ioc->chip->Doorbell + -+ MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET + -+ (i * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET)); -+ } -+ } else -+ ioc->msix96_vector = 0; -+ -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) -+ pr_info(MPT3SAS_FMT "%s: IRQ %d\n", -+ reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : -+ "IO-APIC enabled"), reply_q->vector); -+ -+ pr_info(MPT3SAS_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", -+ ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); -+ pr_info(MPT3SAS_FMT "ioport(0x%016llx), size(%d)\n", -+ ioc->name, (unsigned long long)pio_chip, pio_sz); -+ -+ /* Save PCI configuration state for recovery from PCI AER/EEH errors */ -+ pci_save_state(pdev); -+ return 0; -+ -+ out_fail: -+ mpt2sas_base_unmap_resources(ioc); -+ return r; -+} -+ -+/** -+ * mpt2sas_base_get_msg_frame - obtain request mf pointer -+ * @ioc: per adapter object -+ * @smid: system request message index(smid zero is invalid) -+ * -+ * Returns virt pointer to message frame. -+ */ -+void * -+mpt2sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return (void *)(ioc->request + (smid * ioc->request_sz)); -+} -+ -+/** -+ * mpt2sas_base_get_sense_buffer - obtain a sense buffer virt addr -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns virt pointer to sense buffer. -+ */ -+void * -+mpt2sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); -+} -+ -+/** -+ * mpt2sas_base_get_sense_buffer_dma - obtain a sense buffer dma addr -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns phys pointer to the low 32bit address of the sense buffer. -+ */ -+__le32 -+mpt2sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return cpu_to_le32(ioc->sense_dma + ((smid - 1) * -+ SCSI_SENSE_BUFFERSIZE)); -+} -+ -+/** -+ * mpt2sas_base_get_reply_virt_addr - obtain reply frames virt address -+ * @ioc: per adapter object -+ * @phys_addr: lower 32 physical addr of the reply -+ * -+ * Converts 32bit lower physical addr into a virt address. -+ */ -+void * -+mpt2sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr) -+{ -+ if (!phys_addr) -+ return NULL; -+ return ioc->reply + (phys_addr - (u32)ioc->reply_dma); -+} -+ -+static inline u8 -+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc) -+{ -+ return ioc->cpu_msix_table[raw_smp_processor_id()]; -+} -+ -+/** -+ * mpt2sas_base_get_smid - obtain a free smid from internal queue -+ * @ioc: per adapter object -+ * @cb_idx: callback index -+ * -+ * Returns smid (zero is invalid) -+ */ -+u16 -+mpt2sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx) -+{ -+ unsigned long flags; -+ struct request_tracker *request; -+ u16 smid; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (list_empty(&ioc->internal_free_list)) { -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ pr_err(MPT3SAS_FMT "%s: smid not available\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ request = list_entry(ioc->internal_free_list.next, -+ struct request_tracker, tracker_list); -+ request->cb_idx = cb_idx; -+ smid = request->smid; -+ list_del(&request->tracker_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return smid; -+} -+ -+/** -+ * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue -+ * @ioc: per adapter object -+ * @cb_idx: callback index -+ * @scmd: pointer to scsi command object -+ * -+ * Returns smid (zero is invalid) -+ */ -+u16 -+mpt2sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, -+ struct scsi_cmnd *scmd) -+{ -+ unsigned long flags; -+ struct scsiio_tracker *request; -+ u16 smid; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (list_empty(&ioc->free_list)) { -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ pr_err(MPT3SAS_FMT "%s: smid not available\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ request = list_entry(ioc->free_list.next, -+ struct scsiio_tracker, tracker_list); -+ request->scmd = scmd; -+ request->cb_idx = cb_idx; -+ smid = request->smid; -+ request->msix_io = _base_get_msix_index(ioc); -+ list_del(&request->tracker_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return smid; -+} -+ -+/** -+ * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue -+ * @ioc: per adapter object -+ * @cb_idx: callback index -+ * -+ * Returns smid (zero is invalid) -+ */ -+u16 -+mpt2sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx) -+{ -+ unsigned long flags; -+ struct request_tracker *request; -+ u16 smid; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (list_empty(&ioc->hpr_free_list)) { -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return 0; -+ } -+ -+ request = list_entry(ioc->hpr_free_list.next, -+ struct request_tracker, tracker_list); -+ request->cb_idx = cb_idx; -+ smid = request->smid; -+ list_del(&request->tracker_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return smid; -+} -+ -+/** -+ * mpt2sas_base_free_smid - put smid back on free_list -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ unsigned long flags; -+ int i; -+ struct chain_tracker *chain_req, *next; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (smid < ioc->hi_priority_smid) { -+ /* scsiio queue */ -+ i = smid - 1; -+ if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { -+ list_for_each_entry_safe(chain_req, next, -+ &ioc->scsi_lookup[i].chain_list, tracker_list) { -+ list_del_init(&chain_req->tracker_list); -+ list_add(&chain_req->tracker_list, -+ &ioc->free_chain_list); -+ } -+ } -+ ioc->scsi_lookup[i].cb_idx = 0xFF; -+ ioc->scsi_lookup[i].scmd = NULL; -+ ioc->scsi_lookup[i].direct_io = 0; -+ list_add(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ /* -+ * See _wait_for_commands_to_complete() call with regards -+ * to this code. -+ */ -+ if (ioc->shost_recovery && ioc->pending_io_count) { -+ if (ioc->pending_io_count == 1) -+ wake_up(&ioc->reset_wq); -+ ioc->pending_io_count--; -+ } -+ return; -+ } else if (smid < ioc->internal_smid) { -+ /* hi-priority */ -+ i = smid - ioc->hi_priority_smid; -+ ioc->hpr_lookup[i].cb_idx = 0xFF; -+ list_add(&ioc->hpr_lookup[i].tracker_list, &ioc->hpr_free_list); -+ } else if (smid <= ioc->hba_queue_depth) { -+ /* internal queue */ -+ i = smid - ioc->internal_smid; -+ ioc->internal_lookup[i].cb_idx = 0xFF; -+ list_add(&ioc->internal_lookup[i].tracker_list, -+ &ioc->internal_free_list); -+ } -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+} -+ -+/** -+ * _base_writeq - 64 bit write to MMIO -+ * @ioc: per adapter object -+ * @b: data payload -+ * @addr: address in MMIO space -+ * @writeq_lock: spin lock -+ * -+ * Glue for handling an atomic 64 bit word to MMIO. This special handling takes -+ * care of 32 bit environment where its not quarenteed to send the entire word -+ * in one transfer. -+ */ -+#if defined(writeq) && defined(CONFIG_64BIT) -+static inline void -+_base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) -+{ -+ writeq(cpu_to_le64(b), addr); -+} -+#else -+static inline void -+_base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) -+{ -+ unsigned long flags; -+ __u64 data_out = cpu_to_le64(b); -+ -+ spin_lock_irqsave(writeq_lock, flags); -+ writel((u32)(data_out), addr); -+ writel((u32)(data_out >> 32), (addr + 4)); -+ spin_unlock_irqrestore(writeq_lock, flags); -+} -+#endif -+ -+/** -+ * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @handle: device handle -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) -+{ -+ Mpi2RequestDescriptorUnion_t descriptor; -+ u64 *request = (u64 *)&descriptor; -+ -+ -+ descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; -+ descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); -+ descriptor.SCSIIO.SMID = cpu_to_le16(smid); -+ descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); -+ descriptor.SCSIIO.LMID = 0; -+ _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, -+ &ioc->scsi_lookup_lock); -+} -+ -+/** -+ * mpt2sas_base_put_smid_fast_path - send fast path request to firmware -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @handle: device handle -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u16 handle) -+{ -+ Mpi2RequestDescriptorUnion_t descriptor; -+ u64 *request = (u64 *)&descriptor; -+ -+ descriptor.SCSIIO.RequestFlags = -+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; -+ descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); -+ descriptor.SCSIIO.SMID = cpu_to_le16(smid); -+ descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); -+ descriptor.SCSIIO.LMID = 0; -+ _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, -+ &ioc->scsi_lookup_lock); -+} -+ -+/** -+ * mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_task: msix_task will be same as msix of IO incase of task abort else 0. -+ * Return nothing. -+ */ -+void -+mpt2sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u16 msix_task) -+{ -+ Mpi2RequestDescriptorUnion_t descriptor; -+ u64 *request = (u64 *)&descriptor; -+ -+ descriptor.HighPriority.RequestFlags = -+ MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; -+ descriptor.HighPriority.MSIxIndex = msix_task; -+ descriptor.HighPriority.SMID = cpu_to_le16(smid); -+ descriptor.HighPriority.LMID = 0; -+ descriptor.HighPriority.Reserved1 = 0; -+ _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, -+ &ioc->scsi_lookup_lock); -+} -+ -+/** -+ * mpt2sas_base_put_smid_default - Default, primarily used for config pages -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ Mpi2RequestDescriptorUnion_t descriptor; -+ u64 *request = (u64 *)&descriptor; -+ -+ descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; -+ descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); -+ descriptor.Default.SMID = cpu_to_le16(smid); -+ descriptor.Default.LMID = 0; -+ descriptor.Default.DescriptorTypeDependent = 0; -+ _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, -+ &ioc->scsi_lookup_lock); -+} -+ -+/** -+ * _base_display_OEMs_branding - Display branding string -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) -+{ -+ if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) -+ return; -+ -+ switch (ioc->pdev->subsystem_vendor) { -+ case PCI_VENDOR_ID_INTEL: -+ switch (ioc->pdev->device) { -+ case MPI2_MFGPAGE_DEVID_SAS2008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_INTEL_RMS2LL080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS2LL080_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS2LL040_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS2LL040_BRANDING); -+ break; -+ case MPT2SAS_INTEL_SSD910_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_SSD910_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Intel(R) Controller: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ case MPI2_MFGPAGE_DEVID_SAS2308_2: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_INTEL_RS25GB008_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RS25GB008_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25JB080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25JB080_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25JB040_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25JB040_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25KB080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25KB080_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25KB040_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25KB040_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25LB040_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25LB040_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25LB080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25LB080_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Intel(R) Controller: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ case MPI25_MFGPAGE_DEVID_SAS3008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT3SAS_INTEL_RMS3JC080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_INTEL_RMS3JC080_BRANDING); -+ break; -+ -+ case MPT3SAS_INTEL_RS3GC008_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_INTEL_RS3GC008_BRANDING); -+ break; -+ case MPT3SAS_INTEL_RS3FC044_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_INTEL_RS3FC044_BRANDING); -+ break; -+ case MPT3SAS_INTEL_RS3UC080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_INTEL_RS3UC080_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Intel(R) Controller: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Intel(R) Controller: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case PCI_VENDOR_ID_DELL: -+ switch (ioc->pdev->device) { -+ case MPI2_MFGPAGE_DEVID_SAS2008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_BRANDING); -+ break; -+ case MPT2SAS_DELL_6GBPS_SAS_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_6GBPS_SAS_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Dell 6Gbps HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case MPI25_MFGPAGE_DEVID_SAS3008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT3SAS_DELL_12G_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_DELL_12G_HBA_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Dell HBA: Subsystem ID: 0x%X\n", ioc->name, -+ ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case PCI_VENDOR_ID_CISCO: -+ switch (ioc->pdev->device) { -+ case MPI25_MFGPAGE_DEVID_SAS3008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT3SAS_CISCO_12G_8E_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_8E_HBA_BRANDING); -+ break; -+ case MPT3SAS_CISCO_12G_8I_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_8I_HBA_BRANDING); -+ break; -+ case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case MPI25_MFGPAGE_DEVID_SAS3108_1: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); -+ break; -+ case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING -+ ); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Cisco SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case MPT2SAS_HP_3PAR_SSVID: -+ switch (ioc->pdev->device) { -+ case MPI2_MFGPAGE_DEVID_SAS2004: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ case MPI2_MFGPAGE_DEVID_SAS2308_2: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_HP_2_4_INTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_2_4_INTERNAL_BRANDING); -+ break; -+ case MPT2SAS_HP_2_4_EXTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_2_4_EXTERNAL_BRANDING); -+ break; -+ case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); -+ break; -+ case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ default: -+ pr_info(MPT3SAS_FMT -+ "HP SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ default: -+ break; -+ } -+} -+ -+/** -+ * _base_display_ioc_capabilities - Disply IOC's capabilities. -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int i = 0; -+ char desc[16]; -+ u32 iounit_pg1_flags; -+ u32 bios_version; -+ -+ bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); -+ strncpy(desc, ioc->manu_pg0.ChipName, 16); -+ pr_info(MPT3SAS_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "\ -+ "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n", -+ ioc->name, desc, -+ (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, -+ (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, -+ (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, -+ ioc->facts.FWVersion.Word & 0x000000FF, -+ ioc->pdev->revision, -+ (bios_version & 0xFF000000) >> 24, -+ (bios_version & 0x00FF0000) >> 16, -+ (bios_version & 0x0000FF00) >> 8, -+ bios_version & 0x000000FF); -+ -+ _base_display_OEMs_branding(ioc); -+ -+ pr_info(MPT3SAS_FMT "Protocol=(", ioc->name); -+ -+ if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { -+ pr_info("Initiator"); -+ i++; -+ } -+ -+ if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) { -+ pr_info("%sTarget", i ? "," : ""); -+ i++; -+ } -+ -+ i = 0; -+ pr_info("), "); -+ pr_info("Capabilities=("); -+ -+ if (!ioc->hide_ir_msg) { -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { -+ pr_info("Raid"); -+ i++; -+ } -+ } -+ -+ if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { -+ pr_info("%sTLR", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) { -+ pr_info("%sMulticast", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) { -+ pr_info("%sBIDI Target", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) { -+ pr_info("%sEEDP", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) { -+ pr_info("%sSnapshot Buffer", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) { -+ pr_info("%sDiag Trace Buffer", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { -+ pr_info("%sDiag Extended Buffer", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { -+ pr_info("%sTask Set Full", i ? "," : ""); -+ i++; -+ } -+ -+ iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); -+ if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { -+ pr_info("%sNCQ", i ? "," : ""); -+ i++; -+ } -+ -+ pr_info(")\n"); -+} -+ -+/** -+ * mpt2sas_base_update_missing_delay - change the missing delay timers -+ * @ioc: per adapter object -+ * @device_missing_delay: amount of time till device is reported missing -+ * @io_missing_delay: interval IO is returned when there is a missing device -+ * -+ * Return nothing. -+ * -+ * Passed on the command line, this function will modify the device missing -+ * delay, as well as the io missing delay. This should be called at driver -+ * load time. -+ */ -+void -+mpt2sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, -+ u16 device_missing_delay, u8 io_missing_delay) -+{ -+ u16 dmd, dmd_new, dmd_orignal; -+ u8 io_missing_delay_original; -+ u16 sz; -+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; -+ Mpi2ConfigReply_t mpi_reply; -+ u8 num_phys = 0; -+ u16 ioc_status; -+ -+ mpt2sas_config_get_number_hba_phys(ioc, &num_phys); -+ if (!num_phys) -+ return; -+ -+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys * -+ sizeof(Mpi2SasIOUnit1PhyData_t)); -+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg1) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, -+ sas_iounit_pg1, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ /* device missing delay */ -+ dmd = sas_iounit_pg1->ReportDeviceMissingDelay; -+ if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) -+ dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; -+ else -+ dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; -+ dmd_orignal = dmd; -+ if (device_missing_delay > 0x7F) { -+ dmd = (device_missing_delay > 0x7F0) ? 0x7F0 : -+ device_missing_delay; -+ dmd = dmd / 16; -+ dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16; -+ } else -+ dmd = device_missing_delay; -+ sas_iounit_pg1->ReportDeviceMissingDelay = dmd; -+ -+ /* io missing delay */ -+ io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay; -+ sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay; -+ -+ if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, -+ sz)) { -+ if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) -+ dmd_new = (dmd & -+ MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; -+ else -+ dmd_new = -+ dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; -+ pr_info(MPT3SAS_FMT "device_missing_delay: old(%d), new(%d)\n", -+ ioc->name, dmd_orignal, dmd_new); -+ pr_info(MPT3SAS_FMT "ioc_missing_delay: old(%d), new(%d)\n", -+ ioc->name, io_missing_delay_original, -+ io_missing_delay); -+ ioc->device_missing_delay = dmd_new; -+ ioc->io_missing_delay = io_missing_delay; -+ } -+ -+out: -+ kfree(sas_iounit_pg1); -+} -+/** -+ * _base_static_config_pages - static start of day config pages -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ u32 iounit_pg1_flags; -+ -+ mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); -+ if (ioc->ir_firmware) -+ mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply, -+ &ioc->manu_pg10); -+ -+ /* -+ * Ensure correct T10 PI operation if vendor left EEDPTagMode -+ * flag unset in NVDATA. -+ */ -+ mpt2sas_config_get_manufacturing_pg11(ioc, &mpi_reply, &ioc->manu_pg11); -+ if (ioc->manu_pg11.EEDPTagMode == 0) { -+ pr_err("%s: overriding NVDATA EEDPTagMode setting\n", -+ ioc->name); -+ ioc->manu_pg11.EEDPTagMode &= ~0x3; -+ ioc->manu_pg11.EEDPTagMode |= 0x1; -+ mpt2sas_config_set_manufacturing_pg11(ioc, &mpi_reply, -+ &ioc->manu_pg11); -+ } -+ -+ mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); -+ mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); -+ mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); -+ mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); -+ mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); -+ mpt2sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); -+ _base_display_ioc_capabilities(ioc); -+ -+ /* -+ * Enable task_set_full handling in iounit_pg1 when the -+ * facts capabilities indicate that its supported. -+ */ -+ iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); -+ if ((ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING)) -+ iounit_pg1_flags &= -+ ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; -+ else -+ iounit_pg1_flags |= -+ MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; -+ ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); -+ mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); -+ -+ if (ioc->iounit_pg8.NumSensors) -+ ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; -+} -+ -+/** -+ * _base_release_memory_pools - release memory -+ * @ioc: per adapter object -+ * -+ * Free memory allocated from _base_allocate_memory_pools. -+ * -+ * Return nothing. -+ */ -+static void -+_base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int i = 0; -+ struct reply_post_struct *rps; -+ -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ if (ioc->request) { -+ pci_free_consistent(ioc->pdev, ioc->request_dma_sz, -+ ioc->request, ioc->request_dma); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "request_pool(0x%p): free\n", -+ ioc->name, ioc->request)); -+ ioc->request = NULL; -+ } -+ -+ if (ioc->sense) { -+ pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma); -+ if (ioc->sense_dma_pool) -+ pci_pool_destroy(ioc->sense_dma_pool); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "sense_pool(0x%p): free\n", -+ ioc->name, ioc->sense)); -+ ioc->sense = NULL; -+ } -+ -+ if (ioc->reply) { -+ pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma); -+ if (ioc->reply_dma_pool) -+ pci_pool_destroy(ioc->reply_dma_pool); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_pool(0x%p): free\n", -+ ioc->name, ioc->reply)); -+ ioc->reply = NULL; -+ } -+ -+ if (ioc->reply_free) { -+ pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free, -+ ioc->reply_free_dma); -+ if (ioc->reply_free_dma_pool) -+ pci_pool_destroy(ioc->reply_free_dma_pool); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_free_pool(0x%p): free\n", -+ ioc->name, ioc->reply_free)); -+ ioc->reply_free = NULL; -+ } -+ -+ if (ioc->reply_post) { -+ do { -+ rps = &ioc->reply_post[i]; -+ if (rps->reply_post_free) { -+ pci_pool_free( -+ ioc->reply_post_free_dma_pool, -+ rps->reply_post_free, -+ rps->reply_post_free_dma); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_post_free_pool(0x%p): free\n", -+ ioc->name, rps->reply_post_free)); -+ rps->reply_post_free = NULL; -+ } -+ } while (ioc->rdpq_array_enable && -+ (++i < ioc->reply_queue_count)); -+ -+ if (ioc->reply_post_free_dma_pool) -+ pci_pool_destroy(ioc->reply_post_free_dma_pool); -+ kfree(ioc->reply_post); -+ } -+ -+ if (ioc->config_page) { -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "config_page(0x%p): free\n", ioc->name, -+ ioc->config_page)); -+ pci_free_consistent(ioc->pdev, ioc->config_page_sz, -+ ioc->config_page, ioc->config_page_dma); -+ } -+ -+ if (ioc->scsi_lookup) { -+ free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); -+ ioc->scsi_lookup = NULL; -+ } -+ kfree(ioc->hpr_lookup); -+ kfree(ioc->internal_lookup); -+ if (ioc->chain_lookup) { -+ for (i = 0; i < ioc->chain_depth; i++) { -+ if (ioc->chain_lookup[i].chain_buffer) -+ pci_pool_free(ioc->chain_dma_pool, -+ ioc->chain_lookup[i].chain_buffer, -+ ioc->chain_lookup[i].chain_buffer_dma); -+ } -+ if (ioc->chain_dma_pool) -+ pci_pool_destroy(ioc->chain_dma_pool); -+ free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); -+ ioc->chain_lookup = NULL; -+ } -+} -+ -+/** -+ * _base_allocate_memory_pools - allocate start of day memory pools -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 success, anything else error -+ */ -+static int -+_base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ struct mpt2sas_facts *facts; -+ u16 max_sge_elements; -+ u16 chains_needed_per_io; -+ u32 sz, total_sz, reply_post_free_sz; -+ u32 retry_sz; -+ u16 max_request_credit; -+ unsigned short sg_tablesize; -+ u16 sge_size; -+ int i; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ -+ retry_sz = 0; -+ facts = &ioc->facts; -+ -+ /* command line tunables for max sgl entries */ -+ if (max_sgl_entries != -1) -+ sg_tablesize = max_sgl_entries; -+ else { -+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION) -+ sg_tablesize = MPT2SAS_SG_DEPTH; -+ else -+ sg_tablesize = MPT3SAS_SG_DEPTH; -+ } -+ -+ if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS) -+ sg_tablesize = MPT_MIN_PHYS_SEGMENTS; -+ else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { -+ sg_tablesize = min_t(unsigned short, sg_tablesize, -+ SCSI_MAX_SG_CHAIN_SEGMENTS); -+ pr_warn(MPT3SAS_FMT -+ "sg_tablesize(%u) is bigger than kernel" -+ " defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name, -+ sg_tablesize, MPT_MAX_PHYS_SEGMENTS); -+ } -+ ioc->shost->sg_tablesize = sg_tablesize; -+ -+ ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)), -+ (facts->RequestCredit / 4)); -+ if (ioc->internal_depth < INTERNAL_CMDS_COUNT) { -+ if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT + -+ INTERNAL_SCSIIO_CMDS_COUNT)) { -+ pr_err(MPT3SAS_FMT "IOC doesn't have enough Request \ -+ Credits, it has just %d number of credits\n", -+ ioc->name, facts->RequestCredit); -+ return -ENOMEM; -+ } -+ ioc->internal_depth = 10; -+ } -+ -+ ioc->hi_priority_depth = ioc->internal_depth - (5); -+ /* command line tunables for max controller queue depth */ -+ if (max_queue_depth != -1 && max_queue_depth != 0) { -+ max_request_credit = min_t(u16, max_queue_depth + -+ ioc->internal_depth, facts->RequestCredit); -+ if (max_request_credit > MAX_HBA_QUEUE_DEPTH) -+ max_request_credit = MAX_HBA_QUEUE_DEPTH; -+ } else -+ max_request_credit = min_t(u16, facts->RequestCredit, -+ MAX_HBA_QUEUE_DEPTH); -+ -+ /* Firmware maintains additional facts->HighPriorityCredit number of -+ * credits for HiPriprity Request messages, so hba queue depth will be -+ * sum of max_request_credit and high priority queue depth. -+ */ -+ ioc->hba_queue_depth = max_request_credit + ioc->hi_priority_depth; -+ -+ /* request frame size */ -+ ioc->request_sz = facts->IOCRequestFrameSize * 4; -+ -+ /* reply frame size */ -+ ioc->reply_sz = facts->ReplyFrameSize * 4; -+ -+ /* chain segment size */ -+ if (ioc->hba_mpi_version_belonged != MPI2_VERSION) { -+ if (facts->IOCMaxChainSegmentSize) -+ ioc->chain_segment_sz = -+ facts->IOCMaxChainSegmentSize * -+ MAX_CHAIN_ELEMT_SZ; -+ else -+ /* set to 128 bytes size if IOCMaxChainSegmentSize is zero */ -+ ioc->chain_segment_sz = DEFAULT_NUM_FWCHAIN_ELEMTS * -+ MAX_CHAIN_ELEMT_SZ; -+ } else -+ ioc->chain_segment_sz = ioc->request_sz; -+ -+ /* calculate the max scatter element size */ -+ sge_size = max_t(u16, ioc->sge_size, ioc->sge_size_ieee); -+ -+ retry_allocation: -+ total_sz = 0; -+ /* calculate number of sg elements left over in the 1st frame */ -+ max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) - -+ sizeof(Mpi2SGEIOUnion_t)) + sge_size); -+ ioc->max_sges_in_main_message = max_sge_elements/sge_size; -+ -+ /* now do the same for a chain buffer */ -+ max_sge_elements = ioc->chain_segment_sz - sge_size; -+ ioc->max_sges_in_chain_message = max_sge_elements/sge_size; -+ -+ /* -+ * MPT3SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE -+ */ -+ chains_needed_per_io = ((ioc->shost->sg_tablesize - -+ ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message) -+ + 1; -+ if (chains_needed_per_io > facts->MaxChainDepth) { -+ chains_needed_per_io = facts->MaxChainDepth; -+ ioc->shost->sg_tablesize = min_t(u16, -+ ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message -+ * chains_needed_per_io), ioc->shost->sg_tablesize); -+ } -+ ioc->chains_needed_per_io = chains_needed_per_io; -+ -+ /* reply free queue sizing - taking into account for 64 FW events */ -+ ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; -+ -+ /* calculate reply descriptor post queue depth */ -+ ioc->reply_post_queue_depth = ioc->hba_queue_depth + -+ ioc->reply_free_queue_depth + 1 ; -+ /* align the reply post queue on the next 16 count boundary */ -+ if (ioc->reply_post_queue_depth % 16) -+ ioc->reply_post_queue_depth += 16 - -+ (ioc->reply_post_queue_depth % 16); -+ -+ if (ioc->reply_post_queue_depth > -+ facts->MaxReplyDescriptorPostQueueDepth) { -+ ioc->reply_post_queue_depth = -+ facts->MaxReplyDescriptorPostQueueDepth - -+ (facts->MaxReplyDescriptorPostQueueDepth % 16); -+ ioc->hba_queue_depth = -+ ((ioc->reply_post_queue_depth - 64) / 2) - 1; -+ ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; -+ } -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "scatter gather: " \ -+ "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " -+ "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message, -+ ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize, -+ ioc->chains_needed_per_io)); -+ -+ /* reply post queue, 16 byte align */ -+ reply_post_free_sz = ioc->reply_post_queue_depth * -+ sizeof(Mpi2DefaultReplyDescriptor_t); -+ -+ sz = reply_post_free_sz; -+ if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable) -+ sz *= ioc->reply_queue_count; -+ -+ ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ? -+ (ioc->reply_queue_count):1, -+ sizeof(struct reply_post_struct), GFP_KERNEL); -+ -+ if (!ioc->reply_post) { -+ pr_err(MPT3SAS_FMT "reply_post_free pool: kcalloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool", -+ ioc->pdev, sz, 16, 0); -+ if (!ioc->reply_post_free_dma_pool) { -+ pr_err(MPT3SAS_FMT -+ "reply_post_free pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ i = 0; -+ do { -+ ioc->reply_post[i].reply_post_free = -+ pci_pool_alloc(ioc->reply_post_free_dma_pool, -+ GFP_KERNEL, -+ &ioc->reply_post[i].reply_post_free_dma); -+ if (!ioc->reply_post[i].reply_post_free) { -+ pr_err(MPT3SAS_FMT -+ "reply_post_free pool: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ memset(ioc->reply_post[i].reply_post_free, 0, sz); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply post free pool (0x%p): depth(%d)," -+ "element_size(%d), pool_size(%d kB)\n", ioc->name, -+ ioc->reply_post[i].reply_post_free, -+ ioc->reply_post_queue_depth, 8, sz/1024)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_post_free_dma = (0x%llx)\n", ioc->name, -+ (unsigned long long) -+ ioc->reply_post[i].reply_post_free_dma)); -+ total_sz += sz; -+ } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count)); -+ -+ if (ioc->dma_mask == 64) { -+ if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) { -+ pr_warn(MPT3SAS_FMT -+ "no suitable consistent DMA mask for %s\n", -+ ioc->name, pci_name(ioc->pdev)); -+ goto out; -+ } -+ } -+ -+ ioc->scsiio_depth = ioc->hba_queue_depth - -+ ioc->hi_priority_depth - ioc->internal_depth; -+ -+ /* set the scsi host can_queue depth -+ * with some internal commands that could be outstanding -+ */ -+ ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT; -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "scsi host: can_queue depth (%d)\n", -+ ioc->name, ioc->shost->can_queue)); -+ -+ -+ /* contiguous pool for request and chains, 16 byte align, one extra " -+ * "frame for smid=0 -+ */ -+ ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; -+ sz = ((ioc->scsiio_depth + 1) * ioc->request_sz); -+ -+ /* hi-priority queue */ -+ sz += (ioc->hi_priority_depth * ioc->request_sz); -+ -+ /* internal queue */ -+ sz += (ioc->internal_depth * ioc->request_sz); -+ -+ ioc->request_dma_sz = sz; -+ ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma); -+ if (!ioc->request) { -+ pr_err(MPT3SAS_FMT "request pool: pci_alloc_consistent " \ -+ "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " -+ "total(%d kB)\n", ioc->name, ioc->hba_queue_depth, -+ ioc->chains_needed_per_io, ioc->request_sz, sz/1024); -+ if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH) -+ goto out; -+ retry_sz = 64; -+ ioc->hba_queue_depth -= retry_sz; -+ _base_release_memory_pools(ioc); -+ goto retry_allocation; -+ } -+ -+ if (retry_sz) -+ pr_err(MPT3SAS_FMT "request pool: pci_alloc_consistent " \ -+ "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " -+ "total(%d kb)\n", ioc->name, ioc->hba_queue_depth, -+ ioc->chains_needed_per_io, ioc->request_sz, sz/1024); -+ -+ /* hi-priority queue */ -+ ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * -+ ioc->request_sz); -+ ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) * -+ ioc->request_sz); -+ -+ /* internal queue */ -+ ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth * -+ ioc->request_sz); -+ ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * -+ ioc->request_sz); -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "request pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n", -+ ioc->name, ioc->request, ioc->hba_queue_depth, ioc->request_sz, -+ (ioc->hba_queue_depth * ioc->request_sz)/1024)); -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "request pool: dma(0x%llx)\n", -+ ioc->name, (unsigned long long) ioc->request_dma)); -+ total_sz += sz; -+ -+ sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker); -+ ioc->scsi_lookup_pages = get_order(sz); -+ ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages( -+ GFP_KERNEL, ioc->scsi_lookup_pages); -+ if (!ioc->scsi_lookup) { -+ pr_err(MPT3SAS_FMT "scsi_lookup: get_free_pages failed, sz(%d)\n", -+ ioc->name, (int)sz); -+ goto out; -+ } -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "scsiio(0x%p): depth(%d)\n", -+ ioc->name, ioc->request, ioc->scsiio_depth)); -+ -+ ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); -+ sz = ioc->chain_depth * sizeof(struct chain_tracker); -+ ioc->chain_pages = get_order(sz); -+ ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( -+ GFP_KERNEL, ioc->chain_pages); -+ if (!ioc->chain_lookup) { -+ pr_err(MPT3SAS_FMT "chain_lookup: __get_free_pages failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, -+ ioc->chain_segment_sz, 16, 0); -+ if (!ioc->chain_dma_pool) { -+ pr_err(MPT3SAS_FMT "chain_dma_pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ for (i = 0; i < ioc->chain_depth; i++) { -+ ioc->chain_lookup[i].chain_buffer = pci_pool_alloc( -+ ioc->chain_dma_pool , GFP_KERNEL, -+ &ioc->chain_lookup[i].chain_buffer_dma); -+ if (!ioc->chain_lookup[i].chain_buffer) { -+ ioc->chain_depth = i; -+ goto chain_done; -+ } -+ total_sz += ioc->chain_segment_sz; -+ } -+ chain_done: -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n", -+ ioc->name, ioc->chain_depth, ioc->chain_segment_sz, -+ ((ioc->chain_depth * ioc->chain_segment_sz))/1024)); -+ -+ /* initialize hi-priority queue smid's */ -+ ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, -+ sizeof(struct request_tracker), GFP_KERNEL); -+ if (!ioc->hpr_lookup) { -+ pr_err(MPT3SAS_FMT "hpr_lookup: kcalloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->hi_priority_smid = ioc->scsiio_depth + 1; -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "hi_priority(0x%p): depth(%d), start smid(%d)\n", -+ ioc->name, ioc->hi_priority, -+ ioc->hi_priority_depth, ioc->hi_priority_smid)); -+ -+ /* initialize internal queue smid's */ -+ ioc->internal_lookup = kcalloc(ioc->internal_depth, -+ sizeof(struct request_tracker), GFP_KERNEL); -+ if (!ioc->internal_lookup) { -+ pr_err(MPT3SAS_FMT "internal_lookup: kcalloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "internal(0x%p): depth(%d), start smid(%d)\n", -+ ioc->name, ioc->internal, -+ ioc->internal_depth, ioc->internal_smid)); -+ -+ /* sense buffers, 4 byte align */ -+ sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE; -+ ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4, -+ 0); -+ if (!ioc->sense_dma_pool) { -+ pr_err(MPT3SAS_FMT "sense pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL, -+ &ioc->sense_dma); -+ if (!ioc->sense) { -+ pr_err(MPT3SAS_FMT "sense pool: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "sense pool(0x%p): depth(%d), element_size(%d), pool_size" -+ "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth, -+ SCSI_SENSE_BUFFERSIZE, sz/1024)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "sense_dma(0x%llx)\n", -+ ioc->name, (unsigned long long)ioc->sense_dma)); -+ total_sz += sz; -+ -+ /* reply pool, 4 byte align */ -+ sz = ioc->reply_free_queue_depth * ioc->reply_sz; -+ ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4, -+ 0); -+ if (!ioc->reply_dma_pool) { -+ pr_err(MPT3SAS_FMT "reply pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL, -+ &ioc->reply_dma); -+ if (!ioc->reply) { -+ pr_err(MPT3SAS_FMT "reply pool: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->reply_dma_min_address = (u32)(ioc->reply_dma); -+ ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz; -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n", -+ ioc->name, ioc->reply, -+ ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply_dma(0x%llx)\n", -+ ioc->name, (unsigned long long)ioc->reply_dma)); -+ total_sz += sz; -+ -+ /* reply free queue, 16 byte align */ -+ sz = ioc->reply_free_queue_depth * 4; -+ ioc->reply_free_dma_pool = pci_pool_create("reply_free pool", -+ ioc->pdev, sz, 16, 0); -+ if (!ioc->reply_free_dma_pool) { -+ pr_err(MPT3SAS_FMT "reply_free pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL, -+ &ioc->reply_free_dma); -+ if (!ioc->reply_free) { -+ pr_err(MPT3SAS_FMT "reply_free pool: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ memset(ioc->reply_free, 0, sz); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply_free pool(0x%p): " \ -+ "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name, -+ ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_free_dma (0x%llx)\n", -+ ioc->name, (unsigned long long)ioc->reply_free_dma)); -+ total_sz += sz; -+ -+ ioc->config_page_sz = 512; -+ ioc->config_page = pci_alloc_consistent(ioc->pdev, -+ ioc->config_page_sz, &ioc->config_page_dma); -+ if (!ioc->config_page) { -+ pr_err(MPT3SAS_FMT -+ "config page: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "config page(0x%p): size(%d)\n", -+ ioc->name, ioc->config_page, ioc->config_page_sz)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "config_page_dma(0x%llx)\n", -+ ioc->name, (unsigned long long)ioc->config_page_dma)); -+ total_sz += ioc->config_page_sz; -+ -+ pr_info(MPT3SAS_FMT "Allocated physical memory: size(%d kB)\n", -+ ioc->name, total_sz/1024); -+ pr_info(MPT3SAS_FMT -+ "Current Controller Queue Depth(%d),Max Controller Queue Depth(%d)\n", -+ ioc->name, ioc->shost->can_queue, facts->RequestCredit); -+ pr_info(MPT3SAS_FMT "Scatter Gather Elements per IO(%d)\n", -+ ioc->name, ioc->shost->sg_tablesize); -+ return 0; -+ -+ out: -+ return -ENOMEM; -+} -+ -+/** -+ * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter. -+ * @ioc: Pointer to MPT_ADAPTER structure -+ * @cooked: Request raw or cooked IOC state -+ * -+ * Returns all IOC Doorbell register bits if cooked==0, else just the -+ * Doorbell bits in MPI_IOC_STATE_MASK. -+ */ -+u32 -+mpt2sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked) -+{ -+ u32 s, sc; -+ -+ s = readl(&ioc->chip->Doorbell); -+ sc = s & MPI2_IOC_STATE_MASK; -+ return cooked ? sc : s; -+} -+ -+/** -+ * _base_wait_on_iocstate - waiting on a particular ioc state -+ * @ioc_state: controller state { READY, OPERATIONAL, or RESET } -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout, -+ int sleep_flag) -+{ -+ u32 count, cntdn; -+ u32 current_state; -+ -+ count = 0; -+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; -+ do { -+ current_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (current_state == ioc_state) -+ return 0; -+ if (count && current_state == MPI2_IOC_STATE_FAULT) -+ break; -+ if (sleep_flag == CAN_SLEEP) -+ usleep_range(1000, 1500); -+ else -+ udelay(500); -+ count++; -+ } while (--cntdn); -+ -+ return current_state; -+} -+ -+/** -+ * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by -+ * a write to the doorbell) -+ * @ioc: per adapter object -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. -+ */ -+static int -+_base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag); -+ -+static int -+_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout, -+ int sleep_flag) -+{ -+ u32 cntdn, count; -+ u32 int_status; -+ -+ count = 0; -+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; -+ do { -+ int_status = readl(&ioc->chip->HostInterruptStatus); -+ if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: successful count(%d), timeout(%d)\n", -+ ioc->name, __func__, count, timeout)); -+ return 0; -+ } -+ if (sleep_flag == CAN_SLEEP) -+ usleep_range(1000, 1500); -+ else -+ udelay(500); -+ count++; -+ } while (--cntdn); -+ -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to timeout count(%d), int_status(%x)!\n", -+ ioc->name, __func__, count, int_status); -+ return -EFAULT; -+} -+ -+/** -+ * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell. -+ * @ioc: per adapter object -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to -+ * doorbell. -+ */ -+static int -+_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout, -+ int sleep_flag) -+{ -+ u32 cntdn, count; -+ u32 int_status; -+ u32 doorbell; -+ -+ count = 0; -+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; -+ do { -+ int_status = readl(&ioc->chip->HostInterruptStatus); -+ if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: successful count(%d), timeout(%d)\n", -+ ioc->name, __func__, count, timeout)); -+ return 0; -+ } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { -+ doorbell = readl(&ioc->chip->Doorbell); -+ if ((doorbell & MPI2_IOC_STATE_MASK) == -+ MPI2_IOC_STATE_FAULT) { -+ mpt2sas_base_fault_info(ioc , doorbell); -+ return -EFAULT; -+ } -+ } else if (int_status == 0xFFFFFFFF) -+ goto out; -+ -+ if (sleep_flag == CAN_SLEEP) -+ usleep_range(1000, 1500); -+ else -+ udelay(500); -+ count++; -+ } while (--cntdn); -+ -+ out: -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to timeout count(%d), int_status(%x)!\n", -+ ioc->name, __func__, count, int_status); -+ return -EFAULT; -+} -+ -+/** -+ * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use -+ * @ioc: per adapter object -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ */ -+static int -+_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout, -+ int sleep_flag) -+{ -+ u32 cntdn, count; -+ u32 doorbell_reg; -+ -+ count = 0; -+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; -+ do { -+ doorbell_reg = readl(&ioc->chip->Doorbell); -+ if (!(doorbell_reg & MPI2_DOORBELL_USED)) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: successful count(%d), timeout(%d)\n", -+ ioc->name, __func__, count, timeout)); -+ return 0; -+ } -+ if (sleep_flag == CAN_SLEEP) -+ usleep_range(1000, 1500); -+ else -+ udelay(500); -+ count++; -+ } while (--cntdn); -+ -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n", -+ ioc->name, __func__, count, doorbell_reg); -+ return -EFAULT; -+} -+ -+/** -+ * _base_send_ioc_reset - send doorbell reset -+ * @ioc: per adapter object -+ * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout, -+ int sleep_flag) -+{ -+ u32 ioc_state; -+ int r = 0; -+ -+ if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) { -+ pr_err(MPT3SAS_FMT "%s: unknown reset_type\n", -+ ioc->name, __func__); -+ return -EFAULT; -+ } -+ -+ if (!(ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY)) -+ return -EFAULT; -+ -+ pr_info(MPT3SAS_FMT "sending message unit reset !!\n", ioc->name); -+ -+ writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT, -+ &ioc->chip->Doorbell); -+ if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) { -+ r = -EFAULT; -+ goto out; -+ } -+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, -+ timeout, sleep_flag); -+ if (ioc_state) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed going to ready state (ioc_state=0x%x)\n", -+ ioc->name, __func__, ioc_state); -+ r = -EFAULT; -+ goto out; -+ } -+ out: -+ pr_info(MPT3SAS_FMT "message unit reset: %s\n", -+ ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); -+ return r; -+} -+ -+/** -+ * _base_handshake_req_reply_wait - send request thru doorbell interface -+ * @ioc: per adapter object -+ * @request_bytes: request length -+ * @request: pointer having request payload -+ * @reply_bytes: reply length -+ * @reply: pointer to reply payload -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, -+ u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag) -+{ -+ MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply; -+ int i; -+ u8 failed; -+ u16 dummy; -+ __le32 *mfp; -+ -+ /* make sure doorbell is not in use */ -+ if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { -+ pr_err(MPT3SAS_FMT -+ "doorbell is in use (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ -+ /* clear pending doorbell interrupts from previous state changes */ -+ if (readl(&ioc->chip->HostInterruptStatus) & -+ MPI2_HIS_IOC2SYS_DB_STATUS) -+ writel(0, &ioc->chip->HostInterruptStatus); -+ -+ /* send message to ioc */ -+ writel(((MPI2_FUNCTION_HANDSHAKE<chip->Doorbell); -+ -+ if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake int failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ writel(0, &ioc->chip->HostInterruptStatus); -+ -+ if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake ack failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ -+ /* send message 32-bits at a time */ -+ for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) { -+ writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell); -+ if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) -+ failed = 1; -+ } -+ -+ if (failed) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake sending request failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ -+ /* now wait for the reply */ -+ if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake int failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ -+ /* read the first two 16-bits, it gives the total length of the reply */ -+ reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell) -+ & MPI2_DOORBELL_DATA_MASK); -+ writel(0, &ioc->chip->HostInterruptStatus); -+ if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake int failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell) -+ & MPI2_DOORBELL_DATA_MASK); -+ writel(0, &ioc->chip->HostInterruptStatus); -+ -+ for (i = 2; i < default_reply->MsgLength * 2; i++) { -+ if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake int failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ if (i >= reply_bytes/2) /* overflow case */ -+ dummy = readl(&ioc->chip->Doorbell); -+ else -+ reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell) -+ & MPI2_DOORBELL_DATA_MASK); -+ writel(0, &ioc->chip->HostInterruptStatus); -+ } -+ -+ _base_wait_for_doorbell_int(ioc, 5, sleep_flag); -+ if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "doorbell is in use (line=%d)\n", ioc->name, __LINE__)); -+ } -+ writel(0, &ioc->chip->HostInterruptStatus); -+ -+ if (ioc->logging_level & MPT_DEBUG_INIT) { -+ mfp = (__le32 *)reply; -+ pr_info("\toffset:data\n"); -+ for (i = 0; i < reply_bytes/4; i++) -+ pr_info("\t[0x%02x]:%08x\n", i*4, -+ le32_to_cpu(mfp[i])); -+ } -+ return 0; -+} -+ -+/** -+ * mpt2sas_base_sas_iounit_control - send sas iounit control to FW -+ * @ioc: per adapter object -+ * @mpi_reply: the reply payload from FW -+ * @mpi_request: the request payload sent to FW -+ * -+ * The SAS IO Unit Control Request message allows the host to perform low-level -+ * operations, such as resets on the PHYs of the IO Unit, also allows the host -+ * to obtain the IOC assigned device handles for a device if it has other -+ * identifying information about the device, in addition allows the host to -+ * remove IOC resources associated with the device. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2SasIoUnitControlReply_t *mpi_reply, -+ Mpi2SasIoUnitControlRequest_t *mpi_request) -+{ -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ bool issue_reset = false; -+ int rc; -+ void *request; -+ u16 wait_state_count; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ mutex_lock(&ioc->base_cmds.mutex); -+ -+ if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: base_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ ioc->base_cmds.status = MPT3_CMD_PENDING; -+ request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->base_cmds.smid = smid; -+ memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)); -+ if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || -+ mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) -+ ioc->ioc_link_reset_in_progress = 1; -+ init_completion(&ioc->base_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, -+ msecs_to_jiffies(10000)); -+ if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || -+ mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) && -+ ioc->ioc_link_reset_in_progress) -+ ioc->ioc_link_reset_in_progress = 0; -+ if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SasIoUnitControlRequest_t)/4); -+ if (!(ioc->base_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = true; -+ goto issue_host_reset; -+ } -+ if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) -+ memcpy(mpi_reply, ioc->base_cmds.reply, -+ sizeof(Mpi2SasIoUnitControlReply_t)); -+ else -+ memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t)); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ goto out; -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ rc = -EFAULT; -+ out: -+ mutex_unlock(&ioc->base_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * mpt2sas_base_scsi_enclosure_processor - sending request to sep device -+ * @ioc: per adapter object -+ * @mpi_reply: the reply payload from FW -+ * @mpi_request: the request payload sent to FW -+ * -+ * The SCSI Enclosure Processor request message causes the IOC to -+ * communicate with SES devices to control LED status signals. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request) -+{ -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ bool issue_reset = false; -+ int rc; -+ void *request; -+ u16 wait_state_count; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ mutex_lock(&ioc->base_cmds.mutex); -+ -+ if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: base_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, -+ __func__, wait_state_count); -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ ioc->base_cmds.status = MPT3_CMD_PENDING; -+ request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->base_cmds.smid = smid; -+ memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); -+ init_completion(&ioc->base_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, -+ msecs_to_jiffies(10000)); -+ if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SepRequest_t)/4); -+ if (!(ioc->base_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = false; -+ goto issue_host_reset; -+ } -+ if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) -+ memcpy(mpi_reply, ioc->base_cmds.reply, -+ sizeof(Mpi2SepReply_t)); -+ else -+ memset(mpi_reply, 0, sizeof(Mpi2SepReply_t)); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ goto out; -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ rc = -EFAULT; -+ out: -+ mutex_unlock(&ioc->base_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * _base_get_port_facts - obtain port facts reply and save in ioc -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port, int sleep_flag) -+{ -+ Mpi2PortFactsRequest_t mpi_request; -+ Mpi2PortFactsReply_t mpi_reply; -+ struct mpt2sas_port_facts *pfacts; -+ int mpi_reply_sz, mpi_request_sz, r; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); -+ mpi_request_sz = sizeof(Mpi2PortFactsRequest_t); -+ memset(&mpi_request, 0, mpi_request_sz); -+ mpi_request.Function = MPI2_FUNCTION_PORT_FACTS; -+ mpi_request.PortNumber = port; -+ r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, -+ (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); -+ -+ if (r != 0) { -+ pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", -+ ioc->name, __func__, r); -+ return r; -+ } -+ -+ pfacts = &ioc->pfacts[port]; -+ memset(pfacts, 0, sizeof(struct mpt2sas_port_facts)); -+ pfacts->PortNumber = mpi_reply.PortNumber; -+ pfacts->VP_ID = mpi_reply.VP_ID; -+ pfacts->VF_ID = mpi_reply.VF_ID; -+ pfacts->MaxPostedCmdBuffers = -+ le16_to_cpu(mpi_reply.MaxPostedCmdBuffers); -+ -+ return 0; -+} -+ -+/** -+ * _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL -+ * @ioc: per adapter object -+ * @timeout: -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout, -+ int sleep_flag) -+{ -+ u32 ioc_state; -+ int rc; -+ -+ dinitprintk(ioc, printk(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ if (ioc->pci_error_recovery) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "%s: host in pci error recovery\n", ioc->name, __func__)); -+ return -EFAULT; -+ } -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ dhsprintk(ioc, printk(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n", -+ ioc->name, __func__, ioc_state)); -+ -+ if (((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) || -+ (ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) -+ return 0; -+ -+ if (ioc_state & MPI2_DOORBELL_USED) { -+ dhsprintk(ioc, printk(MPT3SAS_FMT -+ "unexpected doorbell active!\n", ioc->name)); -+ goto issue_diag_reset; -+ } -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { -+ mpt2sas_base_fault_info(ioc, ioc_state & -+ MPI2_DOORBELL_DATA_MASK); -+ goto issue_diag_reset; -+ } -+ -+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, -+ timeout, sleep_flag); -+ if (ioc_state) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "%s: failed going to ready state (ioc_state=0x%x)\n", -+ ioc->name, __func__, ioc_state)); -+ return -EFAULT; -+ } -+ -+ issue_diag_reset: -+ rc = _base_diag_reset(ioc, sleep_flag); -+ return rc; -+} -+ -+/** -+ * _base_get_ioc_facts - obtain ioc facts reply and save in ioc -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ Mpi2IOCFactsRequest_t mpi_request; -+ Mpi2IOCFactsReply_t mpi_reply; -+ struct mpt2sas_facts *facts; -+ int mpi_reply_sz, mpi_request_sz, r; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ r = _base_wait_for_iocstate(ioc, 10, sleep_flag); -+ if (r) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "%s: failed getting to correct state\n", -+ ioc->name, __func__)); -+ return r; -+ } -+ mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); -+ mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t); -+ memset(&mpi_request, 0, mpi_request_sz); -+ mpi_request.Function = MPI2_FUNCTION_IOC_FACTS; -+ r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, -+ (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); -+ -+ if (r != 0) { -+ pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", -+ ioc->name, __func__, r); -+ return r; -+ } -+ -+ facts = &ioc->facts; -+ memset(facts, 0, sizeof(struct mpt2sas_facts)); -+ facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion); -+ facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion); -+ facts->VP_ID = mpi_reply.VP_ID; -+ facts->VF_ID = mpi_reply.VF_ID; -+ facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions); -+ facts->MaxChainDepth = mpi_reply.MaxChainDepth; -+ facts->WhoInit = mpi_reply.WhoInit; -+ facts->NumberOfPorts = mpi_reply.NumberOfPorts; -+ facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors; -+ facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit); -+ facts->MaxReplyDescriptorPostQueueDepth = -+ le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); -+ facts->ProductID = le16_to_cpu(mpi_reply.ProductID); -+ facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities); -+ if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)) -+ ioc->ir_firmware = 1; -+ if ((facts->IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE)) -+ ioc->rdpq_array_capable = 1; -+ facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); -+ facts->IOCRequestFrameSize = -+ le16_to_cpu(mpi_reply.IOCRequestFrameSize); -+ if (ioc->hba_mpi_version_belonged != MPI2_VERSION) { -+ facts->IOCMaxChainSegmentSize = -+ le16_to_cpu(mpi_reply.IOCMaxChainSegmentSize); -+ } -+ facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators); -+ facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets); -+ ioc->shost->max_id = -1; -+ facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders); -+ facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures); -+ facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags); -+ facts->HighPriorityCredit = -+ le16_to_cpu(mpi_reply.HighPriorityCredit); -+ facts->ReplyFrameSize = mpi_reply.ReplyFrameSize; -+ facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle); -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "hba queue depth(%d), max chains per io(%d)\n", -+ ioc->name, facts->RequestCredit, -+ facts->MaxChainDepth)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "request frame size(%d), reply frame size(%d)\n", ioc->name, -+ facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4)); -+ return 0; -+} -+ -+/** -+ * _base_send_ioc_init - send ioc_init to firmware -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ Mpi2IOCInitRequest_t mpi_request; -+ Mpi2IOCInitReply_t mpi_reply; -+ int i, r = 0; -+ ktime_t current_time; -+ u16 ioc_status; -+ u32 reply_post_free_array_sz = 0; -+ Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL; -+ dma_addr_t reply_post_free_array_dma; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_IOC_INIT; -+ mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; -+ mpi_request.VF_ID = 0; /* TODO */ -+ mpi_request.VP_ID = 0; -+ mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged); -+ mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); -+ -+ if (_base_is_controller_msix_enabled(ioc)) -+ mpi_request.HostMSIxVectors = ioc->reply_queue_count; -+ mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); -+ mpi_request.ReplyDescriptorPostQueueDepth = -+ cpu_to_le16(ioc->reply_post_queue_depth); -+ mpi_request.ReplyFreeQueueDepth = -+ cpu_to_le16(ioc->reply_free_queue_depth); -+ -+ mpi_request.SenseBufferAddressHigh = -+ cpu_to_le32((u64)ioc->sense_dma >> 32); -+ mpi_request.SystemReplyAddressHigh = -+ cpu_to_le32((u64)ioc->reply_dma >> 32); -+ mpi_request.SystemRequestFrameBaseAddress = -+ cpu_to_le64((u64)ioc->request_dma); -+ mpi_request.ReplyFreeQueueAddress = -+ cpu_to_le64((u64)ioc->reply_free_dma); -+ -+ if (ioc->rdpq_array_enable) { -+ reply_post_free_array_sz = ioc->reply_queue_count * -+ sizeof(Mpi2IOCInitRDPQArrayEntry); -+ reply_post_free_array = pci_alloc_consistent(ioc->pdev, -+ reply_post_free_array_sz, &reply_post_free_array_dma); -+ if (!reply_post_free_array) { -+ pr_err(MPT3SAS_FMT -+ "reply_post_free_array: pci_alloc_consistent failed\n", -+ ioc->name); -+ r = -ENOMEM; -+ goto out; -+ } -+ memset(reply_post_free_array, 0, reply_post_free_array_sz); -+ for (i = 0; i < ioc->reply_queue_count; i++) -+ reply_post_free_array[i].RDPQBaseAddress = -+ cpu_to_le64( -+ (u64)ioc->reply_post[i].reply_post_free_dma); -+ mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE; -+ mpi_request.ReplyDescriptorPostQueueAddress = -+ cpu_to_le64((u64)reply_post_free_array_dma); -+ } else { -+ mpi_request.ReplyDescriptorPostQueueAddress = -+ cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma); -+ } -+ -+ /* This time stamp specifies number of milliseconds -+ * since epoch ~ midnight January 1, 1970. -+ */ -+ current_time = ktime_get_real(); -+ mpi_request.TimeStamp = cpu_to_le64(ktime_to_ms(current_time)); -+ -+ if (ioc->logging_level & MPT_DEBUG_INIT) { -+ __le32 *mfp; -+ int i; -+ -+ mfp = (__le32 *)&mpi_request; -+ pr_info("\toffset:data\n"); -+ for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) -+ pr_info("\t[0x%02x]:%08x\n", i*4, -+ le32_to_cpu(mfp[i])); -+ } -+ -+ r = _base_handshake_req_reply_wait(ioc, -+ sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request, -+ sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10, -+ sleep_flag); -+ -+ if (r != 0) { -+ pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", -+ ioc->name, __func__, r); -+ goto out; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS || -+ mpi_reply.IOCLogInfo) { -+ pr_err(MPT3SAS_FMT "%s: failed\n", ioc->name, __func__); -+ r = -EIO; -+ } -+ -+out: -+ if (reply_post_free_array) -+ pci_free_consistent(ioc->pdev, reply_post_free_array_sz, -+ reply_post_free_array, -+ reply_post_free_array_dma); -+ return r; -+} -+ -+/** -+ * mpt2sas_port_enable_done - command completion routine for port enable -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ u16 ioc_status; -+ -+ if (ioc->port_enable_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (!mpi_reply) -+ return 1; -+ -+ if (mpi_reply->Function != MPI2_FUNCTION_PORT_ENABLE) -+ return 1; -+ -+ ioc->port_enable_cmds.status &= ~MPT3_CMD_PENDING; -+ ioc->port_enable_cmds.status |= MPT3_CMD_COMPLETE; -+ ioc->port_enable_cmds.status |= MPT3_CMD_REPLY_VALID; -+ memcpy(ioc->port_enable_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ ioc->port_enable_failed = 1; -+ -+ if (ioc->is_driver_loading) { -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ mpt2sas_port_enable_complete(ioc); -+ return 1; -+ } else { -+ ioc->start_scan_failed = ioc_status; -+ ioc->start_scan = 0; -+ return 1; -+ } -+ } -+ complete(&ioc->port_enable_cmds.done); -+ return 1; -+} -+ -+/** -+ * _base_send_port_enable - send port_enable(discovery stuff) to firmware -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_send_port_enable(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ Mpi2PortEnableRequest_t *mpi_request; -+ Mpi2PortEnableReply_t *mpi_reply; -+ unsigned long timeleft; -+ int r = 0; -+ u16 smid; -+ u16 ioc_status; -+ -+ pr_info(MPT3SAS_FMT "sending port enable !!\n", ioc->name); -+ -+ if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { -+ pr_err(MPT3SAS_FMT "%s: internal command already in use\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ ioc->port_enable_cmds.status = MPT3_CMD_PENDING; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->port_enable_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; -+ -+ init_completion(&ioc->port_enable_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done, -+ 300*HZ); -+ if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2PortEnableRequest_t)/4); -+ if (ioc->port_enable_cmds.status & MPT3_CMD_RESET) -+ r = -EFAULT; -+ else -+ r = -ETIME; -+ goto out; -+ } -+ -+ mpi_reply = ioc->port_enable_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "%s: failed with (ioc_status=0x%08x)\n", -+ ioc->name, __func__, ioc_status); -+ r = -EFAULT; -+ goto out; -+ } -+ -+ out: -+ ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; -+ pr_info(MPT3SAS_FMT "port enable: %s\n", ioc->name, ((r == 0) ? -+ "SUCCESS" : "FAILED")); -+ return r; -+} -+ -+/** -+ * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply) -+ * @ioc: per adapter object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_port_enable(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2PortEnableRequest_t *mpi_request; -+ u16 smid; -+ -+ pr_info(MPT3SAS_FMT "sending port enable !!\n", ioc->name); -+ -+ if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { -+ pr_err(MPT3SAS_FMT "%s: internal command already in use\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ ioc->port_enable_cmds.status = MPT3_CMD_PENDING; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->port_enable_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; -+ -+ mpt2sas_base_put_smid_default(ioc, smid); -+ return 0; -+} -+ -+/** -+ * _base_determine_wait_on_discovery - desposition -+ * @ioc: per adapter object -+ * -+ * Decide whether to wait on discovery to complete. Used to either -+ * locate boot device, or report volumes ahead of physical devices. -+ * -+ * Returns 1 for wait, 0 for don't wait -+ */ -+static int -+_base_determine_wait_on_discovery(struct MPT3SAS_ADAPTER *ioc) -+{ -+ /* We wait for discovery to complete if IR firmware is loaded. -+ * The sas topology events arrive before PD events, so we need time to -+ * turn on the bit in ioc->pd_handles to indicate PD -+ * Also, it maybe required to report Volumes ahead of physical -+ * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. -+ */ -+ if (ioc->ir_firmware) -+ return 1; -+ -+ /* if no Bios, then we don't need to wait */ -+ if (!ioc->bios_pg3.BiosVersion) -+ return 0; -+ -+ /* Bios is present, then we drop down here. -+ * -+ * If there any entries in the Bios Page 2, then we wait -+ * for discovery to complete. -+ */ -+ -+ /* Current Boot Device */ -+ if ((ioc->bios_pg2.CurrentBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK) == -+ MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && -+ /* Request Boot Device */ -+ (ioc->bios_pg2.ReqBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK) == -+ MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && -+ /* Alternate Request Boot Device */ -+ (ioc->bios_pg2.ReqAltBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK) == -+ MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) -+ return 0; -+ -+ return 1; -+} -+ -+/** -+ * _base_unmask_events - turn on notification for this event -+ * @ioc: per adapter object -+ * @event: firmware event -+ * -+ * The mask is stored in ioc->event_masks. -+ */ -+static void -+_base_unmask_events(struct MPT3SAS_ADAPTER *ioc, u16 event) -+{ -+ u32 desired_event; -+ -+ if (event >= 128) -+ return; -+ -+ desired_event = (1 << (event % 32)); -+ -+ if (event < 32) -+ ioc->event_masks[0] &= ~desired_event; -+ else if (event < 64) -+ ioc->event_masks[1] &= ~desired_event; -+ else if (event < 96) -+ ioc->event_masks[2] &= ~desired_event; -+ else if (event < 128) -+ ioc->event_masks[3] &= ~desired_event; -+} -+ -+/** -+ * _base_event_notification - send event notification -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_event_notification(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ Mpi2EventNotificationRequest_t *mpi_request; -+ unsigned long timeleft; -+ u16 smid; -+ int r = 0; -+ int i; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ if (ioc->base_cmds.status & MPT3_CMD_PENDING) { -+ pr_err(MPT3SAS_FMT "%s: internal command already in use\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ ioc->base_cmds.status = MPT3_CMD_PENDING; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->base_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) -+ mpi_request->EventMasks[i] = -+ cpu_to_le32(ioc->event_masks[i]); -+ init_completion(&ioc->base_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); -+ if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2EventNotificationRequest_t)/4); -+ if (ioc->base_cmds.status & MPT3_CMD_RESET) -+ r = -EFAULT; -+ else -+ r = -ETIME; -+ } else -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s: complete\n", -+ ioc->name, __func__)); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ return r; -+} -+ -+/** -+ * mpt2sas_base_validate_event_type - validating event types -+ * @ioc: per adapter object -+ * @event: firmware event -+ * -+ * This will turn on firmware event notification when application -+ * ask for that event. We don't mask events that are already enabled. -+ */ -+void -+mpt2sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, u32 *event_type) -+{ -+ int i, j; -+ u32 event_mask, desired_event; -+ u8 send_update_to_fw; -+ -+ for (i = 0, send_update_to_fw = 0; i < -+ MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) { -+ event_mask = ~event_type[i]; -+ desired_event = 1; -+ for (j = 0; j < 32; j++) { -+ if (!(event_mask & desired_event) && -+ (ioc->event_masks[i] & desired_event)) { -+ ioc->event_masks[i] &= ~desired_event; -+ send_update_to_fw = 1; -+ } -+ desired_event = (desired_event << 1); -+ } -+ } -+ -+ if (!send_update_to_fw) -+ return; -+ -+ mutex_lock(&ioc->base_cmds.mutex); -+ _base_event_notification(ioc, CAN_SLEEP); -+ mutex_unlock(&ioc->base_cmds.mutex); -+} -+ -+/** -+ * _base_diag_reset - the "big hammer" start of day reset -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ u32 host_diagnostic; -+ u32 ioc_state; -+ u32 count; -+ u32 hcb_size; -+ -+ pr_info(MPT3SAS_FMT "sending diag reset !!\n", ioc->name); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT "clear interrupts\n", -+ ioc->name)); -+ -+ count = 0; -+ do { -+ /* Write magic sequence to WriteSequence register -+ * Loop until in diagnostic mode -+ */ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "write magic sequence\n", ioc->name)); -+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence); -+ -+ /* wait 100 msec */ -+ if (sleep_flag == CAN_SLEEP) -+ msleep(100); -+ else -+ mdelay(100); -+ -+ if (count++ > 20) -+ goto out; -+ -+ host_diagnostic = readl(&ioc->chip->HostDiagnostic); -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n", -+ ioc->name, count, host_diagnostic)); -+ -+ } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); -+ -+ hcb_size = readl(&ioc->chip->HCBSize); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT "diag reset: issued\n", -+ ioc->name)); -+ writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, -+ &ioc->chip->HostDiagnostic); -+ -+ /*This delay allows the chip PCIe hardware time to finish reset tasks*/ -+ if (sleep_flag == CAN_SLEEP) -+ msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); -+ else -+ mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); -+ -+ /* Approximately 300 second max wait */ -+ for (count = 0; count < (300000000 / -+ MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) { -+ -+ host_diagnostic = readl(&ioc->chip->HostDiagnostic); -+ -+ if (host_diagnostic == 0xFFFFFFFF) -+ goto out; -+ if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) -+ break; -+ -+ /* Wait to pass the second read delay window */ -+ if (sleep_flag == CAN_SLEEP) -+ msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC -+ / 1000); -+ else -+ mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC -+ / 1000); -+ } -+ -+ if (host_diagnostic & MPI2_DIAG_HCB_MODE) { -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "restart the adapter assuming the HCB Address points to good F/W\n", -+ ioc->name)); -+ host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; -+ host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; -+ writel(host_diagnostic, &ioc->chip->HostDiagnostic); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "re-enable the HCDW\n", ioc->name)); -+ writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, -+ &ioc->chip->HCBSize); -+ } -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT "restart the adapter\n", -+ ioc->name)); -+ writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, -+ &ioc->chip->HostDiagnostic); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "disable writes to the diagnostic register\n", ioc->name)); -+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "Wait for FW to go to the READY state\n", ioc->name)); -+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20, -+ sleep_flag); -+ if (ioc_state) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed going to ready state (ioc_state=0x%x)\n", -+ ioc->name, __func__, ioc_state); -+ goto out; -+ } -+ -+ pr_info(MPT3SAS_FMT "diag reset: SUCCESS\n", ioc->name); -+ return 0; -+ -+ out: -+ pr_err(MPT3SAS_FMT "diag reset: FAILED\n", ioc->name); -+ return -EFAULT; -+} -+ -+/** -+ * _base_make_ioc_ready - put controller in READY state -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * @type: FORCE_BIG_HAMMER or SOFT_RESET -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, int sleep_flag, -+ enum reset_type type) -+{ -+ u32 ioc_state; -+ int rc; -+ int count; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ if (ioc->pci_error_recovery) -+ return 0; -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n", -+ ioc->name, __func__, ioc_state)); -+ -+ /* if in RESET state, it should move to READY state shortly */ -+ count = 0; -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_RESET) { -+ while ((ioc_state & MPI2_IOC_STATE_MASK) != -+ MPI2_IOC_STATE_READY) { -+ if (count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed going to ready state (ioc_state=0x%x)\n", -+ ioc->name, __func__, ioc_state); -+ return -EFAULT; -+ } -+ if (sleep_flag == CAN_SLEEP) -+ ssleep(1); -+ else -+ mdelay(1000); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ } -+ } -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) -+ return 0; -+ -+ if (ioc_state & MPI2_DOORBELL_USED) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "unexpected doorbell active!\n", -+ ioc->name)); -+ goto issue_diag_reset; -+ } -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { -+ mpt2sas_base_fault_info(ioc, ioc_state & -+ MPI2_DOORBELL_DATA_MASK); -+ goto issue_diag_reset; -+ } -+ -+ if (type == FORCE_BIG_HAMMER) -+ goto issue_diag_reset; -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) -+ if (!(_base_send_ioc_reset(ioc, -+ MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) { -+ return 0; -+ } -+ -+ issue_diag_reset: -+ rc = _base_diag_reset(ioc, CAN_SLEEP); -+ return rc; -+} -+ -+/** -+ * _base_make_ioc_operational - put controller in OPERATIONAL state -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ int r, i, index; -+ unsigned long flags; -+ u32 reply_address; -+ u16 smid; -+ struct _tr_list *delayed_tr, *delayed_tr_next; -+ struct _sc_list *delayed_sc, *delayed_sc_next; -+ struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next; -+ u8 hide_flag; -+ struct adapter_reply_queue *reply_q; -+ Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ /* clean the delayed target reset list */ -+ list_for_each_entry_safe(delayed_tr, delayed_tr_next, -+ &ioc->delayed_tr_list, list) { -+ list_del(&delayed_tr->list); -+ kfree(delayed_tr); -+ } -+ -+ -+ list_for_each_entry_safe(delayed_tr, delayed_tr_next, -+ &ioc->delayed_tr_volume_list, list) { -+ list_del(&delayed_tr->list); -+ kfree(delayed_tr); -+ } -+ -+ list_for_each_entry_safe(delayed_sc, delayed_sc_next, -+ &ioc->delayed_sc_list, list) { -+ list_del(&delayed_sc->list); -+ kfree(delayed_sc); -+ } -+ -+ list_for_each_entry_safe(delayed_event_ack, delayed_event_ack_next, -+ &ioc->delayed_event_ack_list, list) { -+ list_del(&delayed_event_ack->list); -+ kfree(delayed_event_ack); -+ } -+ -+ /* initialize the scsi lookup free list */ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ INIT_LIST_HEAD(&ioc->free_list); -+ smid = 1; -+ for (i = 0; i < ioc->scsiio_depth; i++, smid++) { -+ INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); -+ ioc->scsi_lookup[i].cb_idx = 0xFF; -+ ioc->scsi_lookup[i].smid = smid; -+ ioc->scsi_lookup[i].scmd = NULL; -+ ioc->scsi_lookup[i].direct_io = 0; -+ list_add_tail(&ioc->scsi_lookup[i].tracker_list, -+ &ioc->free_list); -+ } -+ -+ /* hi-priority queue */ -+ INIT_LIST_HEAD(&ioc->hpr_free_list); -+ smid = ioc->hi_priority_smid; -+ for (i = 0; i < ioc->hi_priority_depth; i++, smid++) { -+ ioc->hpr_lookup[i].cb_idx = 0xFF; -+ ioc->hpr_lookup[i].smid = smid; -+ list_add_tail(&ioc->hpr_lookup[i].tracker_list, -+ &ioc->hpr_free_list); -+ } -+ -+ /* internal queue */ -+ INIT_LIST_HEAD(&ioc->internal_free_list); -+ smid = ioc->internal_smid; -+ for (i = 0; i < ioc->internal_depth; i++, smid++) { -+ ioc->internal_lookup[i].cb_idx = 0xFF; -+ ioc->internal_lookup[i].smid = smid; -+ list_add_tail(&ioc->internal_lookup[i].tracker_list, -+ &ioc->internal_free_list); -+ } -+ -+ /* chain pool */ -+ INIT_LIST_HEAD(&ioc->free_chain_list); -+ for (i = 0; i < ioc->chain_depth; i++) -+ list_add_tail(&ioc->chain_lookup[i].tracker_list, -+ &ioc->free_chain_list); -+ -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ /* initialize Reply Free Queue */ -+ for (i = 0, reply_address = (u32)ioc->reply_dma ; -+ i < ioc->reply_free_queue_depth ; i++, reply_address += -+ ioc->reply_sz) -+ ioc->reply_free[i] = cpu_to_le32(reply_address); -+ -+ /* initialize reply queues */ -+ if (ioc->is_driver_loading) -+ _base_assign_reply_queues(ioc); -+ -+ /* initialize Reply Post Free Queue */ -+ index = 0; -+ reply_post_free_contig = ioc->reply_post[0].reply_post_free; -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { -+ /* -+ * If RDPQ is enabled, switch to the next allocation. -+ * Otherwise advance within the contiguous region. -+ */ -+ if (ioc->rdpq_array_enable) { -+ reply_q->reply_post_free = -+ ioc->reply_post[index++].reply_post_free; -+ } else { -+ reply_q->reply_post_free = reply_post_free_contig; -+ reply_post_free_contig += ioc->reply_post_queue_depth; -+ } -+ -+ reply_q->reply_post_host_index = 0; -+ for (i = 0; i < ioc->reply_post_queue_depth; i++) -+ reply_q->reply_post_free[i].Words = -+ cpu_to_le64(ULLONG_MAX); -+ if (!_base_is_controller_msix_enabled(ioc)) -+ goto skip_init_reply_post_free_queue; -+ } -+ skip_init_reply_post_free_queue: -+ -+ r = _base_send_ioc_init(ioc, sleep_flag); -+ if (r) -+ return r; -+ -+ /* initialize reply free host index */ -+ ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; -+ writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); -+ -+ /* initialize reply post host index */ -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { -+ if (ioc->msix96_vector) -+ writel((reply_q->msix_index & 7)<< -+ MPI2_RPHI_MSIX_INDEX_SHIFT, -+ ioc->replyPostRegisterIndex[reply_q->msix_index/8]); -+ else -+ writel(reply_q->msix_index << -+ MPI2_RPHI_MSIX_INDEX_SHIFT, -+ &ioc->chip->ReplyPostHostIndex); -+ -+ if (!_base_is_controller_msix_enabled(ioc)) -+ goto skip_init_reply_post_host_index; -+ } -+ -+ skip_init_reply_post_host_index: -+ -+ _base_unmask_interrupts(ioc); -+ r = _base_event_notification(ioc, sleep_flag); -+ if (r) -+ return r; -+ -+ if (sleep_flag == CAN_SLEEP) -+ _base_static_config_pages(ioc); -+ -+ -+ if (ioc->is_driver_loading) { -+ -+ if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier -+ == 0x80) { -+ hide_flag = (u8) ( -+ le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & -+ MFG_PAGE10_HIDE_SSDS_MASK); -+ if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) -+ ioc->mfg_pg10_hide_flag = hide_flag; -+ } -+ -+ ioc->wait_for_discovery_to_complete = -+ _base_determine_wait_on_discovery(ioc); -+ -+ return r; /* scan_start and scan_finished support */ -+ } -+ -+ r = _base_send_port_enable(ioc, sleep_flag); -+ if (r) -+ return r; -+ -+ return r; -+} -+ -+/** -+ * mpt2sas_base_free_resources - free resources controller resources -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) -+{ -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ /* synchronizing freeing resource with pci_access_mutex lock */ -+ mutex_lock(&ioc->pci_access_mutex); -+ if (ioc->chip_phys && ioc->chip) { -+ _base_mask_interrupts(ioc); -+ ioc->shost_recovery = 1; -+ _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); -+ ioc->shost_recovery = 0; -+ } -+ -+ mpt2sas_base_unmap_resources(ioc); -+ mutex_unlock(&ioc->pci_access_mutex); -+ return; -+} -+ -+/** -+ * mpt2sas_base_attach - attach controller instance -+ * @ioc: per adapter object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_attach(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int r, i; -+ int cpu_id, last_cpu_id = 0; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ /* setup cpu_msix_table */ -+ ioc->cpu_count = num_online_cpus(); -+ for_each_online_cpu(cpu_id) -+ last_cpu_id = cpu_id; -+ ioc->cpu_msix_table_sz = last_cpu_id + 1; -+ ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); -+ ioc->reply_queue_count = 1; -+ if (!ioc->cpu_msix_table) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT -+ "allocation for cpu_msix_table failed!!!\n", -+ ioc->name)); -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ -+ if (ioc->is_warpdrive) { -+ ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, -+ sizeof(resource_size_t *), GFP_KERNEL); -+ if (!ioc->reply_post_host_index) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT "allocation " -+ "for cpu_msix_table failed!!!\n", ioc->name)); -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ } -+ -+ ioc->rdpq_array_enable_assigned = 0; -+ ioc->dma_mask = 0; -+ r = mpt2sas_base_map_resources(ioc); -+ if (r) -+ goto out_free_resources; -+ -+ if (ioc->is_warpdrive) { -+ ioc->reply_post_host_index[0] = (resource_size_t __iomem *) -+ &ioc->chip->ReplyPostHostIndex; -+ -+ for (i = 1; i < ioc->cpu_msix_table_sz; i++) -+ ioc->reply_post_host_index[i] = -+ (resource_size_t __iomem *) -+ ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) -+ * 4))); -+ } -+ -+ pci_set_drvdata(ioc->pdev, ioc->shost); -+ r = _base_get_ioc_facts(ioc, CAN_SLEEP); -+ if (r) -+ goto out_free_resources; -+ -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ ioc->build_sg_scmd = &_base_build_sg_scmd; -+ ioc->build_sg = &_base_build_sg; -+ ioc->build_zero_len_sge = &_base_build_zero_len_sge; -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ /* -+ * In SAS3.0, -+ * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and -+ * Target Status - all require the IEEE formated scatter gather -+ * elements. -+ */ -+ ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; -+ ioc->build_sg = &_base_build_sg_ieee; -+ ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; -+ ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); -+ break; -+ } -+ -+ /* -+ * These function pointers for other requests that don't -+ * the require IEEE scatter gather elements. -+ * -+ * For example Configuration Pages and SAS IOUNIT Control don't. -+ */ -+ ioc->build_sg_mpi = &_base_build_sg; -+ ioc->build_zero_len_sge_mpi = &_base_build_zero_len_sge; -+ -+ r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); -+ if (r) -+ goto out_free_resources; -+ -+ ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, -+ sizeof(struct mpt2sas_port_facts), GFP_KERNEL); -+ if (!ioc->pfacts) { -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ -+ for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { -+ r = _base_get_port_facts(ioc, i, CAN_SLEEP); -+ if (r) -+ goto out_free_resources; -+ } -+ -+ r = _base_allocate_memory_pools(ioc, CAN_SLEEP); -+ if (r) -+ goto out_free_resources; -+ -+ init_waitqueue_head(&ioc->reset_wq); -+ -+ /* allocate memory pd handle bitmask list */ -+ ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); -+ if (ioc->facts.MaxDevHandle % 8) -+ ioc->pd_handles_sz++; -+ ioc->pd_handles = kzalloc(ioc->pd_handles_sz, -+ GFP_KERNEL); -+ if (!ioc->pd_handles) { -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ ioc->blocking_handles = kzalloc(ioc->pd_handles_sz, -+ GFP_KERNEL); -+ if (!ioc->blocking_handles) { -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ -+ ioc->fwfault_debug = mpt2sas_fwfault_debug; -+ -+ /* base internal command bits */ -+ mutex_init(&ioc->base_cmds.mutex); -+ ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ -+ /* port_enable command bits */ -+ ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; -+ -+ /* transport internal command bits */ -+ ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->transport_cmds.mutex); -+ -+ /* scsih internal command bits */ -+ ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->scsih_cmds.mutex); -+ -+ /* task management internal command bits */ -+ ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->tm_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->tm_cmds.mutex); -+ -+ /* config page internal command bits */ -+ ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->config_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->config_cmds.mutex); -+ -+ /* ctl module internal command bits */ -+ ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->ctl_cmds.mutex); -+ -+ if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || -+ !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || -+ !ioc->config_cmds.reply || !ioc->ctl_cmds.reply || -+ !ioc->ctl_cmds.sense) { -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ -+ for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) -+ ioc->event_masks[i] = -1; -+ -+ /* here we enable the events we care about */ -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY); -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); -+ _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); -+ _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME); -+ _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); -+ _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); -+ _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); -+ _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD); -+ if (ioc->hba_mpi_version_belonged == MPI26_VERSION) -+ _base_unmask_events(ioc, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION); -+ -+ r = _base_make_ioc_operational(ioc, CAN_SLEEP); -+ if (r) -+ goto out_free_resources; -+ -+ ioc->non_operational_loop = 0; -+ return 0; -+ -+ out_free_resources: -+ -+ ioc->remove_host = 1; -+ -+ mpt2sas_base_free_resources(ioc); -+ _base_release_memory_pools(ioc); -+ pci_set_drvdata(ioc->pdev, NULL); -+ kfree(ioc->cpu_msix_table); -+ if (ioc->is_warpdrive) -+ kfree(ioc->reply_post_host_index); -+ kfree(ioc->pd_handles); -+ kfree(ioc->blocking_handles); -+ kfree(ioc->tm_cmds.reply); -+ kfree(ioc->transport_cmds.reply); -+ kfree(ioc->scsih_cmds.reply); -+ kfree(ioc->config_cmds.reply); -+ kfree(ioc->base_cmds.reply); -+ kfree(ioc->port_enable_cmds.reply); -+ kfree(ioc->ctl_cmds.reply); -+ kfree(ioc->ctl_cmds.sense); -+ kfree(ioc->pfacts); -+ ioc->ctl_cmds.reply = NULL; -+ ioc->base_cmds.reply = NULL; -+ ioc->tm_cmds.reply = NULL; -+ ioc->scsih_cmds.reply = NULL; -+ ioc->transport_cmds.reply = NULL; -+ ioc->config_cmds.reply = NULL; -+ ioc->pfacts = NULL; -+ return r; -+} -+ -+ -+/** -+ * mpt2sas_base_detach - remove controller instance -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_detach(struct MPT3SAS_ADAPTER *ioc) -+{ -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ mpt2sas_base_stop_watchdog(ioc); -+ mpt2sas_base_free_resources(ioc); -+ _base_release_memory_pools(ioc); -+ pci_set_drvdata(ioc->pdev, NULL); -+ kfree(ioc->cpu_msix_table); -+ if (ioc->is_warpdrive) -+ kfree(ioc->reply_post_host_index); -+ kfree(ioc->pd_handles); -+ kfree(ioc->blocking_handles); -+ kfree(ioc->pfacts); -+ kfree(ioc->ctl_cmds.reply); -+ kfree(ioc->ctl_cmds.sense); -+ kfree(ioc->base_cmds.reply); -+ kfree(ioc->port_enable_cmds.reply); -+ kfree(ioc->tm_cmds.reply); -+ kfree(ioc->transport_cmds.reply); -+ kfree(ioc->scsih_cmds.reply); -+ kfree(ioc->config_cmds.reply); -+} -+ -+/** -+ * _base_reset_handler - reset callback handler (for base) -+ * @ioc: per adapter object -+ * @reset_phase: phase -+ * -+ * The handler for doing any required cleanup or initialization. -+ * -+ * The reset phase can be MPT3_IOC_PRE_RESET, MPT3_IOC_AFTER_RESET, -+ * MPT3_IOC_DONE_RESET -+ * -+ * Return nothing. -+ */ -+static void -+_base_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) -+{ -+ mpt2sas_scsih_reset_handler(ioc, reset_phase); -+ mpt2sas_ctl_reset_handler(ioc, reset_phase); -+ switch (reset_phase) { -+ case MPT3_IOC_PRE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); -+ break; -+ case MPT3_IOC_AFTER_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); -+ if (ioc->transport_cmds.status & MPT3_CMD_PENDING) { -+ ioc->transport_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->transport_cmds.smid); -+ complete(&ioc->transport_cmds.done); -+ } -+ if (ioc->base_cmds.status & MPT3_CMD_PENDING) { -+ ioc->base_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid); -+ complete(&ioc->base_cmds.done); -+ } -+ if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { -+ ioc->port_enable_failed = 1; -+ ioc->port_enable_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); -+ if (ioc->is_driver_loading) { -+ ioc->start_scan_failed = -+ MPI2_IOCSTATUS_INTERNAL_ERROR; -+ ioc->start_scan = 0; -+ ioc->port_enable_cmds.status = -+ MPT3_CMD_NOT_USED; -+ } else -+ complete(&ioc->port_enable_cmds.done); -+ } -+ if (ioc->config_cmds.status & MPT3_CMD_PENDING) { -+ ioc->config_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); -+ ioc->config_cmds.smid = USHRT_MAX; -+ complete(&ioc->config_cmds.done); -+ } -+ break; -+ case MPT3_IOC_DONE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); -+ break; -+ } -+} -+ -+/** -+ * _wait_for_commands_to_complete - reset controller -+ * @ioc: Pointer to MPT_ADAPTER structure -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * This function waiting(3s) for all pending commands to complete -+ * prior to putting controller in reset. -+ */ -+static void -+_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ u32 ioc_state; -+ unsigned long flags; -+ u16 i; -+ -+ ioc->pending_io_count = 0; -+ if (sleep_flag != CAN_SLEEP) -+ return; -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) -+ return; -+ -+ /* pending command count */ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ for (i = 0; i < ioc->scsiio_depth; i++) -+ if (ioc->scsi_lookup[i].cb_idx != 0xFF) -+ ioc->pending_io_count++; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ if (!ioc->pending_io_count) -+ return; -+ -+ /* wait for pending commands to complete */ -+ wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ); -+} -+ -+/** -+ * mpt2sas_base_hard_reset_handler - reset controller -+ * @ioc: Pointer to MPT_ADAPTER structure -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * @type: FORCE_BIG_HAMMER or SOFT_RESET -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag, -+ enum reset_type type) -+{ -+ int r; -+ unsigned long flags; -+ u32 ioc_state; -+ u8 is_fault = 0, is_trigger = 0; -+ -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ if (ioc->pci_error_recovery) { -+ pr_err(MPT3SAS_FMT "%s: pci error recovery reset\n", -+ ioc->name, __func__); -+ r = 0; -+ goto out_unlocked; -+ } -+ -+ if (mpt2sas_fwfault_debug) -+ mpt2sas_halt_firmware(ioc); -+ -+ /* TODO - What we really should be doing is pulling -+ * out all the code associated with NO_SLEEP; its never used. -+ * That is legacy code from mpt fusion driver, ported over. -+ * I will leave this BUG_ON here for now till its been resolved. -+ */ -+ BUG_ON(sleep_flag == NO_SLEEP); -+ -+ /* wait for an active reset in progress to complete */ -+ if (!mutex_trylock(&ioc->reset_in_progress_mutex)) { -+ do { -+ ssleep(1); -+ } while (ioc->shost_recovery == 1); -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+ return ioc->ioc_reset_in_progress_status; -+ } -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ ioc->shost_recovery = 1; -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) && -+ (!(ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED))) { -+ is_trigger = 1; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) -+ is_fault = 1; -+ } -+ _base_reset_handler(ioc, MPT3_IOC_PRE_RESET); -+ _wait_for_commands_to_complete(ioc, sleep_flag); -+ _base_mask_interrupts(ioc); -+ r = _base_make_ioc_ready(ioc, sleep_flag, type); -+ if (r) -+ goto out; -+ _base_reset_handler(ioc, MPT3_IOC_AFTER_RESET); -+ -+ /* If this hard reset is called while port enable is active, then -+ * there is no reason to call make_ioc_operational -+ */ -+ if (ioc->is_driver_loading && ioc->port_enable_failed) { -+ ioc->remove_host = 1; -+ r = -EFAULT; -+ goto out; -+ } -+ r = _base_get_ioc_facts(ioc, CAN_SLEEP); -+ if (r) -+ goto out; -+ -+ if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable) -+ panic("%s: Issue occurred with flashing controller firmware." -+ "Please reboot the system and ensure that the correct" -+ " firmware version is running\n", ioc->name); -+ -+ r = _base_make_ioc_operational(ioc, sleep_flag); -+ if (!r) -+ _base_reset_handler(ioc, MPT3_IOC_DONE_RESET); -+ -+ out: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: %s\n", -+ ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ ioc->ioc_reset_in_progress_status = r; -+ ioc->shost_recovery = 0; -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+ ioc->ioc_reset_count++; -+ mutex_unlock(&ioc->reset_in_progress_mutex); -+ -+ out_unlocked: -+ if ((r == 0) && is_trigger) { -+ if (is_fault) -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_FW_FAULT); -+ else -+ mpt2sas_trigger_master(ioc, -+ MASTER_TRIGGER_ADAPTER_RESET); -+ } -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+ return r; -+} -diff --git a/drivers/scsi/mpt2sas/mpt3sas_base.h b/drivers/scsi/mpt2sas/mpt3sas_base.h -new file mode 100644 -index 0000000..a580770 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_base.h -@@ -0,0 +1,1462 @@ -+/* -+ * This is the Fusion MPT base driver providing common API layer interface -+ * for access to MPT (Message Passing Technology) firmware. -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#ifndef MPT3SAS_BASE_H_INCLUDED -+#define MPT3SAS_BASE_H_INCLUDED -+ -+#include "mpi/mpi2_type.h" -+#include "mpi/mpi2.h" -+#include "mpi/mpi2_ioc.h" -+#include "mpi/mpi2_cnfg.h" -+#include "mpi/mpi2_init.h" -+#include "mpi/mpi2_raid.h" -+#include "mpi/mpi2_tool.h" -+#include "mpi/mpi2_sas.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_debug.h" -+#include "mpt3sas_trigger_diag.h" -+ -+/* driver versioning info */ -+#define MPT3SAS_DRIVER_NAME "mpt3sas" -+#define MPT3SAS_AUTHOR "Avago Technologies " -+#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -+#define MPT3SAS_DRIVER_VERSION "13.100.00.00" -+#define MPT3SAS_MAJOR_VERSION 13 -+#define MPT3SAS_MINOR_VERSION 100 -+#define MPT3SAS_BUILD_VERSION 0 -+#define MPT3SAS_RELEASE_VERSION 00 -+ -+#define MPT2SAS_DRIVER_NAME "mpt2sas" -+#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -+#define MPT2SAS_DRIVER_VERSION "20.102.00.00" -+#define MPT2SAS_MAJOR_VERSION 20 -+#define MPT2SAS_MINOR_VERSION 102 -+#define MPT2SAS_BUILD_VERSION 0 -+#define MPT2SAS_RELEASE_VERSION 00 -+ -+/* -+ * Set MPT3SAS_SG_DEPTH value based on user input. -+ */ -+#define MPT_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS -+#define MPT_MIN_PHYS_SEGMENTS 16 -+ -+#ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE -+#define MPT3SAS_SG_DEPTH CONFIG_SCSI_MPT3SAS_MAX_SGE -+#else -+#define MPT3SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS -+#endif -+ -+#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE -+#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE -+#else -+#define MPT2SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS -+#endif -+ -+/* -+ * Generic Defines -+ */ -+#define MPT3SAS_SATA_QUEUE_DEPTH 32 -+#define MPT3SAS_SAS_QUEUE_DEPTH 254 -+#define MPT3SAS_RAID_QUEUE_DEPTH 128 -+ -+#define MPT3SAS_RAID_MAX_SECTORS 8192 -+ -+#define MPT_NAME_LENGTH 32 /* generic length of strings */ -+#define MPT_STRING_LENGTH 64 -+ -+#define MPT_MAX_CALLBACKS 32 -+ -+ -+#define CAN_SLEEP 1 -+#define NO_SLEEP 0 -+ -+#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */ -+/* reserved for issuing internally framed scsi io cmds */ -+#define INTERNAL_SCSIIO_CMDS_COUNT 3 -+ -+#define MPI3_HIM_MASK 0xFFFFFFFF /* mask every bit*/ -+ -+#define MPT3SAS_INVALID_DEVICE_HANDLE 0xFFFF -+ -+#define MAX_CHAIN_ELEMT_SZ 16 -+#define DEFAULT_NUM_FWCHAIN_ELEMTS 8 -+ -+/* -+ * reset phases -+ */ -+#define MPT3_IOC_PRE_RESET 1 /* prior to host reset */ -+#define MPT3_IOC_AFTER_RESET 2 /* just after host reset */ -+#define MPT3_IOC_DONE_RESET 3 /* links re-initialized */ -+ -+/* -+ * logging format -+ */ -+#define MPT3SAS_FMT "%s: " -+ -+/* -+ * WarpDrive Specific Log codes -+ */ -+ -+#define MPT2_WARPDRIVE_LOGENTRY (0x8002) -+#define MPT2_WARPDRIVE_LC_SSDT (0x41) -+#define MPT2_WARPDRIVE_LC_SSDLW (0x43) -+#define MPT2_WARPDRIVE_LC_SSDLF (0x44) -+#define MPT2_WARPDRIVE_LC_BRMF (0x4D) -+ -+/* -+ * per target private data -+ */ -+#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01 -+#define MPT_TARGET_FLAGS_VOLUME 0x02 -+#define MPT_TARGET_FLAGS_DELETED 0x04 -+#define MPT_TARGET_FASTPATH_IO 0x08 -+ -+#define SAS2_PCI_DEVICE_B0_REVISION (0x01) -+#define SAS3_PCI_DEVICE_C0_REVISION (0x02) -+ -+/* -+ * Intel HBA branding -+ */ -+#define MPT2SAS_INTEL_RMS25JB080_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25JB080" -+#define MPT2SAS_INTEL_RMS25JB040_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25JB040" -+#define MPT2SAS_INTEL_RMS25KB080_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25KB080" -+#define MPT2SAS_INTEL_RMS25KB040_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25KB040" -+#define MPT2SAS_INTEL_RMS25LB040_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25LB040" -+#define MPT2SAS_INTEL_RMS25LB080_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25LB080" -+#define MPT2SAS_INTEL_RMS2LL080_BRANDING \ -+ "Intel Integrated RAID Module RMS2LL080" -+#define MPT2SAS_INTEL_RMS2LL040_BRANDING \ -+ "Intel Integrated RAID Module RMS2LL040" -+#define MPT2SAS_INTEL_RS25GB008_BRANDING \ -+ "Intel(R) RAID Controller RS25GB008" -+#define MPT2SAS_INTEL_SSD910_BRANDING \ -+ "Intel(R) SSD 910 Series" -+ -+#define MPT3SAS_INTEL_RMS3JC080_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS3JC080" -+#define MPT3SAS_INTEL_RS3GC008_BRANDING \ -+ "Intel(R) RAID Controller RS3GC008" -+#define MPT3SAS_INTEL_RS3FC044_BRANDING \ -+ "Intel(R) RAID Controller RS3FC044" -+#define MPT3SAS_INTEL_RS3UC080_BRANDING \ -+ "Intel(R) RAID Controller RS3UC080" -+ -+/* -+ * Intel HBA SSDIDs -+ */ -+#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516 -+#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517 -+#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518 -+#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519 -+#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A -+#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B -+#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E -+#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F -+#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 -+#define MPT2SAS_INTEL_SSD910_SSDID 0x3700 -+ -+#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521 -+#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522 -+#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523 -+#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524 -+ -+/* -+ * Dell HBA branding -+ */ -+#define MPT2SAS_DELL_BRANDING_SIZE 32 -+ -+#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA" -+#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter" -+#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated" -+#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular" -+#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded" -+#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200" -+#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS" -+ -+#define MPT3SAS_DELL_12G_HBA_BRANDING \ -+ "Dell 12Gbps HBA" -+ -+/* -+ * Dell HBA SSDIDs -+ */ -+#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C -+#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D -+#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E -+#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F -+#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20 -+#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21 -+#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22 -+ -+#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46 -+ -+/* -+ * Cisco HBA branding -+ */ -+#define MPT3SAS_CISCO_12G_8E_HBA_BRANDING \ -+ "Cisco 9300-8E 12G SAS HBA" -+#define MPT3SAS_CISCO_12G_8I_HBA_BRANDING \ -+ "Cisco 9300-8i 12G SAS HBA" -+#define MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING \ -+ "Cisco 12G Modular SAS Pass through Controller" -+#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING \ -+ "UCS C3X60 12G SAS Pass through Controller" -+/* -+ * Cisco HBA SSSDIDs -+ */ -+#define MPT3SAS_CISCO_12G_8E_HBA_SSDID 0x14C -+#define MPT3SAS_CISCO_12G_8I_HBA_SSDID 0x154 -+#define MPT3SAS_CISCO_12G_AVILA_HBA_SSDID 0x155 -+#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID 0x156 -+ -+/* -+ * status bits for ioc->diag_buffer_status -+ */ -+#define MPT3_DIAG_BUFFER_IS_REGISTERED (0x01) -+#define MPT3_DIAG_BUFFER_IS_RELEASED (0x02) -+#define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04) -+ -+/* -+ * HP HBA branding -+ */ -+#define MPT2SAS_HP_3PAR_SSVID 0x1590 -+ -+#define MPT2SAS_HP_2_4_INTERNAL_BRANDING \ -+ "HP H220 Host Bus Adapter" -+#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING \ -+ "HP H221 Host Bus Adapter" -+#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING \ -+ "HP H222 Host Bus Adapter" -+#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING \ -+ "HP H220i Host Bus Adapter" -+#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING \ -+ "HP H210i Host Bus Adapter" -+ -+/* -+ * HO HBA SSDIDs -+ */ -+#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 -+#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 -+#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 -+#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 -+#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 -+ -+/* -+ * Combined Reply Queue constants, -+ * There are twelve Supplemental Reply Post Host Index Registers -+ * and each register is at offset 0x10 bytes from the previous one. -+ */ -+#define MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT 12 -+#define MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET (0x10) -+ -+/* OEM Identifiers */ -+#define MFG10_OEM_ID_INVALID (0x00000000) -+#define MFG10_OEM_ID_DELL (0x00000001) -+#define MFG10_OEM_ID_FSC (0x00000002) -+#define MFG10_OEM_ID_SUN (0x00000003) -+#define MFG10_OEM_ID_IBM (0x00000004) -+ -+/* GENERIC Flags 0*/ -+#define MFG10_GF0_OCE_DISABLED (0x00000001) -+#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002) -+#define MFG10_GF0_R10_DISPLAY (0x00000004) -+#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008) -+#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010) -+ -+#define VIRTUAL_IO_FAILED_RETRY (0x32010081) -+ -+/* OEM Specific Flags will come from OEM specific header files */ -+struct Mpi2ManufacturingPage10_t { -+ MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ -+ U8 OEMIdentifier; /* 04h */ -+ U8 Reserved1; /* 05h */ -+ U16 Reserved2; /* 08h */ -+ U32 Reserved3; /* 0Ch */ -+ U32 GenericFlags0; /* 10h */ -+ U32 GenericFlags1; /* 14h */ -+ U32 Reserved4; /* 18h */ -+ U32 OEMSpecificFlags0; /* 1Ch */ -+ U32 OEMSpecificFlags1; /* 20h */ -+ U32 Reserved5[18]; /* 24h - 60h*/ -+}; -+ -+ -+/* Miscellaneous options */ -+struct Mpi2ManufacturingPage11_t { -+ MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ -+ __le32 Reserved1; /* 04h */ -+ u8 Reserved2; /* 08h */ -+ u8 EEDPTagMode; /* 09h */ -+ u8 Reserved3; /* 0Ah */ -+ u8 Reserved4; /* 0Bh */ -+ __le32 Reserved5[23]; /* 0Ch-60h*/ -+}; -+ -+/** -+ * struct MPT3SAS_TARGET - starget private hostdata -+ * @starget: starget object -+ * @sas_address: target sas address -+ * @raid_device: raid_device pointer to access volume data -+ * @handle: device handle -+ * @num_luns: number luns -+ * @flags: MPT_TARGET_FLAGS_XXX flags -+ * @deleted: target flaged for deletion -+ * @tm_busy: target is busy with TM request. -+ * @sdev: The sas_device associated with this target -+ */ -+struct MPT3SAS_TARGET { -+ struct scsi_target *starget; -+ u64 sas_address; -+ struct _raid_device *raid_device; -+ u16 handle; -+ int num_luns; -+ u32 flags; -+ u8 deleted; -+ u8 tm_busy; -+ struct _sas_device *sdev; -+}; -+ -+ -+/* -+ * per device private data -+ */ -+#define MPT_DEVICE_FLAGS_INIT 0x01 -+#define MPT_DEVICE_TLR_ON 0x02 -+ -+#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) -+#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) -+#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) -+#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) -+ -+/** -+ * struct MPT3SAS_DEVICE - sdev private hostdata -+ * @sas_target: starget private hostdata -+ * @lun: lun number -+ * @flags: MPT_DEVICE_XXX flags -+ * @configured_lun: lun is configured -+ * @block: device is in SDEV_BLOCK state -+ * @tlr_snoop_check: flag used in determining whether to disable TLR -+ * @eedp_enable: eedp support enable bit -+ * @eedp_type: 0(type_1), 1(type_2), 2(type_3) -+ * @eedp_block_length: block size -+ */ -+struct MPT3SAS_DEVICE { -+ struct MPT3SAS_TARGET *sas_target; -+ unsigned int lun; -+ u32 flags; -+ u8 configured_lun; -+ u8 block; -+ u8 tlr_snoop_check; -+ u8 ignore_delay_remove; -+}; -+ -+#define MPT3_CMD_NOT_USED 0x8000 /* free */ -+#define MPT3_CMD_COMPLETE 0x0001 /* completed */ -+#define MPT3_CMD_PENDING 0x0002 /* pending */ -+#define MPT3_CMD_REPLY_VALID 0x0004 /* reply is valid */ -+#define MPT3_CMD_RESET 0x0008 /* host reset dropped the command */ -+ -+/** -+ * struct _internal_cmd - internal commands struct -+ * @mutex: mutex -+ * @done: completion -+ * @reply: reply message pointer -+ * @sense: sense data -+ * @status: MPT3_CMD_XXX status -+ * @smid: system message id -+ */ -+struct _internal_cmd { -+ struct mutex mutex; -+ struct completion done; -+ void *reply; -+ void *sense; -+ u16 status; -+ u16 smid; -+}; -+ -+ -+ -+/** -+ * struct _sas_device - attached device information -+ * @list: sas device list -+ * @starget: starget object -+ * @sas_address: device sas address -+ * @device_name: retrieved from the SAS IDENTIFY frame. -+ * @handle: device handle -+ * @sas_address_parent: sas address of parent expander or sas host -+ * @enclosure_handle: enclosure handle -+ * @enclosure_logical_id: enclosure logical identifier -+ * @volume_handle: volume handle (valid when hidden raid member) -+ * @volume_wwid: volume unique identifier -+ * @device_info: bitfield provides detailed info about the device -+ * @id: target id -+ * @channel: target channel -+ * @slot: number number -+ * @phy: phy identifier provided in sas device page 0 -+ * @responding: used in _scsih_sas_device_mark_responding -+ * @fast_path: fast path feature enable bit -+ * @pfa_led_on: flag for PFA LED status -+ * @pend_sas_rphy_add: flag to check if device is in sas_rphy_add() -+ * addition routine. -+ */ -+struct _sas_device { -+ struct list_head list; -+ struct scsi_target *starget; -+ u64 sas_address; -+ u64 device_name; -+ u16 handle; -+ u64 sas_address_parent; -+ u16 enclosure_handle; -+ u64 enclosure_logical_id; -+ u16 volume_handle; -+ u64 volume_wwid; -+ u32 device_info; -+ int id; -+ int channel; -+ u16 slot; -+ u8 phy; -+ u8 responding; -+ u8 fast_path; -+ u8 pfa_led_on; -+ u8 pend_sas_rphy_add; -+ u8 enclosure_level; -+ u8 connector_name[4]; -+ struct kref refcount; -+}; -+ -+static inline void sas_device_get(struct _sas_device *s) -+{ -+ kref_get(&s->refcount); -+} -+ -+static inline void sas_device_free(struct kref *r) -+{ -+ kfree(container_of(r, struct _sas_device, refcount)); -+} -+ -+static inline void sas_device_put(struct _sas_device *s) -+{ -+ kref_put(&s->refcount, sas_device_free); -+} -+ -+/** -+ * struct _raid_device - raid volume link list -+ * @list: sas device list -+ * @starget: starget object -+ * @sdev: scsi device struct (volumes are single lun) -+ * @wwid: unique identifier for the volume -+ * @handle: device handle -+ * @block_size: Block size of the volume -+ * @id: target id -+ * @channel: target channel -+ * @volume_type: the raid level -+ * @device_info: bitfield provides detailed info about the hidden components -+ * @num_pds: number of hidden raid components -+ * @responding: used in _scsih_raid_device_mark_responding -+ * @percent_complete: resync percent complete -+ * @direct_io_enabled: Whether direct io to PDs are allowed or not -+ * @stripe_exponent: X where 2powX is the stripe sz in blocks -+ * @block_exponent: X where 2powX is the block sz in bytes -+ * @max_lba: Maximum number of LBA in the volume -+ * @stripe_sz: Stripe Size of the volume -+ * @device_info: Device info of the volume member disk -+ * @pd_handle: Array of handles of the physical drives for direct I/O in le16 -+ */ -+#define MPT_MAX_WARPDRIVE_PDS 8 -+struct _raid_device { -+ struct list_head list; -+ struct scsi_target *starget; -+ struct scsi_device *sdev; -+ u64 wwid; -+ u16 handle; -+ u16 block_sz; -+ int id; -+ int channel; -+ u8 volume_type; -+ u8 num_pds; -+ u8 responding; -+ u8 percent_complete; -+ u8 direct_io_enabled; -+ u8 stripe_exponent; -+ u8 block_exponent; -+ u64 max_lba; -+ u32 stripe_sz; -+ u32 device_info; -+ u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; -+}; -+ -+/** -+ * struct _boot_device - boot device info -+ * @is_raid: flag to indicate whether this is volume -+ * @device: holds pointer for either struct _sas_device or -+ * struct _raid_device -+ */ -+struct _boot_device { -+ u8 is_raid; -+ void *device; -+}; -+ -+/** -+ * struct _sas_port - wide/narrow sas port information -+ * @port_list: list of ports belonging to expander -+ * @num_phys: number of phys belonging to this port -+ * @remote_identify: attached device identification -+ * @rphy: sas transport rphy object -+ * @port: sas transport wide/narrow port object -+ * @phy_list: _sas_phy list objects belonging to this port -+ */ -+struct _sas_port { -+ struct list_head port_list; -+ u8 num_phys; -+ struct sas_identify remote_identify; -+ struct sas_rphy *rphy; -+ struct sas_port *port; -+ struct list_head phy_list; -+}; -+ -+/** -+ * struct _sas_phy - phy information -+ * @port_siblings: list of phys belonging to a port -+ * @identify: phy identification -+ * @remote_identify: attached device identification -+ * @phy: sas transport phy object -+ * @phy_id: unique phy id -+ * @handle: device handle for this phy -+ * @attached_handle: device handle for attached device -+ * @phy_belongs_to_port: port has been created for this phy -+ */ -+struct _sas_phy { -+ struct list_head port_siblings; -+ struct sas_identify identify; -+ struct sas_identify remote_identify; -+ struct sas_phy *phy; -+ u8 phy_id; -+ u16 handle; -+ u16 attached_handle; -+ u8 phy_belongs_to_port; -+}; -+ -+/** -+ * struct _sas_node - sas_host/expander information -+ * @list: list of expanders -+ * @parent_dev: parent device class -+ * @num_phys: number phys belonging to this sas_host/expander -+ * @sas_address: sas address of this sas_host/expander -+ * @handle: handle for this sas_host/expander -+ * @sas_address_parent: sas address of parent expander or sas host -+ * @enclosure_handle: handle for this a member of an enclosure -+ * @device_info: bitwise defining capabilities of this sas_host/expander -+ * @responding: used in _scsih_expander_device_mark_responding -+ * @phy: a list of phys that make up this sas_host/expander -+ * @sas_port_list: list of ports attached to this sas_host/expander -+ */ -+struct _sas_node { -+ struct list_head list; -+ struct device *parent_dev; -+ u8 num_phys; -+ u64 sas_address; -+ u16 handle; -+ u64 sas_address_parent; -+ u16 enclosure_handle; -+ u64 enclosure_logical_id; -+ u8 responding; -+ struct _sas_phy *phy; -+ struct list_head sas_port_list; -+}; -+ -+/** -+ * enum reset_type - reset state -+ * @FORCE_BIG_HAMMER: issue diagnostic reset -+ * @SOFT_RESET: issue message_unit_reset, if fails to to big hammer -+ */ -+enum reset_type { -+ FORCE_BIG_HAMMER, -+ SOFT_RESET, -+}; -+ -+/** -+ * struct chain_tracker - firmware chain tracker -+ * @chain_buffer: chain buffer -+ * @chain_buffer_dma: physical address -+ * @tracker_list: list of free request (ioc->free_chain_list) -+ */ -+struct chain_tracker { -+ void *chain_buffer; -+ dma_addr_t chain_buffer_dma; -+ struct list_head tracker_list; -+}; -+ -+/** -+ * struct scsiio_tracker - scsi mf request tracker -+ * @smid: system message id -+ * @scmd: scsi request pointer -+ * @cb_idx: callback index -+ * @direct_io: To indicate whether I/O is direct (WARPDRIVE) -+ * @tracker_list: list of free request (ioc->free_list) -+ * @msix_io: IO's msix -+ */ -+struct scsiio_tracker { -+ u16 smid; -+ struct scsi_cmnd *scmd; -+ u8 cb_idx; -+ u8 direct_io; -+ struct list_head chain_list; -+ struct list_head tracker_list; -+ u16 msix_io; -+}; -+ -+/** -+ * struct request_tracker - firmware request tracker -+ * @smid: system message id -+ * @cb_idx: callback index -+ * @tracker_list: list of free request (ioc->free_list) -+ */ -+struct request_tracker { -+ u16 smid; -+ u8 cb_idx; -+ struct list_head tracker_list; -+}; -+ -+/** -+ * struct _tr_list - target reset list -+ * @handle: device handle -+ * @state: state machine -+ */ -+struct _tr_list { -+ struct list_head list; -+ u16 handle; -+ u16 state; -+}; -+ -+/** -+ * struct _sc_list - delayed SAS_IO_UNIT_CONTROL message list -+ * @handle: device handle -+ */ -+struct _sc_list { -+ struct list_head list; -+ u16 handle; -+}; -+ -+/** -+ * struct _event_ack_list - delayed event acknowledgment list -+ * @Event: Event ID -+ * @EventContext: used to track the event uniquely -+ */ -+struct _event_ack_list { -+ struct list_head list; -+ u16 Event; -+ u32 EventContext; -+}; -+ -+/** -+ * struct adapter_reply_queue - the reply queue struct -+ * @ioc: per adapter object -+ * @msix_index: msix index into vector table -+ * @vector: irq vector -+ * @reply_post_host_index: head index in the pool where FW completes IO -+ * @reply_post_free: reply post base virt address -+ * @name: the name registered to request_irq() -+ * @busy: isr is actively processing replies on another cpu -+ * @list: this list -+*/ -+struct adapter_reply_queue { -+ struct MPT3SAS_ADAPTER *ioc; -+ u8 msix_index; -+ unsigned int vector; -+ u32 reply_post_host_index; -+ Mpi2ReplyDescriptorsUnion_t *reply_post_free; -+ char name[MPT_NAME_LENGTH]; -+ atomic_t busy; -+ cpumask_var_t affinity_hint; -+ struct list_head list; -+}; -+ -+typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); -+ -+/* SAS3.0 support */ -+typedef int (*MPT_BUILD_SG_SCMD)(struct MPT3SAS_ADAPTER *ioc, -+ struct scsi_cmnd *scmd, u16 smid); -+typedef void (*MPT_BUILD_SG)(struct MPT3SAS_ADAPTER *ioc, void *psge, -+ dma_addr_t data_out_dma, size_t data_out_sz, -+ dma_addr_t data_in_dma, size_t data_in_sz); -+typedef void (*MPT_BUILD_ZERO_LEN_SGE)(struct MPT3SAS_ADAPTER *ioc, -+ void *paddr); -+ -+ -+ -+/* IOC Facts and Port Facts converted from little endian to cpu */ -+union mpi3_version_union { -+ MPI2_VERSION_STRUCT Struct; -+ u32 Word; -+}; -+ -+struct mpt2sas_facts { -+ u16 MsgVersion; -+ u16 HeaderVersion; -+ u8 IOCNumber; -+ u8 VP_ID; -+ u8 VF_ID; -+ u16 IOCExceptions; -+ u16 IOCStatus; -+ u32 IOCLogInfo; -+ u8 MaxChainDepth; -+ u8 WhoInit; -+ u8 NumberOfPorts; -+ u8 MaxMSIxVectors; -+ u16 RequestCredit; -+ u16 ProductID; -+ u32 IOCCapabilities; -+ union mpi3_version_union FWVersion; -+ u16 IOCRequestFrameSize; -+ u16 IOCMaxChainSegmentSize; -+ u16 MaxInitiators; -+ u16 MaxTargets; -+ u16 MaxSasExpanders; -+ u16 MaxEnclosures; -+ u16 ProtocolFlags; -+ u16 HighPriorityCredit; -+ u16 MaxReplyDescriptorPostQueueDepth; -+ u8 ReplyFrameSize; -+ u8 MaxVolumes; -+ u16 MaxDevHandle; -+ u16 MaxPersistentEntries; -+ u16 MinDevHandle; -+}; -+ -+struct mpt2sas_port_facts { -+ u8 PortNumber; -+ u8 VP_ID; -+ u8 VF_ID; -+ u8 PortType; -+ u16 MaxPostedCmdBuffers; -+}; -+ -+struct reply_post_struct { -+ Mpi2ReplyDescriptorsUnion_t *reply_post_free; -+ dma_addr_t reply_post_free_dma; -+}; -+ -+/** -+ * enum mutex_type - task management mutex type -+ * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it -+ * @TM_MUTEX_ON: mutex is required -+ */ -+enum mutex_type { -+ TM_MUTEX_OFF = 0, -+ TM_MUTEX_ON = 1, -+}; -+ -+typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); -+/** -+ * struct MPT3SAS_ADAPTER - per adapter struct -+ * @list: ioc_list -+ * @shost: shost object -+ * @id: unique adapter id -+ * @cpu_count: number online cpus -+ * @name: generic ioc string -+ * @tmp_string: tmp string used for logging -+ * @pdev: pci pdev object -+ * @pio_chip: physical io register space -+ * @chip: memory mapped register space -+ * @chip_phys: physical addrss prior to mapping -+ * @logging_level: see mpt3sas_debug.h -+ * @fwfault_debug: debuging FW timeouts -+ * @ir_firmware: IR firmware present -+ * @bars: bitmask of BAR's that must be configured -+ * @mask_interrupts: ignore interrupt -+ * @dma_mask: used to set the consistent dma mask -+ * @fault_reset_work_q_name: fw fault work queue -+ * @fault_reset_work_q: "" -+ * @fault_reset_work: "" -+ * @firmware_event_name: fw event work queue -+ * @firmware_event_thread: "" -+ * @fw_event_lock: -+ * @fw_event_list: list of fw events -+ * @aen_event_read_flag: event log was read -+ * @broadcast_aen_busy: broadcast aen waiting to be serviced -+ * @shost_recovery: host reset in progress -+ * @ioc_reset_in_progress_lock: -+ * @ioc_link_reset_in_progress: phy/hard reset in progress -+ * @ignore_loginfos: ignore loginfos during task management -+ * @remove_host: flag for when driver unloads, to avoid sending dev resets -+ * @pci_error_recovery: flag to prevent ioc access until slot reset completes -+ * @wait_for_discovery_to_complete: flag set at driver load time when -+ * waiting on reporting devices -+ * @is_driver_loading: flag set at driver load time -+ * @port_enable_failed: flag set when port enable has failed -+ * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work -+ * @start_scan_failed: means port enable failed, return's the ioc_status -+ * @msix_enable: flag indicating msix is enabled -+ * @msix_vector_count: number msix vectors -+ * @cpu_msix_table: table for mapping cpus to msix index -+ * @cpu_msix_table_sz: table size -+ * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands -+ * @scsi_io_cb_idx: shost generated commands -+ * @tm_cb_idx: task management commands -+ * @scsih_cb_idx: scsih internal commands -+ * @transport_cb_idx: transport internal commands -+ * @ctl_cb_idx: clt internal commands -+ * @base_cb_idx: base internal commands -+ * @config_cb_idx: base internal commands -+ * @tm_tr_cb_idx : device removal target reset handshake -+ * @tm_tr_volume_cb_idx : volume removal target reset -+ * @base_cmds: -+ * @transport_cmds: -+ * @scsih_cmds: -+ * @tm_cmds: -+ * @ctl_cmds: -+ * @config_cmds: -+ * @base_add_sg_single: handler for either 32/64 bit sgl's -+ * @event_type: bits indicating which events to log -+ * @event_context: unique id for each logged event -+ * @event_log: event log pointer -+ * @event_masks: events that are masked -+ * @facts: static facts data -+ * @pfacts: static port facts data -+ * @manu_pg0: static manufacturing page 0 -+ * @manu_pg10: static manufacturing page 10 -+ * @manu_pg11: static manufacturing page 11 -+ * @bios_pg2: static bios page 2 -+ * @bios_pg3: static bios page 3 -+ * @ioc_pg8: static ioc page 8 -+ * @iounit_pg0: static iounit page 0 -+ * @iounit_pg1: static iounit page 1 -+ * @iounit_pg8: static iounit page 8 -+ * @sas_hba: sas host object -+ * @sas_expander_list: expander object list -+ * @sas_node_lock: -+ * @sas_device_list: sas device object list -+ * @sas_device_init_list: sas device object list (used only at init time) -+ * @sas_device_lock: -+ * @io_missing_delay: time for IO completed by fw when PDR enabled -+ * @device_missing_delay: time for device missing by fw when PDR enabled -+ * @sas_id : used for setting volume target IDs -+ * @blocking_handles: bitmask used to identify which devices need blocking -+ * @pd_handles : bitmask for PD handles -+ * @pd_handles_sz : size of pd_handle bitmask -+ * @config_page_sz: config page size -+ * @config_page: reserve memory for config page payload -+ * @config_page_dma: -+ * @hba_queue_depth: hba request queue depth -+ * @sge_size: sg element size for either 32/64 bit -+ * @scsiio_depth: SCSI_IO queue depth -+ * @request_sz: per request frame size -+ * @request: pool of request frames -+ * @request_dma: -+ * @request_dma_sz: -+ * @scsi_lookup: firmware request tracker list -+ * @scsi_lookup_lock: -+ * @free_list: free list of request -+ * @pending_io_count: -+ * @reset_wq: -+ * @chain: pool of chains -+ * @chain_dma: -+ * @max_sges_in_main_message: number sg elements in main message -+ * @max_sges_in_chain_message: number sg elements per chain -+ * @chains_needed_per_io: max chains per io -+ * @chain_depth: total chains allocated -+ * @chain_segment_sz: gives the max number of -+ * SGEs accommodate on single chain buffer -+ * @hi_priority_smid: -+ * @hi_priority: -+ * @hi_priority_dma: -+ * @hi_priority_depth: -+ * @hpr_lookup: -+ * @hpr_free_list: -+ * @internal_smid: -+ * @internal: -+ * @internal_dma: -+ * @internal_depth: -+ * @internal_lookup: -+ * @internal_free_list: -+ * @sense: pool of sense -+ * @sense_dma: -+ * @sense_dma_pool: -+ * @reply_depth: hba reply queue depth: -+ * @reply_sz: per reply frame size: -+ * @reply: pool of replys: -+ * @reply_dma: -+ * @reply_dma_pool: -+ * @reply_free_queue_depth: reply free depth -+ * @reply_free: pool for reply free queue (32 bit addr) -+ * @reply_free_dma: -+ * @reply_free_dma_pool: -+ * @reply_free_host_index: tail index in pool to insert free replys -+ * @reply_post_queue_depth: reply post queue depth -+ * @reply_post_struct: struct for reply_post_free physical & virt address -+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init -+ * @rdpq_array_enable: rdpq_array support is enabled in the driver -+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag -+ * is assigned only ones -+ * @reply_queue_count: number of reply queue's -+ * @reply_queue_list: link list contaning the reply queue info -+ * @msix96_vector: 96 MSI-X vector support -+ * @replyPostRegisterIndex: index of next position in Reply Desc Post Queue -+ * @delayed_tr_list: target reset link list -+ * @delayed_tr_volume_list: volume target reset link list -+ * @delayed_sc_list: -+ * @delayed_event_ack_list: -+ * @temp_sensors_count: flag to carry the number of temperature sensors -+ * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and -+ * pci resource handling. PCI resource freeing will lead to free -+ * vital hardware/memory resource, which might be in use by cli/sysfs -+ * path functions resulting in Null pointer reference followed by kernel -+ * crash. To avoid the above race condition we use mutex syncrhonization -+ * which ensures the syncrhonization between cli/sysfs_show path. -+ */ -+struct MPT3SAS_ADAPTER { -+ struct list_head list; -+ struct Scsi_Host *shost; -+ u8 id; -+ int cpu_count; -+ char name[MPT_NAME_LENGTH]; -+ char driver_name[MPT_NAME_LENGTH]; -+ char tmp_string[MPT_STRING_LENGTH]; -+ struct pci_dev *pdev; -+ Mpi2SystemInterfaceRegs_t __iomem *chip; -+ resource_size_t chip_phys; -+ int logging_level; -+ int fwfault_debug; -+ u8 ir_firmware; -+ int bars; -+ u8 mask_interrupts; -+ int dma_mask; -+ -+ /* fw fault handler */ -+ char fault_reset_work_q_name[20]; -+ struct workqueue_struct *fault_reset_work_q; -+ struct delayed_work fault_reset_work; -+ -+ /* fw event handler */ -+ char firmware_event_name[20]; -+ struct workqueue_struct *firmware_event_thread; -+ spinlock_t fw_event_lock; -+ struct list_head fw_event_list; -+ -+ /* misc flags */ -+ int aen_event_read_flag; -+ u8 broadcast_aen_busy; -+ u16 broadcast_aen_pending; -+ u8 shost_recovery; -+ -+ struct mutex reset_in_progress_mutex; -+ spinlock_t ioc_reset_in_progress_lock; -+ u8 ioc_link_reset_in_progress; -+ u8 ioc_reset_in_progress_status; -+ -+ u8 ignore_loginfos; -+ u8 remove_host; -+ u8 pci_error_recovery; -+ u8 wait_for_discovery_to_complete; -+ u8 is_driver_loading; -+ u8 port_enable_failed; -+ u8 start_scan; -+ u16 start_scan_failed; -+ -+ u8 msix_enable; -+ u16 msix_vector_count; -+ u8 *cpu_msix_table; -+ u16 cpu_msix_table_sz; -+ resource_size_t __iomem **reply_post_host_index; -+ u32 ioc_reset_count; -+ MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; -+ u32 non_operational_loop; -+ -+ /* internal commands, callback index */ -+ u8 scsi_io_cb_idx; -+ u8 tm_cb_idx; -+ u8 transport_cb_idx; -+ u8 scsih_cb_idx; -+ u8 ctl_cb_idx; -+ u8 base_cb_idx; -+ u8 port_enable_cb_idx; -+ u8 config_cb_idx; -+ u8 tm_tr_cb_idx; -+ u8 tm_tr_volume_cb_idx; -+ u8 tm_sas_control_cb_idx; -+ struct _internal_cmd base_cmds; -+ struct _internal_cmd port_enable_cmds; -+ struct _internal_cmd transport_cmds; -+ struct _internal_cmd scsih_cmds; -+ struct _internal_cmd tm_cmds; -+ struct _internal_cmd ctl_cmds; -+ struct _internal_cmd config_cmds; -+ -+ MPT_ADD_SGE base_add_sg_single; -+ -+ /* function ptr for either IEEE or MPI sg elements */ -+ MPT_BUILD_SG_SCMD build_sg_scmd; -+ MPT_BUILD_SG build_sg; -+ MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge; -+ u16 sge_size_ieee; -+ u16 hba_mpi_version_belonged; -+ -+ /* function ptr for MPI sg elements only */ -+ MPT_BUILD_SG build_sg_mpi; -+ MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge_mpi; -+ -+ /* event log */ -+ u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; -+ u32 event_context; -+ void *event_log; -+ u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; -+ -+ /* static config pages */ -+ struct mpt2sas_facts facts; -+ struct mpt2sas_port_facts *pfacts; -+ Mpi2ManufacturingPage0_t manu_pg0; -+ struct Mpi2ManufacturingPage10_t manu_pg10; -+ struct Mpi2ManufacturingPage11_t manu_pg11; -+ Mpi2BiosPage2_t bios_pg2; -+ Mpi2BiosPage3_t bios_pg3; -+ Mpi2IOCPage8_t ioc_pg8; -+ Mpi2IOUnitPage0_t iounit_pg0; -+ Mpi2IOUnitPage1_t iounit_pg1; -+ Mpi2IOUnitPage8_t iounit_pg8; -+ -+ struct _boot_device req_boot_device; -+ struct _boot_device req_alt_boot_device; -+ struct _boot_device current_boot_device; -+ -+ /* sas hba, expander, and device list */ -+ struct _sas_node sas_hba; -+ struct list_head sas_expander_list; -+ spinlock_t sas_node_lock; -+ struct list_head sas_device_list; -+ struct list_head sas_device_init_list; -+ spinlock_t sas_device_lock; -+ struct list_head raid_device_list; -+ spinlock_t raid_device_lock; -+ u8 io_missing_delay; -+ u16 device_missing_delay; -+ int sas_id; -+ -+ void *blocking_handles; -+ void *pd_handles; -+ u16 pd_handles_sz; -+ -+ /* config page */ -+ u16 config_page_sz; -+ void *config_page; -+ dma_addr_t config_page_dma; -+ -+ /* scsiio request */ -+ u16 hba_queue_depth; -+ u16 sge_size; -+ u16 scsiio_depth; -+ u16 request_sz; -+ u8 *request; -+ dma_addr_t request_dma; -+ u32 request_dma_sz; -+ struct scsiio_tracker *scsi_lookup; -+ ulong scsi_lookup_pages; -+ spinlock_t scsi_lookup_lock; -+ struct list_head free_list; -+ int pending_io_count; -+ wait_queue_head_t reset_wq; -+ -+ /* chain */ -+ struct chain_tracker *chain_lookup; -+ struct list_head free_chain_list; -+ struct dma_pool *chain_dma_pool; -+ ulong chain_pages; -+ u16 max_sges_in_main_message; -+ u16 max_sges_in_chain_message; -+ u16 chains_needed_per_io; -+ u32 chain_depth; -+ u16 chain_segment_sz; -+ -+ /* hi-priority queue */ -+ u16 hi_priority_smid; -+ u8 *hi_priority; -+ dma_addr_t hi_priority_dma; -+ u16 hi_priority_depth; -+ struct request_tracker *hpr_lookup; -+ struct list_head hpr_free_list; -+ -+ /* internal queue */ -+ u16 internal_smid; -+ u8 *internal; -+ dma_addr_t internal_dma; -+ u16 internal_depth; -+ struct request_tracker *internal_lookup; -+ struct list_head internal_free_list; -+ -+ /* sense */ -+ u8 *sense; -+ dma_addr_t sense_dma; -+ struct dma_pool *sense_dma_pool; -+ -+ /* reply */ -+ u16 reply_sz; -+ u8 *reply; -+ dma_addr_t reply_dma; -+ u32 reply_dma_max_address; -+ u32 reply_dma_min_address; -+ struct dma_pool *reply_dma_pool; -+ -+ /* reply free queue */ -+ u16 reply_free_queue_depth; -+ __le32 *reply_free; -+ dma_addr_t reply_free_dma; -+ struct dma_pool *reply_free_dma_pool; -+ u32 reply_free_host_index; -+ -+ /* reply post queue */ -+ u16 reply_post_queue_depth; -+ struct reply_post_struct *reply_post; -+ u8 rdpq_array_capable; -+ u8 rdpq_array_enable; -+ u8 rdpq_array_enable_assigned; -+ struct dma_pool *reply_post_free_dma_pool; -+ u8 reply_queue_count; -+ struct list_head reply_queue_list; -+ -+ u8 msix96_vector; -+ /* reply post register index */ -+ resource_size_t **replyPostRegisterIndex; -+ -+ struct list_head delayed_tr_list; -+ struct list_head delayed_tr_volume_list; -+ struct list_head delayed_sc_list; -+ struct list_head delayed_event_ack_list; -+ u8 temp_sensors_count; -+ struct mutex pci_access_mutex; -+ -+ /* diag buffer support */ -+ u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT]; -+ dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; -+ u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u32 ring_buffer_offset; -+ u32 ring_buffer_sz; -+ u8 is_warpdrive; -+ u8 hide_ir_msg; -+ u8 mfg_pg10_hide_flag; -+ u8 hide_drives; -+ spinlock_t diag_trigger_lock; -+ u8 diag_trigger_active; -+ struct SL_WH_MASTER_TRIGGER_T diag_trigger_master; -+ struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event; -+ struct SL_WH_SCSI_TRIGGERS_T diag_trigger_scsi; -+ struct SL_WH_MPI_TRIGGERS_T diag_trigger_mpi; -+}; -+ -+typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+ -+ -+/* base shared API */ -+extern struct list_head mpt2sas_ioc_list; -+extern char driver_name[MPT_NAME_LENGTH]; -+/* spinlock on list operations over IOCs -+ * Case: when multiple warpdrive cards(IOCs) are in use -+ * Each IOC will added to the ioc list structure on initialization. -+ * Watchdog threads run at regular intervals to check IOC for any -+ * fault conditions which will trigger the dead_ioc thread to -+ * deallocate pci resource, resulting deleting the IOC netry from list, -+ * this deletion need to protected by spinlock to enusre that -+ * ioc removal is syncrhonized, if not synchronized it might lead to -+ * list_del corruption as the ioc list is traversed in cli path. -+ */ -+extern spinlock_t gioc_lock_mpt2sas; -+ -+void mpt2sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc); -+void mpt2sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc); -+ -+int mpt2sas_base_attach(struct MPT3SAS_ADAPTER *ioc); -+void mpt2sas_base_detach(struct MPT3SAS_ADAPTER *ioc); -+int mpt2sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc); -+void mpt2sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc); -+int mpt2sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag, -+ enum reset_type type); -+ -+void *mpt2sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+void *mpt2sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, -+ u16 smid); -+ -+void mpt2sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc); -+ -+/* hi-priority queue */ -+u16 mpt2sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx); -+u16 mpt2sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, -+ struct scsi_cmnd *scmd); -+ -+u16 mpt2sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx); -+void mpt2sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+void mpt2sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u16 handle); -+void mpt2sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u16 handle); -+void mpt2sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, -+ u16 smid, u16 msix_task); -+void mpt2sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+void mpt2sas_base_initialize_callback_handler(void); -+u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func); -+void mpt2sas_base_release_callback_handler(u8 cb_idx); -+ -+u8 mpt2sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+u8 mpt2sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u8 msix_index, u32 reply); -+void *mpt2sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, -+ u32 phys_addr); -+ -+u32 mpt2sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked); -+ -+void mpt2sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code); -+int mpt2sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2SasIoUnitControlReply_t *mpi_reply, -+ Mpi2SasIoUnitControlRequest_t *mpi_request); -+int mpt2sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); -+ -+void mpt2sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, -+ u32 *event_type); -+ -+void mpt2sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc); -+ -+void mpt2sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, -+ u16 device_missing_delay, u8 io_missing_delay); -+ -+int mpt2sas_port_enable(struct MPT3SAS_ADAPTER *ioc); -+ -+ -+/* scsih shared API */ -+u8 mpt2sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, -+ u32 reply); -+void mpt2sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase); -+ -+int mpt2sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ uint channel, uint id, uint lun, u8 type, u16 smid_task, -+ ulong timeout, enum mutex_type m_type); -+void mpt2sas_scsih_set_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle); -+void mpt2sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle); -+void mpt2sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -+void mpt2sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address); -+u8 mpt2sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, -+ u16 smid); -+ -+struct _sas_node *mpt2sas_scsih_expander_find_by_handle( -+ struct MPT3SAS_ADAPTER *ioc, u16 handle); -+struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address( -+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -+struct _sas_device *mpt2sas_get_sdev_by_addr( -+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -+struct _sas_device *__mpt2sas_get_sdev_by_addr( -+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -+ -+void mpt2sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); -+struct _raid_device * -+mpt2sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle); -+ -+/* config shared API */ -+u8 mpt2sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+int mpt2sas_config_get_number_hba_phys(struct MPT3SAS_ADAPTER *ioc, -+ u8 *num_phys); -+int mpt2sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page); -+int mpt2sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, -+ u16 sz); -+int mpt2sas_config_get_manufacturing_pg10(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage10_t *config_page); -+ -+int mpt2sas_config_get_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage11_t *config_page); -+int mpt2sas_config_set_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage11_t *config_page); -+ -+int mpt2sas_config_get_bios_pg2(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2BiosPage2_t *config_page); -+int mpt2sas_config_get_bios_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2BiosPage3_t *config_page); -+int mpt2sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOUnitPage0_t *config_page); -+int mpt2sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage0_t *config_page, -+ u32 form, u32 handle); -+int mpt2sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, -+ u32 form, u32 handle); -+int mpt2sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, -+ u16 sz); -+int mpt2sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOUnitPage1_t *config_page); -+int mpt2sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz); -+int mpt2sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOUnitPage1_t *config_page); -+int mpt2sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOUnitPage8_t *config_page); -+int mpt2sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, -+ u16 sz); -+int mpt2sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, -+ u16 sz); -+int mpt2sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOCPage8_t *config_page); -+int mpt2sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ExpanderPage0_t *config_page, -+ u32 form, u32 handle); -+int mpt2sas_config_get_expander_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ExpanderPage1_t *config_page, -+ u32 phy_number, u16 handle); -+int mpt2sas_config_get_enclosure_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, -+ u32 form, u32 handle); -+int mpt2sas_config_get_phy_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number); -+int mpt2sas_config_get_phy_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number); -+int mpt2sas_config_get_raid_volume_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, -+ u32 handle); -+int mpt2sas_config_get_number_pds(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u8 *num_pds); -+int mpt2sas_config_get_raid_volume_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, -+ u32 handle, u16 sz); -+int mpt2sas_config_get_phys_disk_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, -+ u32 form, u32 form_specific); -+int mpt2sas_config_get_volume_handle(struct MPT3SAS_ADAPTER *ioc, u16 pd_handle, -+ u16 *volume_handle); -+int mpt2sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, -+ u16 volume_handle, u64 *wwid); -+ -+/* ctl shared API */ -+extern struct device_attribute *mpt2sas_host_attrs[]; -+extern struct device_attribute *mpt2sas_dev_attrs[]; -+void mpt2sas_ctl_init(ushort hbas_to_enumerate); -+void mpt2sas_ctl_exit(ushort hbas_to_enumerate); -+u8 mpt2sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+void mpt2sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase); -+u8 mpt2sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, -+ u8 msix_index, u32 reply); -+void mpt2sas_ctl_add_to_event_log(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventNotificationReply_t *mpi_reply); -+ -+void mpt2sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, -+ u8 bits_to_regsiter); -+int mpt2sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, -+ u8 *issue_reset); -+ -+/* transport shared API */ -+extern struct scsi_transport_template *mpt2sas_transport_template; -+u8 mpt2sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+struct _sas_port *mpt2sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, -+ u16 handle, u64 sas_address); -+void mpt2sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, -+ u64 sas_address_parent); -+int mpt2sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy -+ *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); -+int mpt2sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_phy *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, -+ struct device *parent_dev); -+void mpt2sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); -+extern struct sas_function_template mpt2sas_transport_functions; -+extern struct scsi_transport_template *mpt2sas_transport_template; -+extern int scsi_internal_device_block(struct scsi_device *sdev); -+extern int scsi_internal_device_unblock(struct scsi_device *sdev, -+ enum scsi_device_state new_state); -+/* trigger data externs */ -+void mpt2sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data); -+void mpt2sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data); -+void mpt2sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, -+ u32 tigger_bitmask); -+void mpt2sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event, -+ u16 log_entry_qualifier); -+void mpt2sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, -+ u8 asc, u8 ascq); -+void mpt2sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, -+ u32 loginfo); -+ -+/* warpdrive APIs */ -+u8 mpt2sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc); -+void mpt2sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device); -+u8 -+mpt2sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+void -+mpt2sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io); -+void -+mpt2sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, -+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, -+ u16 smid); -+ -+#endif /* MPT3SAS_BASE_H_INCLUDED */ -diff --git a/drivers/scsi/mpt2sas/mpt3sas_config.c b/drivers/scsi/mpt2sas/mpt3sas_config.c -new file mode 100644 -index 0000000..0f67b2c ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_config.c -@@ -0,0 +1,1716 @@ -+/* -+ * This module provides common API for accessing firmware configuration pages -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+/* local definitions */ -+ -+/* Timeout for config page request (in seconds) */ -+#define MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT 15 -+ -+/* Common sgl flags for READING a config page. */ -+#define MPT3_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ -+ | MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT) -+ -+/* Common sgl flags for WRITING a config page. */ -+#define MPT3_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ -+ | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \ -+ << MPI2_SGE_FLAGS_SHIFT) -+ -+/** -+ * struct config_request - obtain dma memory via routine -+ * @sz: size -+ * @page: virt pointer -+ * @page_dma: phys pointer -+ * -+ */ -+struct config_request { -+ u16 sz; -+ void *page; -+ dma_addr_t page_dma; -+}; -+ -+/** -+ * _config_display_some_debug - debug routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @calling_function_name: string pass from calling function -+ * @mpi_reply: reply message frame -+ * Context: none. -+ * -+ * Function for displaying debug info helpful when debugging issues -+ * in this module. -+ */ -+static void -+_config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ char *calling_function_name, MPI2DefaultReply_t *mpi_reply) -+{ -+ Mpi2ConfigRequest_t *mpi_request; -+ char *desc = NULL; -+ -+ if (!(ioc->logging_level & MPT_DEBUG_CONFIG)) -+ return; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) { -+ case MPI2_CONFIG_PAGETYPE_IO_UNIT: -+ desc = "io_unit"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_IOC: -+ desc = "ioc"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_BIOS: -+ desc = "bios"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_RAID_VOLUME: -+ desc = "raid_volume"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_MANUFACTURING: -+ desc = "manufaucturing"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK: -+ desc = "physdisk"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_EXTENDED: -+ switch (mpi_request->ExtPageType) { -+ case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT: -+ desc = "sas_io_unit"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER: -+ desc = "sas_expander"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE: -+ desc = "sas_device"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY: -+ desc = "sas_phy"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_LOG: -+ desc = "log"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE: -+ desc = "enclosure"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG: -+ desc = "raid_config"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING: -+ desc = "driver_mapping"; -+ break; -+ } -+ break; -+ } -+ -+ if (!desc) -+ return; -+ -+ pr_info(MPT3SAS_FMT -+ "%s: %s(%d), action(%d), form(0x%08x), smid(%d)\n", -+ ioc->name, calling_function_name, desc, -+ mpi_request->Header.PageNumber, mpi_request->Action, -+ le32_to_cpu(mpi_request->PageAddress), smid); -+ -+ if (!mpi_reply) -+ return; -+ -+ if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) -+ pr_info(MPT3SAS_FMT -+ "\tiocstatus(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo)); -+} -+ -+/** -+ * _config_alloc_config_dma_memory - obtain physical memory -+ * @ioc: per adapter object -+ * @mem: struct config_request -+ * -+ * A wrapper for obtaining dma-able memory for config page request. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_config_alloc_config_dma_memory(struct MPT3SAS_ADAPTER *ioc, -+ struct config_request *mem) -+{ -+ int r = 0; -+ -+ if (mem->sz > ioc->config_page_sz) { -+ mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz, -+ &mem->page_dma, GFP_KERNEL); -+ if (!mem->page) { -+ pr_err(MPT3SAS_FMT -+ "%s: dma_alloc_coherent failed asking for (%d) bytes!!\n", -+ ioc->name, __func__, mem->sz); -+ r = -ENOMEM; -+ } -+ } else { /* use tmp buffer if less than 512 bytes */ -+ mem->page = ioc->config_page; -+ mem->page_dma = ioc->config_page_dma; -+ } -+ return r; -+} -+ -+/** -+ * _config_free_config_dma_memory - wrapper to free the memory -+ * @ioc: per adapter object -+ * @mem: struct config_request -+ * -+ * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static void -+_config_free_config_dma_memory(struct MPT3SAS_ADAPTER *ioc, -+ struct config_request *mem) -+{ -+ if (mem->sz > ioc->config_page_sz) -+ dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page, -+ mem->page_dma); -+} -+ -+/** -+ * mpt2sas_config_done - config page completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: none. -+ * -+ * The callback handler when using _config_request. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ if (ioc->config_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->config_cmds.smid != smid) -+ return 1; -+ ioc->config_cmds.status |= MPT3_CMD_COMPLETE; -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply) { -+ ioc->config_cmds.status |= MPT3_CMD_REPLY_VALID; -+ memcpy(ioc->config_cmds.reply, mpi_reply, -+ mpi_reply->MsgLength*4); -+ } -+ ioc->config_cmds.status &= ~MPT3_CMD_PENDING; -+ _config_display_some_debug(ioc, smid, "config_done", mpi_reply); -+ ioc->config_cmds.smid = USHRT_MAX; -+ complete(&ioc->config_cmds.done); -+ return 1; -+} -+ -+/** -+ * _config_request - main routine for sending config page requests -+ * @ioc: per adapter object -+ * @mpi_request: request message frame -+ * @mpi_reply: reply mf payload returned from firmware -+ * @timeout: timeout in seconds -+ * @config_page: contents of the config page -+ * @config_page_sz: size of config page -+ * Context: sleep -+ * -+ * A generic API for config page requests to firmware. -+ * -+ * The ioc->config_cmds.status flag should be MPT3_CMD_NOT_USED before calling -+ * this API. -+ * -+ * The callback index is set inside `ioc->config_cb_idx. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t -+ *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout, -+ void *config_page, u16 config_page_sz) -+{ -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ Mpi2ConfigRequest_t *config_request; -+ int r; -+ u8 retry_count, issue_host_reset = 0; -+ u16 wait_state_count; -+ struct config_request mem; -+ u32 ioc_status = UINT_MAX; -+ -+ mutex_lock(&ioc->config_cmds.mutex); -+ if (ioc->config_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: config_cmd in use\n", -+ ioc->name, __func__); -+ mutex_unlock(&ioc->config_cmds.mutex); -+ return -EAGAIN; -+ } -+ -+ retry_count = 0; -+ memset(&mem, 0, sizeof(struct config_request)); -+ -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ -+ if (config_page) { -+ mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion; -+ mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber; -+ mpi_request->Header.PageType = mpi_reply->Header.PageType; -+ mpi_request->Header.PageLength = mpi_reply->Header.PageLength; -+ mpi_request->ExtPageLength = mpi_reply->ExtPageLength; -+ mpi_request->ExtPageType = mpi_reply->ExtPageType; -+ if (mpi_request->Header.PageLength) -+ mem.sz = mpi_request->Header.PageLength * 4; -+ else -+ mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; -+ r = _config_alloc_config_dma_memory(ioc, &mem); -+ if (r != 0) -+ goto out; -+ if (mpi_request->Action == -+ MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT || -+ mpi_request->Action == -+ MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) { -+ ioc->base_add_sg_single(&mpi_request->PageBufferSGE, -+ MPT3_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, -+ mem.page_dma); -+ memcpy(mem.page, config_page, min_t(u16, mem.sz, -+ config_page_sz)); -+ } else { -+ memset(config_page, 0, config_page_sz); -+ ioc->base_add_sg_single(&mpi_request->PageBufferSGE, -+ MPT3_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma); -+ memset(mem.page, 0, min_t(u16, mem.sz, config_page_sz)); -+ } -+ } -+ -+ retry_config: -+ if (retry_count) { -+ if (retry_count > 2) { /* attempt only 2 retries */ -+ r = -EFAULT; -+ goto free_mem; -+ } -+ pr_info(MPT3SAS_FMT "%s: attempting retry (%d)\n", -+ ioc->name, __func__, retry_count); -+ } -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ ioc->config_cmds.status = MPT3_CMD_NOT_USED; -+ r = -EFAULT; -+ goto free_mem; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ioc->config_cmds.status = MPT3_CMD_NOT_USED; -+ r = -EAGAIN; -+ goto free_mem; -+ } -+ -+ r = 0; -+ memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t)); -+ ioc->config_cmds.status = MPT3_CMD_PENDING; -+ config_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->config_cmds.smid = smid; -+ memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); -+ _config_display_some_debug(ioc, smid, "config_request", NULL); -+ init_completion(&ioc->config_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, -+ timeout*HZ); -+ if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2ConfigRequest_t)/4); -+ retry_count++; -+ if (ioc->config_cmds.smid == smid) -+ mpt2sas_base_free_smid(ioc, smid); -+ if ((ioc->shost_recovery) || (ioc->config_cmds.status & -+ MPT3_CMD_RESET) || ioc->pci_error_recovery) -+ goto retry_config; -+ issue_host_reset = 1; -+ r = -EFAULT; -+ goto free_mem; -+ } -+ -+ if (ioc->config_cmds.status & MPT3_CMD_REPLY_VALID) { -+ memcpy(mpi_reply, ioc->config_cmds.reply, -+ sizeof(Mpi2ConfigReply_t)); -+ -+ /* Reply Frame Sanity Checks to workaround FW issues */ -+ if ((mpi_request->Header.PageType & 0xF) != -+ (mpi_reply->Header.PageType & 0xF)) { -+ _debug_dump_mf(mpi_request, ioc->request_sz/4); -+ _debug_dump_reply(mpi_reply, ioc->request_sz/4); -+ panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \ -+ " mpi_reply mismatch: Requested PageType(0x%02x)" \ -+ " Reply PageType(0x%02x)\n", \ -+ ioc->name, __func__, -+ (mpi_request->Header.PageType & 0xF), -+ (mpi_reply->Header.PageType & 0xF)); -+ } -+ -+ if (((mpi_request->Header.PageType & 0xF) == -+ MPI2_CONFIG_PAGETYPE_EXTENDED) && -+ mpi_request->ExtPageType != mpi_reply->ExtPageType) { -+ _debug_dump_mf(mpi_request, ioc->request_sz/4); -+ _debug_dump_reply(mpi_reply, ioc->request_sz/4); -+ panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \ -+ " mpi_reply mismatch: Requested ExtPageType(0x%02x)" -+ " Reply ExtPageType(0x%02x)\n", -+ ioc->name, __func__, mpi_request->ExtPageType, -+ mpi_reply->ExtPageType); -+ } -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) -+ & MPI2_IOCSTATUS_MASK; -+ } -+ -+ if (retry_count) -+ pr_info(MPT3SAS_FMT "%s: retry (%d) completed!!\n", \ -+ ioc->name, __func__, retry_count); -+ -+ if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) && -+ config_page && mpi_request->Action == -+ MPI2_CONFIG_ACTION_PAGE_READ_CURRENT) { -+ u8 *p = (u8 *)mem.page; -+ -+ /* Config Page Sanity Checks to workaround FW issues */ -+ if (p) { -+ if ((mpi_request->Header.PageType & 0xF) != -+ (p[3] & 0xF)) { -+ _debug_dump_mf(mpi_request, ioc->request_sz/4); -+ _debug_dump_reply(mpi_reply, ioc->request_sz/4); -+ _debug_dump_config(p, min_t(u16, mem.sz, -+ config_page_sz)/4); -+ panic(KERN_WARNING MPT3SAS_FMT -+ "%s: Firmware BUG:" \ -+ " config page mismatch:" -+ " Requested PageType(0x%02x)" -+ " Reply PageType(0x%02x)\n", -+ ioc->name, __func__, -+ (mpi_request->Header.PageType & 0xF), -+ (p[3] & 0xF)); -+ } -+ -+ if (((mpi_request->Header.PageType & 0xF) == -+ MPI2_CONFIG_PAGETYPE_EXTENDED) && -+ (mpi_request->ExtPageType != p[6])) { -+ _debug_dump_mf(mpi_request, ioc->request_sz/4); -+ _debug_dump_reply(mpi_reply, ioc->request_sz/4); -+ _debug_dump_config(p, min_t(u16, mem.sz, -+ config_page_sz)/4); -+ panic(KERN_WARNING MPT3SAS_FMT -+ "%s: Firmware BUG:" \ -+ " config page mismatch:" -+ " Requested ExtPageType(0x%02x)" -+ " Reply ExtPageType(0x%02x)\n", -+ ioc->name, __func__, -+ mpi_request->ExtPageType, p[6]); -+ } -+ } -+ memcpy(config_page, mem.page, min_t(u16, mem.sz, -+ config_page_sz)); -+ } -+ -+ free_mem: -+ if (config_page) -+ _config_free_config_dma_memory(ioc, &mem); -+ out: -+ ioc->config_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_unlock(&ioc->config_cmds.mutex); -+ -+ if (issue_host_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_manufacturing_pg7 - obtain manufacturing page 7 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, -+ u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 7; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING7_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_manufacturing_pg10(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage10_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 10; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_manufacturing_pg11 - obtain manufacturing page 11 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage11_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 11; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_set_manufacturing_pg11 - set manufacturing page 11 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_set_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage11_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 11; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_bios_pg2 - obtain bios page 2 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_bios_pg2(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; -+ mpi_request.Header.PageNumber = 2; -+ mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_bios_pg3 - obtain bios page 3 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_bios_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2BiosPage3_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; -+ mpi_request.Header.PageNumber = 3; -+ mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_iounit_pg0 - obtain iounit page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_iounit_pg1 - obtain iounit page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_set_iounit_pg1 - set iounit page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_iounit_pg3 - obtain iounit page 3 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 3; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_iounit_pg8 - obtain iounit page 8 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 8; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; -+ mpi_request.Header.PageNumber = 8; -+ mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: device handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage0_t *config_page, -+ u32 form, u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; -+ mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; -+ mpi_request.Header.PageNumber = 0; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: device handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, -+ u32 form, u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; -+ mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION; -+ mpi_request.Header.PageNumber = 1; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_number_hba_phys - obtain number of phys on the host -+ * @ioc: per adapter object -+ * @num_phys: pointer returned with the number of phys -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_number_hba_phys(struct MPT3SAS_ADAPTER *ioc, u8 *num_phys) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ u16 ioc_status; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasIOUnitPage0_t config_page; -+ -+ *num_phys = 0; -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, -+ sizeof(Mpi2SasIOUnitPage0_t)); -+ if (!r) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) -+ *num_phys = config_page.NumPhys; -+ } -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Calling function should call config_get_number_hba_phys prior to -+ * this function, so enough memory is allocated for config_page. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, -+ u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Calling function should call config_get_number_hba_phys prior to -+ * this function, so enough memory is allocated for config_page. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, -+ u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Calling function should call config_get_number_hba_phys prior to -+ * this function, so enough memory is allocated for config_page. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, -+ u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; -+ _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_expander_pg0 - obtain expander page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: expander handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_expander_pg1 - obtain expander page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @phy_number: phy number -+ * @handle: expander handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_expander_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, -+ u16 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = -+ cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | -+ (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: expander handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_enclosure_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_phy_pg0 - obtain phy page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @phy_number: phy number -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_phy_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = -+ cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_phy_pg1 - obtain phy page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @phy_number: phy number -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_phy_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = -+ cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: volume handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_raid_volume_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, -+ u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume -+ * @ioc: per adapter object -+ * @handle: volume handle -+ * @num_pds: returns pds count -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_number_pds(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u8 *num_pds) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ Mpi2RaidVolPage0_t config_page; -+ Mpi2ConfigReply_t mpi_reply; -+ int r; -+ u16 ioc_status; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ *num_pds = 0; -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = -+ cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, -+ sizeof(Mpi2RaidVolPage0_t)); -+ if (!r) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) -+ *num_pds = config_page.NumPhysDisks; -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: volume handle -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_raid_volume_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, -+ u32 handle, u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE -+ * @form_specific: specific to the form -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_phys_disk_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form, -+ u32 form_specific) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | form_specific); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_volume_handle - returns volume handle for give hidden -+ * raid components -+ * @ioc: per adapter object -+ * @pd_handle: phys disk handle -+ * @volume_handle: volume handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_volume_handle(struct MPT3SAS_ADAPTER *ioc, u16 pd_handle, -+ u16 *volume_handle) -+{ -+ Mpi2RaidConfigurationPage0_t *config_page = NULL; -+ Mpi2ConfigRequest_t mpi_request; -+ Mpi2ConfigReply_t mpi_reply; -+ int r, i, config_page_sz; -+ u16 ioc_status; -+ int config_num; -+ u16 element_type; -+ u16 phys_disk_dev_handle; -+ -+ *volume_handle = 0; -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG; -+ mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION; -+ mpi_request.Header.PageNumber = 0; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); -+ config_page = kmalloc(config_page_sz, GFP_KERNEL); -+ if (!config_page) { -+ r = -1; -+ goto out; -+ } -+ -+ config_num = 0xff; -+ while (1) { -+ mpi_request.PageAddress = cpu_to_le32(config_num + -+ MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM); -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ config_page_sz); -+ if (r) -+ goto out; -+ r = -1; -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ goto out; -+ for (i = 0; i < config_page->NumElements; i++) { -+ element_type = le16_to_cpu(config_page-> -+ ConfigElement[i].ElementFlags) & -+ MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE; -+ if (element_type == -+ MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT || -+ element_type == -+ MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) { -+ phys_disk_dev_handle = -+ le16_to_cpu(config_page->ConfigElement[i]. -+ PhysDiskDevHandle); -+ if (phys_disk_dev_handle == pd_handle) { -+ *volume_handle = -+ le16_to_cpu(config_page-> -+ ConfigElement[i].VolDevHandle); -+ r = 0; -+ goto out; -+ } -+ } else if (element_type == -+ MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) { -+ *volume_handle = 0; -+ r = 0; -+ goto out; -+ } -+ } -+ config_num = config_page->ConfigNum; -+ } -+ out: -+ kfree(config_page); -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_volume_wwid - returns wwid given the volume handle -+ * @ioc: per adapter object -+ * @volume_handle: volume handle -+ * @wwid: volume wwid -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, u16 volume_handle, -+ u64 *wwid) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2RaidVolPage1_t raid_vol_pg1; -+ -+ *wwid = 0; -+ if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, -+ volume_handle))) { -+ *wwid = le64_to_cpu(raid_vol_pg1.WWID); -+ return 0; -+ } else -+ return -1; -+} -diff --git a/drivers/scsi/mpt2sas/mpt3sas_ctl.c b/drivers/scsi/mpt2sas/mpt3sas_ctl.c -new file mode 100644 -index 0000000..5c0cc30 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_ctl.c -@@ -0,0 +1,3483 @@ -+/* -+ * Management Module Support for MPT (Message Passing Technology) based -+ * controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "mpt3sas_base.h" -+#include "mpt3sas_ctl.h" -+ -+ -+static struct fasync_struct *async_queue; -+static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); -+ -+ -+/** -+ * enum block_state - blocking state -+ * @NON_BLOCKING: non blocking -+ * @BLOCKING: blocking -+ * -+ * These states are for ioctls that need to wait for a response -+ * from firmware, so they probably require sleep. -+ */ -+enum block_state { -+ NON_BLOCKING, -+ BLOCKING, -+}; -+ -+/** -+ * _ctl_sas_device_find_by_handle - sas device search -+ * @ioc: per adapter object -+ * @handle: sas device handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->sas_device_lock -+ * -+ * This searches for sas_device based on sas_address, then return sas_device -+ * object. -+ */ -+static struct _sas_device * -+_ctl_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_device *sas_device, *r; -+ -+ r = NULL; -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -+ if (sas_device->handle != handle) -+ continue; -+ r = sas_device; -+ goto out; -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * _ctl_display_some_debug - debug routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @calling_function_name: string pass from calling function -+ * @mpi_reply: reply message frame -+ * Context: none. -+ * -+ * Function for displaying debug info helpful when debugging issues -+ * in this module. -+ */ -+static void -+_ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ char *calling_function_name, MPI2DefaultReply_t *mpi_reply) -+{ -+ Mpi2ConfigRequest_t *mpi_request; -+ char *desc = NULL; -+ -+ if (!(ioc->logging_level & MPT_DEBUG_IOCTL)) -+ return; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ switch (mpi_request->Function) { -+ case MPI2_FUNCTION_SCSI_IO_REQUEST: -+ { -+ Mpi2SCSIIORequest_t *scsi_request = -+ (Mpi2SCSIIORequest_t *)mpi_request; -+ -+ snprintf(ioc->tmp_string, MPT_STRING_LENGTH, -+ "scsi_io, cmd(0x%02x), cdb_len(%d)", -+ scsi_request->CDB.CDB32[0], -+ le16_to_cpu(scsi_request->IoFlags) & 0xF); -+ desc = ioc->tmp_string; -+ break; -+ } -+ case MPI2_FUNCTION_SCSI_TASK_MGMT: -+ desc = "task_mgmt"; -+ break; -+ case MPI2_FUNCTION_IOC_INIT: -+ desc = "ioc_init"; -+ break; -+ case MPI2_FUNCTION_IOC_FACTS: -+ desc = "ioc_facts"; -+ break; -+ case MPI2_FUNCTION_CONFIG: -+ { -+ Mpi2ConfigRequest_t *config_request = -+ (Mpi2ConfigRequest_t *)mpi_request; -+ -+ snprintf(ioc->tmp_string, MPT_STRING_LENGTH, -+ "config, type(0x%02x), ext_type(0x%02x), number(%d)", -+ (config_request->Header.PageType & -+ MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType, -+ config_request->Header.PageNumber); -+ desc = ioc->tmp_string; -+ break; -+ } -+ case MPI2_FUNCTION_PORT_FACTS: -+ desc = "port_facts"; -+ break; -+ case MPI2_FUNCTION_PORT_ENABLE: -+ desc = "port_enable"; -+ break; -+ case MPI2_FUNCTION_EVENT_NOTIFICATION: -+ desc = "event_notification"; -+ break; -+ case MPI2_FUNCTION_FW_DOWNLOAD: -+ desc = "fw_download"; -+ break; -+ case MPI2_FUNCTION_FW_UPLOAD: -+ desc = "fw_upload"; -+ break; -+ case MPI2_FUNCTION_RAID_ACTION: -+ desc = "raid_action"; -+ break; -+ case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: -+ { -+ Mpi2SCSIIORequest_t *scsi_request = -+ (Mpi2SCSIIORequest_t *)mpi_request; -+ -+ snprintf(ioc->tmp_string, MPT_STRING_LENGTH, -+ "raid_pass, cmd(0x%02x), cdb_len(%d)", -+ scsi_request->CDB.CDB32[0], -+ le16_to_cpu(scsi_request->IoFlags) & 0xF); -+ desc = ioc->tmp_string; -+ break; -+ } -+ case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: -+ desc = "sas_iounit_cntl"; -+ break; -+ case MPI2_FUNCTION_SATA_PASSTHROUGH: -+ desc = "sata_pass"; -+ break; -+ case MPI2_FUNCTION_DIAG_BUFFER_POST: -+ desc = "diag_buffer_post"; -+ break; -+ case MPI2_FUNCTION_DIAG_RELEASE: -+ desc = "diag_release"; -+ break; -+ case MPI2_FUNCTION_SMP_PASSTHROUGH: -+ desc = "smp_passthrough"; -+ break; -+ } -+ -+ if (!desc) -+ return; -+ -+ pr_info(MPT3SAS_FMT "%s: %s, smid(%d)\n", -+ ioc->name, calling_function_name, desc, smid); -+ -+ if (!mpi_reply) -+ return; -+ -+ if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) -+ pr_info(MPT3SAS_FMT -+ "\tiocstatus(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo)); -+ -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ mpi_request->Function == -+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { -+ Mpi2SCSIIOReply_t *scsi_reply = -+ (Mpi2SCSIIOReply_t *)mpi_reply; -+ struct _sas_device *sas_device = NULL; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = _ctl_sas_device_find_by_handle(ioc, -+ le16_to_cpu(scsi_reply->DevHandle)); -+ if (sas_device) { -+ pr_warn(MPT3SAS_FMT "\tsas_address(0x%016llx), phy(%d)\n", -+ ioc->name, (unsigned long long) -+ sas_device->sas_address, sas_device->phy); -+ pr_warn(MPT3SAS_FMT -+ "\tenclosure_logical_id(0x%016llx), slot(%d)\n", -+ ioc->name, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) -+ pr_info(MPT3SAS_FMT -+ "\tscsi_state(0x%02x), scsi_status" -+ "(0x%02x)\n", ioc->name, -+ scsi_reply->SCSIState, -+ scsi_reply->SCSIStatus); -+ } -+} -+ -+/** -+ * mpt2sas_ctl_done - ctl module completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: none. -+ * -+ * The callback handler when using ioc->ctl_cb_idx. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ Mpi2SCSIIOReply_t *scsiio_reply; -+ const void *sense_data; -+ u32 sz; -+ -+ if (ioc->ctl_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->ctl_cmds.smid != smid) -+ return 1; -+ ioc->ctl_cmds.status |= MPT3_CMD_COMPLETE; -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply) { -+ memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); -+ ioc->ctl_cmds.status |= MPT3_CMD_REPLY_VALID; -+ /* get sense data */ -+ if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ mpi_reply->Function == -+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { -+ scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; -+ if (scsiio_reply->SCSIState & -+ MPI2_SCSI_STATE_AUTOSENSE_VALID) { -+ sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, -+ le32_to_cpu(scsiio_reply->SenseCount)); -+ sense_data = mpt2sas_base_get_sense_buffer(ioc, -+ smid); -+ memcpy(ioc->ctl_cmds.sense, sense_data, sz); -+ } -+ } -+ } -+ _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); -+ ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING; -+ complete(&ioc->ctl_cmds.done); -+ return 1; -+} -+ -+/** -+ * _ctl_check_event_type - determines when an event needs logging -+ * @ioc: per adapter object -+ * @event: firmware event -+ * -+ * The bitmask in ioc->event_type[] indicates which events should be -+ * be saved in the driver event_log. This bitmask is set by application. -+ * -+ * Returns 1 when event should be captured, or zero means no match. -+ */ -+static int -+_ctl_check_event_type(struct MPT3SAS_ADAPTER *ioc, u16 event) -+{ -+ u16 i; -+ u32 desired_event; -+ -+ if (event >= 128 || !event || !ioc->event_log) -+ return 0; -+ -+ desired_event = (1 << (event % 32)); -+ if (!desired_event) -+ desired_event = 1; -+ i = event / 32; -+ return desired_event & ioc->event_type[i]; -+} -+ -+/** -+ * mpt2sas_ctl_add_to_event_log - add event -+ * @ioc: per adapter object -+ * @mpi_reply: reply message frame -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_ctl_add_to_event_log(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventNotificationReply_t *mpi_reply) -+{ -+ struct MPT3_IOCTL_EVENTS *event_log; -+ u16 event; -+ int i; -+ u32 sz, event_data_sz; -+ u8 send_aen = 0; -+ -+ if (!ioc->event_log) -+ return; -+ -+ event = le16_to_cpu(mpi_reply->Event); -+ -+ if (_ctl_check_event_type(ioc, event)) { -+ -+ /* insert entry into circular event_log */ -+ i = ioc->event_context % MPT3SAS_CTL_EVENT_LOG_SIZE; -+ event_log = ioc->event_log; -+ event_log[i].event = event; -+ event_log[i].context = ioc->event_context++; -+ -+ event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4; -+ sz = min_t(u32, event_data_sz, MPT3_EVENT_DATA_SIZE); -+ memset(event_log[i].data, 0, MPT3_EVENT_DATA_SIZE); -+ memcpy(event_log[i].data, mpi_reply->EventData, sz); -+ send_aen = 1; -+ } -+ -+ /* This aen_event_read_flag flag is set until the -+ * application has read the event log. -+ * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify. -+ */ -+ if (event == MPI2_EVENT_LOG_ENTRY_ADDED || -+ (send_aen && !ioc->aen_event_read_flag)) { -+ ioc->aen_event_read_flag = 1; -+ wake_up_interruptible(&ctl_poll_wait); -+ if (async_queue) -+ kill_fasync(&async_queue, SIGIO, POLL_IN); -+ } -+} -+ -+/** -+ * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time) -+ * @ioc: per adapter object -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt. -+ * -+ * This function merely adds a new work task into ioc->firmware_event_thread. -+ * The tasks are worked from _firmware_event_work in user context. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, -+ u32 reply) -+{ -+ Mpi2EventNotificationReply_t *mpi_reply; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply) -+ mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); -+ return 1; -+} -+ -+/** -+ * _ctl_verify_adapter - validates ioc_number passed from application -+ * @ioc: per adapter object -+ * @iocpp: The ioc pointer is returned in this. -+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & -+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device. -+ * -+ * Return (-1) means error, else ioc_number. -+ */ -+static int -+_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp, -+ int mpi_version) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ int version = 0; -+ /* global ioc lock to protect controller on list operations */ -+ spin_lock(&gioc_lock_mpt2sas); -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { -+ if (ioc->id != ioc_number) -+ continue; -+ /* Check whether this ioctl command is from right -+ * ioctl device or not, if not continue the search. -+ */ -+ version = ioc->hba_mpi_version_belonged; -+ /* MPI25_VERSION and MPI26_VERSION uses same ioctl -+ * device. -+ */ -+ if (mpi_version == (MPI25_VERSION | MPI26_VERSION)) { -+ if ((version == MPI25_VERSION) || -+ (version == MPI26_VERSION)) -+ goto out; -+ else -+ continue; -+ } else { -+ if (version != mpi_version) -+ continue; -+ } -+out: -+ spin_unlock(&gioc_lock_mpt2sas); -+ *iocpp = ioc; -+ return ioc_number; -+ } -+ spin_unlock(&gioc_lock_mpt2sas); -+ *iocpp = NULL; -+ return -1; -+} -+ -+/** -+ * mpt2sas_ctl_reset_handler - reset callback handler (for ctl) -+ * @ioc: per adapter object -+ * @reset_phase: phase -+ * -+ * The handler for doing any required cleanup or initialization. -+ * -+ * The reset phase can be MPT3_IOC_PRE_RESET, MPT3_IOC_AFTER_RESET, -+ * MPT3_IOC_DONE_RESET -+ */ -+void -+mpt2sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) -+{ -+ int i; -+ u8 issue_reset; -+ -+ switch (reset_phase) { -+ case MPT3_IOC_PRE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); -+ for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { -+ if (!(ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED)) -+ continue; -+ if ((ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ continue; -+ mpt2sas_send_diag_release(ioc, i, &issue_reset); -+ } -+ break; -+ case MPT3_IOC_AFTER_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); -+ if (ioc->ctl_cmds.status & MPT3_CMD_PENDING) { -+ ioc->ctl_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid); -+ complete(&ioc->ctl_cmds.done); -+ } -+ break; -+ case MPT3_IOC_DONE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); -+ -+ for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { -+ if (!(ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED)) -+ continue; -+ if ((ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ continue; -+ ioc->diag_buffer_status[i] |= -+ MPT3_DIAG_BUFFER_IS_DIAG_RESET; -+ } -+ break; -+ } -+} -+ -+/** -+ * _ctl_fasync_mpt2sas - -+ * @fd - -+ * @filep - -+ * @mode - -+ * -+ * Called when application request fasyn callback handler. -+ */ -+int -+_ctl_fasync_mpt2sas(int fd, struct file *filep, int mode) -+{ -+ return fasync_helper(fd, filep, mode, &async_queue); -+} -+ -+/** -+ * _ctl_poll_mpt2sas - -+ * @file - -+ * @wait - -+ * -+ */ -+unsigned int -+_ctl_poll_mpt2sas(struct file *filep, poll_table *wait) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ -+ poll_wait(filep, &ctl_poll_wait, wait); -+ -+ /* global ioc lock to protect controller on list operations */ -+ spin_lock(&gioc_lock_mpt2sas); -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { -+ if (ioc->aen_event_read_flag) { -+ spin_unlock(&gioc_lock_mpt2sas); -+ return POLLIN | POLLRDNORM; -+ } -+ } -+ spin_unlock(&gioc_lock_mpt2sas); -+ return 0; -+} -+ -+/** -+ * _ctl_set_task_mid - assign an active smid to tm request -+ * @ioc: per adapter object -+ * @karg - (struct mpt3_ioctl_command) -+ * @tm_request - pointer to mf from user space -+ * -+ * Returns 0 when an smid if found, else fail. -+ * during failure, the reply frame is filled. -+ */ -+static int -+_ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg, -+ Mpi2SCSITaskManagementRequest_t *tm_request) -+{ -+ u8 found = 0; -+ u16 i; -+ u16 handle; -+ struct scsi_cmnd *scmd; -+ struct MPT3SAS_DEVICE *priv_data; -+ unsigned long flags; -+ Mpi2SCSITaskManagementReply_t *tm_reply; -+ u32 sz; -+ u32 lun; -+ char *desc = NULL; -+ -+ if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) -+ desc = "abort_task"; -+ else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) -+ desc = "query_task"; -+ else -+ return 0; -+ -+ lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN); -+ -+ handle = le16_to_cpu(tm_request->DevHandle); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ for (i = ioc->scsiio_depth; i && !found; i--) { -+ scmd = ioc->scsi_lookup[i - 1].scmd; -+ if (scmd == NULL || scmd->device == NULL || -+ scmd->device->hostdata == NULL) -+ continue; -+ if (lun != scmd->device->lun) -+ continue; -+ priv_data = scmd->device->hostdata; -+ if (priv_data->sas_target == NULL) -+ continue; -+ if (priv_data->sas_target->handle != handle) -+ continue; -+ tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid); -+ found = 1; -+ } -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ if (!found) { -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), lun(%d), no active mid!!\n", -+ ioc->name, -+ desc, le16_to_cpu(tm_request->DevHandle), lun)); -+ tm_reply = ioc->ctl_cmds.reply; -+ tm_reply->DevHandle = tm_request->DevHandle; -+ tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; -+ tm_reply->TaskType = tm_request->TaskType; -+ tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4; -+ tm_reply->VP_ID = tm_request->VP_ID; -+ tm_reply->VF_ID = tm_request->VF_ID; -+ sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz); -+ if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply, -+ sz)) -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ return 1; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, -+ desc, le16_to_cpu(tm_request->DevHandle), lun, -+ le16_to_cpu(tm_request->TaskMID))); -+ return 0; -+} -+ -+/** -+ * _ctl_do_mpt_command - main handler for MPT3COMMAND opcode -+ * @ioc: per adapter object -+ * @karg - (struct mpt3_ioctl_command) -+ * @mf - pointer to mf in user space -+ */ -+static long -+_ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, -+ void __user *mf) -+{ -+ MPI2RequestHeader_t *mpi_request = NULL, *request; -+ MPI2DefaultReply_t *mpi_reply; -+ u32 ioc_state; -+ u16 ioc_status; -+ u16 smid; -+ unsigned long timeout, timeleft; -+ u8 issue_reset; -+ u32 sz; -+ void *psge; -+ void *data_out = NULL; -+ dma_addr_t data_out_dma = 0; -+ size_t data_out_sz = 0; -+ void *data_in = NULL; -+ dma_addr_t data_in_dma = 0; -+ size_t data_in_sz = 0; -+ long ret; -+ u16 wait_state_count; -+ -+ issue_reset = 0; -+ -+ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", -+ ioc->name, __func__); -+ ret = -EAGAIN; -+ goto out; -+ } -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ ret = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, -+ __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); -+ if (!mpi_request) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed obtaining a memory for mpi_request\n", -+ ioc->name, __func__); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ /* Check for overflow and wraparound */ -+ if (karg.data_sge_offset * 4 > ioc->request_sz || -+ karg.data_sge_offset > (UINT_MAX / 4)) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* copy in request message frame from user */ -+ if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, -+ __func__); -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { -+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ret = -EAGAIN; -+ goto out; -+ } -+ } else { -+ -+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ret = -EAGAIN; -+ goto out; -+ } -+ } -+ -+ ret = 0; -+ ioc->ctl_cmds.status = MPT3_CMD_PENDING; -+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -+ request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memcpy(request, mpi_request, karg.data_sge_offset*4); -+ ioc->ctl_cmds.smid = smid; -+ data_out_sz = karg.data_out_size; -+ data_in_sz = karg.data_in_size; -+ -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { -+ if (!le16_to_cpu(mpi_request->FunctionDependent1) || -+ le16_to_cpu(mpi_request->FunctionDependent1) > -+ ioc->facts.MaxDevHandle) { -+ ret = -EINVAL; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } -+ -+ /* obtain dma-able memory for data transfer */ -+ if (data_out_sz) /* WRITE */ { -+ data_out = pci_alloc_consistent(ioc->pdev, data_out_sz, -+ &data_out_dma); -+ if (!data_out) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ if (copy_from_user(data_out, karg.data_out_buf_ptr, -+ data_out_sz)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -EFAULT; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } -+ -+ if (data_in_sz) /* READ */ { -+ data_in = pci_alloc_consistent(ioc->pdev, data_in_sz, -+ &data_in_dma); -+ if (!data_in) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } -+ -+ psge = (void *)request + (karg.data_sge_offset*4); -+ -+ /* send command to firmware */ -+ _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); -+ -+ init_completion(&ioc->ctl_cmds.done); -+ switch (mpi_request->Function) { -+ case MPI2_FUNCTION_SCSI_IO_REQUEST: -+ case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: -+ { -+ Mpi2SCSIIORequest_t *scsiio_request = -+ (Mpi2SCSIIORequest_t *)request; -+ scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; -+ scsiio_request->SenseBufferLowAddress = -+ mpt2sas_base_get_sense_buffer_dma(ioc, smid); -+ memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) -+ mpt2sas_base_put_smid_scsi_io(ioc, smid, -+ le16_to_cpu(mpi_request->FunctionDependent1)); -+ else -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ case MPI2_FUNCTION_SCSI_TASK_MGMT: -+ { -+ Mpi2SCSITaskManagementRequest_t *tm_request = -+ (Mpi2SCSITaskManagementRequest_t *)request; -+ -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n", -+ ioc->name, -+ le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); -+ -+ if (tm_request->TaskType == -+ MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || -+ tm_request->TaskType == -+ MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) { -+ if (_ctl_set_task_mid(ioc, &karg, tm_request)) { -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } -+ -+ mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( -+ tm_request->DevHandle)); -+ ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ mpt2sas_base_put_smid_hi_priority(ioc, smid, 0); -+ break; -+ } -+ case MPI2_FUNCTION_SMP_PASSTHROUGH: -+ { -+ Mpi2SmpPassthroughRequest_t *smp_request = -+ (Mpi2SmpPassthroughRequest_t *)mpi_request; -+ u8 *data; -+ -+ /* ioc determines which port to use */ -+ smp_request->PhysicalPort = 0xFF; -+ if (smp_request->PassthroughFlags & -+ MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) -+ data = (u8 *)&smp_request->SGL; -+ else { -+ if (unlikely(data_out == NULL)) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ mpt2sas_base_free_smid(ioc, smid); -+ ret = -EINVAL; -+ goto out; -+ } -+ data = data_out; -+ } -+ -+ if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) { -+ ioc->ioc_link_reset_in_progress = 1; -+ ioc->ignore_loginfos = 1; -+ } -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, -+ data_in_sz); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ case MPI2_FUNCTION_SATA_PASSTHROUGH: -+ case MPI2_FUNCTION_FW_DOWNLOAD: -+ case MPI2_FUNCTION_FW_UPLOAD: -+ { -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, -+ data_in_sz); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ case MPI2_FUNCTION_TOOLBOX: -+ { -+ Mpi2ToolboxCleanRequest_t *toolbox_request = -+ (Mpi2ToolboxCleanRequest_t *)mpi_request; -+ -+ if (toolbox_request->Tool == MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL) { -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ } else { -+ ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ } -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: -+ { -+ Mpi2SasIoUnitControlRequest_t *sasiounit_request = -+ (Mpi2SasIoUnitControlRequest_t *)mpi_request; -+ -+ if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET -+ || sasiounit_request->Operation == -+ MPI2_SAS_OP_PHY_LINK_RESET) { -+ ioc->ioc_link_reset_in_progress = 1; -+ ioc->ignore_loginfos = 1; -+ } -+ /* drop to default case for posting the request */ -+ } -+ default: -+ ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ -+ if (karg.timeout < MPT3_IOCTL_DEFAULT_TIMEOUT) -+ timeout = MPT3_IOCTL_DEFAULT_TIMEOUT; -+ else -+ timeout = karg.timeout; -+ timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, -+ timeout*HZ); -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { -+ Mpi2SCSITaskManagementRequest_t *tm_request = -+ (Mpi2SCSITaskManagementRequest_t *)mpi_request; -+ mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu( -+ tm_request->DevHandle)); -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); -+ } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || -+ mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) && -+ ioc->ioc_link_reset_in_progress) { -+ ioc->ioc_link_reset_in_progress = 0; -+ ioc->ignore_loginfos = 0; -+ } -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", ioc->name, -+ __func__); -+ _debug_dump_mf(mpi_request, karg.data_sge_offset); -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ mpi_reply = ioc->ctl_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ -+ if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && -+ (ioc->logging_level & MPT_DEBUG_TM)) { -+ Mpi2SCSITaskManagementReply_t *tm_reply = -+ (Mpi2SCSITaskManagementReply_t *)mpi_reply; -+ -+ pr_info(MPT3SAS_FMT "TASK_MGMT: " \ -+ "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " -+ "TerminationCount(0x%08x)\n", ioc->name, -+ le16_to_cpu(tm_reply->IOCStatus), -+ le32_to_cpu(tm_reply->IOCLogInfo), -+ le32_to_cpu(tm_reply->TerminationCount)); -+ } -+ -+ /* copy out xdata to user */ -+ if (data_in_sz) { -+ if (copy_to_user(karg.data_in_buf_ptr, data_in, -+ data_in_sz)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENODATA; -+ goto out; -+ } -+ } -+ -+ /* copy out reply message frame to user */ -+ if (karg.max_reply_bytes) { -+ sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz); -+ if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply, -+ sz)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENODATA; -+ goto out; -+ } -+ } -+ -+ /* copy out sense to user */ -+ if (karg.max_sense_bytes && (mpi_request->Function == -+ MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == -+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { -+ sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); -+ if (copy_to_user(karg.sense_data_ptr, ioc->ctl_cmds.sense, -+ sz)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENODATA; -+ goto out; -+ } -+ } -+ -+ issue_host_reset: -+ if (issue_reset) { -+ ret = -ENODATA; -+ if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ mpi_request->Function == -+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || -+ mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) { -+ pr_info(MPT3SAS_FMT "issue target reset: handle = (0x%04x)\n", -+ ioc->name, -+ le16_to_cpu(mpi_request->FunctionDependent1)); -+ mpt2sas_halt_firmware(ioc); -+ mpt2sas_scsih_issue_tm(ioc, -+ le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, -+ 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, -+ TM_MUTEX_ON); -+ } else -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ } -+ -+ out: -+ -+ /* free memory associated with sg buffers */ -+ if (data_in) -+ pci_free_consistent(ioc->pdev, data_in_sz, data_in, -+ data_in_dma); -+ -+ if (data_out) -+ pci_free_consistent(ioc->pdev, data_out_sz, data_out, -+ data_out_dma); -+ -+ kfree(mpi_request); -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ return ret; -+} -+ -+/** -+ * _ctl_getiocinfo - main handler for MPT3IOCINFO opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_iocinfo karg; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ memset(&karg, 0 , sizeof(karg)); -+ if (ioc->pfacts) -+ karg.port_number = ioc->pfacts[0].PortNumber; -+ karg.hw_rev = ioc->pdev->revision; -+ karg.pci_id = ioc->pdev->device; -+ karg.subsystem_device = ioc->pdev->subsystem_device; -+ karg.subsystem_vendor = ioc->pdev->subsystem_vendor; -+ karg.pci_information.u.bits.bus = ioc->pdev->bus->number; -+ karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn); -+ karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn); -+ karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus); -+ karg.firmware_version = ioc->facts.FWVersion.Word; -+ strcpy(karg.driver_version, ioc->driver_name); -+ strcat(karg.driver_version, "-"); -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ if (ioc->is_warpdrive) -+ karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; -+ else -+ karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; -+ strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION); -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3; -+ strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION); -+ break; -+ } -+ karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); -+ -+ if (copy_to_user(arg, &karg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * _ctl_eventquery - main handler for MPT3EVENTQUERY opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_eventquery(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_eventquery karg; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ karg.event_entries = MPT3SAS_CTL_EVENT_LOG_SIZE; -+ memcpy(karg.event_types, ioc->event_type, -+ MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); -+ -+ if (copy_to_user(arg, &karg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * _ctl_eventenable - main handler for MPT3EVENTENABLE opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_eventenable(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_eventenable karg; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ memcpy(ioc->event_type, karg.event_types, -+ MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); -+ mpt2sas_base_validate_event_type(ioc, ioc->event_type); -+ -+ if (ioc->event_log) -+ return 0; -+ /* initialize event_log */ -+ ioc->event_context = 0; -+ ioc->aen_event_read_flag = 0; -+ ioc->event_log = kcalloc(MPT3SAS_CTL_EVENT_LOG_SIZE, -+ sizeof(struct MPT3_IOCTL_EVENTS), GFP_KERNEL); -+ if (!ioc->event_log) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -ENOMEM; -+ } -+ return 0; -+} -+ -+/** -+ * _ctl_eventreport - main handler for MPT3EVENTREPORT opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_eventreport(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_eventreport karg; -+ u32 number_bytes, max_events, max; -+ struct mpt3_ioctl_eventreport __user *uarg = arg; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ number_bytes = karg.hdr.max_data_size - -+ sizeof(struct mpt3_ioctl_header); -+ max_events = number_bytes/sizeof(struct MPT3_IOCTL_EVENTS); -+ max = min_t(u32, MPT3SAS_CTL_EVENT_LOG_SIZE, max_events); -+ -+ /* If fewer than 1 event is requested, there must have -+ * been some type of error. -+ */ -+ if (!max || !ioc->event_log) -+ return -ENODATA; -+ -+ number_bytes = max * sizeof(struct MPT3_IOCTL_EVENTS); -+ if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ /* reset flag so SIGIO can restart */ -+ ioc->aen_event_read_flag = 0; -+ return 0; -+} -+ -+/** -+ * _ctl_do_reset - main handler for MPT3HARDRESET opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_diag_reset karg; -+ int retval; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery || -+ ioc->is_driver_loading) -+ return -EAGAIN; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ pr_info(MPT3SAS_FMT "host reset: %s\n", -+ ioc->name, ((!retval) ? "SUCCESS" : "FAILED")); -+ return 0; -+} -+ -+/** -+ * _ctl_btdh_search_sas_device - searching for sas device -+ * @ioc: per adapter object -+ * @btdh: btdh ioctl payload -+ */ -+static int -+_ctl_btdh_search_sas_device(struct MPT3SAS_ADAPTER *ioc, -+ struct mpt3_ioctl_btdh_mapping *btdh) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ int rc = 0; -+ -+ if (list_empty(&ioc->sas_device_list)) -+ return rc; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -+ if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && -+ btdh->handle == sas_device->handle) { -+ btdh->bus = sas_device->channel; -+ btdh->id = sas_device->id; -+ rc = 1; -+ goto out; -+ } else if (btdh->bus == sas_device->channel && btdh->id == -+ sas_device->id && btdh->handle == 0xFFFF) { -+ btdh->handle = sas_device->handle; -+ rc = 1; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_btdh_search_raid_device - searching for raid device -+ * @ioc: per adapter object -+ * @btdh: btdh ioctl payload -+ */ -+static int -+_ctl_btdh_search_raid_device(struct MPT3SAS_ADAPTER *ioc, -+ struct mpt3_ioctl_btdh_mapping *btdh) -+{ -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ int rc = 0; -+ -+ if (list_empty(&ioc->raid_device_list)) -+ return rc; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && -+ btdh->handle == raid_device->handle) { -+ btdh->bus = raid_device->channel; -+ btdh->id = raid_device->id; -+ rc = 1; -+ goto out; -+ } else if (btdh->bus == raid_device->channel && btdh->id == -+ raid_device->id && btdh->handle == 0xFFFF) { -+ btdh->handle = raid_device->handle; -+ rc = 1; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_btdh_mapping - main handler for MPT3BTDHMAPPING opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_btdh_mapping(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_btdh_mapping karg; -+ int rc; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ rc = _ctl_btdh_search_sas_device(ioc, &karg); -+ if (!rc) -+ _ctl_btdh_search_raid_device(ioc, &karg); -+ -+ if (copy_to_user(arg, &karg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * _ctl_diag_capability - return diag buffer capability -+ * @ioc: per adapter object -+ * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED -+ * -+ * returns 1 when diag buffer support is enabled in firmware -+ */ -+static u8 -+_ctl_diag_capability(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type) -+{ -+ u8 rc = 0; -+ -+ switch (buffer_type) { -+ case MPI2_DIAG_BUF_TYPE_TRACE: -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) -+ rc = 1; -+ break; -+ case MPI2_DIAG_BUF_TYPE_SNAPSHOT: -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) -+ rc = 1; -+ break; -+ case MPI2_DIAG_BUF_TYPE_EXTENDED: -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) -+ rc = 1; -+ } -+ -+ return rc; -+} -+ -+ -+/** -+ * _ctl_diag_register_2 - wrapper for registering diag buffer support -+ * @ioc: per adapter object -+ * @diag_register: the diag_register struct passed in from user space -+ * -+ */ -+static long -+_ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, -+ struct mpt3_diag_register *diag_register) -+{ -+ int rc, i; -+ void *request_data = NULL; -+ dma_addr_t request_data_dma; -+ u32 request_data_sz = 0; -+ Mpi2DiagBufferPostRequest_t *mpi_request; -+ Mpi2DiagBufferPostReply_t *mpi_reply; -+ u8 buffer_type; -+ unsigned long timeleft; -+ u16 smid; -+ u16 ioc_status; -+ u32 ioc_state; -+ u8 issue_reset = 0; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ buffer_type = diag_register->buffer_type; -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if (ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) { -+ pr_err(MPT3SAS_FMT -+ "%s: already has a registered buffer for buffer_type(0x%02x)\n", -+ ioc->name, __func__, -+ buffer_type); -+ return -EINVAL; -+ } -+ -+ if (diag_register->requested_buffer_size % 4) { -+ pr_err(MPT3SAS_FMT -+ "%s: the requested_buffer_size is not 4 byte aligned\n", -+ ioc->name, __func__); -+ return -EINVAL; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ ioc->ctl_cmds.status = MPT3_CMD_PENDING; -+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->ctl_cmds.smid = smid; -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ request_data_sz = diag_register->requested_buffer_size; -+ ioc->unique_id[buffer_type] = diag_register->unique_id; -+ ioc->diag_buffer_status[buffer_type] = 0; -+ memcpy(ioc->product_specific[buffer_type], -+ diag_register->product_specific, MPT3_PRODUCT_SPECIFIC_DWORDS); -+ ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags; -+ -+ if (request_data) { -+ request_data_dma = ioc->diag_buffer_dma[buffer_type]; -+ if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) { -+ pci_free_consistent(ioc->pdev, -+ ioc->diag_buffer_sz[buffer_type], -+ request_data, request_data_dma); -+ request_data = NULL; -+ } -+ } -+ -+ if (request_data == NULL) { -+ ioc->diag_buffer_sz[buffer_type] = 0; -+ ioc->diag_buffer_dma[buffer_type] = 0; -+ request_data = pci_alloc_consistent( -+ ioc->pdev, request_data_sz, &request_data_dma); -+ if (request_data == NULL) { -+ pr_err(MPT3SAS_FMT "%s: failed allocating memory" \ -+ " for diag buffers, requested size(%d)\n", -+ ioc->name, __func__, request_data_sz); -+ mpt2sas_base_free_smid(ioc, smid); -+ return -ENOMEM; -+ } -+ ioc->diag_buffer[buffer_type] = request_data; -+ ioc->diag_buffer_sz[buffer_type] = request_data_sz; -+ ioc->diag_buffer_dma[buffer_type] = request_data_dma; -+ } -+ -+ mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; -+ mpi_request->BufferType = diag_register->buffer_type; -+ mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags); -+ mpi_request->BufferAddress = cpu_to_le64(request_data_dma); -+ mpi_request->BufferLength = cpu_to_le32(request_data_sz); -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: diag_buffer(0x%p), dma(0x%llx), sz(%d)\n", -+ ioc->name, __func__, request_data, -+ (unsigned long long)request_data_dma, -+ le32_to_cpu(mpi_request->BufferLength))); -+ -+ for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) -+ mpi_request->ProductSpecific[i] = -+ cpu_to_le32(ioc->product_specific[buffer_type][i]); -+ -+ init_completion(&ioc->ctl_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, -+ MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); -+ -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", ioc->name, -+ __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2DiagBufferPostRequest_t)/4); -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ /* process the completed Reply Message Frame */ -+ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { -+ pr_err(MPT3SAS_FMT "%s: no reply message\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ mpi_reply = ioc->ctl_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_REGISTERED; -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", -+ ioc->name, __func__)); -+ } else { -+ pr_info(MPT3SAS_FMT -+ "%s: ioc_status(0x%04x) log_info(0x%08x)\n", -+ ioc->name, __func__, -+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); -+ rc = -EFAULT; -+ } -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ -+ out: -+ -+ if (rc && request_data) -+ pci_free_consistent(ioc->pdev, request_data_sz, -+ request_data, request_data_dma); -+ -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ return rc; -+} -+ -+/** -+ * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time -+ * @ioc: per adapter object -+ * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1 -+ * -+ * This is called when command line option diag_buffer_enable is enabled -+ * at driver load time. -+ */ -+void -+mpt2sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) -+{ -+ struct mpt3_diag_register diag_register; -+ -+ memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); -+ -+ if (bits_to_register & 1) { -+ pr_info(MPT3SAS_FMT "registering trace buffer support\n", -+ ioc->name); -+ ioc->diag_trigger_master.MasterData = -+ (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); -+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; -+ /* register for 2MB buffers */ -+ diag_register.requested_buffer_size = 2 * (1024 * 1024); -+ diag_register.unique_id = 0x7075900; -+ _ctl_diag_register_2(ioc, &diag_register); -+ } -+ -+ if (bits_to_register & 2) { -+ pr_info(MPT3SAS_FMT "registering snapshot buffer support\n", -+ ioc->name); -+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; -+ /* register for 2MB buffers */ -+ diag_register.requested_buffer_size = 2 * (1024 * 1024); -+ diag_register.unique_id = 0x7075901; -+ _ctl_diag_register_2(ioc, &diag_register); -+ } -+ -+ if (bits_to_register & 4) { -+ pr_info(MPT3SAS_FMT "registering extended buffer support\n", -+ ioc->name); -+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; -+ /* register for 2MB buffers */ -+ diag_register.requested_buffer_size = 2 * (1024 * 1024); -+ diag_register.unique_id = 0x7075901; -+ _ctl_diag_register_2(ioc, &diag_register); -+ } -+} -+ -+/** -+ * _ctl_diag_register - application register with driver -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ * -+ * This will allow the driver to setup any required buffers that will be -+ * needed by firmware to communicate with the driver. -+ */ -+static long -+_ctl_diag_register(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_register karg; -+ long rc; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ rc = _ctl_diag_register_2(ioc, &karg); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_unregister - application unregister with driver -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ * -+ * This will allow the driver to cleanup any memory allocated for diag -+ * messages and to free up any resources. -+ */ -+static long -+_ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_unregister karg; -+ void *request_data; -+ dma_addr_t request_data_dma; -+ u32 request_data_sz; -+ u8 buffer_type; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ buffer_type = karg.unique_id & 0x000000ff; -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is not registered\n", -+ ioc->name, __func__, buffer_type); -+ return -EINVAL; -+ } -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) has not been released\n", -+ ioc->name, __func__, buffer_type); -+ return -EINVAL; -+ } -+ -+ if (karg.unique_id != ioc->unique_id[buffer_type]) { -+ pr_err(MPT3SAS_FMT -+ "%s: unique_id(0x%08x) is not registered\n", -+ ioc->name, __func__, karg.unique_id); -+ return -EINVAL; -+ } -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ if (!request_data) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -ENOMEM; -+ } -+ -+ request_data_sz = ioc->diag_buffer_sz[buffer_type]; -+ request_data_dma = ioc->diag_buffer_dma[buffer_type]; -+ pci_free_consistent(ioc->pdev, request_data_sz, -+ request_data, request_data_dma); -+ ioc->diag_buffer[buffer_type] = NULL; -+ ioc->diag_buffer_status[buffer_type] = 0; -+ return 0; -+} -+ -+/** -+ * _ctl_diag_query - query relevant info associated with diag buffers -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ * -+ * The application will send only buffer_type and unique_id. Driver will -+ * inspect unique_id first, if valid, fill in all the info. If unique_id is -+ * 0x00, the driver will return info specified by Buffer Type. -+ */ -+static long -+_ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_query karg; -+ void *request_data; -+ int i; -+ u8 buffer_type; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ karg.application_flags = 0; -+ buffer_type = karg.buffer_type; -+ -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is not registered\n", -+ ioc->name, __func__, buffer_type); -+ return -EINVAL; -+ } -+ -+ if (karg.unique_id & 0xffffff00) { -+ if (karg.unique_id != ioc->unique_id[buffer_type]) { -+ pr_err(MPT3SAS_FMT -+ "%s: unique_id(0x%08x) is not registered\n", -+ ioc->name, __func__, karg.unique_id); -+ return -EINVAL; -+ } -+ } -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ if (!request_data) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have buffer for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -ENOMEM; -+ } -+ -+ if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_RELEASED) -+ karg.application_flags = (MPT3_APP_FLAGS_APP_OWNED | -+ MPT3_APP_FLAGS_BUFFER_VALID); -+ else -+ karg.application_flags = (MPT3_APP_FLAGS_APP_OWNED | -+ MPT3_APP_FLAGS_BUFFER_VALID | -+ MPT3_APP_FLAGS_FW_BUFFER_ACCESS); -+ -+ for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) -+ karg.product_specific[i] = -+ ioc->product_specific[buffer_type][i]; -+ -+ karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type]; -+ karg.driver_added_buffer_size = 0; -+ karg.unique_id = ioc->unique_id[buffer_type]; -+ karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type]; -+ -+ if (copy_to_user(arg, &karg, sizeof(struct mpt3_diag_query))) { -+ pr_err(MPT3SAS_FMT -+ "%s: unable to write mpt3_diag_query data @ %p\n", -+ ioc->name, __func__, arg); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * mpt2sas_send_diag_release - Diag Release Message -+ * @ioc: per adapter object -+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED -+ * @issue_reset - specifies whether host reset is required. -+ * -+ */ -+int -+mpt2sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, -+ u8 *issue_reset) -+{ -+ Mpi2DiagReleaseRequest_t *mpi_request; -+ Mpi2DiagReleaseReply_t *mpi_reply; -+ u16 smid; -+ u16 ioc_status; -+ u32 ioc_state; -+ int rc; -+ unsigned long timeleft; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ rc = 0; -+ *issue_reset = 0; -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_RELEASED; -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: skipping due to FAULT state\n", ioc->name, -+ __func__)); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ ioc->ctl_cmds.status = MPT3_CMD_PENDING; -+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->ctl_cmds.smid = smid; -+ -+ mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE; -+ mpi_request->BufferType = buffer_type; -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ -+ init_completion(&ioc->ctl_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, -+ MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); -+ -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", ioc->name, -+ __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2DiagReleaseRequest_t)/4); -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_RESET)) -+ *issue_reset = 1; -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ /* process the completed Reply Message Frame */ -+ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { -+ pr_err(MPT3SAS_FMT "%s: no reply message\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ mpi_reply = ioc->ctl_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_RELEASED; -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", -+ ioc->name, __func__)); -+ } else { -+ pr_info(MPT3SAS_FMT -+ "%s: ioc_status(0x%04x) log_info(0x%08x)\n", -+ ioc->name, __func__, -+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); -+ rc = -EFAULT; -+ } -+ -+ out: -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ return rc; -+} -+ -+/** -+ * _ctl_diag_release - request to send Diag Release Message to firmware -+ * @arg - user space buffer containing ioctl content -+ * -+ * This allows ownership of the specified buffer to returned to the driver, -+ * allowing an application to read the buffer without fear that firmware is -+ * overwritting information in the buffer. -+ */ -+static long -+_ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_release karg; -+ void *request_data; -+ int rc; -+ u8 buffer_type; -+ u8 issue_reset = 0; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ buffer_type = karg.unique_id & 0x000000ff; -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is not registered\n", -+ ioc->name, __func__, buffer_type); -+ return -EINVAL; -+ } -+ -+ if (karg.unique_id != ioc->unique_id[buffer_type]) { -+ pr_err(MPT3SAS_FMT -+ "%s: unique_id(0x%08x) is not registered\n", -+ ioc->name, __func__, karg.unique_id); -+ return -EINVAL; -+ } -+ -+ if (ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is already released\n", -+ ioc->name, __func__, -+ buffer_type); -+ return 0; -+ } -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ -+ if (!request_data) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -ENOMEM; -+ } -+ -+ /* buffers were released by due to host reset */ -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_DIAG_RESET)) { -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_RELEASED; -+ ioc->diag_buffer_status[buffer_type] &= -+ ~MPT3_DIAG_BUFFER_IS_DIAG_RESET; -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) was released due to host reset\n", -+ ioc->name, __func__, buffer_type); -+ return 0; -+ } -+ -+ rc = mpt2sas_send_diag_release(ioc, buffer_type, &issue_reset); -+ -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ -+ return rc; -+} -+ -+/** -+ * _ctl_diag_read_buffer - request for copy of the diag buffer -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_read_buffer karg; -+ struct mpt3_diag_read_buffer __user *uarg = arg; -+ void *request_data, *diag_data; -+ Mpi2DiagBufferPostRequest_t *mpi_request; -+ Mpi2DiagBufferPostReply_t *mpi_reply; -+ int rc, i; -+ u8 buffer_type; -+ unsigned long timeleft, request_size, copy_size; -+ u16 smid; -+ u16 ioc_status; -+ u8 issue_reset = 0; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ buffer_type = karg.unique_id & 0x000000ff; -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if (karg.unique_id != ioc->unique_id[buffer_type]) { -+ pr_err(MPT3SAS_FMT -+ "%s: unique_id(0x%08x) is not registered\n", -+ ioc->name, __func__, karg.unique_id); -+ return -EINVAL; -+ } -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ if (!request_data) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have buffer for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -ENOMEM; -+ } -+ -+ request_size = ioc->diag_buffer_sz[buffer_type]; -+ -+ if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { -+ pr_err(MPT3SAS_FMT "%s: either the starting_offset " \ -+ "or bytes_to_read are not 4 byte aligned\n", ioc->name, -+ __func__); -+ return -EINVAL; -+ } -+ -+ if (karg.starting_offset > request_size) -+ return -EINVAL; -+ -+ diag_data = (void *)(request_data + karg.starting_offset); -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: diag_buffer(%p), offset(%d), sz(%d)\n", -+ ioc->name, __func__, -+ diag_data, karg.starting_offset, karg.bytes_to_read)); -+ -+ /* Truncate data on requests that are too large */ -+ if ((diag_data + karg.bytes_to_read < diag_data) || -+ (diag_data + karg.bytes_to_read > request_data + request_size)) -+ copy_size = request_size - karg.starting_offset; -+ else -+ copy_size = karg.bytes_to_read; -+ -+ if (copy_to_user((void __user *)uarg->diagnostic_data, -+ diag_data, copy_size)) { -+ pr_err(MPT3SAS_FMT -+ "%s: Unable to write mpt_diag_read_buffer_t data @ %p\n", -+ ioc->name, __func__, diag_data); -+ return -EFAULT; -+ } -+ -+ if ((karg.flags & MPT3_FLAGS_REREGISTER) == 0) -+ return 0; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: Reregister buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type)); -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is still registered\n", -+ ioc->name, __func__, buffer_type)); -+ return 0; -+ } -+ /* Get a free request frame and save the message context. -+ */ -+ -+ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ ioc->ctl_cmds.status = MPT3_CMD_PENDING; -+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->ctl_cmds.smid = smid; -+ -+ mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; -+ mpi_request->BufferType = buffer_type; -+ mpi_request->BufferLength = -+ cpu_to_le32(ioc->diag_buffer_sz[buffer_type]); -+ mpi_request->BufferAddress = -+ cpu_to_le64(ioc->diag_buffer_dma[buffer_type]); -+ for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) -+ mpi_request->ProductSpecific[i] = -+ cpu_to_le32(ioc->product_specific[buffer_type][i]); -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ -+ init_completion(&ioc->ctl_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, -+ MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); -+ -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", ioc->name, -+ __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2DiagBufferPostRequest_t)/4); -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ /* process the completed Reply Message Frame */ -+ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { -+ pr_err(MPT3SAS_FMT "%s: no reply message\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ mpi_reply = ioc->ctl_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_REGISTERED; -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", -+ ioc->name, __func__)); -+ } else { -+ pr_info(MPT3SAS_FMT -+ "%s: ioc_status(0x%04x) log_info(0x%08x)\n", -+ ioc->name, __func__, -+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); -+ rc = -EFAULT; -+ } -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ -+ out: -+ -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ return rc; -+} -+ -+ -+ -+#ifdef CONFIG_COMPAT -+/** -+ * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. -+ * @ioc: per adapter object -+ * @cmd - ioctl opcode -+ * @arg - (struct mpt3_ioctl_command32) -+ * -+ * MPT3COMMAND32 - Handle 32bit applications running on 64bit os. -+ */ -+static long -+_ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd, -+ void __user *arg) -+{ -+ struct mpt3_ioctl_command32 karg32; -+ struct mpt3_ioctl_command32 __user *uarg; -+ struct mpt3_ioctl_command karg; -+ -+ if (_IOC_SIZE(cmd) != sizeof(struct mpt3_ioctl_command32)) -+ return -EINVAL; -+ -+ uarg = (struct mpt3_ioctl_command32 __user *) arg; -+ -+ if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ memset(&karg, 0, sizeof(struct mpt3_ioctl_command)); -+ karg.hdr.ioc_number = karg32.hdr.ioc_number; -+ karg.hdr.port_number = karg32.hdr.port_number; -+ karg.hdr.max_data_size = karg32.hdr.max_data_size; -+ karg.timeout = karg32.timeout; -+ karg.max_reply_bytes = karg32.max_reply_bytes; -+ karg.data_in_size = karg32.data_in_size; -+ karg.data_out_size = karg32.data_out_size; -+ karg.max_sense_bytes = karg32.max_sense_bytes; -+ karg.data_sge_offset = karg32.data_sge_offset; -+ karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); -+ karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); -+ karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); -+ karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); -+ return _ctl_do_mpt_command(ioc, karg, &uarg->mf); -+} -+#endif -+ -+/** -+ * _ctl_ioctl_main - main ioctl entry point -+ * @file - (struct file) -+ * @cmd - ioctl opcode -+ * @arg - user space data buffer -+ * @compat - handles 32 bit applications in 64bit os -+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & -+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device. -+ */ -+static long -+_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, -+ u8 compat, u16 mpi_version) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ struct mpt3_ioctl_header ioctl_header; -+ enum block_state state; -+ long ret = -EINVAL; -+ -+ /* get IOCTL header */ -+ if (copy_from_user(&ioctl_header, (char __user *)arg, -+ sizeof(struct mpt3_ioctl_header))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ if (_ctl_verify_adapter(ioctl_header.ioc_number, -+ &ioc, mpi_version) == -1 || !ioc) -+ return -ENODEV; -+ -+ /* pci_access_mutex lock acquired by ioctl path */ -+ mutex_lock(&ioc->pci_access_mutex); -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery || -+ ioc->is_driver_loading || ioc->remove_host) { -+ ret = -EAGAIN; -+ goto out_unlock_pciaccess; -+ } -+ -+ state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; -+ if (state == NON_BLOCKING) { -+ if (!mutex_trylock(&ioc->ctl_cmds.mutex)) { -+ ret = -EAGAIN; -+ goto out_unlock_pciaccess; -+ } -+ } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { -+ ret = -ERESTARTSYS; -+ goto out_unlock_pciaccess; -+ } -+ -+ -+ switch (cmd) { -+ case MPT3IOCINFO: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_iocinfo)) -+ ret = _ctl_getiocinfo(ioc, arg); -+ break; -+#ifdef CONFIG_COMPAT -+ case MPT3COMMAND32: -+#endif -+ case MPT3COMMAND: -+ { -+ struct mpt3_ioctl_command __user *uarg; -+ struct mpt3_ioctl_command karg; -+ -+#ifdef CONFIG_COMPAT -+ if (compat) { -+ ret = _ctl_compat_mpt_command(ioc, cmd, arg); -+ break; -+ } -+#endif -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ ret = -EFAULT; -+ break; -+ } -+ -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) { -+ uarg = arg; -+ ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); -+ } -+ break; -+ } -+ case MPT3EVENTQUERY: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_eventquery)) -+ ret = _ctl_eventquery(ioc, arg); -+ break; -+ case MPT3EVENTENABLE: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_eventenable)) -+ ret = _ctl_eventenable(ioc, arg); -+ break; -+ case MPT3EVENTREPORT: -+ ret = _ctl_eventreport(ioc, arg); -+ break; -+ case MPT3HARDRESET: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_diag_reset)) -+ ret = _ctl_do_reset(ioc, arg); -+ break; -+ case MPT3BTDHMAPPING: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_btdh_mapping)) -+ ret = _ctl_btdh_mapping(ioc, arg); -+ break; -+ case MPT3DIAGREGISTER: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_register)) -+ ret = _ctl_diag_register(ioc, arg); -+ break; -+ case MPT3DIAGUNREGISTER: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_unregister)) -+ ret = _ctl_diag_unregister(ioc, arg); -+ break; -+ case MPT3DIAGQUERY: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_query)) -+ ret = _ctl_diag_query(ioc, arg); -+ break; -+ case MPT3DIAGRELEASE: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_release)) -+ ret = _ctl_diag_release(ioc, arg); -+ break; -+ case MPT3DIAGREADBUFFER: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_read_buffer)) -+ ret = _ctl_diag_read_buffer(ioc, arg); -+ break; -+ default: -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); -+ break; -+ } -+ -+ mutex_unlock(&ioc->ctl_cmds.mutex); -+out_unlock_pciaccess: -+ mutex_unlock(&ioc->pci_access_mutex); -+ return ret; -+} -+ -+/** -+ * _ctl_ioctl_mpt2sas - mpt3ctl main ioctl entry point (unlocked) -+ * @file - (struct file) -+ * @cmd - ioctl opcode -+ * @arg - -+ */ -+long -+_ctl_ioctl_mpt2sas(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ long ret; -+ -+ /* pass MPI25_VERSION | MPI26_VERSION value, -+ * to indicate that this ioctl cmd -+ * came from mpt3ctl ioctl device. -+ */ -+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, -+ MPI25_VERSION | MPI26_VERSION); -+ return ret; -+} -+ -+/** -+ * _ctl_mpt2_ioctl_mpt2sas - mpt2ctl main ioctl entry point (unlocked) -+ * @file - (struct file) -+ * @cmd - ioctl opcode -+ * @arg - -+ */ -+long -+_ctl_mpt2_ioctl_mpt2sas(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ long ret; -+ -+ /* pass MPI2_VERSION value, to indicate that this ioctl cmd -+ * came from mpt2ctl ioctl device. -+ */ -+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION); -+ return ret; -+} -+#ifdef CONFIG_COMPAT -+/** -+ *_ ctl_ioctl_compat - main ioctl entry point (compat) -+ * @file - -+ * @cmd - -+ * @arg - -+ * -+ * This routine handles 32 bit applications in 64bit os. -+ */ -+long -+_ctl_ioctl_compat_mpt2sas(struct file *file, unsigned cmd, unsigned long arg) -+{ -+ long ret; -+ -+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, -+ MPI25_VERSION | MPI26_VERSION); -+ return ret; -+} -+ -+/** -+ *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat) -+ * @file - -+ * @cmd - -+ * @arg - -+ * -+ * This routine handles 32 bit applications in 64bit os. -+ */ -+long -+_ctl_mpt2_ioctl_compat_mpt2sas(struct file *file, unsigned cmd, unsigned long arg) -+{ -+ long ret; -+ -+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION); -+ return ret; -+} -+#endif -+ -+/* scsi host attributes */ -+/** -+ * _ctl_version_fw_show - firmware version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", -+ (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, -+ (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, -+ (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, -+ ioc->facts.FWVersion.Word & 0x000000FF); -+} -+static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); -+ -+/** -+ * _ctl_version_bios_show - bios version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", -+ (version & 0xFF000000) >> 24, -+ (version & 0x00FF0000) >> 16, -+ (version & 0x0000FF00) >> 8, -+ version & 0x000000FF); -+} -+static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); -+ -+/** -+ * _ctl_version_mpi_show - MPI (message passing interface) version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", -+ ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); -+} -+static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); -+ -+/** -+ * _ctl_version_product_show - product name -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_product_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); -+} -+static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL); -+ -+/** -+ * _ctl_version_nvdata_persistent_show - ndvata persistent version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_nvdata_persistent_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%08xh\n", -+ le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); -+} -+static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, -+ _ctl_version_nvdata_persistent_show, NULL); -+ -+/** -+ * _ctl_version_nvdata_default_show - nvdata default version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute -+ *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%08xh\n", -+ le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); -+} -+static DEVICE_ATTR(version_nvdata_default, S_IRUGO, -+ _ctl_version_nvdata_default_show, NULL); -+ -+/** -+ * _ctl_board_name_show - board name -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_board_name_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); -+} -+static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); -+ -+/** -+ * _ctl_board_assembly_show - board assembly name -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); -+} -+static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL); -+ -+/** -+ * _ctl_board_tracer_show - board tracer number -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); -+} -+static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL); -+ -+/** -+ * _ctl_io_delay_show - io missing delay -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is for firmware implemention for deboucing device -+ * removal events. -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); -+} -+static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL); -+ -+/** -+ * _ctl_device_delay_show - device missing delay -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is for firmware implemention for deboucing device -+ * removal events. -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); -+} -+static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL); -+ -+/** -+ * _ctl_fw_queue_depth_show - global credits -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is firmware queue depth limit -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); -+} -+static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL); -+ -+/** -+ * _ctl_sas_address_show - sas address -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is the controller sas address -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+ -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "0x%016llx\n", -+ (unsigned long long)ioc->sas_hba.sas_address); -+} -+static DEVICE_ATTR(host_sas_address, S_IRUGO, -+ _ctl_host_sas_address_show, NULL); -+ -+/** -+ * _ctl_logging_level_show - logging level -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); -+} -+static ssize_t -+_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int val = 0; -+ -+ if (sscanf(buf, "%x", &val) != 1) -+ return -EINVAL; -+ -+ ioc->logging_level = val; -+ pr_info(MPT3SAS_FMT "logging_level=%08xh\n", ioc->name, -+ ioc->logging_level); -+ return strlen(buf); -+} -+static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, -+ _ctl_logging_level_store); -+ -+/** -+ * _ctl_fwfault_debug_show - show/store fwfault_debug -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * mpt2sas_fwfault_debug is command line option -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); -+} -+static ssize_t -+_ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int val = 0; -+ -+ if (sscanf(buf, "%d", &val) != 1) -+ return -EINVAL; -+ -+ ioc->fwfault_debug = val; -+ pr_info(MPT3SAS_FMT "fwfault_debug=%d\n", ioc->name, -+ ioc->fwfault_debug); -+ return strlen(buf); -+} -+static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, -+ _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); -+ -+/** -+ * _ctl_ioc_reset_count_show - ioc reset count -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is firmware queue depth limit -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count); -+} -+static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); -+ -+/** -+ * _ctl_ioc_reply_queue_count_show - number of reply queues -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is number of reply queues -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_ioc_reply_queue_count_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ u8 reply_queue_count; -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ if ((ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable) -+ reply_queue_count = ioc->reply_queue_count; -+ else -+ reply_queue_count = 1; -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); -+} -+static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show, -+ NULL); -+ -+/** -+ * _ctl_BRM_status_show - Backup Rail Monitor Status -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is number of reply queues -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ Mpi2IOUnitPage3_t *io_unit_pg3 = NULL; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 backup_rail_monitor_status = 0; -+ u16 ioc_status; -+ int sz; -+ ssize_t rc = 0; -+ -+ if (!ioc->is_warpdrive) { -+ pr_err(MPT3SAS_FMT "%s: BRM attribute is only for" -+ " warpdrive\n", ioc->name, __func__); -+ goto out; -+ } -+ /* pci_access_mutex lock acquired by sysfs show path */ -+ mutex_lock(&ioc->pci_access_mutex); -+ if (ioc->pci_error_recovery || ioc->remove_host) { -+ mutex_unlock(&ioc->pci_access_mutex); -+ return 0; -+ } -+ -+ /* allocate upto GPIOVal 36 entries */ -+ sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); -+ io_unit_pg3 = kzalloc(sz, GFP_KERNEL); -+ if (!io_unit_pg3) { -+ pr_err(MPT3SAS_FMT "%s: failed allocating memory " -+ "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz); -+ goto out; -+ } -+ -+ if (mpt2sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != -+ 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed reading iounit_pg3\n", ioc->name, -+ __func__); -+ goto out; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "%s: iounit_pg3 failed with " -+ "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status); -+ goto out; -+ } -+ -+ if (io_unit_pg3->GPIOCount < 25) { -+ pr_err(MPT3SAS_FMT "%s: iounit_pg3->GPIOCount less than " -+ "25 entries, detected (%d) entries\n", ioc->name, __func__, -+ io_unit_pg3->GPIOCount); -+ goto out; -+ } -+ -+ /* BRM status is in bit zero of GPIOVal[24] */ -+ backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]); -+ rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1)); -+ -+ out: -+ kfree(io_unit_pg3); -+ mutex_unlock(&ioc->pci_access_mutex); -+ return rc; -+} -+static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); -+ -+struct DIAG_BUFFER_START { -+ __le32 Size; -+ __le32 DiagVersion; -+ u8 BufferType; -+ u8 Reserved[3]; -+ __le32 Reserved1; -+ __le32 Reserved2; -+ __le32 Reserved3; -+}; -+ -+/** -+ * _ctl_host_trace_buffer_size_show - host buffer size (trace only) -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_host_trace_buffer_size_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ u32 size = 0; -+ struct DIAG_BUFFER_START *request_data; -+ -+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { -+ pr_err(MPT3SAS_FMT -+ "%s: host_trace_buffer is not registered\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: host_trace_buffer is not registered\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ request_data = (struct DIAG_BUFFER_START *) -+ ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; -+ if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || -+ le32_to_cpu(request_data->DiagVersion) == 0x01000000 || -+ le32_to_cpu(request_data->DiagVersion) == 0x01010000) && -+ le32_to_cpu(request_data->Reserved3) == 0x4742444c) -+ size = le32_to_cpu(request_data->Size); -+ -+ ioc->ring_buffer_sz = size; -+ return snprintf(buf, PAGE_SIZE, "%d\n", size); -+} -+static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, -+ _ctl_host_trace_buffer_size_show, NULL); -+ -+/** -+ * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ * -+ * You will only be able to read 4k bytes of ring buffer at a time. -+ * In order to read beyond 4k bytes, you will have to write out the -+ * offset to the same attribute, it will move the pointer. -+ */ -+static ssize_t -+_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ void *request_data; -+ u32 size; -+ -+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { -+ pr_err(MPT3SAS_FMT -+ "%s: host_trace_buffer is not registered\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: host_trace_buffer is not registered\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) -+ return 0; -+ -+ size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; -+ size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size; -+ request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; -+ memcpy(buf, request_data, size); -+ return size; -+} -+ -+static ssize_t -+_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int val = 0; -+ -+ if (sscanf(buf, "%d", &val) != 1) -+ return -EINVAL; -+ -+ ioc->ring_buffer_offset = val; -+ return strlen(buf); -+} -+static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, -+ _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); -+ -+ -+/*****************************************/ -+ -+/** -+ * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ * -+ * This is a mechnism to post/release host_trace_buffers -+ */ -+static ssize_t -+_ctl_host_trace_buffer_enable_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || -+ ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0)) -+ return snprintf(buf, PAGE_SIZE, "off\n"); -+ else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ return snprintf(buf, PAGE_SIZE, "release\n"); -+ else -+ return snprintf(buf, PAGE_SIZE, "post\n"); -+} -+ -+static ssize_t -+_ctl_host_trace_buffer_enable_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ char str[10] = ""; -+ struct mpt3_diag_register diag_register; -+ u8 issue_reset = 0; -+ -+ /* don't allow post/release occurr while recovery is active */ -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery || ioc->is_driver_loading) -+ return -EBUSY; -+ -+ if (sscanf(buf, "%9s", str) != 1) -+ return -EINVAL; -+ -+ if (!strcmp(str, "post")) { -+ /* exit out if host buffers are already posted */ -+ if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && -+ (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) && -+ ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) == 0)) -+ goto out; -+ memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); -+ pr_info(MPT3SAS_FMT "posting host trace buffers\n", -+ ioc->name); -+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; -+ diag_register.requested_buffer_size = (1024 * 1024); -+ diag_register.unique_id = 0x7075900; -+ ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; -+ _ctl_diag_register_2(ioc, &diag_register); -+ } else if (!strcmp(str, "release")) { -+ /* exit out if host buffers are already released */ -+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) -+ goto out; -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) -+ goto out; -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ goto out; -+ pr_info(MPT3SAS_FMT "releasing host trace buffer\n", -+ ioc->name); -+ mpt2sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, -+ &issue_reset); -+ } -+ -+ out: -+ return strlen(buf); -+} -+static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, -+ _ctl_host_trace_buffer_enable_show, -+ _ctl_host_trace_buffer_enable_store); -+ -+/*********** diagnostic trigger suppport *********************************/ -+ -+/** -+ * _ctl_diag_trigger_master_show - show the diag_trigger_master attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_master_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+ -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = sizeof(struct SL_WH_MASTER_TRIGGER_T); -+ memcpy(buf, &ioc->diag_trigger_master, rc); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_trigger_master_store - store the diag_trigger_master attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_master_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+ -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = min(sizeof(struct SL_WH_MASTER_TRIGGER_T), count); -+ memset(&ioc->diag_trigger_master, 0, -+ sizeof(struct SL_WH_MASTER_TRIGGER_T)); -+ memcpy(&ioc->diag_trigger_master, buf, rc); -+ ioc->diag_trigger_master.MasterData |= -+ (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR, -+ _ctl_diag_trigger_master_show, _ctl_diag_trigger_master_store); -+ -+ -+/** -+ * _ctl_diag_trigger_event_show - show the diag_trigger_event attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_event_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = sizeof(struct SL_WH_EVENT_TRIGGERS_T); -+ memcpy(buf, &ioc->diag_trigger_event, rc); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_trigger_event_store - store the diag_trigger_event attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_event_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+ -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t sz; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ sz = min(sizeof(struct SL_WH_EVENT_TRIGGERS_T), count); -+ memset(&ioc->diag_trigger_event, 0, -+ sizeof(struct SL_WH_EVENT_TRIGGERS_T)); -+ memcpy(&ioc->diag_trigger_event, buf, sz); -+ if (ioc->diag_trigger_event.ValidEntries > NUM_VALID_ENTRIES) -+ ioc->diag_trigger_event.ValidEntries = NUM_VALID_ENTRIES; -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return sz; -+} -+static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR, -+ _ctl_diag_trigger_event_show, _ctl_diag_trigger_event_store); -+ -+ -+/** -+ * _ctl_diag_trigger_scsi_show - show the diag_trigger_scsi attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_scsi_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = sizeof(struct SL_WH_SCSI_TRIGGERS_T); -+ memcpy(buf, &ioc->diag_trigger_scsi, rc); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_trigger_scsi_store - store the diag_trigger_scsi attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_scsi_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t sz; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ sz = min(sizeof(struct SL_WH_SCSI_TRIGGERS_T), count); -+ memset(&ioc->diag_trigger_scsi, 0, -+ sizeof(struct SL_WH_EVENT_TRIGGERS_T)); -+ memcpy(&ioc->diag_trigger_scsi, buf, sz); -+ if (ioc->diag_trigger_scsi.ValidEntries > NUM_VALID_ENTRIES) -+ ioc->diag_trigger_scsi.ValidEntries = NUM_VALID_ENTRIES; -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return sz; -+} -+static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR, -+ _ctl_diag_trigger_scsi_show, _ctl_diag_trigger_scsi_store); -+ -+ -+/** -+ * _ctl_diag_trigger_scsi_show - show the diag_trigger_mpi attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_mpi_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = sizeof(struct SL_WH_MPI_TRIGGERS_T); -+ memcpy(buf, &ioc->diag_trigger_mpi, rc); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_trigger_mpi_store - store the diag_trigger_mpi attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_mpi_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t sz; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ sz = min(sizeof(struct SL_WH_MPI_TRIGGERS_T), count); -+ memset(&ioc->diag_trigger_mpi, 0, -+ sizeof(ioc->diag_trigger_mpi)); -+ memcpy(&ioc->diag_trigger_mpi, buf, sz); -+ if (ioc->diag_trigger_mpi.ValidEntries > NUM_VALID_ENTRIES) -+ ioc->diag_trigger_mpi.ValidEntries = NUM_VALID_ENTRIES; -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return sz; -+} -+ -+static DEVICE_ATTR(diag_trigger_mpi, S_IRUGO | S_IWUSR, -+ _ctl_diag_trigger_mpi_show, _ctl_diag_trigger_mpi_store); -+ -+/*********** diagnostic trigger suppport *** END ****************************/ -+ -+ -+ -+/*****************************************/ -+ -+struct device_attribute *mpt2sas_host_attrs[] = { -+ &dev_attr_version_fw, -+ &dev_attr_version_bios, -+ &dev_attr_version_mpi, -+ &dev_attr_version_product, -+ &dev_attr_version_nvdata_persistent, -+ &dev_attr_version_nvdata_default, -+ &dev_attr_board_name, -+ &dev_attr_board_assembly, -+ &dev_attr_board_tracer, -+ &dev_attr_io_delay, -+ &dev_attr_device_delay, -+ &dev_attr_logging_level, -+ &dev_attr_fwfault_debug, -+ &dev_attr_fw_queue_depth, -+ &dev_attr_host_sas_address, -+ &dev_attr_ioc_reset_count, -+ &dev_attr_host_trace_buffer_size, -+ &dev_attr_host_trace_buffer, -+ &dev_attr_host_trace_buffer_enable, -+ &dev_attr_reply_queue_count, -+ &dev_attr_diag_trigger_master, -+ &dev_attr_diag_trigger_event, -+ &dev_attr_diag_trigger_scsi, -+ &dev_attr_diag_trigger_mpi, -+ &dev_attr_BRM_status, -+ NULL, -+}; -+ -+/* device attributes */ -+ -+/** -+ * _ctl_device_sas_address_show - sas address -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is the sas address for the target -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; -+ -+ return snprintf(buf, PAGE_SIZE, "0x%016llx\n", -+ (unsigned long long)sas_device_priv_data->sas_target->sas_address); -+} -+static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); -+ -+/** -+ * _ctl_device_handle_show - device handle -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is the firmware assigned device handle -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_device_handle_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; -+ -+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", -+ sas_device_priv_data->sas_target->handle); -+} -+static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); -+ -+struct device_attribute *mpt2sas_dev_attrs[] = { -+ &dev_attr_sas_address, -+ &dev_attr_sas_device_handle, -+ NULL, -+}; -+ -+/* file operations table for mpt3ctl device */ -+static const struct file_operations ctl_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = _ctl_ioctl_mpt2sas, -+ .poll = _ctl_poll_mpt2sas, -+ .fasync = _ctl_fasync_mpt2sas, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = _ctl_ioctl_compat_mpt2sas, -+#endif -+}; -+ -+/* file operations table for mpt2ctl device */ -+static const struct file_operations ctl_gen2_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = _ctl_mpt2_ioctl_mpt2sas, -+ .poll = _ctl_poll_mpt2sas, -+ .fasync = _ctl_fasync_mpt2sas, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = _ctl_mpt2_ioctl_compat_mpt2sas, -+#endif -+}; -+ -+static struct miscdevice ctl_dev = { -+ .minor = MPT3SAS_MINOR, -+ .name = MPT3SAS_DEV_NAME, -+ .fops = &ctl_fops, -+}; -+ -+static struct miscdevice gen2_ctl_dev = { -+ .minor = MPT2SAS_MINOR, -+ .name = MPT2SAS_DEV_NAME, -+ .fops = &ctl_gen2_fops, -+}; -+ -+/** -+ * mpt2sas_ctl_init - main entry point for ctl. -+ * -+ */ -+void -+mpt2sas_ctl_init(ushort hbas_to_enumerate) -+{ -+ async_queue = NULL; -+ -+ /* Don't register mpt3ctl ioctl device if -+ * hbas_to_enumarate is one. -+ */ -+ if (hbas_to_enumerate != 1) -+ if (misc_register(&ctl_dev) < 0) -+ pr_err("%s can't register misc device [minor=%d]\n", -+ MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR); -+ -+ /* Don't register mpt3ctl ioctl device if -+ * hbas_to_enumarate is two. -+ */ -+ if (hbas_to_enumerate != 2) -+ if (misc_register(&gen2_ctl_dev) < 0) -+ pr_err("%s can't register misc device [minor=%d]\n", -+ MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); -+ -+ init_waitqueue_head(&ctl_poll_wait); -+} -+ -+/** -+ * mpt2sas_ctl_exit - exit point for ctl -+ * -+ */ -+void -+mpt2sas_ctl_exit(ushort hbas_to_enumerate) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ int i; -+ -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { -+ -+ /* free memory associated to diag buffers */ -+ for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { -+ if (!ioc->diag_buffer[i]) -+ continue; -+ if (!(ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED)) -+ continue; -+ if ((ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ continue; -+ pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i], -+ ioc->diag_buffer[i], ioc->diag_buffer_dma[i]); -+ ioc->diag_buffer[i] = NULL; -+ ioc->diag_buffer_status[i] = 0; -+ } -+ -+ kfree(ioc->event_log); -+ } -+ if (hbas_to_enumerate != 1) -+ misc_deregister(&ctl_dev); -+ if (hbas_to_enumerate != 2) -+ misc_deregister(&gen2_ctl_dev); -+} -diff --git a/drivers/scsi/mpt2sas/mpt3sas_ctl.h b/drivers/scsi/mpt2sas/mpt3sas_ctl.h -new file mode 100644 -index 0000000..8940835 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_ctl.h -@@ -0,0 +1,423 @@ -+/* -+ * Management Module Support for MPT (Message Passing Technology) based -+ * controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.h -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#ifndef MPT3SAS_CTL_H_INCLUDED -+#define MPT3SAS_CTL_H_INCLUDED -+ -+#ifdef __KERNEL__ -+#include -+#endif -+ -+#ifndef MPT2SAS_MINOR -+#define MPT2SAS_MINOR (MPT_MINOR + 1) -+#endif -+#ifndef MPT3SAS_MINOR -+#define MPT3SAS_MINOR (MPT_MINOR + 2) -+#endif -+#define MPT2SAS_DEV_NAME "mpt2ctl" -+#define MPT3SAS_DEV_NAME "mpt3ctl" -+#define MPT3_MAGIC_NUMBER 'L' -+#define MPT3_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */ -+ -+/** -+ * IOCTL opcodes -+ */ -+#define MPT3IOCINFO _IOWR(MPT3_MAGIC_NUMBER, 17, \ -+ struct mpt3_ioctl_iocinfo) -+#define MPT3COMMAND _IOWR(MPT3_MAGIC_NUMBER, 20, \ -+ struct mpt3_ioctl_command) -+#ifdef CONFIG_COMPAT -+#define MPT3COMMAND32 _IOWR(MPT3_MAGIC_NUMBER, 20, \ -+ struct mpt3_ioctl_command32) -+#endif -+#define MPT3EVENTQUERY _IOWR(MPT3_MAGIC_NUMBER, 21, \ -+ struct mpt3_ioctl_eventquery) -+#define MPT3EVENTENABLE _IOWR(MPT3_MAGIC_NUMBER, 22, \ -+ struct mpt3_ioctl_eventenable) -+#define MPT3EVENTREPORT _IOWR(MPT3_MAGIC_NUMBER, 23, \ -+ struct mpt3_ioctl_eventreport) -+#define MPT3HARDRESET _IOWR(MPT3_MAGIC_NUMBER, 24, \ -+ struct mpt3_ioctl_diag_reset) -+#define MPT3BTDHMAPPING _IOWR(MPT3_MAGIC_NUMBER, 31, \ -+ struct mpt3_ioctl_btdh_mapping) -+ -+/* diag buffer support */ -+#define MPT3DIAGREGISTER _IOWR(MPT3_MAGIC_NUMBER, 26, \ -+ struct mpt3_diag_register) -+#define MPT3DIAGRELEASE _IOWR(MPT3_MAGIC_NUMBER, 27, \ -+ struct mpt3_diag_release) -+#define MPT3DIAGUNREGISTER _IOWR(MPT3_MAGIC_NUMBER, 28, \ -+ struct mpt3_diag_unregister) -+#define MPT3DIAGQUERY _IOWR(MPT3_MAGIC_NUMBER, 29, \ -+ struct mpt3_diag_query) -+#define MPT3DIAGREADBUFFER _IOWR(MPT3_MAGIC_NUMBER, 30, \ -+ struct mpt3_diag_read_buffer) -+ -+/** -+ * struct mpt3_ioctl_header - main header structure -+ * @ioc_number - IOC unit number -+ * @port_number - IOC port number -+ * @max_data_size - maximum number bytes to transfer on read -+ */ -+struct mpt3_ioctl_header { -+ uint32_t ioc_number; -+ uint32_t port_number; -+ uint32_t max_data_size; -+}; -+ -+/** -+ * struct mpt3_ioctl_diag_reset - diagnostic reset -+ * @hdr - generic header -+ */ -+struct mpt3_ioctl_diag_reset { -+ struct mpt3_ioctl_header hdr; -+}; -+ -+ -+/** -+ * struct mpt3_ioctl_pci_info - pci device info -+ * @device - pci device id -+ * @function - pci function id -+ * @bus - pci bus id -+ * @segment_id - pci segment id -+ */ -+struct mpt3_ioctl_pci_info { -+ union { -+ struct { -+ uint32_t device:5; -+ uint32_t function:3; -+ uint32_t bus:24; -+ } bits; -+ uint32_t word; -+ } u; -+ uint32_t segment_id; -+}; -+ -+ -+#define MPT2_IOCTL_INTERFACE_SCSI (0x00) -+#define MPT2_IOCTL_INTERFACE_FC (0x01) -+#define MPT2_IOCTL_INTERFACE_FC_IP (0x02) -+#define MPT2_IOCTL_INTERFACE_SAS (0x03) -+#define MPT2_IOCTL_INTERFACE_SAS2 (0x04) -+#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05) -+#define MPT3_IOCTL_INTERFACE_SAS3 (0x06) -+#define MPT2_IOCTL_VERSION_LENGTH (32) -+ -+/** -+ * struct mpt3_ioctl_iocinfo - generic controller info -+ * @hdr - generic header -+ * @adapter_type - type of adapter (spi, fc, sas) -+ * @port_number - port number -+ * @pci_id - PCI Id -+ * @hw_rev - hardware revision -+ * @sub_system_device - PCI subsystem Device ID -+ * @sub_system_vendor - PCI subsystem Vendor ID -+ * @rsvd0 - reserved -+ * @firmware_version - firmware version -+ * @bios_version - BIOS version -+ * @driver_version - driver version - 32 ASCII characters -+ * @rsvd1 - reserved -+ * @scsi_id - scsi id of adapter 0 -+ * @rsvd2 - reserved -+ * @pci_information - pci info (2nd revision) -+ */ -+struct mpt3_ioctl_iocinfo { -+ struct mpt3_ioctl_header hdr; -+ uint32_t adapter_type; -+ uint32_t port_number; -+ uint32_t pci_id; -+ uint32_t hw_rev; -+ uint32_t subsystem_device; -+ uint32_t subsystem_vendor; -+ uint32_t rsvd0; -+ uint32_t firmware_version; -+ uint32_t bios_version; -+ uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH]; -+ uint8_t rsvd1; -+ uint8_t scsi_id; -+ uint16_t rsvd2; -+ struct mpt3_ioctl_pci_info pci_information; -+}; -+ -+ -+/* number of event log entries */ -+#define MPT3SAS_CTL_EVENT_LOG_SIZE (50) -+ -+/** -+ * struct mpt3_ioctl_eventquery - query event count and type -+ * @hdr - generic header -+ * @event_entries - number of events returned by get_event_report -+ * @rsvd - reserved -+ * @event_types - type of events currently being captured -+ */ -+struct mpt3_ioctl_eventquery { -+ struct mpt3_ioctl_header hdr; -+ uint16_t event_entries; -+ uint16_t rsvd; -+ uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; -+}; -+ -+/** -+ * struct mpt3_ioctl_eventenable - enable/disable event capturing -+ * @hdr - generic header -+ * @event_types - toggle off/on type of events to be captured -+ */ -+struct mpt3_ioctl_eventenable { -+ struct mpt3_ioctl_header hdr; -+ uint32_t event_types[4]; -+}; -+ -+#define MPT3_EVENT_DATA_SIZE (192) -+/** -+ * struct MPT3_IOCTL_EVENTS - -+ * @event - the event that was reported -+ * @context - unique value for each event assigned by driver -+ * @data - event data returned in fw reply message -+ */ -+struct MPT3_IOCTL_EVENTS { -+ uint32_t event; -+ uint32_t context; -+ uint8_t data[MPT3_EVENT_DATA_SIZE]; -+}; -+ -+/** -+ * struct mpt3_ioctl_eventreport - returing event log -+ * @hdr - generic header -+ * @event_data - (see struct MPT3_IOCTL_EVENTS) -+ */ -+struct mpt3_ioctl_eventreport { -+ struct mpt3_ioctl_header hdr; -+ struct MPT3_IOCTL_EVENTS event_data[1]; -+}; -+ -+/** -+ * struct mpt3_ioctl_command - generic mpt firmware passthru ioctl -+ * @hdr - generic header -+ * @timeout - command timeout in seconds. (if zero then use driver default -+ * value). -+ * @reply_frame_buf_ptr - reply location -+ * @data_in_buf_ptr - destination for read -+ * @data_out_buf_ptr - data source for write -+ * @sense_data_ptr - sense data location -+ * @max_reply_bytes - maximum number of reply bytes to be sent to app. -+ * @data_in_size - number bytes for data transfer in (read) -+ * @data_out_size - number bytes for data transfer out (write) -+ * @max_sense_bytes - maximum number of bytes for auto sense buffers -+ * @data_sge_offset - offset in words from the start of the request message to -+ * the first SGL -+ * @mf[1]; -+ */ -+struct mpt3_ioctl_command { -+ struct mpt3_ioctl_header hdr; -+ uint32_t timeout; -+ void __user *reply_frame_buf_ptr; -+ void __user *data_in_buf_ptr; -+ void __user *data_out_buf_ptr; -+ void __user *sense_data_ptr; -+ uint32_t max_reply_bytes; -+ uint32_t data_in_size; -+ uint32_t data_out_size; -+ uint32_t max_sense_bytes; -+ uint32_t data_sge_offset; -+ uint8_t mf[1]; -+}; -+ -+#ifdef CONFIG_COMPAT -+struct mpt3_ioctl_command32 { -+ struct mpt3_ioctl_header hdr; -+ uint32_t timeout; -+ uint32_t reply_frame_buf_ptr; -+ uint32_t data_in_buf_ptr; -+ uint32_t data_out_buf_ptr; -+ uint32_t sense_data_ptr; -+ uint32_t max_reply_bytes; -+ uint32_t data_in_size; -+ uint32_t data_out_size; -+ uint32_t max_sense_bytes; -+ uint32_t data_sge_offset; -+ uint8_t mf[1]; -+}; -+#endif -+ -+/** -+ * struct mpt3_ioctl_btdh_mapping - mapping info -+ * @hdr - generic header -+ * @id - target device identification number -+ * @bus - SCSI bus number that the target device exists on -+ * @handle - device handle for the target device -+ * @rsvd - reserved -+ * -+ * To obtain a bus/id the application sets -+ * handle to valid handle, and bus/id to 0xFFFF. -+ * -+ * To obtain the device handle the application sets -+ * bus/id valid value, and the handle to 0xFFFF. -+ */ -+struct mpt3_ioctl_btdh_mapping { -+ struct mpt3_ioctl_header hdr; -+ uint32_t id; -+ uint32_t bus; -+ uint16_t handle; -+ uint16_t rsvd; -+}; -+ -+ -+ -+/* application flags for mpt3_diag_register, mpt3_diag_query */ -+#define MPT3_APP_FLAGS_APP_OWNED (0x0001) -+#define MPT3_APP_FLAGS_BUFFER_VALID (0x0002) -+#define MPT3_APP_FLAGS_FW_BUFFER_ACCESS (0x0004) -+ -+/* flags for mpt3_diag_read_buffer */ -+#define MPT3_FLAGS_REREGISTER (0x0001) -+ -+#define MPT3_PRODUCT_SPECIFIC_DWORDS 23 -+ -+/** -+ * struct mpt3_diag_register - application register with driver -+ * @hdr - generic header -+ * @reserved - -+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED -+ * @application_flags - misc flags -+ * @diagnostic_flags - specifies flags affecting command processing -+ * @product_specific - product specific information -+ * @requested_buffer_size - buffers size in bytes -+ * @unique_id - tag specified by application that is used to signal ownership -+ * of the buffer. -+ * -+ * This will allow the driver to setup any required buffers that will be -+ * needed by firmware to communicate with the driver. -+ */ -+struct mpt3_diag_register { -+ struct mpt3_ioctl_header hdr; -+ uint8_t reserved; -+ uint8_t buffer_type; -+ uint16_t application_flags; -+ uint32_t diagnostic_flags; -+ uint32_t product_specific[MPT3_PRODUCT_SPECIFIC_DWORDS]; -+ uint32_t requested_buffer_size; -+ uint32_t unique_id; -+}; -+ -+/** -+ * struct mpt3_diag_unregister - application unregister with driver -+ * @hdr - generic header -+ * @unique_id - tag uniquely identifies the buffer to be unregistered -+ * -+ * This will allow the driver to cleanup any memory allocated for diag -+ * messages and to free up any resources. -+ */ -+struct mpt3_diag_unregister { -+ struct mpt3_ioctl_header hdr; -+ uint32_t unique_id; -+}; -+ -+/** -+ * struct mpt3_diag_query - query relevant info associated with diag buffers -+ * @hdr - generic header -+ * @reserved - -+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED -+ * @application_flags - misc flags -+ * @diagnostic_flags - specifies flags affecting command processing -+ * @product_specific - product specific information -+ * @total_buffer_size - diag buffer size in bytes -+ * @driver_added_buffer_size - size of extra space appended to end of buffer -+ * @unique_id - unique id associated with this buffer. -+ * -+ * The application will send only buffer_type and unique_id. Driver will -+ * inspect unique_id first, if valid, fill in all the info. If unique_id is -+ * 0x00, the driver will return info specified by Buffer Type. -+ */ -+struct mpt3_diag_query { -+ struct mpt3_ioctl_header hdr; -+ uint8_t reserved; -+ uint8_t buffer_type; -+ uint16_t application_flags; -+ uint32_t diagnostic_flags; -+ uint32_t product_specific[MPT3_PRODUCT_SPECIFIC_DWORDS]; -+ uint32_t total_buffer_size; -+ uint32_t driver_added_buffer_size; -+ uint32_t unique_id; -+}; -+ -+/** -+ * struct mpt3_diag_release - request to send Diag Release Message to firmware -+ * @hdr - generic header -+ * @unique_id - tag uniquely identifies the buffer to be released -+ * -+ * This allows ownership of the specified buffer to returned to the driver, -+ * allowing an application to read the buffer without fear that firmware is -+ * overwritting information in the buffer. -+ */ -+struct mpt3_diag_release { -+ struct mpt3_ioctl_header hdr; -+ uint32_t unique_id; -+}; -+ -+/** -+ * struct mpt3_diag_read_buffer - request for copy of the diag buffer -+ * @hdr - generic header -+ * @status - -+ * @reserved - -+ * @flags - misc flags -+ * @starting_offset - starting offset within drivers buffer where to start -+ * reading data at into the specified application buffer -+ * @bytes_to_read - number of bytes to copy from the drivers buffer into the -+ * application buffer starting at starting_offset. -+ * @unique_id - unique id associated with this buffer. -+ * @diagnostic_data - data payload -+ */ -+struct mpt3_diag_read_buffer { -+ struct mpt3_ioctl_header hdr; -+ uint8_t status; -+ uint8_t reserved; -+ uint16_t flags; -+ uint32_t starting_offset; -+ uint32_t bytes_to_read; -+ uint32_t unique_id; -+ uint32_t diagnostic_data[1]; -+}; -+ -+#endif /* MPT3SAS_CTL_H_INCLUDED */ -diff --git a/drivers/scsi/mpt2sas/mpt3sas_debug.h b/drivers/scsi/mpt2sas/mpt3sas_debug.h -new file mode 100644 -index 0000000..cceeb2c ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_debug.h -@@ -0,0 +1,206 @@ -+/* -+ * Logging Support for MPT (Message Passing Technology) based controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_debug.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#ifndef MPT3SAS_DEBUG_H_INCLUDED -+#define MPT3SAS_DEBUG_H_INCLUDED -+ -+#define MPT_DEBUG 0x00000001 -+#define MPT_DEBUG_MSG_FRAME 0x00000002 -+#define MPT_DEBUG_SG 0x00000004 -+#define MPT_DEBUG_EVENTS 0x00000008 -+#define MPT_DEBUG_EVENT_WORK_TASK 0x00000010 -+#define MPT_DEBUG_INIT 0x00000020 -+#define MPT_DEBUG_EXIT 0x00000040 -+#define MPT_DEBUG_FAIL 0x00000080 -+#define MPT_DEBUG_TM 0x00000100 -+#define MPT_DEBUG_REPLY 0x00000200 -+#define MPT_DEBUG_HANDSHAKE 0x00000400 -+#define MPT_DEBUG_CONFIG 0x00000800 -+#define MPT_DEBUG_DL 0x00001000 -+#define MPT_DEBUG_RESET 0x00002000 -+#define MPT_DEBUG_SCSI 0x00004000 -+#define MPT_DEBUG_IOCTL 0x00008000 -+#define MPT_DEBUG_SAS 0x00020000 -+#define MPT_DEBUG_TRANSPORT 0x00040000 -+#define MPT_DEBUG_TASK_SET_FULL 0x00080000 -+ -+#define MPT_DEBUG_TRIGGER_DIAG 0x00200000 -+ -+ -+#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \ -+{ \ -+ if (IOC->logging_level & BITS) \ -+ CMD; \ -+} -+ -+/* -+ * debug macros -+ */ -+ -+#define dprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG) -+ -+#define dsgprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG) -+ -+#define devtprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS) -+ -+#define dewtprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK) -+ -+#define dinitprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT) -+ -+#define dexitprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT) -+ -+#define dfailprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL) -+ -+#define dtmprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM) -+ -+#define dreplyprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY) -+ -+#define dhsprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE) -+ -+#define dcprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG) -+ -+#define ddlprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL) -+ -+#define drsprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET) -+ -+#define dsprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI) -+ -+#define dctlprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL) -+ -+#define dsasprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS) -+ -+#define dsastransport(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) -+ -+#define dmfprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME) -+ -+#define dtsfprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL) -+ -+#define dtransportprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT) -+ -+#define dTriggerDiagPrintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRIGGER_DIAG) -+ -+ -+ -+/* inline functions for dumping debug data*/ -+ -+/** -+ * _debug_dump_mf - print message frame contents -+ * @mpi_request: pointer to message frame -+ * @sz: number of dwords -+ */ -+static inline void -+_debug_dump_mf(void *mpi_request, int sz) -+{ -+ int i; -+ __le32 *mfp = (__le32 *)mpi_request; -+ -+ pr_info("mf:\n\t"); -+ for (i = 0; i < sz; i++) { -+ if (i && ((i % 8) == 0)) -+ pr_info("\n\t"); -+ pr_info("%08x ", le32_to_cpu(mfp[i])); -+ } -+ pr_info("\n"); -+} -+/** -+ * _debug_dump_reply - print message frame contents -+ * @mpi_request: pointer to message frame -+ * @sz: number of dwords -+ */ -+static inline void -+_debug_dump_reply(void *mpi_request, int sz) -+{ -+ int i; -+ __le32 *mfp = (__le32 *)mpi_request; -+ -+ pr_info("reply:\n\t"); -+ for (i = 0; i < sz; i++) { -+ if (i && ((i % 8) == 0)) -+ pr_info("\n\t"); -+ pr_info("%08x ", le32_to_cpu(mfp[i])); -+ } -+ pr_info("\n"); -+} -+/** -+ * _debug_dump_config - print config page contents -+ * @mpi_request: pointer to message frame -+ * @sz: number of dwords -+ */ -+static inline void -+_debug_dump_config(void *mpi_request, int sz) -+{ -+ int i; -+ __le32 *mfp = (__le32 *)mpi_request; -+ -+ pr_info("config:\n\t"); -+ for (i = 0; i < sz; i++) { -+ if (i && ((i % 8) == 0)) -+ pr_info("\n\t"); -+ pr_info("%08x ", le32_to_cpu(mfp[i])); -+ } -+ pr_info("\n"); -+} -+ -+#endif /* MPT3SAS_DEBUG_H_INCLUDED */ -diff --git a/drivers/scsi/mpt2sas/mpt3sas_scsih.c b/drivers/scsi/mpt2sas/mpt3sas_scsih.c -new file mode 100644 -index 0000000..0a3ad2b ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_scsih.c -@@ -0,0 +1,9356 @@ -+/* -+ * Scsi Host Layer for MPT (Message Passing Technology) based controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_scsih.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+#define RAID_CHANNEL 1 -+/* forward proto's */ -+static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander); -+static void _firmware_event_work(struct work_struct *work); -+ -+static void _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device); -+static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u8 retry_count, u8 is_pd); -+ -+static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+ -+/* global parameters */ -+LIST_HEAD(mpt2sas_ioc_list); -+/* global ioc lock for list operations */ -+DEFINE_SPINLOCK(gioc_lock_mpt2sas); -+ -+MODULE_AUTHOR(MPT3SAS_AUTHOR); -+#ifdef MPT2SAS_SCSI -+MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION); -+MODULE_VERSION(MPT2SAS_DRIVER_VERSION); -+#else -+MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION); -+MODULE_VERSION(MPT3SAS_DRIVER_VERSION); -+#endif /* MPT2SAS_SCSI */ -+MODULE_LICENSE("GPL"); -+ -+/* local parameters */ -+static u8 scsi_io_cb_idx = -1; -+static u8 tm_cb_idx = -1; -+static u8 ctl_cb_idx = -1; -+static u8 base_cb_idx = -1; -+static u8 port_enable_cb_idx = -1; -+static u8 transport_cb_idx = -1; -+static u8 scsih_cb_idx = -1; -+static u8 config_cb_idx = -1; -+static int mpt2_ids; -+static int mpt3_ids; -+ -+static u8 tm_tr_cb_idx = -1 ; -+static u8 tm_tr_volume_cb_idx = -1 ; -+static u8 tm_sas_control_cb_idx = -1; -+ -+/* command line options */ -+static u32 logging_level; -+MODULE_PARM_DESC(logging_level, -+ " bits for enabling additional logging info (default=0)"); -+ -+ -+static ushort max_sectors = 0xFFFF; -+module_param(max_sectors, ushort, 0); -+MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767"); -+ -+ -+static int missing_delay[2] = {-1, -1}; -+module_param_array(missing_delay, int, NULL, 0); -+MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); -+ -+/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ -+#define MPT3SAS_MAX_LUN (16895) -+static int max_lun = MPT3SAS_MAX_LUN; -+module_param(max_lun, int, 0); -+MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); -+ -+/* diag_buffer_enable is bitwise -+ * bit 0 set = TRACE -+ * bit 1 set = SNAPSHOT -+ * bit 2 set = EXTENDED -+ * -+ * Either bit can be set, or both -+ */ -+static int diag_buffer_enable = -1; -+module_param(diag_buffer_enable, int, 0); -+MODULE_PARM_DESC(diag_buffer_enable, -+ " post diag buffers (TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); -+static int disable_discovery = -1; -+module_param(disable_discovery, int, 0); -+MODULE_PARM_DESC(disable_discovery, " disable discovery "); -+ -+ -+/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ -+static int prot_mask = -1; -+module_param(prot_mask, int, 0); -+MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); -+ -+ -+/* raid transport support */ -+struct raid_template *mpt3sas_raid_template_mpt2sas; -+struct raid_template *mpt2sas_raid_template_mpt2sas; -+ -+ -+/** -+ * struct sense_info - common structure for obtaining sense keys -+ * @skey: sense key -+ * @asc: additional sense code -+ * @ascq: additional sense code qualifier -+ */ -+struct sense_info { -+ u8 skey; -+ u8 asc; -+ u8 ascq; -+}; -+ -+#define MPT3SAS_PROCESS_TRIGGER_DIAG (0xFFFB) -+#define MPT3SAS_TURN_ON_PFA_LED (0xFFFC) -+#define MPT3SAS_PORT_ENABLE_COMPLETE (0xFFFD) -+#define MPT3SAS_ABRT_TASK_SET (0xFFFE) -+#define MPT3SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF) -+/** -+ * struct fw_event_work - firmware event struct -+ * @list: link list framework -+ * @work: work object (ioc->fault_reset_work_q) -+ * @ioc: per adapter object -+ * @device_handle: device handle -+ * @VF_ID: virtual function id -+ * @VP_ID: virtual port id -+ * @ignore: flag meaning this event has been marked to ignore -+ * @event: firmware event MPI2_EVENT_XXX defined in mpi2_ioc.h -+ * @refcount: kref for this event -+ * @event_data: reply event data payload follows -+ * -+ * This object stored on ioc->fw_event_list. -+ */ -+struct fw_event_work { -+ struct list_head list; -+ struct work_struct work; -+ -+ struct MPT3SAS_ADAPTER *ioc; -+ u16 device_handle; -+ u8 VF_ID; -+ u8 VP_ID; -+ u8 ignore; -+ u16 event; -+ struct kref refcount; -+ char event_data[0] __aligned(4); -+}; -+ -+static void fw_event_work_free(struct kref *r) -+{ -+ kfree(container_of(r, struct fw_event_work, refcount)); -+} -+ -+static void fw_event_work_get(struct fw_event_work *fw_work) -+{ -+ kref_get(&fw_work->refcount); -+} -+ -+static void fw_event_work_put(struct fw_event_work *fw_work) -+{ -+ kref_put(&fw_work->refcount, fw_event_work_free); -+} -+ -+static struct fw_event_work *alloc_fw_event_work(int len) -+{ -+ struct fw_event_work *fw_event; -+ -+ fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC); -+ if (!fw_event) -+ return NULL; -+ -+ kref_init(&fw_event->refcount); -+ return fw_event; -+} -+ -+/** -+ * struct _scsi_io_transfer - scsi io transfer -+ * @handle: sas device handle (assigned by firmware) -+ * @is_raid: flag set for hidden raid components -+ * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE, -+ * @data_length: data transfer length -+ * @data_dma: dma pointer to data -+ * @sense: sense data -+ * @lun: lun number -+ * @cdb_length: cdb length -+ * @cdb: cdb contents -+ * @timeout: timeout for this command -+ * @VF_ID: virtual function id -+ * @VP_ID: virtual port id -+ * @valid_reply: flag set for reply message -+ * @sense_length: sense length -+ * @ioc_status: ioc status -+ * @scsi_state: scsi state -+ * @scsi_status: scsi staus -+ * @log_info: log information -+ * @transfer_length: data length transfer when there is a reply message -+ * -+ * Used for sending internal scsi commands to devices within this module. -+ * Refer to _scsi_send_scsi_io(). -+ */ -+struct _scsi_io_transfer { -+ u16 handle; -+ u8 is_raid; -+ enum dma_data_direction dir; -+ u32 data_length; -+ dma_addr_t data_dma; -+ u8 sense[SCSI_SENSE_BUFFERSIZE]; -+ u32 lun; -+ u8 cdb_length; -+ u8 cdb[32]; -+ u8 timeout; -+ u8 VF_ID; -+ u8 VP_ID; -+ u8 valid_reply; -+ /* the following bits are only valid when 'valid_reply = 1' */ -+ u32 sense_length; -+ u16 ioc_status; -+ u8 scsi_state; -+ u8 scsi_status; -+ u32 log_info; -+ u32 transfer_length; -+}; -+ -+/** -+ * _scsih_set_debug_level - global setting of ioc->logging_level. -+ * -+ * Note: The logging levels are defined in mpt3sas_debug.h. -+ */ -+static int -+_scsih_set_debug_level(const char *val, struct kernel_param *kp) -+{ -+ int ret = param_set_int(val, kp); -+ struct MPT3SAS_ADAPTER *ioc; -+ -+ if (ret) -+ return ret; -+ -+ pr_info("setting logging_level(0x%08x)\n", logging_level); -+ spin_lock(&gioc_lock_mpt2sas); -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) -+ ioc->logging_level = logging_level; -+ spin_unlock(&gioc_lock_mpt2sas); -+ return 0; -+} -+module_param_call(logging_level, _scsih_set_debug_level, param_get_int, -+ &logging_level, 0644); -+ -+/** -+ * _scsih_srch_boot_sas_address - search based on sas_address -+ * @sas_address: sas address -+ * @boot_device: boot device object from bios page 2 -+ * -+ * Returns 1 when there's a match, 0 means no match. -+ */ -+static inline int -+_scsih_srch_boot_sas_address(u64 sas_address, -+ Mpi2BootDeviceSasWwid_t *boot_device) -+{ -+ return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0; -+} -+ -+/** -+ * _scsih_srch_boot_device_name - search based on device name -+ * @device_name: device name specified in INDENTIFY fram -+ * @boot_device: boot device object from bios page 2 -+ * -+ * Returns 1 when there's a match, 0 means no match. -+ */ -+static inline int -+_scsih_srch_boot_device_name(u64 device_name, -+ Mpi2BootDeviceDeviceName_t *boot_device) -+{ -+ return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0; -+} -+ -+/** -+ * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot -+ * @enclosure_logical_id: enclosure logical id -+ * @slot_number: slot number -+ * @boot_device: boot device object from bios page 2 -+ * -+ * Returns 1 when there's a match, 0 means no match. -+ */ -+static inline int -+_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number, -+ Mpi2BootDeviceEnclosureSlot_t *boot_device) -+{ -+ return (enclosure_logical_id == le64_to_cpu(boot_device-> -+ EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device-> -+ SlotNumber)) ? 1 : 0; -+} -+ -+/** -+ * _scsih_is_boot_device - search for matching boot device. -+ * @sas_address: sas address -+ * @device_name: device name specified in INDENTIFY fram -+ * @enclosure_logical_id: enclosure logical id -+ * @slot_number: slot number -+ * @form: specifies boot device form -+ * @boot_device: boot device object from bios page 2 -+ * -+ * Returns 1 when there's a match, 0 means no match. -+ */ -+static int -+_scsih_is_boot_device(u64 sas_address, u64 device_name, -+ u64 enclosure_logical_id, u16 slot, u8 form, -+ Mpi2BiosPage2BootDevice_t *boot_device) -+{ -+ int rc = 0; -+ -+ switch (form) { -+ case MPI2_BIOSPAGE2_FORM_SAS_WWID: -+ if (!sas_address) -+ break; -+ rc = _scsih_srch_boot_sas_address( -+ sas_address, &boot_device->SasWwid); -+ break; -+ case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT: -+ if (!enclosure_logical_id) -+ break; -+ rc = _scsih_srch_boot_encl_slot( -+ enclosure_logical_id, -+ slot, &boot_device->EnclosureSlot); -+ break; -+ case MPI2_BIOSPAGE2_FORM_DEVICE_NAME: -+ if (!device_name) -+ break; -+ rc = _scsih_srch_boot_device_name( -+ device_name, &boot_device->DeviceName); -+ break; -+ case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED: -+ break; -+ } -+ -+ return rc; -+} -+ -+/** -+ * _scsih_get_sas_address - set the sas_address for given device handle -+ * @handle: device handle -+ * @sas_address: sas address -+ * -+ * Returns 0 success, non-zero when failure -+ */ -+static int -+_scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u64 *sas_address) -+{ -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u32 ioc_status; -+ -+ *sas_address = 0; -+ -+ if (handle <= ioc->sas_hba.num_phys) { -+ *sas_address = ioc->sas_hba.sas_address; -+ return 0; -+ } -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ return -ENXIO; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ return 0; -+ } -+ -+ /* we hit this becuase the given parent handle doesn't exist */ -+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) -+ return -ENXIO; -+ -+ /* else error case */ -+ pr_err(MPT3SAS_FMT -+ "handle(0x%04x), ioc_status(0x%04x), failure at %s:%d/%s()!\n", -+ ioc->name, handle, ioc_status, -+ __FILE__, __LINE__, __func__); -+ return -EIO; -+} -+ -+/** -+ * _scsih_determine_boot_device - determine boot device. -+ * @ioc: per adapter object -+ * @device: either sas_device or raid_device object -+ * @is_raid: [flag] 1 = raid object, 0 = sas object -+ * -+ * Determines whether this device should be first reported device to -+ * to scsi-ml or sas transport, this purpose is for persistent boot device. -+ * There are primary, alternate, and current entries in bios page 2. The order -+ * priority is primary, alternate, then current. This routine saves -+ * the corresponding device object and is_raid flag in the ioc object. -+ * The saved data to be used later in _scsih_probe_boot_devices(). -+ */ -+static void -+_scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, -+ void *device, u8 is_raid) -+{ -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ u64 sas_address; -+ u64 device_name; -+ u64 enclosure_logical_id; -+ u16 slot; -+ -+ /* only process this function when driver loads */ -+ if (!ioc->is_driver_loading) -+ return; -+ -+ /* no Bios, return immediately */ -+ if (!ioc->bios_pg3.BiosVersion) -+ return; -+ -+ if (!is_raid) { -+ sas_device = device; -+ sas_address = sas_device->sas_address; -+ device_name = sas_device->device_name; -+ enclosure_logical_id = sas_device->enclosure_logical_id; -+ slot = sas_device->slot; -+ } else { -+ raid_device = device; -+ sas_address = raid_device->wwid; -+ device_name = 0; -+ enclosure_logical_id = 0; -+ slot = 0; -+ } -+ -+ if (!ioc->req_boot_device.device) { -+ if (_scsih_is_boot_device(sas_address, device_name, -+ enclosure_logical_id, slot, -+ (ioc->bios_pg2.ReqBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK), -+ &ioc->bios_pg2.RequestedBootDevice)) { -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: req_boot_device(0x%016llx)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_address)); -+ ioc->req_boot_device.device = device; -+ ioc->req_boot_device.is_raid = is_raid; -+ } -+ } -+ -+ if (!ioc->req_alt_boot_device.device) { -+ if (_scsih_is_boot_device(sas_address, device_name, -+ enclosure_logical_id, slot, -+ (ioc->bios_pg2.ReqAltBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK), -+ &ioc->bios_pg2.RequestedAltBootDevice)) { -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: req_alt_boot_device(0x%016llx)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_address)); -+ ioc->req_alt_boot_device.device = device; -+ ioc->req_alt_boot_device.is_raid = is_raid; -+ } -+ } -+ -+ if (!ioc->current_boot_device.device) { -+ if (_scsih_is_boot_device(sas_address, device_name, -+ enclosure_logical_id, slot, -+ (ioc->bios_pg2.CurrentBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK), -+ &ioc->bios_pg2.CurrentBootDevice)) { -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: current_boot_device(0x%016llx)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_address)); -+ ioc->current_boot_device.device = device; -+ ioc->current_boot_device.is_raid = is_raid; -+ } -+ } -+} -+ -+static struct _sas_device * -+__mpt2sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, -+ struct MPT3SAS_TARGET *tgt_priv) -+{ -+ struct _sas_device *ret; -+ -+ assert_spin_locked(&ioc->sas_device_lock); -+ -+ ret = tgt_priv->sdev; -+ if (ret) -+ sas_device_get(ret); -+ -+ return ret; -+} -+ -+static struct _sas_device * -+mpt2sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, -+ struct MPT3SAS_TARGET *tgt_priv) -+{ -+ struct _sas_device *ret; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ ret = __mpt2sas_get_sdev_from_target(ioc, tgt_priv); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return ret; -+} -+ -+ -+struct _sas_device * -+__mpt2sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ struct _sas_device *sas_device; -+ -+ assert_spin_locked(&ioc->sas_device_lock); -+ -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) -+ if (sas_device->sas_address == sas_address) -+ goto found_device; -+ -+ list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) -+ if (sas_device->sas_address == sas_address) -+ goto found_device; -+ -+ return NULL; -+ -+found_device: -+ sas_device_get(sas_device); -+ return sas_device; -+} -+ -+/** -+ * mpt2sas_get_sdev_by_addr - sas device search -+ * @ioc: per adapter object -+ * @sas_address: sas address -+ * Context: Calling function should acquire ioc->sas_device_lock -+ * -+ * This searches for sas_device based on sas_address, then return sas_device -+ * object. -+ */ -+struct _sas_device * -+mpt2sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_address); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return sas_device; -+} -+ -+static struct _sas_device * -+__mpt2sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_device *sas_device; -+ -+ assert_spin_locked(&ioc->sas_device_lock); -+ -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) -+ if (sas_device->handle == handle) -+ goto found_device; -+ -+ list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) -+ if (sas_device->handle == handle) -+ goto found_device; -+ -+ return NULL; -+ -+found_device: -+ sas_device_get(sas_device); -+ return sas_device; -+} -+ -+/** -+ * mpt2sas_get_sdev_by_handle - sas device search -+ * @ioc: per adapter object -+ * @handle: sas device handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->sas_device_lock -+ * -+ * This searches for sas_device based on sas_address, then return sas_device -+ * object. -+ */ -+static struct _sas_device * -+mpt2sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return sas_device; -+} -+ -+/** -+ * _scsih_sas_device_remove - remove sas_device from list. -+ * @ioc: per adapter object -+ * @sas_device: the sas_device object -+ * Context: This function will acquire ioc->sas_device_lock. -+ * -+ * If sas_device is on the list, remove it and decrement its reference count. -+ */ -+static void -+_scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ unsigned long flags; -+ -+ if (!sas_device) -+ return; -+ pr_info(MPT3SAS_FMT -+ "removing handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, sas_device->handle, -+ (unsigned long long) sas_device->sas_address); -+ -+ if (sas_device->enclosure_handle != 0) -+ pr_info(MPT3SAS_FMT -+ "removing enclosure logical id(0x%016llx), slot(%d)\n", -+ ioc->name, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot); -+ -+ if (sas_device->connector_name[0] != '\0') -+ pr_info(MPT3SAS_FMT -+ "removing enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ /* -+ * The lock serializes access to the list, but we still need to verify -+ * that nobody removed the entry while we were waiting on the lock. -+ */ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ if (!list_empty(&sas_device->list)) { -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+} -+ -+/** -+ * _scsih_device_remove_by_handle - removing device object by handle -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (sas_device) { -+ _scsih_remove_device(ioc, sas_device); -+ sas_device_put(sas_device); -+ } -+} -+ -+/** -+ * mpt2sas_device_remove_by_sas_address - removing device object by sas address -+ * @ioc: per adapter object -+ * @sas_address: device sas_address -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address); -+ if (sas_device) { -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (sas_device) { -+ _scsih_remove_device(ioc, sas_device); -+ sas_device_put(sas_device); -+ } -+} -+ -+/** -+ * _scsih_sas_device_add - insert sas_device to the list. -+ * @ioc: per adapter object -+ * @sas_device: the sas_device object -+ * Context: This function will acquire ioc->sas_device_lock. -+ * -+ * Adding new object to the ioc->sas_device_list. -+ */ -+static void -+_scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ unsigned long flags; -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, __func__, sas_device->handle, -+ (unsigned long long)sas_device->sas_address)); -+ -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enclosure logical id(0x%016llx), slot( %d)\n", -+ ioc->name, __func__, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot)); -+ -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, __func__, -+ sas_device->enclosure_level, sas_device->connector_name)); -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device_get(sas_device); -+ list_add_tail(&sas_device->list, &ioc->sas_device_list); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle, -+ sas_device->sas_address_parent)) { -+ _scsih_sas_device_remove(ioc, sas_device); -+ } else if (!sas_device->starget) { -+ /* -+ * When asyn scanning is enabled, its not possible to remove -+ * devices while scanning is turned on due to an oops in -+ * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start() -+ */ -+ if (!ioc->is_driver_loading) { -+ mpt2sas_transport_port_remove(ioc, -+ sas_device->sas_address, -+ sas_device->sas_address_parent); -+ _scsih_sas_device_remove(ioc, sas_device); -+ } -+ } -+} -+ -+/** -+ * _scsih_sas_device_init_add - insert sas_device to the list. -+ * @ioc: per adapter object -+ * @sas_device: the sas_device object -+ * Context: This function will acquire ioc->sas_device_lock. -+ * -+ * Adding new object at driver load time to the ioc->sas_device_init_list. -+ */ -+static void -+_scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ unsigned long flags; -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ __func__, sas_device->handle, -+ (unsigned long long)sas_device->sas_address)); -+ -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enclosure logical id(0x%016llx), slot( %d)\n", -+ ioc->name, __func__, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot)); -+ -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, __func__, sas_device->enclosure_level, -+ sas_device->connector_name)); -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device_get(sas_device); -+ list_add_tail(&sas_device->list, &ioc->sas_device_init_list); -+ _scsih_determine_boot_device(ioc, sas_device, 0); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+} -+ -+/** -+ * _scsih_raid_device_find_by_id - raid device search -+ * @ioc: per adapter object -+ * @id: sas device target id -+ * @channel: sas device channel -+ * Context: Calling function should acquire ioc->raid_device_lock -+ * -+ * This searches for raid_device based on target id, then return raid_device -+ * object. -+ */ -+static struct _raid_device * -+_scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel) -+{ -+ struct _raid_device *raid_device, *r; -+ -+ r = NULL; -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (raid_device->id == id && raid_device->channel == channel) { -+ r = raid_device; -+ goto out; -+ } -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_raid_device_find_by_handle - raid device search -+ * @ioc: per adapter object -+ * @handle: sas device handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->raid_device_lock -+ * -+ * This searches for raid_device based on handle, then return raid_device -+ * object. -+ */ -+struct _raid_device * -+mpt2sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _raid_device *raid_device, *r; -+ -+ r = NULL; -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (raid_device->handle != handle) -+ continue; -+ r = raid_device; -+ goto out; -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * _scsih_raid_device_find_by_wwid - raid device search -+ * @ioc: per adapter object -+ * @handle: sas device handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->raid_device_lock -+ * -+ * This searches for raid_device based on wwid, then return raid_device -+ * object. -+ */ -+static struct _raid_device * -+_scsih_raid_device_find_by_wwid(struct MPT3SAS_ADAPTER *ioc, u64 wwid) -+{ -+ struct _raid_device *raid_device, *r; -+ -+ r = NULL; -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (raid_device->wwid != wwid) -+ continue; -+ r = raid_device; -+ goto out; -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * _scsih_raid_device_add - add raid_device object -+ * @ioc: per adapter object -+ * @raid_device: raid_device object -+ * -+ * This is added to the raid_device_list link list. -+ */ -+static void -+_scsih_raid_device_add(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device) -+{ -+ unsigned long flags; -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, -+ raid_device->handle, (unsigned long long)raid_device->wwid)); -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ list_add_tail(&raid_device->list, &ioc->raid_device_list); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+} -+ -+/** -+ * _scsih_raid_device_remove - delete raid_device object -+ * @ioc: per adapter object -+ * @raid_device: raid_device object -+ * -+ */ -+static void -+_scsih_raid_device_remove(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ list_del(&raid_device->list); -+ kfree(raid_device); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+} -+ -+/** -+ * mpt2sas_scsih_expander_find_by_handle - expander device search -+ * @ioc: per adapter object -+ * @handle: expander handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->sas_device_lock -+ * -+ * This searches for expander device based on handle, then returns the -+ * sas_node object. -+ */ -+struct _sas_node * -+mpt2sas_scsih_expander_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_node *sas_expander, *r; -+ -+ r = NULL; -+ list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { -+ if (sas_expander->handle != handle) -+ continue; -+ r = sas_expander; -+ goto out; -+ } -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_scsih_expander_find_by_sas_address - expander device search -+ * @ioc: per adapter object -+ * @sas_address: sas address -+ * Context: Calling function should acquire ioc->sas_node_lock. -+ * -+ * This searches for expander device based on sas_address, then returns the -+ * sas_node object. -+ */ -+struct _sas_node * -+mpt2sas_scsih_expander_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ struct _sas_node *sas_expander, *r; -+ -+ r = NULL; -+ list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { -+ if (sas_expander->sas_address != sas_address) -+ continue; -+ r = sas_expander; -+ goto out; -+ } -+ out: -+ return r; -+} -+ -+/** -+ * _scsih_expander_node_add - insert expander device to the list. -+ * @ioc: per adapter object -+ * @sas_expander: the sas_device object -+ * Context: This function will acquire ioc->sas_node_lock. -+ * -+ * Adding new object to the ioc->sas_expander_list. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_expander_node_add(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ list_add_tail(&sas_expander->list, &ioc->sas_expander_list); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+} -+ -+/** -+ * _scsih_is_end_device - determines if device is an end device -+ * @device_info: bitfield providing information about the device. -+ * Context: none -+ * -+ * Returns 1 if end device. -+ */ -+static int -+_scsih_is_end_device(u32 device_info) -+{ -+ if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE && -+ ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) | -+ (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) | -+ (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE))) -+ return 1; -+ else -+ return 0; -+} -+ -+/** -+ * _scsih_scsi_lookup_get - returns scmd entry -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns the smid stored scmd pointer. -+ */ -+static struct scsi_cmnd * -+_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return ioc->scsi_lookup[smid - 1].scmd; -+} -+ -+/** -+ * _scsih_scsi_lookup_get_clear - returns scmd entry -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns the smid stored scmd pointer. -+ * Then will derefrence the stored scmd pointer. -+ */ -+static inline struct scsi_cmnd * -+_scsih_scsi_lookup_get_clear(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ unsigned long flags; -+ struct scsi_cmnd *scmd; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ scmd = ioc->scsi_lookup[smid - 1].scmd; -+ ioc->scsi_lookup[smid - 1].scmd = NULL; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ return scmd; -+} -+ -+/** -+ * _scsih_scsi_lookup_find_by_scmd - scmd lookup -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @scmd: pointer to scsi command object -+ * Context: This function will acquire ioc->scsi_lookup_lock. -+ * -+ * This will search for a scmd pointer in the scsi_lookup array, -+ * returning the revelent smid. A returned value of zero means invalid. -+ */ -+static u16 -+_scsih_scsi_lookup_find_by_scmd(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd -+ *scmd) -+{ -+ u16 smid; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ smid = 0; -+ for (i = 0; i < ioc->scsiio_depth; i++) { -+ if (ioc->scsi_lookup[i].scmd == scmd) { -+ smid = ioc->scsi_lookup[i].smid; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return smid; -+} -+ -+/** -+ * _scsih_scsi_lookup_find_by_target - search for matching channel:id -+ * @ioc: per adapter object -+ * @id: target id -+ * @channel: channel -+ * Context: This function will acquire ioc->scsi_lookup_lock. -+ * -+ * This will search for a matching channel:id in the scsi_lookup array, -+ * returning 1 if found. -+ */ -+static u8 -+_scsih_scsi_lookup_find_by_target(struct MPT3SAS_ADAPTER *ioc, int id, -+ int channel) -+{ -+ u8 found; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ found = 0; -+ for (i = 0 ; i < ioc->scsiio_depth; i++) { -+ if (ioc->scsi_lookup[i].scmd && -+ (ioc->scsi_lookup[i].scmd->device->id == id && -+ ioc->scsi_lookup[i].scmd->device->channel == channel)) { -+ found = 1; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return found; -+} -+ -+/** -+ * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun -+ * @ioc: per adapter object -+ * @id: target id -+ * @lun: lun number -+ * @channel: channel -+ * Context: This function will acquire ioc->scsi_lookup_lock. -+ * -+ * This will search for a matching channel:id:lun in the scsi_lookup array, -+ * returning 1 if found. -+ */ -+static u8 -+_scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id, -+ unsigned int lun, int channel) -+{ -+ u8 found; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ found = 0; -+ for (i = 0 ; i < ioc->scsiio_depth; i++) { -+ if (ioc->scsi_lookup[i].scmd && -+ (ioc->scsi_lookup[i].scmd->device->id == id && -+ ioc->scsi_lookup[i].scmd->device->channel == channel && -+ ioc->scsi_lookup[i].scmd->device->lun == lun)) { -+ found = 1; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return found; -+} -+ -+static void -+_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) -+{ -+ struct Scsi_Host *shost = sdev->host; -+ int max_depth; -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ max_depth = shost->can_queue; -+ -+ /* limit max device queue for SATA to 32 */ -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ goto not_sata; -+ sas_target_priv_data = sas_device_priv_data->sas_target; -+ if (!sas_target_priv_data) -+ goto not_sata; -+ if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) -+ goto not_sata; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); -+ if (sas_device) { -+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -+ max_depth = MPT3SAS_SATA_QUEUE_DEPTH; -+ -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ not_sata: -+ -+ if (!sdev->tagged_supported) -+ max_depth = 1; -+ if (qdepth > max_depth) -+ qdepth = max_depth; -+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); -+} -+ -+/** -+ * scsih_change_queue_depth_mpt2sas - setting device queue depth -+ * @sdev: scsi device struct -+ * @qdepth: requested queue depth -+ * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP -+ * (see include/scsi/scsi_host.h for definition) -+ * -+ * Returns queue depth. -+ */ -+int -+scsih_change_queue_depth_mpt2sas(struct scsi_device *sdev, int qdepth, int reason) -+{ -+ if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) -+ _scsih_adjust_queue_depth(sdev, qdepth); -+ else if (reason == SCSI_QDEPTH_QFULL) -+ scsi_track_queue_full(sdev, qdepth); -+ else -+ return -EOPNOTSUPP; -+ -+ if (sdev->inquiry_len > 7) -+ sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), " \ -+ "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n", -+ sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags, -+ sdev->ordered_tags, sdev->scsi_level, -+ (sdev->inquiry[7] & 2) >> 1); -+ -+ return sdev->queue_depth; -+} -+ -+/** -+ * _scsih_change_queue_type_mpt2sas - changing device queue tag type -+ * @sdev: scsi device struct -+ * @tag_type: requested tag type -+ * -+ * Returns queue tag type. -+ */ -+int -+_scsih_change_queue_type_mpt2sas(struct scsi_device *sdev, int tag_type) -+{ -+ if (sdev->tagged_supported) { -+ scsi_set_tag_type(sdev, tag_type); -+ if (tag_type) -+ scsi_activate_tcq(sdev, sdev->queue_depth); -+ else -+ scsi_deactivate_tcq(sdev, sdev->queue_depth); -+ } else -+ tag_type = 0; -+ -+ return tag_type; -+} -+ -+ -+/** -+ * scsih_target_alloc_mpt2sas - target add routine -+ * @starget: scsi target struct -+ * -+ * Returns 0 if ok. Any other return is assumed to be an error and -+ * the device is ignored. -+ */ -+int -+scsih_target_alloc_mpt2sas(struct scsi_target *starget) -+{ -+ struct Scsi_Host *shost = dev_to_shost(&starget->dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ struct sas_rphy *rphy; -+ -+ sas_target_priv_data = kzalloc(sizeof(*sas_target_priv_data), -+ GFP_KERNEL); -+ if (!sas_target_priv_data) -+ return -ENOMEM; -+ -+ starget->hostdata = sas_target_priv_data; -+ sas_target_priv_data->starget = starget; -+ sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; -+ -+ /* RAID volumes */ -+ if (starget->channel == RAID_CHANNEL) { -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, -+ starget->channel); -+ if (raid_device) { -+ sas_target_priv_data->handle = raid_device->handle; -+ sas_target_priv_data->sas_address = raid_device->wwid; -+ sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; -+ sas_target_priv_data->raid_device = raid_device; -+ if (ioc->is_warpdrive) -+ raid_device->starget = starget; -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ return 0; -+ } -+ -+ /* sas/sata devices */ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ rphy = dev_to_rphy(starget->dev.parent); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ rphy->identify.sas_address); -+ -+ if (sas_device) { -+ sas_target_priv_data->handle = sas_device->handle; -+ sas_target_priv_data->sas_address = sas_device->sas_address; -+ sas_target_priv_data->sdev = sas_device; -+ sas_device->starget = starget; -+ sas_device->id = starget->id; -+ sas_device->channel = starget->channel; -+ if (test_bit(sas_device->handle, ioc->pd_handles)) -+ sas_target_priv_data->flags |= -+ MPT_TARGET_FLAGS_RAID_COMPONENT; -+ if (sas_device->fast_path) -+ sas_target_priv_data->flags |= MPT_TARGET_FASTPATH_IO; -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return 0; -+} -+ -+/** -+ * scsih_target_destroy_mpt2sas - target destroy routine -+ * @starget: scsi target struct -+ * -+ * Returns nothing. -+ */ -+void -+scsih_target_destroy_mpt2sas(struct scsi_target *starget) -+{ -+ struct Scsi_Host *shost = dev_to_shost(&starget->dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ struct sas_rphy *rphy; -+ -+ sas_target_priv_data = starget->hostdata; -+ if (!sas_target_priv_data) -+ return; -+ -+ if (starget->channel == RAID_CHANNEL) { -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, -+ starget->channel); -+ if (raid_device) { -+ raid_device->starget = NULL; -+ raid_device->sdev = NULL; -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ goto out; -+ } -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ rphy = dev_to_rphy(starget->dev.parent); -+ sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); -+ if (sas_device && (sas_device->starget == starget) && -+ (sas_device->id == starget->id) && -+ (sas_device->channel == starget->channel)) -+ sas_device->starget = NULL; -+ -+ if (sas_device) { -+ /* -+ * Corresponding get() is in _scsih_target_alloc_mpt2sas() -+ */ -+ sas_target_priv_data->sdev = NULL; -+ sas_device_put(sas_device); -+ -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ out: -+ kfree(sas_target_priv_data); -+ starget->hostdata = NULL; -+} -+ -+/** -+ * scsih_slave_alloc_mpt2sas - device add routine -+ * @sdev: scsi device struct -+ * -+ * Returns 0 if ok. Any other return is assumed to be an error and -+ * the device is ignored. -+ */ -+int -+scsih_slave_alloc_mpt2sas(struct scsi_device *sdev) -+{ -+ struct Scsi_Host *shost; -+ struct MPT3SAS_ADAPTER *ioc; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_target *starget; -+ struct _raid_device *raid_device; -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ sas_device_priv_data = kzalloc(sizeof(*sas_device_priv_data), -+ GFP_KERNEL); -+ if (!sas_device_priv_data) -+ return -ENOMEM; -+ -+ sas_device_priv_data->lun = sdev->lun; -+ sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT; -+ -+ starget = scsi_target(sdev); -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->num_luns++; -+ sas_device_priv_data->sas_target = sas_target_priv_data; -+ sdev->hostdata = sas_device_priv_data; -+ if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT)) -+ sdev->no_uld_attach = 1; -+ -+ shost = dev_to_shost(&starget->dev); -+ ioc = shost_priv(shost); -+ if (starget->channel == RAID_CHANNEL) { -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, -+ starget->id, starget->channel); -+ if (raid_device) -+ raid_device->sdev = sdev; /* raid is single lun */ -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ } -+ -+ if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_target_priv_data->sas_address); -+ if (sas_device && (sas_device->starget == NULL)) { -+ sdev_printk(KERN_INFO, sdev, -+ "%s : sas_device->starget set to starget @ %d\n", -+ __func__, __LINE__); -+ sas_device->starget = starget; -+ } -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ } -+ -+ return 0; -+} -+ -+/** -+ * scsih_slave_destroy_mpt2sas - device destroy routine -+ * @sdev: scsi device struct -+ * -+ * Returns nothing. -+ */ -+void -+scsih_slave_destroy_mpt2sas(struct scsi_device *sdev) -+{ -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct scsi_target *starget; -+ struct Scsi_Host *shost; -+ struct MPT3SAS_ADAPTER *ioc; -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ if (!sdev->hostdata) -+ return; -+ -+ starget = scsi_target(sdev); -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->num_luns--; -+ -+ shost = dev_to_shost(&starget->dev); -+ ioc = shost_priv(shost); -+ -+ if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_from_target(ioc, -+ sas_target_priv_data); -+ if (sas_device && !sas_target_priv_data->num_luns) -+ sas_device->starget = NULL; -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ } -+ -+ kfree(sdev->hostdata); -+ sdev->hostdata = NULL; -+} -+ -+/** -+ * _scsih_display_sata_capabilities - sata capabilities -+ * @ioc: per adapter object -+ * @handle: device handle -+ * @sdev: scsi device struct -+ */ -+static void -+_scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc, -+ u16 handle, struct scsi_device *sdev) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ u32 ioc_status; -+ u16 flags; -+ u32 device_info; -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ flags = le16_to_cpu(sas_device_pg0.Flags); -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ -+ sdev_printk(KERN_INFO, sdev, -+ "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " -+ "sw_preserve(%s)\n", -+ (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" : -+ "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n"); -+} -+ -+/* -+ * raid transport support - -+ * Enabled for SLES11 and newer, in older kernels the driver will panic when -+ * unloading the driver followed by a load - I beleive that the subroutine -+ * raid_class_release() is not cleaning up properly. -+ */ -+ -+/** -+ * scsih_is_raid_mpt2sas - return boolean indicating device is raid volume -+ * @dev the device struct object -+ */ -+int -+scsih_is_raid_mpt2sas(struct device *dev) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); -+ -+ if (ioc->is_warpdrive) -+ return 0; -+ return (sdev->channel == RAID_CHANNEL) ? 1 : 0; -+} -+ -+/** -+ * scsih_get_resync_mpt2sas - get raid volume resync percent complete -+ * @dev the device struct object -+ */ -+void -+scsih_get_resync_mpt2sas(struct device *dev) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); -+ static struct _raid_device *raid_device; -+ unsigned long flags; -+ Mpi2RaidVolPage0_t vol_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u32 volume_status_flags; -+ u8 percent_complete; -+ u16 handle; -+ -+ percent_complete = 0; -+ handle = 0; -+ if (ioc->is_warpdrive) -+ goto out; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, -+ sdev->channel); -+ if (raid_device) { -+ handle = raid_device->handle; -+ percent_complete = raid_device->percent_complete; -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ -+ if (!handle) -+ goto out; -+ -+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, -+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, -+ sizeof(Mpi2RaidVolPage0_t))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ percent_complete = 0; -+ goto out; -+ } -+ -+ volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); -+ if (!(volume_status_flags & -+ MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)) -+ percent_complete = 0; -+ -+ out: -+ -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ raid_set_resync(mpt2sas_raid_template_mpt2sas, dev, percent_complete); -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ raid_set_resync(mpt3sas_raid_template_mpt2sas, dev, percent_complete); -+ break; -+ } -+} -+ -+/** -+ * scsih_get_state_mpt2sas - get raid volume level -+ * @dev the device struct object -+ */ -+void -+scsih_get_state_mpt2sas(struct device *dev) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); -+ static struct _raid_device *raid_device; -+ unsigned long flags; -+ Mpi2RaidVolPage0_t vol_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u32 volstate; -+ enum raid_state state = RAID_STATE_UNKNOWN; -+ u16 handle = 0; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, -+ sdev->channel); -+ if (raid_device) -+ handle = raid_device->handle; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ -+ if (!raid_device) -+ goto out; -+ -+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, -+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, -+ sizeof(Mpi2RaidVolPage0_t))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags); -+ if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { -+ state = RAID_STATE_RESYNCING; -+ goto out; -+ } -+ -+ switch (vol_pg0.VolumeState) { -+ case MPI2_RAID_VOL_STATE_OPTIMAL: -+ case MPI2_RAID_VOL_STATE_ONLINE: -+ state = RAID_STATE_ACTIVE; -+ break; -+ case MPI2_RAID_VOL_STATE_DEGRADED: -+ state = RAID_STATE_DEGRADED; -+ break; -+ case MPI2_RAID_VOL_STATE_FAILED: -+ case MPI2_RAID_VOL_STATE_MISSING: -+ state = RAID_STATE_OFFLINE; -+ break; -+ } -+ out: -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ raid_set_state(mpt2sas_raid_template_mpt2sas, dev, state); -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ raid_set_state(mpt3sas_raid_template_mpt2sas, dev, state); -+ break; -+ } -+} -+ -+/** -+ * _scsih_set_level - set raid level -+ * @sdev: scsi device struct -+ * @volume_type: volume type -+ */ -+static void -+_scsih_set_level(struct MPT3SAS_ADAPTER *ioc, -+ struct scsi_device *sdev, u8 volume_type) -+{ -+ enum raid_level level = RAID_LEVEL_UNKNOWN; -+ -+ switch (volume_type) { -+ case MPI2_RAID_VOL_TYPE_RAID0: -+ level = RAID_LEVEL_0; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID10: -+ level = RAID_LEVEL_10; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID1E: -+ level = RAID_LEVEL_1E; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID1: -+ level = RAID_LEVEL_1; -+ break; -+ } -+ -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ raid_set_level(mpt2sas_raid_template_mpt2sas, -+ &sdev->sdev_gendev, level); -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ raid_set_level(mpt3sas_raid_template_mpt2sas, -+ &sdev->sdev_gendev, level); -+ break; -+ } -+} -+ -+ -+/** -+ * _scsih_get_volume_capabilities - volume capabilities -+ * @ioc: per adapter object -+ * @sas_device: the raid_device object -+ * -+ * Returns 0 for success, else 1 -+ */ -+static int -+_scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device) -+{ -+ Mpi2RaidVolPage0_t *vol_pg0; -+ Mpi2RaidPhysDiskPage0_t pd_pg0; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 sz; -+ u8 num_pds; -+ -+ if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, -+ &num_pds)) || !num_pds) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, -+ __func__)); -+ return 1; -+ } -+ -+ raid_device->num_pds = num_pds; -+ sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * -+ sizeof(Mpi2RaidVol0PhysDisk_t)); -+ vol_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!vol_pg0) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, -+ __func__)); -+ return 1; -+ } -+ -+ if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, -+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, -+ __func__)); -+ kfree(vol_pg0); -+ return 1; -+ } -+ -+ raid_device->volume_type = vol_pg0->VolumeType; -+ -+ /* figure out what the underlying devices are by -+ * obtaining the device_info bits for the 1st device -+ */ -+ if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, -+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, -+ vol_pg0->PhysDisk[0].PhysDiskNum))) { -+ if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, -+ le16_to_cpu(pd_pg0.DevHandle)))) { -+ raid_device->device_info = -+ le32_to_cpu(sas_device_pg0.DeviceInfo); -+ } -+ } -+ -+ kfree(vol_pg0); -+ return 0; -+} -+ -+/** -+ * _scsih_enable_tlr - setting TLR flags -+ * @ioc: per adapter object -+ * @sdev: scsi device struct -+ * -+ * Enabling Transaction Layer Retries for tape devices when -+ * vpd page 0x90 is present -+ * -+ */ -+static void -+_scsih_enable_tlr(struct MPT3SAS_ADAPTER *ioc, struct scsi_device *sdev) -+{ -+ -+ /* only for TAPE */ -+ if (sdev->type != TYPE_TAPE) -+ return; -+ -+ if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)) -+ return; -+ -+ sas_enable_tlr(sdev); -+ sdev_printk(KERN_INFO, sdev, "TLR %s\n", -+ sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled"); -+ return; -+ -+} -+ -+/** -+ * scsih_slave_configure_mpt2sas - device configure routine. -+ * @sdev: scsi device struct -+ * -+ * Returns 0 if ok. Any other return is assumed to be an error and -+ * the device is ignored. -+ */ -+int -+scsih_slave_configure_mpt2sas(struct scsi_device *sdev) -+{ -+ struct Scsi_Host *shost = sdev->host; -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ int qdepth; -+ u8 ssp_target = 0; -+ char *ds = ""; -+ char *r_level = ""; -+ u16 handle, volume_handle = 0; -+ u64 volume_wwid = 0; -+ -+ qdepth = 1; -+ sas_device_priv_data = sdev->hostdata; -+ sas_device_priv_data->configured_lun = 1; -+ sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT; -+ sas_target_priv_data = sas_device_priv_data->sas_target; -+ handle = sas_target_priv_data->handle; -+ -+ /* raid volume handling */ -+ if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) { -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ if (!raid_device) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, -+ __LINE__, __func__)); -+ return 1; -+ } -+ -+ if (_scsih_get_volume_capabilities(ioc, raid_device)) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, -+ __LINE__, __func__)); -+ return 1; -+ } -+ -+ /* -+ * WARPDRIVE: Initialize the required data for Direct IO -+ */ -+ mpt2sas_init_warpdrive_properties(ioc, raid_device); -+ -+ /* RAID Queue Depth Support -+ * IS volume = underlying qdepth of drive type, either -+ * MPT3SAS_SAS_QUEUE_DEPTH or MPT3SAS_SATA_QUEUE_DEPTH -+ * IM/IME/R10 = 128 (MPT3SAS_RAID_QUEUE_DEPTH) -+ */ -+ if (raid_device->device_info & -+ MPI2_SAS_DEVICE_INFO_SSP_TARGET) { -+ qdepth = MPT3SAS_SAS_QUEUE_DEPTH; -+ ds = "SSP"; -+ } else { -+ qdepth = MPT3SAS_SATA_QUEUE_DEPTH; -+ if (raid_device->device_info & -+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -+ ds = "SATA"; -+ else -+ ds = "STP"; -+ } -+ -+ switch (raid_device->volume_type) { -+ case MPI2_RAID_VOL_TYPE_RAID0: -+ r_level = "RAID0"; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID1E: -+ qdepth = MPT3SAS_RAID_QUEUE_DEPTH; -+ if (ioc->manu_pg10.OEMIdentifier && -+ (le32_to_cpu(ioc->manu_pg10.GenericFlags0) & -+ MFG10_GF0_R10_DISPLAY) && -+ !(raid_device->num_pds % 2)) -+ r_level = "RAID10"; -+ else -+ r_level = "RAID1E"; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID1: -+ qdepth = MPT3SAS_RAID_QUEUE_DEPTH; -+ r_level = "RAID1"; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID10: -+ qdepth = MPT3SAS_RAID_QUEUE_DEPTH; -+ r_level = "RAID10"; -+ break; -+ case MPI2_RAID_VOL_TYPE_UNKNOWN: -+ default: -+ qdepth = MPT3SAS_RAID_QUEUE_DEPTH; -+ r_level = "RAIDX"; -+ break; -+ } -+ -+ if (!ioc->hide_ir_msg) -+ sdev_printk(KERN_INFO, sdev, -+ "%s: handle(0x%04x), wwid(0x%016llx)," -+ " pd_count(%d), type(%s)\n", -+ r_level, raid_device->handle, -+ (unsigned long long)raid_device->wwid, -+ raid_device->num_pds, ds); -+ -+ if (shost->max_sectors > MPT3SAS_RAID_MAX_SECTORS) { -+ blk_queue_max_hw_sectors(sdev->request_queue, -+ MPT3SAS_RAID_MAX_SECTORS); -+ sdev_printk(KERN_INFO, sdev, -+ "Set queue's max_sector to: %u\n", -+ MPT3SAS_RAID_MAX_SECTORS); -+ } -+ -+ scsih_change_queue_depth_mpt2sas(sdev, qdepth, SCSI_QDEPTH_DEFAULT); -+ -+ /* raid transport support */ -+ if (!ioc->is_warpdrive) -+ _scsih_set_level(ioc, sdev, raid_device->volume_type); -+ return 0; -+ } -+ -+ /* non-raid handling */ -+ if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { -+ if (mpt2sas_config_get_volume_handle(ioc, handle, -+ &volume_handle)) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__)); -+ return 1; -+ } -+ if (volume_handle && mpt2sas_config_get_volume_wwid(ioc, -+ volume_handle, &volume_wwid)) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__)); -+ return 1; -+ } -+ } -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_device_priv_data->sas_target->sas_address); -+ if (!sas_device) { -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, -+ __func__)); -+ return 1; -+ } -+ -+ sas_device->volume_handle = volume_handle; -+ sas_device->volume_wwid = volume_wwid; -+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { -+ qdepth = MPT3SAS_SAS_QUEUE_DEPTH; -+ ssp_target = 1; -+ if (sas_device->device_info & -+ MPI2_SAS_DEVICE_INFO_SEP) { -+ sdev_printk(KERN_WARNING, sdev, -+ "set ignore_delay_remove for handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle); -+ sas_device_priv_data->ignore_delay_remove = 1; -+ ds = "SES"; -+ } else -+ ds = "SSP"; -+ } else { -+ qdepth = MPT3SAS_SATA_QUEUE_DEPTH; -+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) -+ ds = "STP"; -+ else if (sas_device->device_info & -+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -+ ds = "SATA"; -+ } -+ -+ sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " \ -+ "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", -+ ds, handle, (unsigned long long)sas_device->sas_address, -+ sas_device->phy, (unsigned long long)sas_device->device_name); -+ if (sas_device->enclosure_handle != 0) -+ sdev_printk(KERN_INFO, sdev, -+ "%s: enclosure_logical_id(0x%016llx), slot(%d)\n", -+ ds, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot); -+ if (sas_device->connector_name[0] != '\0') -+ sdev_printk(KERN_INFO, sdev, -+ "%s: enclosure level(0x%04x), connector name( %s)\n", -+ ds, sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ sas_device_put(sas_device); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (!ssp_target) -+ _scsih_display_sata_capabilities(ioc, handle, sdev); -+ -+ -+ scsih_change_queue_depth_mpt2sas(sdev, qdepth, SCSI_QDEPTH_DEFAULT); -+ -+ if (ssp_target) { -+ sas_read_port_mode_page(sdev); -+ _scsih_enable_tlr(ioc, sdev); -+ } -+ -+ return 0; -+} -+ -+/** -+ * scsih_bios_param_mpt2sas - fetch head, sector, cylinder info for a disk -+ * @sdev: scsi device struct -+ * @bdev: pointer to block device context -+ * @capacity: device size (in 512 byte sectors) -+ * @params: three element array to place output: -+ * params[0] number of heads (max 255) -+ * params[1] number of sectors (max 63) -+ * params[2] number of cylinders -+ * -+ * Return nothing. -+ */ -+int -+scsih_bios_param_mpt2sas(struct scsi_device *sdev, struct block_device *bdev, -+ sector_t capacity, int params[]) -+{ -+ int heads; -+ int sectors; -+ sector_t cylinders; -+ ulong dummy; -+ -+ heads = 64; -+ sectors = 32; -+ -+ dummy = heads * sectors; -+ cylinders = capacity; -+ sector_div(cylinders, dummy); -+ -+ /* -+ * Handle extended translation size for logical drives -+ * > 1Gb -+ */ -+ if ((ulong)capacity >= 0x200000) { -+ heads = 255; -+ sectors = 63; -+ dummy = heads * sectors; -+ cylinders = capacity; -+ sector_div(cylinders, dummy); -+ } -+ -+ /* return result */ -+ params[0] = heads; -+ params[1] = sectors; -+ params[2] = cylinders; -+ -+ return 0; -+} -+ -+/** -+ * _scsih_response_code - translation of device response code -+ * @ioc: per adapter object -+ * @response_code: response code returned by the device -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_response_code(struct MPT3SAS_ADAPTER *ioc, u8 response_code) -+{ -+ char *desc; -+ -+ switch (response_code) { -+ case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: -+ desc = "task management request completed"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: -+ desc = "invalid frame"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: -+ desc = "task management request not supported"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_TM_FAILED: -+ desc = "task management request failed"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: -+ desc = "task management request succeeded"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: -+ desc = "invalid lun"; -+ break; -+ case 0xA: -+ desc = "overlapped tag attempted"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: -+ desc = "task queued, however not sent to target"; -+ break; -+ default: -+ desc = "unknown"; -+ break; -+ } -+ pr_warn(MPT3SAS_FMT "response_code(0x%01x): %s\n", -+ ioc->name, response_code, desc); -+} -+ -+/** -+ * _scsih_tm_done - tm completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: none. -+ * -+ * The callback handler when using scsih_issue_tm. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_tm_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ if (ioc->tm_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->tm_cmds.smid != smid) -+ return 1; -+ ioc->tm_cmds.status |= MPT3_CMD_COMPLETE; -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply) { -+ memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); -+ ioc->tm_cmds.status |= MPT3_CMD_REPLY_VALID; -+ } -+ ioc->tm_cmds.status &= ~MPT3_CMD_PENDING; -+ complete(&ioc->tm_cmds.done); -+ return 1; -+} -+ -+/** -+ * mpt2sas_scsih_set_tm_flag - set per target tm_busy -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * During taskmangement request, we need to freeze the device queue. -+ */ -+void -+mpt2sas_scsih_set_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ u8 skip = 0; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ if (skip) -+ continue; -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->sas_target->handle == handle) { -+ sas_device_priv_data->sas_target->tm_busy = 1; -+ skip = 1; -+ ioc->ignore_loginfos = 1; -+ } -+ } -+} -+ -+/** -+ * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * During taskmangement request, we need to freeze the device queue. -+ */ -+void -+mpt2sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ u8 skip = 0; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ if (skip) -+ continue; -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->sas_target->handle == handle) { -+ sas_device_priv_data->sas_target->tm_busy = 0; -+ skip = 1; -+ ioc->ignore_loginfos = 0; -+ } -+ } -+} -+ -+/** -+ * mpt2sas_scsih_issue_tm - main routine for sending tm requests -+ * @ioc: per adapter struct -+ * @device_handle: device handle -+ * @channel: the channel assigned by the OS -+ * @id: the id assigned by the OS -+ * @lun: lun number -+ * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) -+ * @smid_task: smid assigned to the task -+ * @timeout: timeout in seconds -+ * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF -+ * Context: user -+ * -+ * A generic API for sending task management requests to firmware. -+ * -+ * The callback index is set inside `ioc->tm_cb_idx`. -+ * -+ * Return SUCCESS or FAILED. -+ */ -+int -+mpt2sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel, -+ uint id, uint lun, u8 type, u16 smid_task, ulong timeout, -+ enum mutex_type m_type) -+{ -+ Mpi2SCSITaskManagementRequest_t *mpi_request; -+ Mpi2SCSITaskManagementReply_t *mpi_reply; -+ u16 smid = 0; -+ u32 ioc_state; -+ unsigned long timeleft; -+ struct scsiio_tracker *scsi_lookup = NULL; -+ int rc; -+ u16 msix_task = 0; -+ -+ if (m_type == TM_MUTEX_ON) -+ mutex_lock(&ioc->tm_cmds.mutex); -+ if (ioc->tm_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_info(MPT3SAS_FMT "%s: tm_cmd busy!!!\n", -+ __func__, ioc->name); -+ rc = FAILED; -+ goto err_out; -+ } -+ -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ rc = FAILED; -+ goto err_out; -+ } -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ if (ioc_state & MPI2_DOORBELL_USED) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "unexpected doorbell active!\n", ioc->name)); -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ rc = (!rc) ? SUCCESS : FAILED; -+ goto err_out; -+ } -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { -+ mpt2sas_base_fault_info(ioc, ioc_state & -+ MPI2_DOORBELL_DATA_MASK); -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ rc = (!rc) ? SUCCESS : FAILED; -+ goto err_out; -+ } -+ -+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = FAILED; -+ goto err_out; -+ } -+ -+ if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) -+ scsi_lookup = &ioc->scsi_lookup[smid_task - 1]; -+ -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "sending tm: handle(0x%04x), task_type(0x%02x), smid(%d)\n", -+ ioc->name, handle, type, smid_task)); -+ ioc->tm_cmds.status = MPT3_CMD_PENDING; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->tm_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); -+ memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t)); -+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; -+ mpi_request->DevHandle = cpu_to_le16(handle); -+ mpi_request->TaskType = type; -+ mpi_request->TaskMID = cpu_to_le16(smid_task); -+ int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); -+ mpt2sas_scsih_set_tm_flag(ioc, handle); -+ init_completion(&ioc->tm_cmds.done); -+ if ((type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) && -+ (scsi_lookup->msix_io < ioc->reply_queue_count)) -+ msix_task = scsi_lookup->msix_io; -+ else -+ msix_task = 0; -+ mpt2sas_base_put_smid_hi_priority(ioc, smid, msix_task); -+ timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); -+ if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SCSITaskManagementRequest_t)/4); -+ if (!(ioc->tm_cmds.status & MPT3_CMD_RESET)) { -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ rc = (!rc) ? SUCCESS : FAILED; -+ ioc->tm_cmds.status = MPT3_CMD_NOT_USED; -+ mpt2sas_scsih_clear_tm_flag(ioc, handle); -+ goto err_out; -+ } -+ } -+ -+ /* sync IRQs in case those were busy during flush. */ -+ mpt2sas_base_sync_reply_irqs(ioc); -+ -+ if (ioc->tm_cmds.status & MPT3_CMD_REPLY_VALID) { -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); -+ mpi_reply = ioc->tm_cmds.reply; -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "complete tm: " \ -+ "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo), -+ le32_to_cpu(mpi_reply->TerminationCount))); -+ if (ioc->logging_level & MPT_DEBUG_TM) { -+ _scsih_response_code(ioc, mpi_reply->ResponseCode); -+ if (mpi_reply->IOCStatus) -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SCSITaskManagementRequest_t)/4); -+ } -+ } -+ -+ switch (type) { -+ case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: -+ rc = SUCCESS; -+ if (scsi_lookup->scmd == NULL) -+ break; -+ rc = FAILED; -+ break; -+ -+ case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: -+ if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) -+ rc = FAILED; -+ else -+ rc = SUCCESS; -+ break; -+ case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: -+ case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: -+ if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) -+ rc = FAILED; -+ else -+ rc = SUCCESS; -+ break; -+ case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: -+ rc = SUCCESS; -+ break; -+ default: -+ rc = FAILED; -+ break; -+ } -+ -+ mpt2sas_scsih_clear_tm_flag(ioc, handle); -+ ioc->tm_cmds.status = MPT3_CMD_NOT_USED; -+ if (m_type == TM_MUTEX_ON) -+ mutex_unlock(&ioc->tm_cmds.mutex); -+ -+ return rc; -+ -+ err_out: -+ if (m_type == TM_MUTEX_ON) -+ mutex_unlock(&ioc->tm_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * _scsih_tm_display_info - displays info about the device -+ * @ioc: per adapter struct -+ * @scmd: pointer to scsi command object -+ * -+ * Called by task management callback handlers. -+ */ -+static void -+_scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) -+{ -+ struct scsi_target *starget = scmd->device->sdev_target; -+ struct MPT3SAS_TARGET *priv_target = starget->hostdata; -+ struct _sas_device *sas_device = NULL; -+ unsigned long flags; -+ char *device_str = NULL; -+ -+ if (!priv_target) -+ return; -+ if (ioc->hide_ir_msg) -+ device_str = "WarpDrive"; -+ else -+ device_str = "volume"; -+ -+ scsi_print_command(scmd); -+ if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { -+ starget_printk(KERN_INFO, starget, -+ "%s handle(0x%04x), %s wwid(0x%016llx)\n", -+ device_str, priv_target->handle, -+ device_str, (unsigned long long)priv_target->sas_address); -+ } else { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_from_target(ioc, priv_target); -+ if (sas_device) { -+ if (priv_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) { -+ starget_printk(KERN_INFO, starget, -+ "volume handle(0x%04x), " -+ "volume wwid(0x%016llx)\n", -+ sas_device->volume_handle, -+ (unsigned long long)sas_device->volume_wwid); -+ } -+ starget_printk(KERN_INFO, starget, -+ "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n", -+ sas_device->handle, -+ (unsigned long long)sas_device->sas_address, -+ sas_device->phy); -+ if (sas_device->enclosure_handle != 0) -+ starget_printk(KERN_INFO, starget, -+ "enclosure_logical_id(0x%016llx), slot(%d)\n", -+ (unsigned long long) -+ sas_device->enclosure_logical_id, -+ sas_device->slot); -+ if (sas_device->connector_name[0] != '\0') -+ starget_printk(KERN_INFO, starget, -+ "enclosure level(0x%04x),connector name(%s)\n", -+ sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ } -+} -+ -+/** -+ * scsih_abort_mpt2sas - eh threads main abort routine -+ * @scmd: pointer to scsi command object -+ * -+ * Returns SUCCESS if command aborted else FAILED -+ */ -+int -+scsih_abort_mpt2sas(struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ u16 smid; -+ u16 handle; -+ int r; -+ -+ sdev_printk(KERN_INFO, scmd->device, -+ "attempting task abort! scmd(%p)\n", scmd); -+ _scsih_tm_display_info(ioc, scmd); -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { -+ sdev_printk(KERN_INFO, scmd->device, -+ "device been deleted! scmd(%p)\n", scmd); -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ r = SUCCESS; -+ goto out; -+ } -+ -+ /* search for the command */ -+ smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd); -+ if (!smid) { -+ scmd->result = DID_RESET << 16; -+ r = SUCCESS; -+ goto out; -+ } -+ -+ /* for hidden raid components and volumes this is not supported */ -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT || -+ sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) { -+ scmd->result = DID_RESET << 16; -+ r = FAILED; -+ goto out; -+ } -+ -+ mpt2sas_halt_firmware(ioc); -+ -+ handle = sas_device_priv_data->sas_target->handle; -+ r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, -+ scmd->device->id, scmd->device->lun, -+ MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, TM_MUTEX_ON); -+ -+ out: -+ sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", -+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); -+ return r; -+} -+ -+/** -+ * scsih_dev_reset_mpt2sas - eh threads main device reset routine -+ * @scmd: pointer to scsi command object -+ * -+ * Returns SUCCESS if command aborted else FAILED -+ */ -+int -+scsih_dev_reset_mpt2sas(struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct _sas_device *sas_device = NULL; -+ u16 handle; -+ int r; -+ -+ struct scsi_target *starget = scmd->device->sdev_target; -+ struct MPT3SAS_TARGET *target_priv_data = starget->hostdata; -+ -+ sdev_printk(KERN_INFO, scmd->device, -+ "attempting device reset! scmd(%p)\n", scmd); -+ _scsih_tm_display_info(ioc, scmd); -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { -+ sdev_printk(KERN_INFO, scmd->device, -+ "device been deleted! scmd(%p)\n", scmd); -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ r = SUCCESS; -+ goto out; -+ } -+ -+ /* for hidden raid components obtain the volume_handle */ -+ handle = 0; -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) { -+ sas_device = mpt2sas_get_sdev_from_target(ioc, -+ target_priv_data); -+ if (sas_device) -+ handle = sas_device->volume_handle; -+ } else -+ handle = sas_device_priv_data->sas_target->handle; -+ -+ if (!handle) { -+ scmd->result = DID_RESET << 16; -+ r = FAILED; -+ goto out; -+ } -+ -+ r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, -+ scmd->device->id, scmd->device->lun, -+ MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, TM_MUTEX_ON); -+ -+ out: -+ sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", -+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ -+ return r; -+} -+ -+/** -+ * scsih_target_reset_mpt2sas - eh threads main target reset routine -+ * @scmd: pointer to scsi command object -+ * -+ * Returns SUCCESS if command aborted else FAILED -+ */ -+int -+scsih_target_reset_mpt2sas(struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct _sas_device *sas_device = NULL; -+ u16 handle; -+ int r; -+ struct scsi_target *starget = scmd->device->sdev_target; -+ struct MPT3SAS_TARGET *target_priv_data = starget->hostdata; -+ -+ starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n", -+ scmd); -+ _scsih_tm_display_info(ioc, scmd); -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { -+ starget_printk(KERN_INFO, starget, "target been deleted! scmd(%p)\n", -+ scmd); -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ r = SUCCESS; -+ goto out; -+ } -+ -+ /* for hidden raid components obtain the volume_handle */ -+ handle = 0; -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) { -+ sas_device = mpt2sas_get_sdev_from_target(ioc, -+ target_priv_data); -+ if (sas_device) -+ handle = sas_device->volume_handle; -+ } else -+ handle = sas_device_priv_data->sas_target->handle; -+ -+ if (!handle) { -+ scmd->result = DID_RESET << 16; -+ r = FAILED; -+ goto out; -+ } -+ -+ r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, -+ scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, -+ 30, TM_MUTEX_ON); -+ -+ out: -+ starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", -+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ -+ return r; -+} -+ -+ -+/** -+ * scsih_host_reset_mpt2sas - eh threads main host reset routine -+ * @scmd: pointer to scsi command object -+ * -+ * Returns SUCCESS if command aborted else FAILED -+ */ -+int -+scsih_host_reset_mpt2sas(struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); -+ int r, retval; -+ -+ pr_info(MPT3SAS_FMT "attempting host reset! scmd(%p)\n", -+ ioc->name, scmd); -+ scsi_print_command(scmd); -+ -+ if (ioc->is_driver_loading) { -+ pr_info(MPT3SAS_FMT "Blocking the host reset\n", -+ ioc->name); -+ r = FAILED; -+ goto out; -+ } -+ -+ retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ r = (retval < 0) ? FAILED : SUCCESS; -+out: -+ pr_info(MPT3SAS_FMT "host reset: %s scmd(%p)\n", -+ ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); -+ -+ return r; -+} -+ -+/** -+ * _scsih_fw_event_add - insert and queue up fw_event -+ * @ioc: per adapter object -+ * @fw_event: object describing the event -+ * Context: This function will acquire ioc->fw_event_lock. -+ * -+ * This adds the firmware event object into link list, then queues it up to -+ * be processed from user context. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_fw_event_add(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) -+{ -+ unsigned long flags; -+ -+ if (ioc->firmware_event_thread == NULL) -+ return; -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ fw_event_work_get(fw_event); -+ INIT_LIST_HEAD(&fw_event->list); -+ list_add_tail(&fw_event->list, &ioc->fw_event_list); -+ INIT_WORK(&fw_event->work, _firmware_event_work); -+ fw_event_work_get(fw_event); -+ queue_work(ioc->firmware_event_thread, &fw_event->work); -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+} -+ -+/** -+ * _scsih_fw_event_del_from_list - delete fw_event from the list -+ * @ioc: per adapter object -+ * @fw_event: object describing the event -+ * Context: This function will acquire ioc->fw_event_lock. -+ * -+ * If the fw_event is on the fw_event_list, remove it and do a put. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_fw_event_del_from_list(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work -+ *fw_event) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ if (!list_empty(&fw_event->list)) { -+ list_del_init(&fw_event->list); -+ fw_event_work_put(fw_event); -+ } -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+} -+ -+ -+ /** -+ * mpt2sas_send_trigger_data_event - send event for processing trigger data -+ * @ioc: per adapter object -+ * @event_data: trigger event data -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) -+{ -+ struct fw_event_work *fw_event; -+ u16 sz; -+ -+ if (ioc->is_driver_loading) -+ return; -+ sz = sizeof(*event_data); -+ fw_event = alloc_fw_event_work(sz); -+ if (!fw_event) -+ return; -+ fw_event->event = MPT3SAS_PROCESS_TRIGGER_DIAG; -+ fw_event->ioc = ioc; -+ memcpy(fw_event->event_data, event_data, sizeof(*event_data)); -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+} -+ -+/** -+ * _scsih_error_recovery_delete_devices - remove devices not responding -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_error_recovery_delete_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct fw_event_work *fw_event; -+ -+ if (ioc->is_driver_loading) -+ return; -+ fw_event = alloc_fw_event_work(0); -+ if (!fw_event) -+ return; -+ fw_event->event = MPT3SAS_REMOVE_UNRESPONDING_DEVICES; -+ fw_event->ioc = ioc; -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+} -+ -+/** -+ * mpt2sas_port_enable_complete - port enable completed (fake event) -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct fw_event_work *fw_event; -+ -+ fw_event = alloc_fw_event_work(0); -+ if (!fw_event) -+ return; -+ fw_event->event = MPT3SAS_PORT_ENABLE_COMPLETE; -+ fw_event->ioc = ioc; -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+} -+ -+static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc) -+{ -+ unsigned long flags; -+ struct fw_event_work *fw_event = NULL; -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ if (!list_empty(&ioc->fw_event_list)) { -+ fw_event = list_first_entry(&ioc->fw_event_list, -+ struct fw_event_work, list); -+ list_del_init(&fw_event->list); -+ } -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+ -+ return fw_event; -+} -+ -+/** -+ * _scsih_fw_event_cleanup_queue - cleanup event queue -+ * @ioc: per adapter object -+ * -+ * Walk the firmware event queue, either killing timers, or waiting -+ * for outstanding events to complete -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct fw_event_work *fw_event; -+ -+ if (list_empty(&ioc->fw_event_list) || -+ !ioc->firmware_event_thread || in_interrupt()) -+ return; -+ -+ while ((fw_event = dequeue_next_fw_event(ioc))) { -+ /* -+ * Wait on the fw_event to complete. If this returns 1, then -+ * the event was never executed, and we need a put for the -+ * reference the work had on the fw_event. -+ * -+ * If it did execute, we wait for it to finish, and the put will -+ * happen from _firmware_event_work() -+ */ -+ if (cancel_work_sync(&fw_event->work)) -+ fw_event_work_put(fw_event); -+ -+ fw_event_work_put(fw_event); -+ } -+} -+ -+/** -+ * _scsih_internal_device_block - block the sdev device -+ * @sdev: per device object -+ * @sas_device_priv_data : per device driver private data -+ * -+ * make sure device is blocked without error, if not -+ * print an error -+ */ -+static void -+_scsih_internal_device_block(struct scsi_device *sdev, -+ struct MPT3SAS_DEVICE *sas_device_priv_data) -+{ -+ int r = 0; -+ -+ sdev_printk(KERN_INFO, sdev, "device_block, handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle); -+ sas_device_priv_data->block = 1; -+ -+ r = scsi_internal_device_block(sdev); -+ if (r == -EINVAL) -+ sdev_printk(KERN_WARNING, sdev, -+ "device_block failed with return(%d) for handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle, r); -+} -+ -+/** -+ * _scsih_internal_device_unblock - unblock the sdev device -+ * @sdev: per device object -+ * @sas_device_priv_data : per device driver private data -+ * make sure device is unblocked without error, if not retry -+ * by blocking and then unblocking -+ */ -+ -+static void -+_scsih_internal_device_unblock(struct scsi_device *sdev, -+ struct MPT3SAS_DEVICE *sas_device_priv_data) -+{ -+ int r = 0; -+ -+ sdev_printk(KERN_WARNING, sdev, "device_unblock and setting to running, " -+ "handle(0x%04x)\n", sas_device_priv_data->sas_target->handle); -+ sas_device_priv_data->block = 0; -+ r = scsi_internal_device_unblock(sdev, SDEV_RUNNING); -+ if (r == -EINVAL) { -+ /* The device has been set to SDEV_RUNNING by SD layer during -+ * device addition but the request queue is still stopped by -+ * our earlier block call. We need to perform a block again -+ * to get the device to SDEV_BLOCK and then to SDEV_RUNNING */ -+ -+ sdev_printk(KERN_WARNING, sdev, -+ "device_unblock failed with return(%d) for handle(0x%04x) " -+ "performing a block followed by an unblock\n", -+ sas_device_priv_data->sas_target->handle, r); -+ sas_device_priv_data->block = 1; -+ r = scsi_internal_device_block(sdev); -+ if (r) -+ sdev_printk(KERN_WARNING, sdev, "retried device_block " -+ "failed with return(%d) for handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle, r); -+ -+ sas_device_priv_data->block = 0; -+ r = scsi_internal_device_unblock(sdev, SDEV_RUNNING); -+ if (r) -+ sdev_printk(KERN_WARNING, sdev, "retried device_unblock" -+ " failed with return(%d) for handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle, r); -+ } -+} -+ -+/** -+ * _scsih_ublock_io_all_device - unblock every device -+ * @ioc: per adapter object -+ * -+ * change the device state from block to running -+ */ -+static void -+_scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (!sas_device_priv_data->block) -+ continue; -+ -+ dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, -+ "device_running, handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle)); -+ _scsih_internal_device_unblock(sdev, sas_device_priv_data); -+ } -+} -+ -+ -+/** -+ * _scsih_ublock_io_device - prepare device to be deleted -+ * @ioc: per adapter object -+ * @sas_addr: sas address -+ * -+ * unblock then put device in offline state -+ */ -+static void -+_scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->sas_target->sas_address -+ != sas_address) -+ continue; -+ if (sas_device_priv_data->block) -+ _scsih_internal_device_unblock(sdev, -+ sas_device_priv_data); -+ } -+} -+ -+/** -+ * _scsih_block_io_all_device - set the device state to SDEV_BLOCK -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * During device pull we need to appropiately set the sdev state. -+ */ -+static void -+_scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->block) -+ continue; -+ if (sas_device_priv_data->ignore_delay_remove) { -+ sdev_printk(KERN_INFO, sdev, -+ "%s skip device_block for SES handle(0x%04x)\n", -+ __func__, sas_device_priv_data->sas_target->handle); -+ continue; -+ } -+ _scsih_internal_device_block(sdev, sas_device_priv_data); -+ } -+} -+ -+/** -+ * _scsih_block_io_device - set the device state to SDEV_BLOCK -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * During device pull we need to appropiately set the sdev state. -+ */ -+static void -+_scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ struct _sas_device *sas_device; -+ -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (!sas_device) -+ return; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->sas_target->handle != handle) -+ continue; -+ if (sas_device_priv_data->block) -+ continue; -+ if (sas_device->pend_sas_rphy_add) -+ continue; -+ if (sas_device_priv_data->ignore_delay_remove) { -+ sdev_printk(KERN_INFO, sdev, -+ "%s skip device_block for SES handle(0x%04x)\n", -+ __func__, sas_device_priv_data->sas_target->handle); -+ continue; -+ } -+ _scsih_internal_device_block(sdev, sas_device_priv_data); -+ } -+ -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_block_io_to_children_attached_to_ex -+ * @ioc: per adapter object -+ * @sas_expander: the sas_device object -+ * -+ * This routine set sdev state to SDEV_BLOCK for all devices -+ * attached to this expander. This function called when expander is -+ * pulled. -+ */ -+static void -+_scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander) -+{ -+ struct _sas_port *mpt2sas_port; -+ struct _sas_device *sas_device; -+ struct _sas_node *expander_sibling; -+ unsigned long flags; -+ -+ if (!sas_expander) -+ return; -+ -+ list_for_each_entry(mpt2sas_port, -+ &sas_expander->sas_port_list, port_list) { -+ if (mpt2sas_port->remote_identify.device_type == -+ SAS_END_DEVICE) { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ if (sas_device) { -+ set_bit(sas_device->handle, -+ ioc->blocking_handles); -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ } -+ } -+ -+ list_for_each_entry(mpt2sas_port, -+ &sas_expander->sas_port_list, port_list) { -+ -+ if (mpt2sas_port->remote_identify.device_type == -+ SAS_EDGE_EXPANDER_DEVICE || -+ mpt2sas_port->remote_identify.device_type == -+ SAS_FANOUT_EXPANDER_DEVICE) { -+ expander_sibling = -+ mpt2sas_scsih_expander_find_by_sas_address( -+ ioc, mpt2sas_port->remote_identify.sas_address); -+ _scsih_block_io_to_children_attached_to_ex(ioc, -+ expander_sibling); -+ } -+ } -+} -+ -+/** -+ * _scsih_block_io_to_children_attached_directly -+ * @ioc: per adapter object -+ * @event_data: topology change event data -+ * -+ * This routine set sdev state to SDEV_BLOCK for all devices -+ * direct attached during device pull. -+ */ -+static void -+_scsih_block_io_to_children_attached_directly(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasTopologyChangeList_t *event_data) -+{ -+ int i; -+ u16 handle; -+ u16 reason_code; -+ -+ for (i = 0; i < event_data->NumEntries; i++) { -+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); -+ if (!handle) -+ continue; -+ reason_code = event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_RC_MASK; -+ if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING) -+ _scsih_block_io_device(ioc, handle); -+ } -+} -+ -+/** -+ * _scsih_tm_tr_send - send task management request -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: interrupt time. -+ * -+ * This code is to initiate the device removal handshake protocol -+ * with controller firmware. This function will issue target reset -+ * using high priority request queue. It will send a sas iounit -+ * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. -+ * -+ * This is designed to send muliple task management request at the same -+ * time to the fifo. If the fifo is full, we will append the request, -+ * and process it in a future completion. -+ */ -+static void -+_scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ Mpi2SCSITaskManagementRequest_t *mpi_request; -+ u16 smid; -+ struct _sas_device *sas_device = NULL; -+ struct MPT3SAS_TARGET *sas_target_priv_data = NULL; -+ u64 sas_address = 0; -+ unsigned long flags; -+ struct _tr_list *delayed_tr; -+ u32 ioc_state; -+ -+ if (ioc->remove_host) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host has been removed: handle(0x%04x)\n", -+ __func__, ioc->name, handle)); -+ return; -+ } else if (ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host in pci error recovery: handle(0x%04x)\n", -+ __func__, ioc->name, -+ handle)); -+ return; -+ } -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host is not operational: handle(0x%04x)\n", -+ __func__, ioc->name, -+ handle)); -+ return; -+ } -+ -+ /* if PD, then return */ -+ if (test_bit(handle, ioc->pd_handles)) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device && sas_device->starget && -+ sas_device->starget->hostdata) { -+ sas_target_priv_data = sas_device->starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ sas_address = sas_device->sas_address; -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (sas_target_priv_data) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, handle, -+ (unsigned long long)sas_address)); -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting delete flag:enclosure logical id(0x%016llx)," -+ " slot(%d)\n", ioc->name, (unsigned long long) -+ sas_device->enclosure_logical_id, -+ sas_device->slot)); -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting delete flag: enclosure level(0x%04x)," -+ " connector name( %s)\n", ioc->name, -+ sas_device->enclosure_level, -+ sas_device->connector_name)); -+ _scsih_ublock_io_device(ioc, sas_address); -+ sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; -+ } -+ -+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); -+ if (!smid) { -+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); -+ if (!delayed_tr) -+ goto out; -+ INIT_LIST_HEAD(&delayed_tr->list); -+ delayed_tr->handle = handle; -+ list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED:tr:handle(0x%04x), (open)\n", -+ ioc->name, handle)); -+ goto out; -+ } -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", -+ ioc->name, handle, smid, -+ ioc->tm_tr_cb_idx)); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; -+ mpi_request->DevHandle = cpu_to_le16(handle); -+ mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; -+ mpt2sas_base_put_smid_hi_priority(ioc, smid, 0); -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); -+ -+out: -+ if (sas_device) -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_tm_tr_complete - -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt time. -+ * -+ * This is the target reset completion routine. -+ * This code is part of the code to initiate the device removal -+ * handshake protocol with controller firmware. -+ * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE) -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ u16 handle; -+ Mpi2SCSITaskManagementRequest_t *mpi_request_tm; -+ Mpi2SCSITaskManagementReply_t *mpi_reply = -+ mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ Mpi2SasIoUnitControlRequest_t *mpi_request; -+ u16 smid_sas_ctrl; -+ u32 ioc_state; -+ struct _sc_list *delayed_sc; -+ -+ if (ioc->remove_host) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host has been removed\n", __func__, ioc->name)); -+ return 1; -+ } else if (ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host in pci error recovery\n", __func__, -+ ioc->name)); -+ return 1; -+ } -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host is not operational\n", __func__, ioc->name)); -+ return 1; -+ } -+ if (unlikely(!mpi_reply)) { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 1; -+ } -+ mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); -+ handle = le16_to_cpu(mpi_request_tm->DevHandle); -+ if (handle != le16_to_cpu(mpi_reply->DevHandle)) { -+ dewtprintk(ioc, pr_err(MPT3SAS_FMT -+ "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n", -+ ioc->name, handle, -+ le16_to_cpu(mpi_reply->DevHandle), smid)); -+ return 0; -+ } -+ -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " -+ "loginfo(0x%08x), completed(%d)\n", ioc->name, -+ handle, smid, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo), -+ le32_to_cpu(mpi_reply->TerminationCount))); -+ -+ smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); -+ if (!smid_sas_ctrl) { -+ delayed_sc = kzalloc(sizeof(*delayed_sc), GFP_ATOMIC); -+ if (!delayed_sc) -+ return _scsih_check_for_pending_tm(ioc, smid); -+ INIT_LIST_HEAD(&delayed_sc->list); -+ delayed_sc->handle = mpi_request_tm->DevHandle; -+ list_add_tail(&delayed_sc->list, &ioc->delayed_sc_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED:sc:handle(0x%04x), (open)\n", -+ ioc->name, handle)); -+ return _scsih_check_for_pending_tm(ioc, smid); -+ } -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", -+ ioc->name, handle, smid_sas_ctrl, -+ ioc->tm_sas_control_cb_idx)); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); -+ memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; -+ mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; -+ mpi_request->DevHandle = mpi_request_tm->DevHandle; -+ mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); -+ -+ return _scsih_check_for_pending_tm(ioc, smid); -+} -+ -+ -+/** -+ * _scsih_sas_control_complete - completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt time. -+ * -+ * This is the sas iounit control completion routine. -+ * This code is part of the code to initiate the device removal -+ * handshake protocol with controller firmware. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_sas_control_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u8 msix_index, u32 reply) -+{ -+ Mpi2SasIoUnitControlReply_t *mpi_reply = -+ mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ -+ if (likely(mpi_reply)) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "sc_complete:handle(0x%04x), (open) " -+ "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, -+ le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo))); -+ } else { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ } -+ return mpt2sas_check_for_pending_internal_cmds(ioc, smid); -+} -+ -+/** -+ * _scsih_tm_tr_volume_send - send target reset request for volumes -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: interrupt time. -+ * -+ * This is designed to send muliple task management request at the same -+ * time to the fifo. If the fifo is full, we will append the request, -+ * and process it in a future completion. -+ */ -+static void -+_scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ Mpi2SCSITaskManagementRequest_t *mpi_request; -+ u16 smid; -+ struct _tr_list *delayed_tr; -+ -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host reset in progress!\n", -+ __func__, ioc->name)); -+ return; -+ } -+ -+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx); -+ if (!smid) { -+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); -+ if (!delayed_tr) -+ return; -+ INIT_LIST_HEAD(&delayed_tr->list); -+ delayed_tr->handle = handle; -+ list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED:tr:handle(0x%04x), (open)\n", -+ ioc->name, handle)); -+ return; -+ } -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", -+ ioc->name, handle, smid, -+ ioc->tm_tr_volume_cb_idx)); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; -+ mpi_request->DevHandle = cpu_to_le16(handle); -+ mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; -+ mpt2sas_base_put_smid_hi_priority(ioc, smid, 0); -+} -+ -+/** -+ * _scsih_tm_volume_tr_complete - target reset completion -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt time. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_tm_volume_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u8 msix_index, u32 reply) -+{ -+ u16 handle; -+ Mpi2SCSITaskManagementRequest_t *mpi_request_tm; -+ Mpi2SCSITaskManagementReply_t *mpi_reply = -+ mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host reset in progress!\n", -+ __func__, ioc->name)); -+ return 1; -+ } -+ if (unlikely(!mpi_reply)) { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 1; -+ } -+ -+ mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); -+ handle = le16_to_cpu(mpi_request_tm->DevHandle); -+ if (handle != le16_to_cpu(mpi_reply->DevHandle)) { -+ dewtprintk(ioc, pr_err(MPT3SAS_FMT -+ "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n", -+ ioc->name, handle, -+ le16_to_cpu(mpi_reply->DevHandle), smid)); -+ return 0; -+ } -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " -+ "loginfo(0x%08x), completed(%d)\n", ioc->name, -+ handle, smid, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo), -+ le32_to_cpu(mpi_reply->TerminationCount))); -+ -+ return _scsih_check_for_pending_tm(ioc, smid); -+} -+ -+/** -+ * _scsih_issue_delayed_event_ack_mpt2sas - issue delayed Event ACK messages -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @event: Event ID -+ * @event_context: used to track events uniquely -+ * -+ * Context - processed in interrupt context. -+ */ -+void -+_scsih_issue_delayed_event_ack_mpt2sas(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event, -+ u32 event_context) -+{ -+ Mpi2EventAckRequest_t *ack_request; -+ int i = smid - ioc->internal_smid; -+ unsigned long flags; -+ -+ /* Without releasing the smid just update the -+ * call back index and reuse the same smid for -+ * processing this delayed request -+ */ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ ioc->internal_lookup[i].cb_idx = ioc->base_cb_idx; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n", -+ ioc->name, le16_to_cpu(event), smid, -+ ioc->base_cb_idx)); -+ ack_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); -+ ack_request->Function = MPI2_FUNCTION_EVENT_ACK; -+ ack_request->Event = event; -+ ack_request->EventContext = event_context; -+ ack_request->VF_ID = 0; /* TODO */ -+ ack_request->VP_ID = 0; -+ mpt2sas_base_put_smid_default(ioc, smid); -+} -+ -+/** -+ * _scsih_issue_delayed_sas_io_unit_ctrl_mpt2sas - issue delayed -+ * sas_io_unit_ctrl messages -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @handle: device handle -+ * -+ * Context - processed in interrupt context. -+ */ -+void -+_scsih_issue_delayed_sas_io_unit_ctrl_mpt2sas(struct MPT3SAS_ADAPTER *ioc, -+ u16 smid, u16 handle) -+ { -+ Mpi2SasIoUnitControlRequest_t *mpi_request; -+ u32 ioc_state; -+ int i = smid - ioc->internal_smid; -+ unsigned long flags; -+ -+ if (ioc->remove_host) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host has been removed\n", -+ __func__, ioc->name)); -+ return; -+ } else if (ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host in pci error recovery\n", -+ __func__, ioc->name)); -+ return; -+ } -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host is not operational\n", -+ __func__, ioc->name)); -+ return; -+ } -+ -+ /* Without releasing the smid just update the -+ * call back index and reuse the same smid for -+ * processing this delayed request -+ */ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ ioc->internal_lookup[i].cb_idx = ioc->tm_sas_control_cb_idx; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", -+ ioc->name, le16_to_cpu(handle), smid, -+ ioc->tm_sas_control_cb_idx)); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; -+ mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; -+ mpi_request->DevHandle = handle; -+ mpt2sas_base_put_smid_default(ioc, smid); -+} -+ -+/** -+ * _scsih_check_for_pending_internal_cmds - check for pending internal messages -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Context: Executed in interrupt context -+ * -+ * This will check delayed internal messages list, and process the -+ * next request. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ struct _sc_list *delayed_sc; -+ struct _event_ack_list *delayed_event_ack; -+ -+ if (!list_empty(&ioc->delayed_event_ack_list)) { -+ delayed_event_ack = list_entry(ioc->delayed_event_ack_list.next, -+ struct _event_ack_list, list); -+ _scsih_issue_delayed_event_ack_mpt2sas(ioc, smid, -+ delayed_event_ack->Event, delayed_event_ack->EventContext); -+ list_del(&delayed_event_ack->list); -+ kfree(delayed_event_ack); -+ return 0; -+ } -+ -+ if (!list_empty(&ioc->delayed_sc_list)) { -+ delayed_sc = list_entry(ioc->delayed_sc_list.next, -+ struct _sc_list, list); -+ _scsih_issue_delayed_sas_io_unit_ctrl_mpt2sas(ioc, smid, -+ delayed_sc->handle); -+ list_del(&delayed_sc->list); -+ kfree(delayed_sc); -+ return 0; -+ } -+ return 1; -+} -+ -+/** -+ * _scsih_check_for_pending_tm - check for pending task management -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * This will check delayed target reset list, and feed the -+ * next reqeust. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ struct _tr_list *delayed_tr; -+ -+ if (!list_empty(&ioc->delayed_tr_volume_list)) { -+ delayed_tr = list_entry(ioc->delayed_tr_volume_list.next, -+ struct _tr_list, list); -+ mpt2sas_base_free_smid(ioc, smid); -+ _scsih_tm_tr_volume_send(ioc, delayed_tr->handle); -+ list_del(&delayed_tr->list); -+ kfree(delayed_tr); -+ return 0; -+ } -+ -+ if (!list_empty(&ioc->delayed_tr_list)) { -+ delayed_tr = list_entry(ioc->delayed_tr_list.next, -+ struct _tr_list, list); -+ mpt2sas_base_free_smid(ioc, smid); -+ _scsih_tm_tr_send(ioc, delayed_tr->handle); -+ list_del(&delayed_tr->list); -+ kfree(delayed_tr); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+/** -+ * _scsih_check_topo_delete_events - sanity check on topo events -+ * @ioc: per adapter object -+ * @event_data: the event data payload -+ * -+ * This routine added to better handle cable breaker. -+ * -+ * This handles the case where driver receives multiple expander -+ * add and delete events in a single shot. When there is a delete event -+ * the routine will void any pending add events waiting in the event queue. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_check_topo_delete_events(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasTopologyChangeList_t *event_data) -+{ -+ struct fw_event_work *fw_event; -+ Mpi2EventDataSasTopologyChangeList_t *local_event_data; -+ u16 expander_handle; -+ struct _sas_node *sas_expander; -+ unsigned long flags; -+ int i, reason_code; -+ u16 handle; -+ -+ for (i = 0 ; i < event_data->NumEntries; i++) { -+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); -+ if (!handle) -+ continue; -+ reason_code = event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_RC_MASK; -+ if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING) -+ _scsih_tm_tr_send(ioc, handle); -+ } -+ -+ expander_handle = le16_to_cpu(event_data->ExpanderDevHandle); -+ if (expander_handle < ioc->sas_hba.num_phys) { -+ _scsih_block_io_to_children_attached_directly(ioc, event_data); -+ return; -+ } -+ if (event_data->ExpStatus == -+ MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) { -+ /* put expander attached devices into blocking state */ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, -+ expander_handle); -+ _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ do { -+ handle = find_first_bit(ioc->blocking_handles, -+ ioc->facts.MaxDevHandle); -+ if (handle < ioc->facts.MaxDevHandle) -+ _scsih_block_io_device(ioc, handle); -+ } while (test_and_clear_bit(handle, ioc->blocking_handles)); -+ } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING) -+ _scsih_block_io_to_children_attached_directly(ioc, event_data); -+ -+ if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) -+ return; -+ -+ /* mark ignore flag for pending events */ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ list_for_each_entry(fw_event, &ioc->fw_event_list, list) { -+ if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || -+ fw_event->ignore) -+ continue; -+ local_event_data = (Mpi2EventDataSasTopologyChangeList_t *) -+ fw_event->event_data; -+ if (local_event_data->ExpStatus == -+ MPI2_EVENT_SAS_TOPO_ES_ADDED || -+ local_event_data->ExpStatus == -+ MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { -+ if (le16_to_cpu(local_event_data->ExpanderDevHandle) == -+ expander_handle) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting ignoring flag\n", ioc->name)); -+ fw_event->ignore = 1; -+ } -+ } -+ } -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+} -+ -+/** -+ * _scsih_set_volume_delete_flag - setting volume delete flag -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * This returns nothing. -+ */ -+static void -+_scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _raid_device *raid_device; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ if (raid_device && raid_device->starget && -+ raid_device->starget->hostdata) { -+ sas_target_priv_data = -+ raid_device->starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting delete flag: handle(0x%04x), " -+ "wwid(0x%016llx)\n", ioc->name, handle, -+ (unsigned long long) raid_device->wwid)); -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+} -+ -+/** -+ * _scsih_set_volume_handle_for_tr - set handle for target reset to volume -+ * @handle: input handle -+ * @a: handle for volume a -+ * @b: handle for volume b -+ * -+ * IR firmware only supports two raid volumes. The purpose of this -+ * routine is to set the volume handle in either a or b. When the given -+ * input handle is non-zero, or when a and b have not been set before. -+ */ -+static void -+_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b) -+{ -+ if (!handle || handle == *a || handle == *b) -+ return; -+ if (!*a) -+ *a = handle; -+ else if (!*b) -+ *b = handle; -+} -+ -+/** -+ * _scsih_check_ir_config_unhide_events - check for UNHIDE events -+ * @ioc: per adapter object -+ * @event_data: the event data payload -+ * Context: interrupt time. -+ * -+ * This routine will send target reset to volume, followed by target -+ * resets to the PDs. This is called when a PD has been removed, or -+ * volume has been deleted or removed. When the target reset is sent -+ * to volume, the PD target resets need to be queued to start upon -+ * completion of the volume target reset. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataIrConfigChangeList_t *event_data) -+{ -+ Mpi2EventIrConfigElement_t *element; -+ int i; -+ u16 handle, volume_handle, a, b; -+ struct _tr_list *delayed_tr; -+ -+ a = 0; -+ b = 0; -+ -+ if (ioc->is_warpdrive) -+ return; -+ -+ /* Volume Resets for Deleted or Removed */ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ if (le32_to_cpu(event_data->Flags) & -+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) -+ continue; -+ if (element->ReasonCode == -+ MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED || -+ element->ReasonCode == -+ MPI2_EVENT_IR_CHANGE_RC_REMOVED) { -+ volume_handle = le16_to_cpu(element->VolDevHandle); -+ _scsih_set_volume_delete_flag(ioc, volume_handle); -+ _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); -+ } -+ } -+ -+ /* Volume Resets for UNHIDE events */ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ if (le32_to_cpu(event_data->Flags) & -+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) -+ continue; -+ if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) { -+ volume_handle = le16_to_cpu(element->VolDevHandle); -+ _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); -+ } -+ } -+ -+ if (a) -+ _scsih_tm_tr_volume_send(ioc, a); -+ if (b) -+ _scsih_tm_tr_volume_send(ioc, b); -+ -+ /* PD target resets */ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) -+ continue; -+ handle = le16_to_cpu(element->PhysDiskDevHandle); -+ volume_handle = le16_to_cpu(element->VolDevHandle); -+ clear_bit(handle, ioc->pd_handles); -+ if (!volume_handle) -+ _scsih_tm_tr_send(ioc, handle); -+ else if (volume_handle == a || volume_handle == b) { -+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); -+ BUG_ON(!delayed_tr); -+ INIT_LIST_HEAD(&delayed_tr->list); -+ delayed_tr->handle = handle; -+ list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, -+ handle)); -+ } else -+ _scsih_tm_tr_send(ioc, handle); -+ } -+} -+ -+ -+/** -+ * _scsih_check_volume_delete_events - set delete flag for volumes -+ * @ioc: per adapter object -+ * @event_data: the event data payload -+ * Context: interrupt time. -+ * -+ * This will handle the case when the cable connected to entire volume is -+ * pulled. We will take care of setting the deleted flag so normal IO will -+ * not be sent. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_check_volume_delete_events(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataIrVolume_t *event_data) -+{ -+ u32 state; -+ -+ if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) -+ return; -+ state = le32_to_cpu(event_data->NewValue); -+ if (state == MPI2_RAID_VOL_STATE_MISSING || state == -+ MPI2_RAID_VOL_STATE_FAILED) -+ _scsih_set_volume_delete_flag(ioc, -+ le16_to_cpu(event_data->VolDevHandle)); -+} -+ -+/** -+ * _scsih_temp_threshold_events - display temperature threshold exceeded events -+ * @ioc: per adapter object -+ * @event_data: the temp threshold event data -+ * Context: interrupt time. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataTemperature_t *event_data) -+{ -+ if (ioc->temp_sensors_count >= event_data->SensorNum) { -+ pr_err(MPT3SAS_FMT "Temperature Threshold flags %s%s%s%s" -+ " exceeded for Sensor: %d !!!\n", ioc->name, -+ ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ", -+ ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ", -+ ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ", -+ ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ", -+ event_data->SensorNum); -+ pr_err(MPT3SAS_FMT "Current Temp In Celsius: %d\n", -+ ioc->name, event_data->CurrentTemperature); -+ } -+} -+ -+/** -+ * _scsih_flush_running_cmds - completing outstanding commands. -+ * @ioc: per adapter object -+ * -+ * The flushing out of all pending scmd commands following host reset, -+ * where all IO is dropped to the floor. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct scsi_cmnd *scmd; -+ u16 smid; -+ u16 count = 0; -+ -+ for (smid = 1; smid <= ioc->scsiio_depth; smid++) { -+ scmd = _scsih_scsi_lookup_get_clear(ioc, smid); -+ if (!scmd) -+ continue; -+ count++; -+ mpt2sas_base_free_smid(ioc, smid); -+ scsi_dma_unmap(scmd); -+ if (ioc->pci_error_recovery) -+ scmd->result = DID_NO_CONNECT << 16; -+ else -+ scmd->result = DID_RESET << 16; -+ scmd->scsi_done(scmd); -+ } -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "completing %d cmds\n", -+ ioc->name, count)); -+} -+ -+/** -+ * _scsih_setup_eedp - setup MPI request for EEDP transfer -+ * @ioc: per adapter object -+ * @scmd: pointer to scsi command object -+ * @mpi_request: pointer to the SCSI_IO reqest message frame -+ * -+ * Supporting protection 1 and 3. -+ * -+ * Returns nothing -+ */ -+static void -+_scsih_setup_eedp(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, -+ Mpi2SCSIIORequest_t *mpi_request) -+{ -+ u16 eedp_flags; -+ unsigned char prot_op = scsi_get_prot_op(scmd); -+ unsigned char prot_type = scsi_get_prot_type(scmd); -+ Mpi25SCSIIORequest_t *mpi_request_3v = -+ (Mpi25SCSIIORequest_t *)mpi_request; -+ -+ if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL) -+ return; -+ -+ if (prot_op == SCSI_PROT_READ_STRIP) -+ eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP; -+ else if (prot_op == SCSI_PROT_WRITE_INSERT) -+ eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; -+ else -+ return; -+ -+ switch (prot_type) { -+ case SCSI_PROT_DIF_TYPE1: -+ case SCSI_PROT_DIF_TYPE2: -+ -+ /* -+ * enable ref/guard checking -+ * auto increment ref tag -+ */ -+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | -+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | -+ MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; -+ mpi_request->CDB.EEDP32.PrimaryReferenceTag = -+ cpu_to_be32(scsi_get_lba(scmd)); -+ break; -+ -+ case SCSI_PROT_DIF_TYPE3: -+ -+ /* -+ * enable guard checking -+ */ -+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; -+ -+ break; -+ } -+ -+ mpi_request_3v->EEDPBlockSize = -+ cpu_to_le16(scmd->device->sector_size); -+ mpi_request->EEDPFlags = cpu_to_le16(eedp_flags); -+} -+ -+/** -+ * _scsih_eedp_error_handling - return sense code for EEDP errors -+ * @scmd: pointer to scsi command object -+ * @ioc_status: ioc status -+ * -+ * Returns nothing -+ */ -+static void -+_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) -+{ -+ u8 ascq; -+ -+ switch (ioc_status) { -+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: -+ ascq = 0x01; -+ break; -+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: -+ ascq = 0x02; -+ break; -+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: -+ ascq = 0x03; -+ break; -+ default: -+ ascq = 0x00; -+ break; -+ } -+ scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x10, -+ ascq); -+ scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) | -+ SAM_STAT_CHECK_CONDITION; -+} -+ -+ -+ -+/** -+ * scsih_qcmd_mpt2sas - main scsi request entry point -+ * @scmd: pointer to scsi command object -+ * @done: function pointer to be invoked on completion -+ * -+ * The callback index is set inside `ioc->scsi_io_cb_idx`. -+ * -+ * Returns 0 on success. If there's a failure, return either: -+ * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or -+ * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full -+ */ -+int -+scsih_qcmd_mpt2sas(struct Scsi_Host *shost, struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _raid_device *raid_device; -+ Mpi2SCSIIORequest_t *mpi_request; -+ u32 mpi_control; -+ u16 smid; -+ u16 handle; -+ -+ if (ioc->logging_level & MPT_DEBUG_SCSI) -+ scsi_print_command(scmd); -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ return 0; -+ } -+ -+ if (ioc->pci_error_recovery || ioc->remove_host) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ return 0; -+ } -+ -+ sas_target_priv_data = sas_device_priv_data->sas_target; -+ -+ /* invalid device handle */ -+ handle = sas_target_priv_data->handle; -+ if (handle == MPT3SAS_INVALID_DEVICE_HANDLE) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ return 0; -+ } -+ -+ -+ /* host recovery or link resets sent via IOCTLs */ -+ if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) -+ return SCSI_MLQUEUE_HOST_BUSY; -+ -+ /* device has been deleted */ -+ else if (sas_target_priv_data->deleted) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ return 0; -+ /* device busy with task managment */ -+ } else if (sas_target_priv_data->tm_busy || -+ sas_device_priv_data->block) -+ return SCSI_MLQUEUE_DEVICE_BUSY; -+ -+ if (scmd->sc_data_direction == DMA_FROM_DEVICE) -+ mpi_control = MPI2_SCSIIO_CONTROL_READ; -+ else if (scmd->sc_data_direction == DMA_TO_DEVICE) -+ mpi_control = MPI2_SCSIIO_CONTROL_WRITE; -+ else -+ mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; -+ -+ /* set tags */ -+ if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) { -+ if (scmd->device->tagged_supported) { -+ if (scmd->device->ordered_tags) -+ mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; -+ else -+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; -+ } else -+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; -+ } else -+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; -+ -+ /* Make sure Device is not raid volume. -+ * We do not expose raid functionality to upper layer for warpdrive. -+ */ -+ if (!ioc->is_warpdrive && !scsih_is_raid_mpt2sas(&scmd->device->sdev_gendev) -+ && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) -+ mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; -+ -+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ goto out; -+ } -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); -+ _scsih_setup_eedp(ioc, scmd, mpi_request); -+ -+ if (scmd->cmd_len == 32) -+ mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; -+ mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) -+ mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; -+ else -+ mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; -+ mpi_request->DevHandle = cpu_to_le16(handle); -+ mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); -+ mpi_request->Control = cpu_to_le32(mpi_control); -+ mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len); -+ mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; -+ mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; -+ mpi_request->SenseBufferLowAddress = -+ mpt2sas_base_get_sense_buffer_dma(ioc, smid); -+ mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; -+ int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *) -+ mpi_request->LUN); -+ memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); -+ -+ if (mpi_request->DataLength) { -+ if (ioc->build_sg_scmd(ioc, scmd, smid)) { -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } else -+ ioc->build_zero_len_sge(ioc, &mpi_request->SGL); -+ -+ raid_device = sas_target_priv_data->raid_device; -+ if (raid_device && raid_device->direct_io_enabled) -+ mpt2sas_setup_direct_io(ioc, scmd, raid_device, mpi_request, -+ smid); -+ -+ if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) { -+ if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) { -+ mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len | -+ MPI25_SCSIIO_IOFLAGS_FAST_PATH); -+ mpt2sas_base_put_smid_fast_path(ioc, smid, handle); -+ } else -+ mpt2sas_base_put_smid_scsi_io(ioc, smid, -+ le16_to_cpu(mpi_request->DevHandle)); -+ } else -+ mpt2sas_base_put_smid_default(ioc, smid); -+ return 0; -+ -+ out: -+ return SCSI_MLQUEUE_HOST_BUSY; -+} -+ -+/** -+ * _scsih_normalize_sense - normalize descriptor and fixed format sense data -+ * @sense_buffer: sense data returned by target -+ * @data: normalized skey/asc/ascq -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_normalize_sense(char *sense_buffer, struct sense_info *data) -+{ -+ if ((sense_buffer[0] & 0x7F) >= 0x72) { -+ /* descriptor format */ -+ data->skey = sense_buffer[1] & 0x0F; -+ data->asc = sense_buffer[2]; -+ data->ascq = sense_buffer[3]; -+ } else { -+ /* fixed format */ -+ data->skey = sense_buffer[2] & 0x0F; -+ data->asc = sense_buffer[12]; -+ data->ascq = sense_buffer[13]; -+ } -+} -+ -+/** -+ * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request -+ * @ioc: per adapter object -+ * @scmd: pointer to scsi command object -+ * @mpi_reply: reply mf payload returned from firmware -+ * -+ * scsi_status - SCSI Status code returned from target device -+ * scsi_state - state info associated with SCSI_IO determined by ioc -+ * ioc_status - ioc supplied status info -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, -+ Mpi2SCSIIOReply_t *mpi_reply, u16 smid) -+{ -+ u32 response_info; -+ u8 *response_bytes; -+ u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ u8 scsi_state = mpi_reply->SCSIState; -+ u8 scsi_status = mpi_reply->SCSIStatus; -+ char *desc_ioc_state = NULL; -+ char *desc_scsi_status = NULL; -+ char *desc_scsi_state = ioc->tmp_string; -+ u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); -+ struct _sas_device *sas_device = NULL; -+ struct scsi_target *starget = scmd->device->sdev_target; -+ struct MPT3SAS_TARGET *priv_target = starget->hostdata; -+ char *device_str = NULL; -+ -+ if (!priv_target) -+ return; -+ if (ioc->hide_ir_msg) -+ device_str = "WarpDrive"; -+ else -+ device_str = "volume"; -+ -+ if (log_info == 0x31170000) -+ return; -+ -+ switch (ioc_status) { -+ case MPI2_IOCSTATUS_SUCCESS: -+ desc_ioc_state = "success"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_FUNCTION: -+ desc_ioc_state = "invalid function"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: -+ desc_ioc_state = "scsi recovered error"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: -+ desc_ioc_state = "scsi invalid dev handle"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: -+ desc_ioc_state = "scsi device not there"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: -+ desc_ioc_state = "scsi data overrun"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: -+ desc_ioc_state = "scsi data underrun"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: -+ desc_ioc_state = "scsi io data error"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: -+ desc_ioc_state = "scsi protocol error"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: -+ desc_ioc_state = "scsi task terminated"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: -+ desc_ioc_state = "scsi residual mismatch"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: -+ desc_ioc_state = "scsi task mgmt failed"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: -+ desc_ioc_state = "scsi ioc terminated"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: -+ desc_ioc_state = "scsi ext terminated"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: -+ desc_ioc_state = "eedp guard error"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: -+ desc_ioc_state = "eedp ref tag error"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: -+ desc_ioc_state = "eedp app tag error"; -+ break; -+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER: -+ desc_ioc_state = "insufficient power"; -+ break; -+ default: -+ desc_ioc_state = "unknown"; -+ break; -+ } -+ -+ switch (scsi_status) { -+ case MPI2_SCSI_STATUS_GOOD: -+ desc_scsi_status = "good"; -+ break; -+ case MPI2_SCSI_STATUS_CHECK_CONDITION: -+ desc_scsi_status = "check condition"; -+ break; -+ case MPI2_SCSI_STATUS_CONDITION_MET: -+ desc_scsi_status = "condition met"; -+ break; -+ case MPI2_SCSI_STATUS_BUSY: -+ desc_scsi_status = "busy"; -+ break; -+ case MPI2_SCSI_STATUS_INTERMEDIATE: -+ desc_scsi_status = "intermediate"; -+ break; -+ case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: -+ desc_scsi_status = "intermediate condmet"; -+ break; -+ case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: -+ desc_scsi_status = "reservation conflict"; -+ break; -+ case MPI2_SCSI_STATUS_COMMAND_TERMINATED: -+ desc_scsi_status = "command terminated"; -+ break; -+ case MPI2_SCSI_STATUS_TASK_SET_FULL: -+ desc_scsi_status = "task set full"; -+ break; -+ case MPI2_SCSI_STATUS_ACA_ACTIVE: -+ desc_scsi_status = "aca active"; -+ break; -+ case MPI2_SCSI_STATUS_TASK_ABORTED: -+ desc_scsi_status = "task aborted"; -+ break; -+ default: -+ desc_scsi_status = "unknown"; -+ break; -+ } -+ -+ desc_scsi_state[0] = '\0'; -+ if (!scsi_state) -+ desc_scsi_state = " "; -+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) -+ strcat(desc_scsi_state, "response info "); -+ if (scsi_state & MPI2_SCSI_STATE_TERMINATED) -+ strcat(desc_scsi_state, "state terminated "); -+ if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) -+ strcat(desc_scsi_state, "no status "); -+ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) -+ strcat(desc_scsi_state, "autosense failed "); -+ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) -+ strcat(desc_scsi_state, "autosense valid "); -+ -+ scsi_print_command(scmd); -+ -+ if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { -+ pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name, -+ device_str, (unsigned long long)priv_target->sas_address); -+ } else { -+ sas_device = mpt2sas_get_sdev_from_target(ioc, priv_target); -+ if (sas_device) { -+ pr_warn(MPT3SAS_FMT -+ "\tsas_address(0x%016llx), phy(%d)\n", -+ ioc->name, (unsigned long long) -+ sas_device->sas_address, sas_device->phy); -+ if (sas_device->enclosure_handle != 0) -+ pr_warn(MPT3SAS_FMT -+ "\tenclosure_logical_id(0x%016llx)," -+ "slot(%d)\n", ioc->name, -+ (unsigned long long) -+ sas_device->enclosure_logical_id, -+ sas_device->slot); -+ if (sas_device->connector_name[0]) -+ pr_warn(MPT3SAS_FMT -+ "\tenclosure level(0x%04x)," -+ " connector name( %s)\n", ioc->name, -+ sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ sas_device_put(sas_device); -+ } -+ } -+ -+ pr_warn(MPT3SAS_FMT -+ "\thandle(0x%04x), ioc_status(%s)(0x%04x), smid(%d)\n", -+ ioc->name, le16_to_cpu(mpi_reply->DevHandle), -+ desc_ioc_state, ioc_status, smid); -+ pr_warn(MPT3SAS_FMT -+ "\trequest_len(%d), underflow(%d), resid(%d)\n", -+ ioc->name, scsi_bufflen(scmd), scmd->underflow, -+ scsi_get_resid(scmd)); -+ pr_warn(MPT3SAS_FMT -+ "\ttag(%d), transfer_count(%d), sc->result(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->TaskTag), -+ le32_to_cpu(mpi_reply->TransferCount), scmd->result); -+ pr_warn(MPT3SAS_FMT -+ "\tscsi_status(%s)(0x%02x), scsi_state(%s)(0x%02x)\n", -+ ioc->name, desc_scsi_status, -+ scsi_status, desc_scsi_state, scsi_state); -+ -+ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { -+ struct sense_info data; -+ _scsih_normalize_sense(scmd->sense_buffer, &data); -+ pr_warn(MPT3SAS_FMT -+ "\t[sense_key,asc,ascq]: [0x%02x,0x%02x,0x%02x], count(%d)\n", -+ ioc->name, data.skey, -+ data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); -+ } -+ -+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { -+ response_info = le32_to_cpu(mpi_reply->ResponseInfo); -+ response_bytes = (u8 *)&response_info; -+ _scsih_response_code(ioc, response_bytes[0]); -+ } -+} -+ -+/** -+ * _scsih_turn_on_pfa_led - illuminate PFA LED -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: process -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ Mpi2SepReply_t mpi_reply; -+ Mpi2SepRequest_t mpi_request; -+ struct _sas_device *sas_device; -+ -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (!sas_device) -+ return; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; -+ mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; -+ mpi_request.SlotStatus = -+ cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); -+ mpi_request.DevHandle = cpu_to_le16(handle); -+ mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; -+ if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, -+ &mpi_request)) != 0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ sas_device->pfa_led_on = 1; -+ -+ if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply.IOCStatus), -+ le32_to_cpu(mpi_reply.IOCLogInfo))); -+ goto out; -+ } -+out: -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_turn_off_pfa_led - turn off Fault LED -+ * @ioc: per adapter object -+ * @sas_device: sas device whose PFA LED has to turned off -+ * Context: process -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ Mpi2SepReply_t mpi_reply; -+ Mpi2SepRequest_t mpi_request; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; -+ mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; -+ mpi_request.SlotStatus = 0; -+ mpi_request.Slot = cpu_to_le16(sas_device->slot); -+ mpi_request.DevHandle = 0; -+ mpi_request.EnclosureHandle = cpu_to_le16(sas_device->enclosure_handle); -+ mpi_request.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS; -+ if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, -+ &mpi_request)) != 0) { -+ printk(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { -+ dewtprintk(ioc, printk(MPT3SAS_FMT -+ "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply.IOCStatus), -+ le32_to_cpu(mpi_reply.IOCLogInfo))); -+ return; -+ } -+} -+ -+/** -+ * _scsih_send_event_to_turn_on_pfa_led - fire delayed event -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: interrupt. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_send_event_to_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct fw_event_work *fw_event; -+ -+ fw_event = alloc_fw_event_work(0); -+ if (!fw_event) -+ return; -+ fw_event->event = MPT3SAS_TURN_ON_PFA_LED; -+ fw_event->device_handle = handle; -+ fw_event->ioc = ioc; -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+} -+ -+/** -+ * _scsih_smart_predicted_fault - process smart errors -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: interrupt. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct scsi_target *starget; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ Mpi2EventNotificationReply_t *event_reply; -+ Mpi2EventDataSasDeviceStatusChange_t *event_data; -+ struct _sas_device *sas_device; -+ ssize_t sz; -+ unsigned long flags; -+ -+ /* only handle non-raid devices */ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (!sas_device) -+ goto out_unlock; -+ -+ starget = sas_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ -+ if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) || -+ ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) -+ goto out_unlock; -+ -+ if (sas_device->enclosure_handle != 0) -+ starget_printk(KERN_INFO, starget, "predicted fault, " -+ "enclosure logical id(0x%016llx), slot(%d)\n", -+ (unsigned long long)sas_device->enclosure_logical_id, -+ sas_device->slot); -+ if (sas_device->connector_name[0] != '\0') -+ starget_printk(KERN_WARNING, starget, "predicted fault, " -+ "enclosure level(0x%04x), connector name( %s)\n", -+ sas_device->enclosure_level, -+ sas_device->connector_name); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) -+ _scsih_send_event_to_turn_on_pfa_led(ioc, handle); -+ -+ /* insert into event log */ -+ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + -+ sizeof(Mpi2EventDataSasDeviceStatusChange_t); -+ event_reply = kzalloc(sz, GFP_KERNEL); -+ if (!event_reply) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; -+ event_reply->Event = -+ cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); -+ event_reply->MsgLength = sz/4; -+ event_reply->EventDataLength = -+ cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4); -+ event_data = (Mpi2EventDataSasDeviceStatusChange_t *) -+ event_reply->EventData; -+ event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA; -+ event_data->ASC = 0x5D; -+ event_data->DevHandle = cpu_to_le16(handle); -+ event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); -+ mpt2sas_ctl_add_to_event_log(ioc, event_reply); -+ kfree(event_reply); -+out: -+ if (sas_device) -+ sas_device_put(sas_device); -+ return; -+ -+out_unlock: -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ goto out; -+} -+ -+/** -+ * _scsih_io_done - scsi request callback -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Callback handler when using _scsih_qcmd_mpt2sas. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -+{ -+ Mpi2SCSIIORequest_t *mpi_request; -+ Mpi2SCSIIOReply_t *mpi_reply; -+ struct scsi_cmnd *scmd; -+ u16 ioc_status; -+ u32 xfer_cnt; -+ u8 scsi_state; -+ u8 scsi_status; -+ u32 log_info; -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ u32 response_code = 0; -+ unsigned long flags; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ scmd = _scsih_scsi_lookup_get_clear(ioc, smid); -+ if (scmd == NULL) -+ return 1; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ -+ if (mpi_reply == NULL) { -+ scmd->result = DID_OK << 16; -+ goto out; -+ } -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target || -+ sas_device_priv_data->sas_target->deleted) { -+ scmd->result = DID_NO_CONNECT << 16; -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -+ -+ /* -+ * WARPDRIVE: If direct_io is set then it is directIO, -+ * the failed direct I/O should be redirected to volume -+ */ -+ if (mpt2sas_scsi_direct_io_get(ioc, smid) && -+ ((ioc_status & MPI2_IOCSTATUS_MASK) -+ != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ ioc->scsi_lookup[smid - 1].scmd = scmd; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ mpt2sas_scsi_direct_io_set(ioc, smid, 0); -+ memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); -+ mpi_request->DevHandle = -+ cpu_to_le16(sas_device_priv_data->sas_target->handle); -+ mpt2sas_base_put_smid_scsi_io(ioc, smid, -+ sas_device_priv_data->sas_target->handle); -+ return 0; -+ } -+ /* turning off TLR */ -+ scsi_state = mpi_reply->SCSIState; -+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) -+ response_code = -+ le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; -+ if (!sas_device_priv_data->tlr_snoop_check) { -+ sas_device_priv_data->tlr_snoop_check++; -+ if (!ioc->is_warpdrive && -+ !scsih_is_raid_mpt2sas(&scmd->device->sdev_gendev) && -+ sas_is_tlr_enabled(scmd->device) && -+ response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { -+ sas_disable_tlr(scmd->device); -+ sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); -+ } -+ } -+ -+ xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); -+ scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); -+ if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) -+ log_info = le32_to_cpu(mpi_reply->IOCLogInfo); -+ else -+ log_info = 0; -+ ioc_status &= MPI2_IOCSTATUS_MASK; -+ scsi_status = mpi_reply->SCSIStatus; -+ -+ if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && -+ (scsi_status == MPI2_SCSI_STATUS_BUSY || -+ scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT || -+ scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) { -+ ioc_status = MPI2_IOCSTATUS_SUCCESS; -+ } -+ -+ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { -+ struct sense_info data; -+ const void *sense_data = mpt2sas_base_get_sense_buffer(ioc, -+ smid); -+ u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, -+ le32_to_cpu(mpi_reply->SenseCount)); -+ memcpy(scmd->sense_buffer, sense_data, sz); -+ _scsih_normalize_sense(scmd->sense_buffer, &data); -+ /* failure prediction threshold exceeded */ -+ if (data.asc == 0x5D) -+ _scsih_smart_predicted_fault(ioc, -+ le16_to_cpu(mpi_reply->DevHandle)); -+ mpt2sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq); -+ -+ if (!(ioc->logging_level & MPT_DEBUG_REPLY) && -+ ((scmd->sense_buffer[2] == UNIT_ATTENTION) || -+ (scmd->sense_buffer[2] == MEDIUM_ERROR) || -+ (scmd->sense_buffer[2] == HARDWARE_ERROR))) -+ _scsih_scsi_ioc_info(ioc, scmd, mpi_reply, smid); -+ } -+ switch (ioc_status) { -+ case MPI2_IOCSTATUS_BUSY: -+ case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: -+ scmd->result = SAM_STAT_BUSY; -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: -+ scmd->result = DID_NO_CONNECT << 16; -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: -+ if (sas_device_priv_data->block) { -+ scmd->result = DID_TRANSPORT_DISRUPTED << 16; -+ goto out; -+ } -+ if (log_info == 0x31110630) { -+ if (scmd->retries > 2) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scsi_device_set_state(scmd->device, -+ SDEV_OFFLINE); -+ } else { -+ scmd->result = DID_SOFT_ERROR << 16; -+ scmd->device->expecting_cc_ua = 1; -+ } -+ break; -+ } else if (log_info == VIRTUAL_IO_FAILED_RETRY) { -+ scmd->result = DID_RESET << 16; -+ break; -+ } -+ scmd->result = DID_SOFT_ERROR << 16; -+ break; -+ case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: -+ case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: -+ scmd->result = DID_RESET << 16; -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: -+ if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt)) -+ scmd->result = DID_SOFT_ERROR << 16; -+ else -+ scmd->result = (DID_OK << 16) | scsi_status; -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: -+ scmd->result = (DID_OK << 16) | scsi_status; -+ -+ if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)) -+ break; -+ -+ if (xfer_cnt < scmd->underflow) { -+ if (scsi_status == SAM_STAT_BUSY) -+ scmd->result = SAM_STAT_BUSY; -+ else -+ scmd->result = DID_SOFT_ERROR << 16; -+ } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | -+ MPI2_SCSI_STATE_NO_SCSI_STATUS)) -+ scmd->result = DID_SOFT_ERROR << 16; -+ else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) -+ scmd->result = DID_RESET << 16; -+ else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) { -+ mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID; -+ mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION; -+ scmd->result = (DRIVER_SENSE << 24) | -+ SAM_STAT_CHECK_CONDITION; -+ scmd->sense_buffer[0] = 0x70; -+ scmd->sense_buffer[2] = ILLEGAL_REQUEST; -+ scmd->sense_buffer[12] = 0x20; -+ scmd->sense_buffer[13] = 0; -+ } -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: -+ scsi_set_resid(scmd, 0); -+ case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: -+ case MPI2_IOCSTATUS_SUCCESS: -+ scmd->result = (DID_OK << 16) | scsi_status; -+ if (response_code == -+ MPI2_SCSITASKMGMT_RSP_INVALID_FRAME || -+ (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | -+ MPI2_SCSI_STATE_NO_SCSI_STATUS))) -+ scmd->result = DID_SOFT_ERROR << 16; -+ else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) -+ scmd->result = DID_RESET << 16; -+ break; -+ -+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: -+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: -+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: -+ _scsih_eedp_error_handling(scmd, ioc_status); -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: -+ case MPI2_IOCSTATUS_INVALID_FUNCTION: -+ case MPI2_IOCSTATUS_INVALID_SGL: -+ case MPI2_IOCSTATUS_INTERNAL_ERROR: -+ case MPI2_IOCSTATUS_INVALID_FIELD: -+ case MPI2_IOCSTATUS_INVALID_STATE: -+ case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: -+ case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: -+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER: -+ default: -+ scmd->result = DID_SOFT_ERROR << 16; -+ break; -+ -+ } -+ -+ if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY)) -+ _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid); -+ -+ out: -+ -+ scsi_dma_unmap(scmd); -+ -+ scmd->scsi_done(scmd); -+ return 1; -+} -+ -+/** -+ * _scsih_sas_host_refresh - refreshing sas host object contents -+ * @ioc: per adapter object -+ * Context: user -+ * -+ * During port enable, fw will send topology events for every device. Its -+ * possible that the handles may change from the previous setting, so this -+ * code keeping handles updating if changed. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u16 sz; -+ u16 ioc_status; -+ int i; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; -+ u16 attached_handle; -+ u8 link_rate; -+ -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "updating handles for sas_host(0x%016llx)\n", -+ ioc->name, (unsigned long long)ioc->sas_hba.sas_address)); -+ -+ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys -+ * sizeof(Mpi2SasIOUnit0PhyData_t)); -+ sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, -+ sas_iounit_pg0, sz)) != 0) -+ goto out; -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ goto out; -+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) { -+ link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4; -+ if (i == 0) -+ ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> -+ PhyData[0].ControllerDevHandle); -+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; -+ attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. -+ AttachedDevHandle); -+ if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) -+ link_rate = MPI2_SAS_NEG_LINK_RATE_1_5; -+ mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, -+ attached_handle, i, link_rate); -+ } -+ out: -+ kfree(sas_iounit_pg0); -+} -+ -+/** -+ * _scsih_sas_host_add - create sas host object -+ * @ioc: per adapter object -+ * -+ * Creating host side data object, stored in ioc->sas_hba -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int i; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; -+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; -+ Mpi2SasPhyPage0_t phy_pg0; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2SasEnclosurePage0_t enclosure_pg0; -+ u16 ioc_status; -+ u16 sz; -+ u8 device_missing_delay; -+ -+ mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys); -+ if (!ioc->sas_hba.num_phys) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ /* sas_iounit page 0 */ -+ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit0PhyData_t)); -+ sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, -+ sas_iounit_pg0, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ /* sas_iounit page 1 */ -+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit1PhyData_t)); -+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg1) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, -+ sas_iounit_pg1, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ ioc->io_missing_delay = -+ sas_iounit_pg1->IODeviceMissingDelay; -+ device_missing_delay = -+ sas_iounit_pg1->ReportDeviceMissingDelay; -+ if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) -+ ioc->device_missing_delay = (device_missing_delay & -+ MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; -+ else -+ ioc->device_missing_delay = device_missing_delay & -+ MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; -+ -+ ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev; -+ ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys, -+ sizeof(struct _sas_phy), GFP_KERNEL); -+ if (!ioc->sas_hba.phy) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) { -+ if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, -+ i))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ if (i == 0) -+ ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> -+ PhyData[0].ControllerDevHandle); -+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; -+ ioc->sas_hba.phy[i].phy_id = i; -+ mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], -+ phy_pg0, ioc->sas_hba.parent_dev); -+ } -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc->sas_hba.enclosure_handle = -+ le16_to_cpu(sas_device_pg0.EnclosureHandle); -+ ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ pr_info(MPT3SAS_FMT -+ "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n", -+ ioc->name, ioc->sas_hba.handle, -+ (unsigned long long) ioc->sas_hba.sas_address, -+ ioc->sas_hba.num_phys) ; -+ -+ if (ioc->sas_hba.enclosure_handle) { -+ if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, -+ &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, -+ ioc->sas_hba.enclosure_handle))) -+ ioc->sas_hba.enclosure_logical_id = -+ le64_to_cpu(enclosure_pg0.EnclosureLogicalID); -+ } -+ -+ out: -+ kfree(sas_iounit_pg1); -+ kfree(sas_iounit_pg0); -+} -+ -+/** -+ * _scsih_expander_add - creating expander object -+ * @ioc: per adapter object -+ * @handle: expander handle -+ * -+ * Creating expander object, stored in ioc->sas_expander_list. -+ * -+ * Return 0 for success, else error. -+ */ -+static int -+_scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_node *sas_expander; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2ExpanderPage0_t expander_pg0; -+ Mpi2ExpanderPage1_t expander_pg1; -+ Mpi2SasEnclosurePage0_t enclosure_pg0; -+ u32 ioc_status; -+ u16 parent_handle; -+ u64 sas_address, sas_address_parent = 0; -+ int i; -+ unsigned long flags; -+ struct _sas_port *mpt2sas_port = NULL; -+ -+ int rc = 0; -+ -+ if (!handle) -+ return -1; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) -+ return -1; -+ -+ if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, -+ MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ /* handle out of order topology events */ -+ parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle); -+ if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent) -+ != 0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ if (sas_address_parent != ioc->sas_hba.sas_address) { -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, -+ sas_address_parent); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ if (!sas_expander) { -+ rc = _scsih_expander_add(ioc, parent_handle); -+ if (rc != 0) -+ return rc; -+ } -+ } -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_address = le64_to_cpu(expander_pg0.SASAddress); -+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, -+ sas_address); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ if (sas_expander) -+ return 0; -+ -+ sas_expander = kzalloc(sizeof(struct _sas_node), -+ GFP_KERNEL); -+ if (!sas_expander) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ sas_expander->handle = handle; -+ sas_expander->num_phys = expander_pg0.NumPhys; -+ sas_expander->sas_address_parent = sas_address_parent; -+ sas_expander->sas_address = sas_address; -+ -+ pr_info(MPT3SAS_FMT "expander_add: handle(0x%04x)," \ -+ " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name, -+ handle, parent_handle, (unsigned long long) -+ sas_expander->sas_address, sas_expander->num_phys); -+ -+ if (!sas_expander->num_phys) -+ goto out_fail; -+ sas_expander->phy = kcalloc(sas_expander->num_phys, -+ sizeof(struct _sas_phy), GFP_KERNEL); -+ if (!sas_expander->phy) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -1; -+ goto out_fail; -+ } -+ -+ INIT_LIST_HEAD(&sas_expander->sas_port_list); -+ mpt2sas_port = mpt2sas_transport_port_add(ioc, handle, -+ sas_address_parent); -+ if (!mpt2sas_port) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -1; -+ goto out_fail; -+ } -+ sas_expander->parent_dev = &mpt2sas_port->rphy->dev; -+ -+ for (i = 0 ; i < sas_expander->num_phys ; i++) { -+ if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, -+ &expander_pg1, i, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -1; -+ goto out_fail; -+ } -+ sas_expander->phy[i].handle = handle; -+ sas_expander->phy[i].phy_id = i; -+ -+ if ((mpt2sas_transport_add_expander_phy(ioc, -+ &sas_expander->phy[i], expander_pg1, -+ sas_expander->parent_dev))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -1; -+ goto out_fail; -+ } -+ } -+ -+ if (sas_expander->enclosure_handle) { -+ if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, -+ &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, -+ sas_expander->enclosure_handle))) -+ sas_expander->enclosure_logical_id = -+ le64_to_cpu(enclosure_pg0.EnclosureLogicalID); -+ } -+ -+ _scsih_expander_node_add(ioc, sas_expander); -+ return 0; -+ -+ out_fail: -+ -+ if (mpt2sas_port) -+ mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, -+ sas_address_parent); -+ kfree(sas_expander); -+ return rc; -+} -+ -+/** -+ * mpt2sas_expander_remove - removing expander object -+ * @ioc: per adapter object -+ * @sas_address: expander sas_address -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) -+{ -+ struct _sas_node *sas_expander; -+ unsigned long flags; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, -+ sas_address); -+ if (sas_expander) -+ list_del(&sas_expander->list); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ if (sas_expander) -+ _scsih_expander_node_remove(ioc, sas_expander); -+} -+ -+/** -+ * _scsih_done - internal SCSI_IO callback handler. -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Callback handler when sending internal generated SCSI_IO. -+ * The callback index passed is `ioc->scsih_cb_idx` -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (ioc->scsih_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->scsih_cmds.smid != smid) -+ return 1; -+ ioc->scsih_cmds.status |= MPT3_CMD_COMPLETE; -+ if (mpi_reply) { -+ memcpy(ioc->scsih_cmds.reply, mpi_reply, -+ mpi_reply->MsgLength*4); -+ ioc->scsih_cmds.status |= MPT3_CMD_REPLY_VALID; -+ } -+ ioc->scsih_cmds.status &= ~MPT3_CMD_PENDING; -+ complete(&ioc->scsih_cmds.done); -+ return 1; -+} -+ -+ -+ -+ -+#define MPT3_MAX_LUNS (255) -+ -+ -+/** -+ * _scsih_check_access_status - check access flags -+ * @ioc: per adapter object -+ * @sas_address: sas address -+ * @handle: sas device handle -+ * @access_flags: errors returned during discovery of the device -+ * -+ * Return 0 for success, else failure -+ */ -+static u8 -+_scsih_check_access_status(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, -+ u16 handle, u8 access_status) -+{ -+ u8 rc = 1; -+ char *desc = NULL; -+ -+ switch (access_status) { -+ case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: -+ case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: -+ rc = 0; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: -+ desc = "sata capability failed"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: -+ desc = "sata affiliation conflict"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: -+ desc = "route not addressable"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: -+ desc = "smp error not addressable"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: -+ desc = "device blocked"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: -+ desc = "sata initialization failed"; -+ break; -+ default: -+ desc = "unknown"; -+ break; -+ } -+ -+ if (!rc) -+ return 0; -+ -+ pr_err(MPT3SAS_FMT -+ "discovery errors(%s): sas_address(0x%016llx), handle(0x%04x)\n", -+ ioc->name, desc, (unsigned long long)sas_address, handle); -+ return rc; -+} -+ -+/** -+ * _scsih_check_device - checking device responsiveness -+ * @ioc: per adapter object -+ * @parent_sas_address: sas address of parent expander or sas host -+ * @handle: attached device handle -+ * @phy_numberv: phy number -+ * @link_rate: new link rate -+ * -+ * Returns nothing. -+ */ -+static void -+_scsih_check_device(struct MPT3SAS_ADAPTER *ioc, -+ u64 parent_sas_address, u16 handle, u8 phy_number, u8 link_rate) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ struct _sas_device *sas_device; -+ u32 ioc_status; -+ unsigned long flags; -+ u64 sas_address; -+ struct scsi_target *starget; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ u32 device_info; -+ -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) -+ return; -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ return; -+ -+ /* wide port handling ~ we need only handle device once for the phy that -+ * is matched in sas device page zero -+ */ -+ if (phy_number != sas_device_pg0.PhyNum) -+ return; -+ -+ /* check if this is end device */ -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ if (!(_scsih_is_end_device(device_info))) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_address); -+ -+ if (!sas_device) -+ goto out_unlock; -+ -+ if (unlikely(sas_device->handle != handle)) { -+ starget = sas_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ starget_printk(KERN_INFO, starget, -+ "handle changed from(0x%04x) to (0x%04x)!!!\n", -+ sas_device->handle, handle); -+ sas_target_priv_data->handle = handle; -+ sas_device->handle = handle; -+ if (sas_device_pg0.Flags & -+ MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { -+ sas_device->enclosure_level = -+ le16_to_cpu(sas_device_pg0.EnclosureLevel); -+ memcpy(&sas_device->connector_name[0], -+ &sas_device_pg0.ConnectorName[0], 4); -+ } else { -+ sas_device->enclosure_level = 0; -+ sas_device->connector_name[0] = '\0'; -+ } -+ } -+ -+ /* check if device is present */ -+ if (!(le16_to_cpu(sas_device_pg0.Flags) & -+ MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { -+ pr_err(MPT3SAS_FMT -+ "device is not present handle(0x%04x), flags!!!\n", -+ ioc->name, handle); -+ goto out_unlock; -+ } -+ -+ /* check if there were any issues with discovery */ -+ if (_scsih_check_access_status(ioc, sas_address, handle, -+ sas_device_pg0.AccessStatus)) -+ goto out_unlock; -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ _scsih_ublock_io_device(ioc, sas_address); -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ return; -+ -+out_unlock: -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (sas_device) -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_add_device - creating sas device object -+ * @ioc: per adapter object -+ * @handle: sas device handle -+ * @phy_num: phy number end device attached to -+ * @is_pd: is this hidden raid component -+ * -+ * Creating end device object, stored in ioc->sas_device_list. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, -+ u8 is_pd) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2SasEnclosurePage0_t enclosure_pg0; -+ struct _sas_device *sas_device; -+ u32 ioc_status; -+ u64 sas_address; -+ u32 device_info; -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ /* check if this is end device */ -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ if (!(_scsih_is_end_device(device_info))) -+ return -1; -+ sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ -+ /* check if device is present */ -+ if (!(le16_to_cpu(sas_device_pg0.Flags) & -+ MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { -+ pr_err(MPT3SAS_FMT "device is not present handle(0x04%x)!!!\n", -+ ioc->name, handle); -+ return -1; -+ } -+ -+ /* check if there were any issues with discovery */ -+ if (_scsih_check_access_status(ioc, sas_address, handle, -+ sas_device_pg0.AccessStatus)) -+ return -1; -+ -+ sas_device = mpt2sas_get_sdev_by_addr(ioc, -+ sas_address); -+ if (sas_device) { -+ sas_device_put(sas_device); -+ return -1; -+ } -+ -+ sas_device = kzalloc(sizeof(struct _sas_device), -+ GFP_KERNEL); -+ if (!sas_device) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 0; -+ } -+ -+ kref_init(&sas_device->refcount); -+ sas_device->handle = handle; -+ if (_scsih_get_sas_address(ioc, -+ le16_to_cpu(sas_device_pg0.ParentDevHandle), -+ &sas_device->sas_address_parent) != 0) -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_device->enclosure_handle = -+ le16_to_cpu(sas_device_pg0.EnclosureHandle); -+ if (sas_device->enclosure_handle != 0) -+ sas_device->slot = -+ le16_to_cpu(sas_device_pg0.Slot); -+ sas_device->device_info = device_info; -+ sas_device->sas_address = sas_address; -+ sas_device->phy = sas_device_pg0.PhyNum; -+ sas_device->fast_path = (le16_to_cpu(sas_device_pg0.Flags) & -+ MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0; -+ -+ if (sas_device_pg0.Flags & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { -+ sas_device->enclosure_level = -+ le16_to_cpu(sas_device_pg0.EnclosureLevel); -+ memcpy(&sas_device->connector_name[0], -+ &sas_device_pg0.ConnectorName[0], 4); -+ } else { -+ sas_device->enclosure_level = 0; -+ sas_device->connector_name[0] = '\0'; -+ } -+ /* get enclosure_logical_id */ -+ if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0( -+ ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, -+ sas_device->enclosure_handle))) -+ sas_device->enclosure_logical_id = -+ le64_to_cpu(enclosure_pg0.EnclosureLogicalID); -+ -+ /* get device name */ -+ sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); -+ -+ if (ioc->wait_for_discovery_to_complete) -+ _scsih_sas_device_init_add(ioc, sas_device); -+ else -+ _scsih_sas_device_add(ioc, sas_device); -+ -+ sas_device_put(sas_device); -+ return 0; -+} -+ -+/** -+ * _scsih_remove_device - removing sas device object -+ * @ioc: per adapter object -+ * @sas_device_delete: the sas_device object -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ -+ if ((ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) && -+ (sas_device->pfa_led_on)) { -+ _scsih_turn_off_pfa_led(ioc, sas_device); -+ sas_device->pfa_led_on = 0; -+ } -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, __func__, -+ sas_device->handle, (unsigned long long) -+ sas_device->sas_address)); -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_device->enclosure_logical_id, -+ sas_device->slot)); -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter: enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, __func__, -+ sas_device->enclosure_level, -+ sas_device->connector_name)); -+ -+ if (sas_device->starget && sas_device->starget->hostdata) { -+ sas_target_priv_data = sas_device->starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ _scsih_ublock_io_device(ioc, sas_device->sas_address); -+ sas_target_priv_data->handle = -+ MPT3SAS_INVALID_DEVICE_HANDLE; -+ } -+ -+ if (!ioc->hide_drives) -+ mpt2sas_transport_port_remove(ioc, -+ sas_device->sas_address, -+ sas_device->sas_address_parent); -+ -+ pr_info(MPT3SAS_FMT -+ "removing handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, sas_device->handle, -+ (unsigned long long) sas_device->sas_address); -+ if (sas_device->enclosure_handle != 0) -+ pr_info(MPT3SAS_FMT -+ "removing : enclosure logical id(0x%016llx), slot(%d)\n", -+ ioc->name, -+ (unsigned long long)sas_device->enclosure_logical_id, -+ sas_device->slot); -+ if (sas_device->connector_name[0] != '\0') -+ pr_info(MPT3SAS_FMT -+ "removing enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, __func__, -+ sas_device->handle, (unsigned long long) -+ sas_device->sas_address)); -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_device->enclosure_logical_id, -+ sas_device->slot)); -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: exit: enclosure level(0x%04x), connector name(%s)\n", -+ ioc->name, __func__, sas_device->enclosure_level, -+ sas_device->connector_name)); -+} -+ -+/** -+ * _scsih_sas_topology_change_event_debug - debug for topology event -+ * @ioc: per adapter object -+ * @event_data: event data payload -+ * Context: user. -+ */ -+static void -+_scsih_sas_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasTopologyChangeList_t *event_data) -+{ -+ int i; -+ u16 handle; -+ u16 reason_code; -+ u8 phy_number; -+ char *status_str = NULL; -+ u8 link_rate, prev_link_rate; -+ -+ switch (event_data->ExpStatus) { -+ case MPI2_EVENT_SAS_TOPO_ES_ADDED: -+ status_str = "add"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING: -+ status_str = "remove"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_ES_RESPONDING: -+ case 0: -+ status_str = "responding"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: -+ status_str = "remove delay"; -+ break; -+ default: -+ status_str = "unknown status"; -+ break; -+ } -+ pr_info(MPT3SAS_FMT "sas topology change: (%s)\n", -+ ioc->name, status_str); -+ pr_info("\thandle(0x%04x), enclosure_handle(0x%04x) " \ -+ "start_phy(%02d), count(%d)\n", -+ le16_to_cpu(event_data->ExpanderDevHandle), -+ le16_to_cpu(event_data->EnclosureHandle), -+ event_data->StartPhyNum, event_data->NumEntries); -+ for (i = 0; i < event_data->NumEntries; i++) { -+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); -+ if (!handle) -+ continue; -+ phy_number = event_data->StartPhyNum + i; -+ reason_code = event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_RC_MASK; -+ switch (reason_code) { -+ case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: -+ status_str = "target add"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: -+ status_str = "target remove"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: -+ status_str = "delay target remove"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: -+ status_str = "link rate change"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: -+ status_str = "target responding"; -+ break; -+ default: -+ status_str = "unknown"; -+ break; -+ } -+ link_rate = event_data->PHY[i].LinkRate >> 4; -+ prev_link_rate = event_data->PHY[i].LinkRate & 0xF; -+ pr_info("\tphy(%02d), attached_handle(0x%04x): %s:" \ -+ " link rate: new(0x%02x), old(0x%02x)\n", phy_number, -+ handle, status_str, link_rate, prev_link_rate); -+ -+ } -+} -+ -+/** -+ * _scsih_sas_topology_change_event - handle topology changes -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ */ -+static int -+_scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ int i; -+ u16 parent_handle, handle; -+ u16 reason_code; -+ u8 phy_number, max_phys; -+ struct _sas_node *sas_expander; -+ u64 sas_address; -+ unsigned long flags; -+ u8 link_rate, prev_link_rate; -+ Mpi2EventDataSasTopologyChangeList_t *event_data = -+ (Mpi2EventDataSasTopologyChangeList_t *) -+ fw_event->event_data; -+ -+ if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) -+ _scsih_sas_topology_change_event_debug(ioc, event_data); -+ -+ if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) -+ return 0; -+ -+ if (!ioc->sas_hba.num_phys) -+ _scsih_sas_host_add(ioc); -+ else -+ _scsih_sas_host_refresh(ioc); -+ -+ if (fw_event->ignore) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "ignoring expander event\n", ioc->name)); -+ return 0; -+ } -+ -+ parent_handle = le16_to_cpu(event_data->ExpanderDevHandle); -+ -+ /* handle expander add */ -+ if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) -+ if (_scsih_expander_add(ioc, parent_handle) != 0) -+ return 0; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, -+ parent_handle); -+ if (sas_expander) { -+ sas_address = sas_expander->sas_address; -+ max_phys = sas_expander->num_phys; -+ } else if (parent_handle < ioc->sas_hba.num_phys) { -+ sas_address = ioc->sas_hba.sas_address; -+ max_phys = ioc->sas_hba.num_phys; -+ } else { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return 0; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ /* handle siblings events */ -+ for (i = 0; i < event_data->NumEntries; i++) { -+ if (fw_event->ignore) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "ignoring expander event\n", ioc->name)); -+ return 0; -+ } -+ if (ioc->remove_host || ioc->pci_error_recovery) -+ return 0; -+ phy_number = event_data->StartPhyNum + i; -+ if (phy_number >= max_phys) -+ continue; -+ reason_code = event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_RC_MASK; -+ if ((event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != -+ MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) -+ continue; -+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); -+ if (!handle) -+ continue; -+ link_rate = event_data->PHY[i].LinkRate >> 4; -+ prev_link_rate = event_data->PHY[i].LinkRate & 0xF; -+ switch (reason_code) { -+ case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: -+ -+ if (ioc->shost_recovery) -+ break; -+ -+ if (link_rate == prev_link_rate) -+ break; -+ -+ mpt2sas_transport_update_links(ioc, sas_address, -+ handle, phy_number, link_rate); -+ -+ if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) -+ break; -+ -+ _scsih_check_device(ioc, sas_address, handle, -+ phy_number, link_rate); -+ -+ -+ case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: -+ -+ if (ioc->shost_recovery) -+ break; -+ -+ mpt2sas_transport_update_links(ioc, sas_address, -+ handle, phy_number, link_rate); -+ -+ _scsih_add_device(ioc, handle, phy_number, 0); -+ -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: -+ -+ _scsih_device_remove_by_handle(ioc, handle); -+ break; -+ } -+ } -+ -+ /* handle expander removal */ -+ if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && -+ sas_expander) -+ mpt2sas_expander_remove(ioc, sas_address); -+ -+ return 0; -+} -+ -+/** -+ * _scsih_sas_device_status_change_event_debug - debug for device event -+ * @event_data: event data payload -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasDeviceStatusChange_t *event_data) -+{ -+ char *reason_str = NULL; -+ -+ switch (event_data->ReasonCode) { -+ case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA: -+ reason_str = "smart data"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: -+ reason_str = "unsupported device discovered"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: -+ reason_str = "internal device reset"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: -+ reason_str = "internal task abort"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: -+ reason_str = "internal task abort set"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: -+ reason_str = "internal clear task set"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: -+ reason_str = "internal query task"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE: -+ reason_str = "sata init failure"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET: -+ reason_str = "internal device reset complete"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL: -+ reason_str = "internal task abort complete"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: -+ reason_str = "internal async notification"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY: -+ reason_str = "expander reduced functionality"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY: -+ reason_str = "expander reduced functionality complete"; -+ break; -+ default: -+ reason_str = "unknown reason"; -+ break; -+ } -+ pr_info(MPT3SAS_FMT "device status change: (%s)\n" -+ "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", -+ ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), -+ (unsigned long long)le64_to_cpu(event_data->SASAddress), -+ le16_to_cpu(event_data->TaskTag)); -+ if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) -+ pr_info(MPT3SAS_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, -+ event_data->ASC, event_data->ASCQ); -+ pr_info("\n"); -+} -+ -+/** -+ * _scsih_sas_device_status_change_event - handle device status change -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ struct MPT3SAS_TARGET *target_priv_data; -+ struct _sas_device *sas_device; -+ u64 sas_address; -+ unsigned long flags; -+ Mpi2EventDataSasDeviceStatusChange_t *event_data = -+ (Mpi2EventDataSasDeviceStatusChange_t *) -+ fw_event->event_data; -+ -+ if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) -+ _scsih_sas_device_status_change_event_debug(ioc, -+ event_data); -+ -+ /* In MPI Revision K (0xC), the internal device reset complete was -+ * implemented, so avoid setting tm_busy flag for older firmware. -+ */ -+ if ((ioc->facts.HeaderVersion >> 8) < 0xC) -+ return; -+ -+ if (event_data->ReasonCode != -+ MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && -+ event_data->ReasonCode != -+ MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_address = le64_to_cpu(event_data->SASAddress); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_address); -+ -+ if (!sas_device || !sas_device->starget) -+ goto out; -+ -+ target_priv_data = sas_device->starget->hostdata; -+ if (!target_priv_data) -+ goto out; -+ -+ if (event_data->ReasonCode == -+ MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) -+ target_priv_data->tm_busy = 1; -+ else -+ target_priv_data->tm_busy = 0; -+ -+out: -+ if (sas_device) -+ sas_device_put(sas_device); -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+} -+ -+/** -+ * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure -+ * event -+ * @ioc: per adapter object -+ * @event_data: event data payload -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasEnclDevStatusChange_t *event_data) -+{ -+ char *reason_str = NULL; -+ -+ switch (event_data->ReasonCode) { -+ case MPI2_EVENT_SAS_ENCL_RC_ADDED: -+ reason_str = "enclosure add"; -+ break; -+ case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING: -+ reason_str = "enclosure remove"; -+ break; -+ default: -+ reason_str = "unknown reason"; -+ break; -+ } -+ -+ pr_info(MPT3SAS_FMT "enclosure status change: (%s)\n" -+ "\thandle(0x%04x), enclosure logical id(0x%016llx)" -+ " number slots(%d)\n", ioc->name, reason_str, -+ le16_to_cpu(event_data->EnclosureHandle), -+ (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID), -+ le16_to_cpu(event_data->StartSlot)); -+} -+ -+/** -+ * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) -+ _scsih_sas_enclosure_dev_status_change_event_debug(ioc, -+ (Mpi2EventDataSasEnclDevStatusChange_t *) -+ fw_event->event_data); -+} -+ -+/** -+ * _scsih_sas_broadcast_primitive_event - handle broadcast events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ struct scsi_cmnd *scmd; -+ struct scsi_device *sdev; -+ u16 smid, handle; -+ u32 lun; -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ u32 termination_count; -+ u32 query_count; -+ Mpi2SCSITaskManagementReply_t *mpi_reply; -+ Mpi2EventDataSasBroadcastPrimitive_t *event_data = -+ (Mpi2EventDataSasBroadcastPrimitive_t *) -+ fw_event->event_data; -+ u16 ioc_status; -+ unsigned long flags; -+ int r; -+ u8 max_retries = 0; -+ u8 task_abort_retries; -+ -+ mutex_lock(&ioc->tm_cmds.mutex); -+ pr_info(MPT3SAS_FMT -+ "%s: enter: phy number(%d), width(%d)\n", -+ ioc->name, __func__, event_data->PhyNum, -+ event_data->PortWidth); -+ -+ _scsih_block_io_all_device(ioc); -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ mpi_reply = ioc->tm_cmds.reply; -+ broadcast_aen_retry: -+ -+ /* sanity checks for retrying this loop */ -+ if (max_retries++ == 5) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: giving up\n", -+ ioc->name, __func__)); -+ goto out; -+ } else if (max_retries > 1) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: %d retry\n", -+ ioc->name, __func__, max_retries - 1)); -+ -+ termination_count = 0; -+ query_count = 0; -+ for (smid = 1; smid <= ioc->scsiio_depth; smid++) { -+ if (ioc->shost_recovery) -+ goto out; -+ scmd = _scsih_scsi_lookup_get(ioc, smid); -+ if (!scmd) -+ continue; -+ sdev = scmd->device; -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) -+ continue; -+ /* skip hidden raid components */ -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) -+ continue; -+ /* skip volumes */ -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_VOLUME) -+ continue; -+ -+ handle = sas_device_priv_data->sas_target->handle; -+ lun = sas_device_priv_data->lun; -+ query_count++; -+ -+ if (ioc->shost_recovery) -+ goto out; -+ -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, -+ MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, -+ TM_MUTEX_OFF); -+ if (r == FAILED) { -+ sdev_printk(KERN_WARNING, sdev, -+ "mpt2sas_scsih_issue_tm: FAILED when sending " -+ "QUERY_TASK: scmd(%p)\n", scmd); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ goto broadcast_aen_retry; -+ } -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) -+ & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ sdev_printk(KERN_WARNING, sdev, -+ "query task: FAILED with IOCSTATUS(0x%04x), scmd(%p)\n", -+ ioc_status, scmd); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ goto broadcast_aen_retry; -+ } -+ -+ /* see if IO is still owned by IOC and target */ -+ if (mpi_reply->ResponseCode == -+ MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || -+ mpi_reply->ResponseCode == -+ MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) { -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ continue; -+ } -+ task_abort_retries = 0; -+ tm_retry: -+ if (task_abort_retries++ == 60) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: ABORT_TASK: giving up\n", ioc->name, -+ __func__)); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ goto broadcast_aen_retry; -+ } -+ -+ if (ioc->shost_recovery) -+ goto out_no_lock; -+ -+ r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, -+ sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, -+ TM_MUTEX_OFF); -+ if (r == FAILED) { -+ sdev_printk(KERN_WARNING, sdev, -+ "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : " -+ "scmd(%p)\n", scmd); -+ goto tm_retry; -+ } -+ -+ if (task_abort_retries > 1) -+ sdev_printk(KERN_WARNING, sdev, -+ "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):" -+ " scmd(%p)\n", -+ task_abort_retries - 1, scmd); -+ -+ termination_count += le32_to_cpu(mpi_reply->TerminationCount); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ } -+ -+ if (ioc->broadcast_aen_pending) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: loop back due to pending AEN\n", -+ ioc->name, __func__)); -+ ioc->broadcast_aen_pending = 0; -+ goto broadcast_aen_retry; -+ } -+ -+ out: -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ out_no_lock: -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - exit, query_count = %d termination_count = %d\n", -+ ioc->name, __func__, query_count, termination_count)); -+ -+ ioc->broadcast_aen_busy = 0; -+ if (!ioc->shost_recovery) -+ _scsih_ublock_io_all_device(ioc); -+ mutex_unlock(&ioc->tm_cmds.mutex); -+} -+ -+/** -+ * _scsih_sas_discovery_event - handle discovery events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ Mpi2EventDataSasDiscovery_t *event_data = -+ (Mpi2EventDataSasDiscovery_t *) fw_event->event_data; -+ -+ if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { -+ pr_info(MPT3SAS_FMT "discovery event: (%s)", ioc->name, -+ (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? -+ "start" : "stop"); -+ if (event_data->DiscoveryStatus) -+ pr_info("discovery_status(0x%08x)", -+ le32_to_cpu(event_data->DiscoveryStatus)); -+ pr_info("\n"); -+ } -+ -+ if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && -+ !ioc->sas_hba.num_phys) { -+ if (disable_discovery > 0 && ioc->shost_recovery) { -+ /* Wait for the reset to complete */ -+ while (ioc->shost_recovery) -+ ssleep(1); -+ } -+ _scsih_sas_host_add(ioc); -+ } -+} -+ -+/** -+ * _scsih_ir_fastpath - turn on fastpath for IR physdisk -+ * @ioc: per adapter object -+ * @handle: device handle for physical disk -+ * @phys_disk_num: physical disk number -+ * -+ * Return 0 for success, else failure. -+ */ -+static int -+_scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) -+{ -+ Mpi2RaidActionRequest_t *mpi_request; -+ Mpi2RaidActionReply_t *mpi_reply; -+ u16 smid; -+ u8 issue_reset = 0; -+ int rc = 0; -+ u16 ioc_status; -+ u32 log_info; -+ -+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION) -+ return rc; -+ -+ mutex_lock(&ioc->scsih_cmds.mutex); -+ -+ if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: scsih_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->scsih_cmds.status = MPT3_CMD_PENDING; -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->scsih_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); -+ -+ mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; -+ mpi_request->Action = MPI2_RAID_ACTION_PHYSDISK_HIDDEN; -+ mpi_request->PhysDiskNum = phys_disk_num; -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT "IR RAID_ACTION: turning fast "\ -+ "path on for handle(0x%04x), phys_disk_num (0x%02x)\n", ioc->name, -+ handle, phys_disk_num)); -+ -+ init_completion(&ioc->scsih_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); -+ -+ if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ if (!(ioc->scsih_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { -+ -+ mpi_reply = ioc->scsih_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -+ if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) -+ log_info = le32_to_cpu(mpi_reply->IOCLogInfo); -+ else -+ log_info = 0; -+ ioc_status &= MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "IR RAID_ACTION: failed: ioc_status(0x%04x), " -+ "loginfo(0x%08x)!!!\n", ioc->name, ioc_status, -+ log_info)); -+ rc = -EFAULT; -+ } else -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "IR RAID_ACTION: completed successfully\n", -+ ioc->name)); -+ } -+ -+ out: -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_unlock(&ioc->scsih_cmds.mutex); -+ -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ return rc; -+} -+ -+/** -+ * _scsih_reprobe_lun - reprobing lun -+ * @sdev: scsi device struct -+ * @no_uld_attach: sdev->no_uld_attach flag setting -+ * -+ **/ -+static void -+_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach) -+{ -+ int rc; -+ sdev->no_uld_attach = no_uld_attach ? 1 : 0; -+ sdev_printk(KERN_INFO, sdev, "%s raid component\n", -+ sdev->no_uld_attach ? "hidding" : "exposing"); -+ rc = scsi_device_reprobe(sdev); -+} -+ -+/** -+ * _scsih_sas_volume_add - add new volume -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_volume_add(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ u64 wwid; -+ u16 handle = le16_to_cpu(element->VolDevHandle); -+ int rc; -+ -+ mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); -+ if (!wwid) { -+ pr_err(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ -+ if (raid_device) -+ return; -+ -+ raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); -+ if (!raid_device) { -+ pr_err(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ raid_device->id = ioc->sas_id++; -+ raid_device->channel = RAID_CHANNEL; -+ raid_device->handle = handle; -+ raid_device->wwid = wwid; -+ _scsih_raid_device_add(ioc, raid_device); -+ if (!ioc->wait_for_discovery_to_complete) { -+ rc = scsi_add_device(ioc->shost, RAID_CHANNEL, -+ raid_device->id, 0); -+ if (rc) -+ _scsih_raid_device_remove(ioc, raid_device); -+ } else { -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ _scsih_determine_boot_device(ioc, raid_device, 1); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ } -+} -+ -+/** -+ * _scsih_sas_volume_delete - delete volume -+ * @ioc: per adapter object -+ * @handle: volume device handle -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct scsi_target *starget = NULL; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ if (raid_device) { -+ if (raid_device->starget) { -+ starget = raid_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ } -+ pr_info(MPT3SAS_FMT "removing handle(0x%04x), wwid(0x%016llx)\n", -+ ioc->name, raid_device->handle, -+ (unsigned long long) raid_device->wwid); -+ list_del(&raid_device->list); -+ kfree(raid_device); -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ if (starget) -+ scsi_remove_target(&starget->dev); -+} -+ -+/** -+ * _scsih_sas_pd_expose - expose pd component to /dev/sdX -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ struct _sas_device *sas_device; -+ struct scsi_target *starget = NULL; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ unsigned long flags; -+ u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ sas_device->volume_handle = 0; -+ sas_device->volume_wwid = 0; -+ clear_bit(handle, ioc->pd_handles); -+ if (sas_device->starget && sas_device->starget->hostdata) { -+ starget = sas_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->flags &= -+ ~MPT_TARGET_FLAGS_RAID_COMPONENT; -+ } -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (!sas_device) -+ return; -+ -+ /* exposing raid component */ -+ if (starget) -+ starget_for_each_device(starget, NULL, _scsih_reprobe_lun); -+ -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_sas_pd_hide - hide pd component from /dev/sdX -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ struct _sas_device *sas_device; -+ struct scsi_target *starget = NULL; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ unsigned long flags; -+ u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -+ u16 volume_handle = 0; -+ u64 volume_wwid = 0; -+ -+ mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle); -+ if (volume_handle) -+ mpt2sas_config_get_volume_wwid(ioc, volume_handle, -+ &volume_wwid); -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ set_bit(handle, ioc->pd_handles); -+ if (sas_device->starget && sas_device->starget->hostdata) { -+ starget = sas_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->flags |= -+ MPT_TARGET_FLAGS_RAID_COMPONENT; -+ sas_device->volume_handle = volume_handle; -+ sas_device->volume_wwid = volume_wwid; -+ } -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (!sas_device) -+ return; -+ -+ /* hiding raid component */ -+ _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); -+ -+ if (starget) -+ starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); -+ -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_sas_pd_delete - delete pd component -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_pd_delete(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -+ -+ _scsih_device_remove_by_handle(ioc, handle); -+} -+ -+/** -+ * _scsih_sas_pd_add - remove pd component -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ struct _sas_device *sas_device; -+ u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ u32 ioc_status; -+ u64 sas_address; -+ u16 parent_handle; -+ -+ set_bit(handle, ioc->pd_handles); -+ -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); -+ sas_device_put(sas_device); -+ return; -+ } -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); -+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) -+ mpt2sas_transport_update_links(ioc, sas_address, handle, -+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); -+ -+ _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); -+ _scsih_add_device(ioc, handle, 0, 1); -+} -+ -+/** -+ * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events -+ * @ioc: per adapter object -+ * @event_data: event data payload -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_config_change_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataIrConfigChangeList_t *event_data) -+{ -+ Mpi2EventIrConfigElement_t *element; -+ u8 element_type; -+ int i; -+ char *reason_str = NULL, *element_str = NULL; -+ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ -+ pr_info(MPT3SAS_FMT "raid config change: (%s), elements(%d)\n", -+ ioc->name, (le32_to_cpu(event_data->Flags) & -+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? -+ "foreign" : "native", event_data->NumElements); -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ switch (element->ReasonCode) { -+ case MPI2_EVENT_IR_CHANGE_RC_ADDED: -+ reason_str = "add"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_REMOVED: -+ reason_str = "remove"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE: -+ reason_str = "no change"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_HIDE: -+ reason_str = "hide"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: -+ reason_str = "unhide"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: -+ reason_str = "volume_created"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: -+ reason_str = "volume_deleted"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: -+ reason_str = "pd_created"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: -+ reason_str = "pd_deleted"; -+ break; -+ default: -+ reason_str = "unknown reason"; -+ break; -+ } -+ element_type = le16_to_cpu(element->ElementFlags) & -+ MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK; -+ switch (element_type) { -+ case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT: -+ element_str = "volume"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT: -+ element_str = "phys disk"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT: -+ element_str = "hot spare"; -+ break; -+ default: -+ element_str = "unknown element"; -+ break; -+ } -+ pr_info("\t(%s:%s), vol handle(0x%04x), " \ -+ "pd handle(0x%04x), pd num(0x%02x)\n", element_str, -+ reason_str, le16_to_cpu(element->VolDevHandle), -+ le16_to_cpu(element->PhysDiskDevHandle), -+ element->PhysDiskNum); -+ } -+} -+ -+/** -+ * _scsih_sas_ir_config_change_event - handle ir configuration change events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ Mpi2EventIrConfigElement_t *element; -+ int i; -+ u8 foreign_config; -+ Mpi2EventDataIrConfigChangeList_t *event_data = -+ (Mpi2EventDataIrConfigChangeList_t *) -+ fw_event->event_data; -+ -+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) && -+ (!ioc->hide_ir_msg)) -+ _scsih_sas_ir_config_change_event_debug(ioc, event_data); -+ -+ foreign_config = (le32_to_cpu(event_data->Flags) & -+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; -+ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ if (ioc->shost_recovery && -+ ioc->hba_mpi_version_belonged != MPI2_VERSION) { -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_HIDE) -+ _scsih_ir_fastpath(ioc, -+ le16_to_cpu(element->PhysDiskDevHandle), -+ element->PhysDiskNum); -+ } -+ return; -+ } -+ -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ -+ switch (element->ReasonCode) { -+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: -+ case MPI2_EVENT_IR_CHANGE_RC_ADDED: -+ if (!foreign_config) -+ _scsih_sas_volume_add(ioc, element); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: -+ case MPI2_EVENT_IR_CHANGE_RC_REMOVED: -+ if (!foreign_config) -+ _scsih_sas_volume_delete(ioc, -+ le16_to_cpu(element->VolDevHandle)); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: -+ if (!ioc->is_warpdrive) -+ _scsih_sas_pd_hide(ioc, element); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: -+ if (!ioc->is_warpdrive) -+ _scsih_sas_pd_expose(ioc, element); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_HIDE: -+ if (!ioc->is_warpdrive) -+ _scsih_sas_pd_add(ioc, element); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: -+ if (!ioc->is_warpdrive) -+ _scsih_sas_pd_delete(ioc, element); -+ break; -+ } -+ } -+} -+ -+/** -+ * _scsih_sas_ir_volume_event - IR volume event -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ u64 wwid; -+ unsigned long flags; -+ struct _raid_device *raid_device; -+ u16 handle; -+ u32 state; -+ int rc; -+ Mpi2EventDataIrVolume_t *event_data = -+ (Mpi2EventDataIrVolume_t *) fw_event->event_data; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) -+ return; -+ -+ handle = le16_to_cpu(event_data->VolDevHandle); -+ state = le32_to_cpu(event_data->NewValue); -+ if (!ioc->hide_ir_msg) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", -+ ioc->name, __func__, handle, -+ le32_to_cpu(event_data->PreviousValue), state)); -+ switch (state) { -+ case MPI2_RAID_VOL_STATE_MISSING: -+ case MPI2_RAID_VOL_STATE_FAILED: -+ _scsih_sas_volume_delete(ioc, handle); -+ break; -+ -+ case MPI2_RAID_VOL_STATE_ONLINE: -+ case MPI2_RAID_VOL_STATE_DEGRADED: -+ case MPI2_RAID_VOL_STATE_OPTIMAL: -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ -+ if (raid_device) -+ break; -+ -+ mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); -+ if (!wwid) { -+ pr_err(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ break; -+ } -+ -+ raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); -+ if (!raid_device) { -+ pr_err(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ break; -+ } -+ -+ raid_device->id = ioc->sas_id++; -+ raid_device->channel = RAID_CHANNEL; -+ raid_device->handle = handle; -+ raid_device->wwid = wwid; -+ _scsih_raid_device_add(ioc, raid_device); -+ rc = scsi_add_device(ioc->shost, RAID_CHANNEL, -+ raid_device->id, 0); -+ if (rc) -+ _scsih_raid_device_remove(ioc, raid_device); -+ break; -+ -+ case MPI2_RAID_VOL_STATE_INITIALIZING: -+ default: -+ break; -+ } -+} -+ -+/** -+ * _scsih_sas_ir_physical_disk_event - PD event -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ u16 handle, parent_handle; -+ u32 state; -+ struct _sas_device *sas_device; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ u32 ioc_status; -+ Mpi2EventDataIrPhysicalDisk_t *event_data = -+ (Mpi2EventDataIrPhysicalDisk_t *) fw_event->event_data; -+ u64 sas_address; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED) -+ return; -+ -+ handle = le16_to_cpu(event_data->PhysDiskDevHandle); -+ state = le32_to_cpu(event_data->NewValue); -+ -+ if (!ioc->hide_ir_msg) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", -+ ioc->name, __func__, handle, -+ le32_to_cpu(event_data->PreviousValue), state)); -+ -+ switch (state) { -+ case MPI2_RAID_PD_STATE_ONLINE: -+ case MPI2_RAID_PD_STATE_DEGRADED: -+ case MPI2_RAID_PD_STATE_REBUILDING: -+ case MPI2_RAID_PD_STATE_OPTIMAL: -+ case MPI2_RAID_PD_STATE_HOT_SPARE: -+ -+ if (!ioc->is_warpdrive) -+ set_bit(handle, ioc->pd_handles); -+ -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ sas_device_put(sas_device); -+ return; -+ } -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, -+ handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); -+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) -+ mpt2sas_transport_update_links(ioc, sas_address, handle, -+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); -+ -+ _scsih_add_device(ioc, handle, 0, 1); -+ -+ break; -+ -+ case MPI2_RAID_PD_STATE_OFFLINE: -+ case MPI2_RAID_PD_STATE_NOT_CONFIGURED: -+ case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: -+ default: -+ break; -+ } -+} -+ -+/** -+ * _scsih_sas_ir_operation_status_event_debug - debug for IR op event -+ * @ioc: per adapter object -+ * @event_data: event data payload -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_operation_status_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataIrOperationStatus_t *event_data) -+{ -+ char *reason_str = NULL; -+ -+ switch (event_data->RAIDOperation) { -+ case MPI2_EVENT_IR_RAIDOP_RESYNC: -+ reason_str = "resync"; -+ break; -+ case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION: -+ reason_str = "online capacity expansion"; -+ break; -+ case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK: -+ reason_str = "consistency check"; -+ break; -+ case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT: -+ reason_str = "background init"; -+ break; -+ case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT: -+ reason_str = "make data consistent"; -+ break; -+ } -+ -+ if (!reason_str) -+ return; -+ -+ pr_info(MPT3SAS_FMT "raid operational status: (%s)" \ -+ "\thandle(0x%04x), percent complete(%d)\n", -+ ioc->name, reason_str, -+ le16_to_cpu(event_data->VolDevHandle), -+ event_data->PercentComplete); -+} -+ -+/** -+ * _scsih_sas_ir_operation_status_event - handle RAID operation events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_operation_status_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ Mpi2EventDataIrOperationStatus_t *event_data = -+ (Mpi2EventDataIrOperationStatus_t *) -+ fw_event->event_data; -+ static struct _raid_device *raid_device; -+ unsigned long flags; -+ u16 handle; -+ -+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) && -+ (!ioc->hide_ir_msg)) -+ _scsih_sas_ir_operation_status_event_debug(ioc, -+ event_data); -+ -+ /* code added for raid transport support */ -+ if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ handle = le16_to_cpu(event_data->VolDevHandle); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ if (raid_device) -+ raid_device->percent_complete = -+ event_data->PercentComplete; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ } -+} -+ -+/** -+ * _scsih_prep_device_scan - initialize parameters prior to device scan -+ * @ioc: per adapter object -+ * -+ * Set the deleted flag prior to device scan. If the device is found during -+ * the scan, then we clear the deleted flag. -+ */ -+static void -+_scsih_prep_device_scan(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (sas_device_priv_data && sas_device_priv_data->sas_target) -+ sas_device_priv_data->sas_target->deleted = 1; -+ } -+} -+ -+/** -+ * _scsih_mark_responding_sas_device - mark a sas_devices as responding -+ * @ioc: per adapter object -+ * @sas_device_pg0: SAS Device page 0 -+ * -+ * After host reset, find out whether devices are still responding. -+ * Used in _scsih_remove_unresponsive_sas_devices. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, -+Mpi2SasDevicePage0_t *sas_device_pg0) -+{ -+ struct MPT3SAS_TARGET *sas_target_priv_data = NULL; -+ struct scsi_target *starget; -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -+ if ((sas_device->sas_address == sas_device_pg0->SASAddress) && -+ (sas_device->slot == sas_device_pg0->Slot)) { -+ sas_device->responding = 1; -+ starget = sas_device->starget; -+ if (starget && starget->hostdata) { -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->tm_busy = 0; -+ sas_target_priv_data->deleted = 0; -+ } else -+ sas_target_priv_data = NULL; -+ if (starget) { -+ starget_printk(KERN_INFO, starget, -+ "handle(0x%04x), sas_addr(0x%016llx)\n", -+ sas_device_pg0->DevHandle, -+ (unsigned long long) -+ sas_device->sas_address); -+ -+ if (sas_device->enclosure_handle != 0) -+ starget_printk(KERN_INFO, starget, -+ "enclosure logical id(0x%016llx)," -+ " slot(%d)\n", -+ (unsigned long long) -+ sas_device->enclosure_logical_id, -+ sas_device->slot); -+ } -+ if (sas_device_pg0->Flags & -+ MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { -+ sas_device->enclosure_level = -+ le16_to_cpu(sas_device_pg0->EnclosureLevel); -+ memcpy(&sas_device->connector_name[0], -+ &sas_device_pg0->ConnectorName[0], 4); -+ } else { -+ sas_device->enclosure_level = 0; -+ sas_device->connector_name[0] = '\0'; -+ } -+ -+ if (sas_device->handle == sas_device_pg0->DevHandle) -+ goto out; -+ pr_info("\thandle changed from(0x%04x)!!!\n", -+ sas_device->handle); -+ sas_device->handle = sas_device_pg0->DevHandle; -+ if (sas_target_priv_data) -+ sas_target_priv_data->handle = -+ sas_device_pg0->DevHandle; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+} -+ -+/** -+ * _scsih_search_responding_sas_devices - -+ * @ioc: per adapter object -+ * -+ * After host reset, find out whether devices are still responding. -+ * If not remove. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u16 handle; -+ u32 device_info; -+ -+ pr_info(MPT3SAS_FMT "search for end-devices: start\n", ioc->name); -+ -+ if (list_empty(&ioc->sas_device_list)) -+ goto out; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, -+ handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ break; -+ handle = sas_device_pg0.DevHandle = -+ le16_to_cpu(sas_device_pg0.DevHandle); -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ if (!(_scsih_is_end_device(device_info))) -+ continue; -+ sas_device_pg0.SASAddress = -+ le64_to_cpu(sas_device_pg0.SASAddress); -+ sas_device_pg0.Slot = le16_to_cpu(sas_device_pg0.Slot); -+ _scsih_mark_responding_sas_device(ioc, &sas_device_pg0); -+ } -+ -+ out: -+ pr_info(MPT3SAS_FMT "search for end-devices: complete\n", -+ ioc->name); -+} -+ -+/** -+ * _scsih_mark_responding_raid_device - mark a raid_device as responding -+ * @ioc: per adapter object -+ * @wwid: world wide identifier for raid volume -+ * @handle: device handle -+ * -+ * After host reset, find out whether devices are still responding. -+ * Used in _scsih_remove_unresponsive_raid_devices. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid, -+ u16 handle) -+{ -+ struct MPT3SAS_TARGET *sas_target_priv_data = NULL; -+ struct scsi_target *starget; -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (raid_device->wwid == wwid && raid_device->starget) { -+ starget = raid_device->starget; -+ if (starget && starget->hostdata) { -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->deleted = 0; -+ } else -+ sas_target_priv_data = NULL; -+ raid_device->responding = 1; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ starget_printk(KERN_INFO, raid_device->starget, -+ "handle(0x%04x), wwid(0x%016llx)\n", handle, -+ (unsigned long long)raid_device->wwid); -+ -+ /* -+ * WARPDRIVE: The handles of the PDs might have changed -+ * across the host reset so re-initialize the -+ * required data for Direct IO -+ */ -+ mpt2sas_init_warpdrive_properties(ioc, raid_device); -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ if (raid_device->handle == handle) { -+ spin_unlock_irqrestore(&ioc->raid_device_lock, -+ flags); -+ return; -+ } -+ pr_info("\thandle changed from(0x%04x)!!!\n", -+ raid_device->handle); -+ raid_device->handle = handle; -+ if (sas_target_priv_data) -+ sas_target_priv_data->handle = handle; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ return; -+ } -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+} -+ -+/** -+ * _scsih_search_responding_raid_devices - -+ * @ioc: per adapter object -+ * -+ * After host reset, find out whether devices are still responding. -+ * If not remove. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2RaidVolPage1_t volume_pg1; -+ Mpi2RaidVolPage0_t volume_pg0; -+ Mpi2RaidPhysDiskPage0_t pd_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u16 handle; -+ u8 phys_disk_num; -+ -+ if (!ioc->ir_firmware) -+ return; -+ -+ pr_info(MPT3SAS_FMT "search for raid volumes: start\n", -+ ioc->name); -+ -+ if (list_empty(&ioc->raid_device_list)) -+ goto out; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ break; -+ handle = le16_to_cpu(volume_pg1.DevHandle); -+ -+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, -+ &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, -+ sizeof(Mpi2RaidVolPage0_t))) -+ continue; -+ -+ if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || -+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || -+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) -+ _scsih_mark_responding_raid_device(ioc, -+ le64_to_cpu(volume_pg1.WWID), handle); -+ } -+ -+ /* refresh the pd_handles */ -+ if (!ioc->is_warpdrive) { -+ phys_disk_num = 0xFF; -+ memset(ioc->pd_handles, 0, ioc->pd_handles_sz); -+ while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, -+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, -+ phys_disk_num))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ break; -+ phys_disk_num = pd_pg0.PhysDiskNum; -+ handle = le16_to_cpu(pd_pg0.DevHandle); -+ set_bit(handle, ioc->pd_handles); -+ } -+ } -+ out: -+ pr_info(MPT3SAS_FMT "search for responding raid volumes: complete\n", -+ ioc->name); -+} -+ -+/** -+ * _scsih_mark_responding_expander - mark a expander as responding -+ * @ioc: per adapter object -+ * @sas_address: sas address -+ * @handle: -+ * -+ * After host reset, find out whether devices are still responding. -+ * Used in _scsih_remove_unresponsive_expanders. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_mark_responding_expander(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, -+ u16 handle) -+{ -+ struct _sas_node *sas_expander; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { -+ if (sas_expander->sas_address != sas_address) -+ continue; -+ sas_expander->responding = 1; -+ if (sas_expander->handle == handle) -+ goto out; -+ pr_info("\texpander(0x%016llx): handle changed" \ -+ " from(0x%04x) to (0x%04x)!!!\n", -+ (unsigned long long)sas_expander->sas_address, -+ sas_expander->handle, handle); -+ sas_expander->handle = handle; -+ for (i = 0 ; i < sas_expander->num_phys ; i++) -+ sas_expander->phy[i].handle = handle; -+ goto out; -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+} -+ -+/** -+ * _scsih_search_responding_expanders - -+ * @ioc: per adapter object -+ * -+ * After host reset, find out whether devices are still responding. -+ * If not remove. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2ExpanderPage0_t expander_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u64 sas_address; -+ u16 handle; -+ -+ pr_info(MPT3SAS_FMT "search for expanders: start\n", ioc->name); -+ -+ if (list_empty(&ioc->sas_expander_list)) -+ goto out; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, -+ MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ break; -+ -+ handle = le16_to_cpu(expander_pg0.DevHandle); -+ sas_address = le64_to_cpu(expander_pg0.SASAddress); -+ pr_info("\texpander present: handle(0x%04x), sas_addr(0x%016llx)\n", -+ handle, -+ (unsigned long long)sas_address); -+ _scsih_mark_responding_expander(ioc, sas_address, handle); -+ } -+ -+ out: -+ pr_info(MPT3SAS_FMT "search for expanders: complete\n", ioc->name); -+} -+ -+/** -+ * _scsih_remove_unresponding_sas_devices - removing unresponding devices -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct _sas_device *sas_device, *sas_device_next; -+ struct _sas_node *sas_expander, *sas_expander_next; -+ struct _raid_device *raid_device, *raid_device_next; -+ struct list_head tmp_list; -+ unsigned long flags; -+ LIST_HEAD(head); -+ -+ pr_info(MPT3SAS_FMT "removing unresponding devices: start\n", -+ ioc->name); -+ -+ /* removing unresponding end devices */ -+ pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n", -+ ioc->name); -+ /* -+ * Iterate, pulling off devices marked as non-responding. We become the -+ * owner for the reference the list had on any object we prune. -+ */ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ list_for_each_entry_safe(sas_device, sas_device_next, -+ &ioc->sas_device_list, list) { -+ if (!sas_device->responding) -+ list_move_tail(&sas_device->list, &head); -+ else -+ sas_device->responding = 0; -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ /* -+ * Now, uninitialize and remove the unresponding devices we pruned. -+ */ -+ list_for_each_entry_safe(sas_device, sas_device_next, &head, list) { -+ _scsih_remove_device(ioc, sas_device); -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ -+ /* removing unresponding volumes */ -+ if (ioc->ir_firmware) { -+ pr_info(MPT3SAS_FMT "removing unresponding devices: volumes\n", -+ ioc->name); -+ list_for_each_entry_safe(raid_device, raid_device_next, -+ &ioc->raid_device_list, list) { -+ if (!raid_device->responding) -+ _scsih_sas_volume_delete(ioc, -+ raid_device->handle); -+ else -+ raid_device->responding = 0; -+ } -+ } -+ -+ /* removing unresponding expanders */ -+ pr_info(MPT3SAS_FMT "removing unresponding devices: expanders\n", -+ ioc->name); -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ INIT_LIST_HEAD(&tmp_list); -+ list_for_each_entry_safe(sas_expander, sas_expander_next, -+ &ioc->sas_expander_list, list) { -+ if (!sas_expander->responding) -+ list_move_tail(&sas_expander->list, &tmp_list); -+ else -+ sas_expander->responding = 0; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list, -+ list) { -+ list_del(&sas_expander->list); -+ _scsih_expander_node_remove(ioc, sas_expander); -+ } -+ -+ pr_info(MPT3SAS_FMT "removing unresponding devices: complete\n", -+ ioc->name); -+ -+ /* unblock devices */ -+ _scsih_ublock_io_all_device(ioc); -+} -+ -+static void -+_scsih_refresh_expander_links(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander, u16 handle) -+{ -+ Mpi2ExpanderPage1_t expander_pg1; -+ Mpi2ConfigReply_t mpi_reply; -+ int i; -+ -+ for (i = 0 ; i < sas_expander->num_phys ; i++) { -+ if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, -+ &expander_pg1, i, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ mpt2sas_transport_update_links(ioc, sas_expander->sas_address, -+ le16_to_cpu(expander_pg1.AttachedDevHandle), i, -+ expander_pg1.NegotiatedLinkRate >> 4); -+ } -+} -+ -+/** -+ * _scsih_scan_for_devices_after_reset - scan for devices after host reset -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2ExpanderPage0_t expander_pg0; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2RaidVolPage1_t volume_pg1; -+ Mpi2RaidVolPage0_t volume_pg0; -+ Mpi2RaidPhysDiskPage0_t pd_pg0; -+ Mpi2EventIrConfigElement_t element; -+ Mpi2ConfigReply_t mpi_reply; -+ u8 phys_disk_num; -+ u16 ioc_status; -+ u16 handle, parent_handle; -+ u64 sas_address; -+ struct _sas_device *sas_device; -+ struct _sas_node *expander_device; -+ static struct _raid_device *raid_device; -+ u8 retry_count; -+ unsigned long flags; -+ -+ pr_info(MPT3SAS_FMT "scan devices: start\n", ioc->name); -+ -+ _scsih_sas_host_refresh(ioc); -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: expanders start\n", ioc->name); -+ -+ /* expanders */ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, -+ MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from expander scan: " \ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ handle = le16_to_cpu(expander_pg0.DevHandle); -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ expander_device = mpt2sas_scsih_expander_find_by_sas_address( -+ ioc, le64_to_cpu(expander_pg0.SASAddress)); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ if (expander_device) -+ _scsih_refresh_expander_links(ioc, expander_device, -+ handle); -+ else { -+ pr_info(MPT3SAS_FMT "\tBEFORE adding expander: " \ -+ "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ handle, (unsigned long long) -+ le64_to_cpu(expander_pg0.SASAddress)); -+ _scsih_expander_add(ioc, handle); -+ pr_info(MPT3SAS_FMT "\tAFTER adding expander: " \ -+ "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ handle, (unsigned long long) -+ le64_to_cpu(expander_pg0.SASAddress)); -+ } -+ } -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: expanders complete\n", -+ ioc->name); -+ -+ if (!ioc->ir_firmware) -+ goto skip_to_sas; -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: phys disk start\n", ioc->name); -+ -+ /* phys disk */ -+ phys_disk_num = 0xFF; -+ while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, -+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, -+ phys_disk_num))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from phys disk scan: "\ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ phys_disk_num = pd_pg0.PhysDiskNum; -+ handle = le16_to_cpu(pd_pg0.DevHandle); -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ sas_device_put(sas_device); -+ continue; -+ } -+ if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, -+ handle) != 0) -+ continue; -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from phys disk scan " \ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); -+ if (!_scsih_get_sas_address(ioc, parent_handle, -+ &sas_address)) { -+ pr_info(MPT3SAS_FMT "\tBEFORE adding phys disk: " \ -+ " handle (0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, handle, (unsigned long long) -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ mpt2sas_transport_update_links(ioc, sas_address, -+ handle, sas_device_pg0.PhyNum, -+ MPI2_SAS_NEG_LINK_RATE_1_5); -+ set_bit(handle, ioc->pd_handles); -+ retry_count = 0; -+ /* This will retry adding the end device. -+ * _scsih_add_device() will decide on retries and -+ * return "1" when it should be retried -+ */ -+ while (_scsih_add_device(ioc, handle, retry_count++, -+ 1)) { -+ ssleep(1); -+ } -+ pr_info(MPT3SAS_FMT "\tAFTER adding phys disk: " \ -+ " handle (0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, handle, (unsigned long long) -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ } -+ } -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: phys disk complete\n", -+ ioc->name); -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: volumes start\n", ioc->name); -+ -+ /* volumes */ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ handle = le16_to_cpu(volume_pg1.DevHandle); -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_wwid(ioc, -+ le64_to_cpu(volume_pg1.WWID)); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ if (raid_device) -+ continue; -+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, -+ &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, -+ sizeof(Mpi2RaidVolPage0_t))) -+ continue; -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || -+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || -+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { -+ memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); -+ element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; -+ element.VolDevHandle = volume_pg1.DevHandle; -+ pr_info(MPT3SAS_FMT -+ "\tBEFORE adding volume: handle (0x%04x)\n", -+ ioc->name, volume_pg1.DevHandle); -+ _scsih_sas_volume_add(ioc, &element); -+ pr_info(MPT3SAS_FMT -+ "\tAFTER adding volume: handle (0x%04x)\n", -+ ioc->name, volume_pg1.DevHandle); -+ } -+ } -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: volumes complete\n", -+ ioc->name); -+ -+ skip_to_sas: -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: end devices start\n", -+ ioc->name); -+ -+ /* sas devices */ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, -+ handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from end device scan:"\ -+ " ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ handle = le16_to_cpu(sas_device_pg0.DevHandle); -+ if (!(_scsih_is_end_device( -+ le32_to_cpu(sas_device_pg0.DeviceInfo)))) -+ continue; -+ sas_device = mpt2sas_get_sdev_by_addr(ioc, -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ if (sas_device) { -+ sas_device_put(sas_device); -+ continue; -+ } -+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); -+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { -+ pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \ -+ "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ handle, (unsigned long long) -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ mpt2sas_transport_update_links(ioc, sas_address, handle, -+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); -+ retry_count = 0; -+ /* This will retry adding the end device. -+ * _scsih_add_device() will decide on retries and -+ * return "1" when it should be retried -+ */ -+ while (_scsih_add_device(ioc, handle, retry_count++, -+ 0)) { -+ ssleep(1); -+ } -+ pr_info(MPT3SAS_FMT "\tAFTER adding end device: " \ -+ "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ handle, (unsigned long long) -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ } -+ } -+ pr_info(MPT3SAS_FMT "\tscan devices: end devices complete\n", -+ ioc->name); -+ -+ pr_info(MPT3SAS_FMT "scan devices: complete\n", ioc->name); -+} -+/** -+ * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) -+ * @ioc: per adapter object -+ * @reset_phase: phase -+ * -+ * The handler for doing any required cleanup or initialization. -+ * -+ * The reset phase can be MPT3_IOC_PRE_RESET, MPT3_IOC_AFTER_RESET, -+ * MPT3_IOC_DONE_RESET -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) -+{ -+ switch (reset_phase) { -+ case MPT3_IOC_PRE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); -+ break; -+ case MPT3_IOC_AFTER_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); -+ if (ioc->scsih_cmds.status & MPT3_CMD_PENDING) { -+ ioc->scsih_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); -+ complete(&ioc->scsih_cmds.done); -+ } -+ if (ioc->tm_cmds.status & MPT3_CMD_PENDING) { -+ ioc->tm_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); -+ complete(&ioc->tm_cmds.done); -+ } -+ -+ _scsih_fw_event_cleanup_queue(ioc); -+ _scsih_flush_running_cmds(ioc); -+ break; -+ case MPT3_IOC_DONE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); -+ if ((!ioc->is_driver_loading) && !(disable_discovery > 0 && -+ !ioc->sas_hba.num_phys)) { -+ _scsih_prep_device_scan(ioc); -+ _scsih_search_responding_sas_devices(ioc); -+ _scsih_search_responding_raid_devices(ioc); -+ _scsih_search_responding_expanders(ioc); -+ _scsih_error_recovery_delete_devices(ioc); -+ } -+ break; -+ } -+} -+ -+/** -+ * _mpt2sas_fw_work - delayed task for processing firmware events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_mpt2sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) -+{ -+ _scsih_fw_event_del_from_list(ioc, fw_event); -+ -+ /* the queue is being flushed so ignore this event */ -+ if (ioc->remove_host || ioc->pci_error_recovery) { -+ fw_event_work_put(fw_event); -+ return; -+ } -+ -+ switch (fw_event->event) { -+ case MPT3SAS_PROCESS_TRIGGER_DIAG: -+ mpt2sas_process_trigger_data(ioc, -+ (struct SL_WH_TRIGGERS_EVENT_DATA_T *) -+ fw_event->event_data); -+ break; -+ case MPT3SAS_REMOVE_UNRESPONDING_DEVICES: -+ while (scsi_host_in_recovery(ioc->shost) || -+ ioc->shost_recovery) { -+ /* -+ * If we're unloading, bail. Otherwise, this can become -+ * an infinite loop. -+ */ -+ if (ioc->remove_host) -+ goto out; -+ ssleep(1); -+ } -+ _scsih_remove_unresponding_sas_devices(ioc); -+ _scsih_scan_for_devices_after_reset(ioc); -+ break; -+ case MPT3SAS_PORT_ENABLE_COMPLETE: -+ ioc->start_scan = 0; -+ if (missing_delay[0] != -1 && missing_delay[1] != -1) -+ mpt2sas_base_update_missing_delay(ioc, missing_delay[0], -+ missing_delay[1]); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "port enable: complete from worker thread\n", -+ ioc->name)); -+ break; -+ case MPT3SAS_TURN_ON_PFA_LED: -+ _scsih_turn_on_pfa_led(ioc, fw_event->device_handle); -+ break; -+ case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: -+ _scsih_sas_topology_change_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: -+ _scsih_sas_device_status_change_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_SAS_DISCOVERY: -+ _scsih_sas_discovery_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: -+ _scsih_sas_broadcast_primitive_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: -+ _scsih_sas_enclosure_dev_status_change_event(ioc, -+ fw_event); -+ break; -+ case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: -+ _scsih_sas_ir_config_change_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_IR_VOLUME: -+ _scsih_sas_ir_volume_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_IR_PHYSICAL_DISK: -+ _scsih_sas_ir_physical_disk_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_IR_OPERATION_STATUS: -+ _scsih_sas_ir_operation_status_event(ioc, fw_event); -+ break; -+ } -+out: -+ fw_event_work_put(fw_event); -+} -+ -+/** -+ * _firmware_event_work -+ * @ioc: per adapter object -+ * @work: The fw_event_work object -+ * Context: user. -+ * -+ * wrappers for the work thread handling firmware events -+ * -+ * Return nothing. -+ */ -+ -+static void -+_firmware_event_work(struct work_struct *work) -+{ -+ struct fw_event_work *fw_event = container_of(work, -+ struct fw_event_work, work); -+ -+ _mpt2sas_fw_work(fw_event->ioc, fw_event); -+} -+ -+/** -+ * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time) -+ * @ioc: per adapter object -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt. -+ * -+ * This function merely adds a new work task into ioc->firmware_event_thread. -+ * The tasks are worked from _firmware_event_work in user context. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, -+ u32 reply) -+{ -+ struct fw_event_work *fw_event; -+ Mpi2EventNotificationReply_t *mpi_reply; -+ u16 event; -+ u16 sz; -+ Mpi26EventDataActiveCableExcept_t *ActiveCableEventData; -+ -+ /* events turned off due to host reset or driver unloading */ -+ if (ioc->remove_host || ioc->pci_error_recovery) -+ return 1; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ -+ if (unlikely(!mpi_reply)) { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 1; -+ } -+ -+ event = le16_to_cpu(mpi_reply->Event); -+ -+ if (event != MPI2_EVENT_LOG_ENTRY_ADDED) -+ mpt2sas_trigger_event(ioc, event, 0); -+ -+ switch (event) { -+ /* handle these */ -+ case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: -+ { -+ Mpi2EventDataSasBroadcastPrimitive_t *baen_data = -+ (Mpi2EventDataSasBroadcastPrimitive_t *) -+ mpi_reply->EventData; -+ -+ if (baen_data->Primitive != -+ MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) -+ return 1; -+ -+ if (ioc->broadcast_aen_busy) { -+ ioc->broadcast_aen_pending++; -+ return 1; -+ } else -+ ioc->broadcast_aen_busy = 1; -+ break; -+ } -+ -+ case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: -+ _scsih_check_topo_delete_events(ioc, -+ (Mpi2EventDataSasTopologyChangeList_t *) -+ mpi_reply->EventData); -+ break; -+ case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: -+ _scsih_check_ir_config_unhide_events(ioc, -+ (Mpi2EventDataIrConfigChangeList_t *) -+ mpi_reply->EventData); -+ break; -+ case MPI2_EVENT_IR_VOLUME: -+ _scsih_check_volume_delete_events(ioc, -+ (Mpi2EventDataIrVolume_t *) -+ mpi_reply->EventData); -+ break; -+ case MPI2_EVENT_LOG_ENTRY_ADDED: -+ { -+ Mpi2EventDataLogEntryAdded_t *log_entry; -+ u32 *log_code; -+ -+ if (!ioc->is_warpdrive) -+ break; -+ -+ log_entry = (Mpi2EventDataLogEntryAdded_t *) -+ mpi_reply->EventData; -+ log_code = (u32 *)log_entry->LogData; -+ -+ if (le16_to_cpu(log_entry->LogEntryQualifier) -+ != MPT2_WARPDRIVE_LOGENTRY) -+ break; -+ -+ switch (le32_to_cpu(*log_code)) { -+ case MPT2_WARPDRIVE_LC_SSDT: -+ pr_warn(MPT3SAS_FMT "WarpDrive Warning: " -+ "IO Throttling has occurred in the WarpDrive " -+ "subsystem. Check WarpDrive documentation for " -+ "additional details.\n", ioc->name); -+ break; -+ case MPT2_WARPDRIVE_LC_SSDLW: -+ pr_warn(MPT3SAS_FMT "WarpDrive Warning: " -+ "Program/Erase Cycles for the WarpDrive subsystem " -+ "in degraded range. Check WarpDrive documentation " -+ "for additional details.\n", ioc->name); -+ break; -+ case MPT2_WARPDRIVE_LC_SSDLF: -+ pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " -+ "There are no Program/Erase Cycles for the " -+ "WarpDrive subsystem. The storage device will be " -+ "in read-only mode. Check WarpDrive documentation " -+ "for additional details.\n", ioc->name); -+ break; -+ case MPT2_WARPDRIVE_LC_BRMF: -+ pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " -+ "The Backup Rail Monitor has failed on the " -+ "WarpDrive subsystem. Check WarpDrive " -+ "documentation for additional details.\n", -+ ioc->name); -+ break; -+ } -+ -+ break; -+ } -+ case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: -+ case MPI2_EVENT_IR_OPERATION_STATUS: -+ case MPI2_EVENT_SAS_DISCOVERY: -+ case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: -+ case MPI2_EVENT_IR_PHYSICAL_DISK: -+ break; -+ -+ case MPI2_EVENT_TEMP_THRESHOLD: -+ _scsih_temp_threshold_events(ioc, -+ (Mpi2EventDataTemperature_t *) -+ mpi_reply->EventData); -+ break; -+ case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION: -+ ActiveCableEventData = -+ (Mpi26EventDataActiveCableExcept_t *) mpi_reply->EventData; -+ if (ActiveCableEventData->ReasonCode == -+ MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER) -+ pr_info(MPT3SAS_FMT "Currently an active cable with ReceptacleID %d", -+ ioc->name, ActiveCableEventData->ReceptacleID); -+ pr_info("cannot be powered and devices connected to this active cable"); -+ pr_info("will not be seen. This active cable"); -+ pr_info("requires %d mW of power", -+ ActiveCableEventData->ActiveCablePowerRequirement); -+ break; -+ -+ default: /* ignore the rest */ -+ return 1; -+ } -+ -+ sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; -+ fw_event = alloc_fw_event_work(sz); -+ if (!fw_event) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 1; -+ } -+ -+ memcpy(fw_event->event_data, mpi_reply->EventData, sz); -+ fw_event->ioc = ioc; -+ fw_event->VF_ID = mpi_reply->VF_ID; -+ fw_event->VP_ID = mpi_reply->VP_ID; -+ fw_event->event = event; -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+ return 1; -+} -+ -+/** -+ * _scsih_expander_node_remove - removing expander device from list. -+ * @ioc: per adapter object -+ * @sas_expander: the sas_device object -+ * Context: Calling function should acquire ioc->sas_node_lock. -+ * -+ * Removing object and freeing associated memory from the -+ * ioc->sas_expander_list. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander) -+{ -+ struct _sas_port *mpt2sas_port, *next; -+ -+ /* remove sibling ports attached to this expander */ -+ list_for_each_entry_safe(mpt2sas_port, next, -+ &sas_expander->sas_port_list, port_list) { -+ if (ioc->shost_recovery) -+ return; -+ if (mpt2sas_port->remote_identify.device_type == -+ SAS_END_DEVICE) -+ mpt2sas_device_remove_by_sas_address(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ else if (mpt2sas_port->remote_identify.device_type == -+ SAS_EDGE_EXPANDER_DEVICE || -+ mpt2sas_port->remote_identify.device_type == -+ SAS_FANOUT_EXPANDER_DEVICE) -+ mpt2sas_expander_remove(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ } -+ -+ mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, -+ sas_expander->sas_address_parent); -+ -+ pr_info(MPT3SAS_FMT -+ "expander_remove: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, -+ sas_expander->handle, (unsigned long long) -+ sas_expander->sas_address); -+ -+ kfree(sas_expander->phy); -+ kfree(sas_expander); -+} -+ -+/** -+ * _scsih_ir_shutdown - IR shutdown notification -+ * @ioc: per adapter object -+ * -+ * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that -+ * the host system is shutting down. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2RaidActionRequest_t *mpi_request; -+ Mpi2RaidActionReply_t *mpi_reply; -+ u16 smid; -+ -+ /* is IR firmware build loaded ? */ -+ if (!ioc->ir_firmware) -+ return; -+ -+ /* are there any volumes ? */ -+ if (list_empty(&ioc->raid_device_list)) -+ return; -+ -+ mutex_lock(&ioc->scsih_cmds.mutex); -+ -+ if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: scsih_cmd in use\n", -+ ioc->name, __func__); -+ goto out; -+ } -+ ioc->scsih_cmds.status = MPT3_CMD_PENDING; -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ goto out; -+ } -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->scsih_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); -+ -+ mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; -+ mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; -+ -+ if (!ioc->hide_ir_msg) -+ pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); -+ init_completion(&ioc->scsih_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); -+ -+ if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ goto out; -+ } -+ -+ if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { -+ mpi_reply = ioc->scsih_cmds.reply; -+ if (!ioc->hide_ir_msg) -+ pr_info(MPT3SAS_FMT "IR shutdown " -+ "(complete): ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo)); -+ } -+ -+ out: -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_unlock(&ioc->scsih_cmds.mutex); -+} -+ -+/** -+ * scsih_remove_mpt2sas - detach and remove add host -+ * @pdev: PCI device struct -+ * -+ * Routine called when unloading the driver. -+ * Return nothing. -+ */ -+void scsih_remove_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct _sas_port *mpt2sas_port, *next_port; -+ struct _raid_device *raid_device, *next; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct workqueue_struct *wq; -+ unsigned long flags; -+ -+ ioc->remove_host = 1; -+ _scsih_fw_event_cleanup_queue(ioc); -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ wq = ioc->firmware_event_thread; -+ ioc->firmware_event_thread = NULL; -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+ if (wq) -+ destroy_workqueue(wq); -+ -+ /* release all the volumes */ -+ _scsih_ir_shutdown(ioc); -+ list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, -+ list) { -+ if (raid_device->starget) { -+ sas_target_priv_data = -+ raid_device->starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ scsi_remove_target(&raid_device->starget->dev); -+ } -+ pr_info(MPT3SAS_FMT "removing handle(0x%04x), wwid(0x%016llx)\n", -+ ioc->name, raid_device->handle, -+ (unsigned long long) raid_device->wwid); -+ _scsih_raid_device_remove(ioc, raid_device); -+ } -+ -+ /* free ports attached to the sas_host */ -+ list_for_each_entry_safe(mpt2sas_port, next_port, -+ &ioc->sas_hba.sas_port_list, port_list) { -+ if (mpt2sas_port->remote_identify.device_type == -+ SAS_END_DEVICE) -+ mpt2sas_device_remove_by_sas_address(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ else if (mpt2sas_port->remote_identify.device_type == -+ SAS_EDGE_EXPANDER_DEVICE || -+ mpt2sas_port->remote_identify.device_type == -+ SAS_FANOUT_EXPANDER_DEVICE) -+ mpt2sas_expander_remove(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ } -+ -+ /* free phys attached to the sas_host */ -+ if (ioc->sas_hba.num_phys) { -+ kfree(ioc->sas_hba.phy); -+ ioc->sas_hba.phy = NULL; -+ ioc->sas_hba.num_phys = 0; -+ } -+ -+ sas_remove_host(shost); -+ scsi_remove_host(shost); -+ mpt2sas_base_detach(ioc); -+ spin_lock(&gioc_lock_mpt2sas); -+ list_del(&ioc->list); -+ spin_unlock(&gioc_lock_mpt2sas); -+ scsi_host_put(shost); -+} -+ -+/** -+ * scsih_shutdown_mpt2sas - routine call during system shutdown -+ * @pdev: PCI device struct -+ * -+ * Return nothing. -+ */ -+void -+scsih_shutdown_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct workqueue_struct *wq; -+ unsigned long flags; -+ -+ ioc->remove_host = 1; -+ _scsih_fw_event_cleanup_queue(ioc); -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ wq = ioc->firmware_event_thread; -+ ioc->firmware_event_thread = NULL; -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+ if (wq) -+ destroy_workqueue(wq); -+ -+ _scsih_ir_shutdown(ioc); -+ mpt2sas_base_detach(ioc); -+} -+ -+ -+/** -+ * _scsih_probe_boot_devices - reports 1st device -+ * @ioc: per adapter object -+ * -+ * If specified in bios page 2, this routine reports the 1st -+ * device scsi-ml or sas transport for persistent boot device -+ * purposes. Please refer to function _scsih_determine_boot_device() -+ */ -+static void -+_scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u8 is_raid; -+ void *device; -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ u16 handle; -+ u64 sas_address_parent; -+ u64 sas_address; -+ unsigned long flags; -+ int rc; -+ -+ /* no Bios, return immediately */ -+ if (!ioc->bios_pg3.BiosVersion) -+ return; -+ -+ device = NULL; -+ is_raid = 0; -+ if (ioc->req_boot_device.device) { -+ device = ioc->req_boot_device.device; -+ is_raid = ioc->req_boot_device.is_raid; -+ } else if (ioc->req_alt_boot_device.device) { -+ device = ioc->req_alt_boot_device.device; -+ is_raid = ioc->req_alt_boot_device.is_raid; -+ } else if (ioc->current_boot_device.device) { -+ device = ioc->current_boot_device.device; -+ is_raid = ioc->current_boot_device.is_raid; -+ } -+ -+ if (!device) -+ return; -+ -+ if (is_raid) { -+ raid_device = device; -+ rc = scsi_add_device(ioc->shost, RAID_CHANNEL, -+ raid_device->id, 0); -+ if (rc) -+ _scsih_raid_device_remove(ioc, raid_device); -+ } else { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = device; -+ handle = sas_device->handle; -+ sas_address_parent = sas_device->sas_address_parent; -+ sas_address = sas_device->sas_address; -+ list_move_tail(&sas_device->list, &ioc->sas_device_list); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (ioc->hide_drives) -+ return; -+ if (!mpt2sas_transport_port_add(ioc, handle, -+ sas_address_parent)) { -+ _scsih_sas_device_remove(ioc, sas_device); -+ } else if (!sas_device->starget) { -+ if (!ioc->is_driver_loading) { -+ mpt2sas_transport_port_remove(ioc, -+ sas_address, -+ sas_address_parent); -+ _scsih_sas_device_remove(ioc, sas_device); -+ } -+ } -+ } -+} -+ -+/** -+ * _scsih_probe_raid - reporting raid volumes to scsi-ml -+ * @ioc: per adapter object -+ * -+ * Called during initial loading of the driver. -+ */ -+static void -+_scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct _raid_device *raid_device, *raid_next; -+ int rc; -+ -+ list_for_each_entry_safe(raid_device, raid_next, -+ &ioc->raid_device_list, list) { -+ if (raid_device->starget) -+ continue; -+ rc = scsi_add_device(ioc->shost, RAID_CHANNEL, -+ raid_device->id, 0); -+ if (rc) -+ _scsih_raid_device_remove(ioc, raid_device); -+ } -+} -+ -+static struct _sas_device *get_next_sas_device(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct _sas_device *sas_device = NULL; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ if (!list_empty(&ioc->sas_device_init_list)) { -+ sas_device = list_first_entry(&ioc->sas_device_init_list, -+ struct _sas_device, list); -+ sas_device_get(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return sas_device; -+} -+ -+static void sas_device_make_active(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ -+ /* -+ * Since we dropped the lock during the call to port_add(), we need to -+ * be careful here that somebody else didn't move or delete this item -+ * while we were busy with other things. -+ * -+ * If it was on the list, we need a put() for the reference the list -+ * had. Either way, we need a get() for the destination list. -+ */ -+ if (!list_empty(&sas_device->list)) { -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ -+ sas_device_get(sas_device); -+ list_add_tail(&sas_device->list, &ioc->sas_device_list); -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+} -+ -+/** -+ * _scsih_probe_sas - reporting sas devices to sas transport -+ * @ioc: per adapter object -+ * -+ * Called during initial loading of the driver. -+ */ -+static void -+_scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct _sas_device *sas_device; -+ -+ if (ioc->hide_drives) -+ return; -+ -+ while ((sas_device = get_next_sas_device(ioc))) { -+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle, -+ sas_device->sas_address_parent)) { -+ _scsih_sas_device_remove(ioc, sas_device); -+ sas_device_put(sas_device); -+ continue; -+ } else if (!sas_device->starget) { -+ /* -+ * When asyn scanning is enabled, its not possible to -+ * remove devices while scanning is turned on due to an -+ * oops in scsi_sysfs_add_sdev()->add_device()-> -+ * sysfs_addrm_start() -+ */ -+ if (!ioc->is_driver_loading) { -+ mpt2sas_transport_port_remove(ioc, -+ sas_device->sas_address, -+ sas_device->sas_address_parent); -+ _scsih_sas_device_remove(ioc, sas_device); -+ sas_device_put(sas_device); -+ continue; -+ } -+ } -+ sas_device_make_active(ioc, sas_device); -+ sas_device_put(sas_device); -+ } -+} -+ -+/** -+ * _scsih_probe_devices - probing for devices -+ * @ioc: per adapter object -+ * -+ * Called during initial loading of the driver. -+ */ -+static void -+_scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u16 volume_mapping_flags; -+ -+ if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR)) -+ return; /* return when IOC doesn't support initiator mode */ -+ -+ _scsih_probe_boot_devices(ioc); -+ -+ if (ioc->ir_firmware) { -+ volume_mapping_flags = -+ le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & -+ MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; -+ if (volume_mapping_flags == -+ MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { -+ _scsih_probe_raid(ioc); -+ _scsih_probe_sas(ioc); -+ } else { -+ _scsih_probe_sas(ioc); -+ _scsih_probe_raid(ioc); -+ } -+ } else -+ _scsih_probe_sas(ioc); -+} -+ -+/** -+ * scsih_scan_start_mpt2sas - scsi lld callback for .scan_start -+ * @shost: SCSI host pointer -+ * -+ * The shost has the ability to discover targets on its own instead -+ * of scanning the entire bus. In our implemention, we will kick off -+ * firmware discovery. -+ */ -+void -+scsih_scan_start_mpt2sas(struct Scsi_Host *shost) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int rc; -+ if (diag_buffer_enable != -1 && diag_buffer_enable != 0) -+ mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); -+ -+ if (disable_discovery > 0) -+ return; -+ -+ ioc->start_scan = 1; -+ rc = mpt2sas_port_enable(ioc); -+ -+ if (rc != 0) -+ pr_info(MPT3SAS_FMT "port enable: FAILED\n", ioc->name); -+} -+ -+/** -+ * scsih_scan_finished_mpt2sas - scsi lld callback for .scan_finished -+ * @shost: SCSI host pointer -+ * @time: elapsed time of the scan in jiffies -+ * -+ * This function will be called periodicallyn until it returns 1 with the -+ * scsi_host and the elapsed time of the scan in jiffies. In our implemention, -+ * we wait for firmware discovery to complete, then return 1. -+ */ -+int -+scsih_scan_finished_mpt2sas(struct Scsi_Host *shost, unsigned long time) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ if (disable_discovery > 0) { -+ ioc->is_driver_loading = 0; -+ ioc->wait_for_discovery_to_complete = 0; -+ return 1; -+ } -+ -+ if (time >= (300 * HZ)) { -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ pr_info(MPT3SAS_FMT -+ "port enable: FAILED with timeout (timeout=300s)\n", -+ ioc->name); -+ ioc->is_driver_loading = 0; -+ return 1; -+ } -+ -+ if (ioc->start_scan) -+ return 0; -+ -+ if (ioc->start_scan_failed) { -+ pr_info(MPT3SAS_FMT -+ "port enable: FAILED with (ioc_status=0x%08x)\n", -+ ioc->name, ioc->start_scan_failed); -+ ioc->is_driver_loading = 0; -+ ioc->wait_for_discovery_to_complete = 0; -+ ioc->remove_host = 1; -+ return 1; -+ } -+ -+ pr_info(MPT3SAS_FMT "port enable: SUCCESS\n", ioc->name); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ -+ if (ioc->wait_for_discovery_to_complete) { -+ ioc->wait_for_discovery_to_complete = 0; -+ _scsih_probe_devices(ioc); -+ } -+ mpt2sas_base_start_watchdog(ioc); -+ ioc->is_driver_loading = 0; -+ return 1; -+} -+ -+/* shost template for SAS 2.0 HBA devices */ -+static struct scsi_host_template mpt2sas_driver_template_mpt2sas = { -+ .module = THIS_MODULE, -+ .name = "Fusion MPT SAS Host", -+ .proc_name = MPT2SAS_DRIVER_NAME, -+ .queuecommand = scsih_qcmd_mpt2sas, -+ .target_alloc = scsih_target_alloc_mpt2sas, -+ .slave_alloc = scsih_slave_alloc_mpt2sas, -+ .slave_configure = scsih_slave_configure_mpt2sas, -+ .target_destroy = scsih_target_destroy_mpt2sas, -+ .slave_destroy = scsih_slave_destroy_mpt2sas, -+ .scan_finished = scsih_scan_finished_mpt2sas, -+ .scan_start = scsih_scan_start_mpt2sas, -+ .change_queue_depth = scsih_change_queue_depth_mpt2sas, -+ .change_queue_type = _scsih_change_queue_type_mpt2sas, -+ .eh_abort_handler = scsih_abort_mpt2sas, -+ .eh_device_reset_handler = scsih_dev_reset_mpt2sas, -+ .eh_target_reset_handler = scsih_target_reset_mpt2sas, -+ .eh_host_reset_handler = scsih_host_reset_mpt2sas, -+ .bios_param = scsih_bios_param_mpt2sas, -+ .can_queue = 1, -+ .this_id = -1, -+ .sg_tablesize = MPT2SAS_SG_DEPTH, -+ .max_sectors = 32767, -+ .cmd_per_lun = 7, -+ .use_clustering = ENABLE_CLUSTERING, -+ .shost_attrs = mpt2sas_host_attrs, -+ .sdev_attrs = mpt2sas_dev_attrs, -+}; -+ -+#ifdef MPT2SAS_SCSI -+/* raid transport support for SAS 2.0 HBA devices */ -+static struct raid_function_template mpt2sas_raid_functions = { -+ .cookie = &mpt2sas_driver_template_mpt2sas, -+ .is_raid = scsih_is_raid_mpt2sas, -+ .get_resync = scsih_get_resync_mpt2sas, -+ .get_state = scsih_get_state_mpt2sas, -+}; -+#endif /* MPT2SAS_SCSI */ -+ -+/* shost template for SAS 3.0 HBA devices */ -+static struct scsi_host_template mpt3sas_driver_template_mpt2sas = { -+ .module = THIS_MODULE, -+ .name = "Fusion MPT SAS Host", -+ .proc_name = MPT3SAS_DRIVER_NAME, -+ .queuecommand = scsih_qcmd_mpt2sas, -+ .target_alloc = scsih_target_alloc_mpt2sas, -+ .slave_alloc = scsih_slave_alloc_mpt2sas, -+ .slave_configure = scsih_slave_configure_mpt2sas, -+ .target_destroy = scsih_target_destroy_mpt2sas, -+ .slave_destroy = scsih_slave_destroy_mpt2sas, -+ .scan_finished = scsih_scan_finished_mpt2sas, -+ .scan_start = scsih_scan_start_mpt2sas, -+ .change_queue_depth = scsih_change_queue_depth_mpt2sas, -+ .change_queue_type = _scsih_change_queue_type_mpt2sas, -+ .eh_abort_handler = scsih_abort_mpt2sas, -+ .eh_device_reset_handler = scsih_dev_reset_mpt2sas, -+ .eh_target_reset_handler = scsih_target_reset_mpt2sas, -+ .eh_host_reset_handler = scsih_host_reset_mpt2sas, -+ .bios_param = scsih_bios_param_mpt2sas, -+ .can_queue = 1, -+ .this_id = -1, -+ .sg_tablesize = MPT3SAS_SG_DEPTH, -+ .max_sectors = 32767, -+ .cmd_per_lun = 7, -+ .use_clustering = ENABLE_CLUSTERING, -+ .shost_attrs = mpt2sas_host_attrs, -+ .sdev_attrs = mpt2sas_dev_attrs, -+}; -+ -+#ifndef MPT2SAS_SCSI -+/* raid transport support for SAS 3.0 HBA devices */ -+static struct raid_function_template mpt3sas_raid_functions = { -+ .cookie = &mpt3sas_driver_template_mpt2sas, -+ .is_raid = scsih_is_raid_mpt2sas, -+ .get_resync = scsih_get_resync_mpt2sas, -+ .get_state = scsih_get_state_mpt2sas, -+}; -+#endif /* MPT2SAS_SCSI */ -+ -+/** -+ * _scsih_determine_hba_mpi_version_mpt2sas - determine in which MPI version class -+ * this device belongs to. -+ * @pdev: PCI device struct -+ * -+ * return MPI2_VERSION for SAS 2.0 HBA devices, -+ * MPI25_VERSION for SAS 3.0 HBA devices, and -+ * MPI26 VERSION for Cutlass & Invader SAS 3.0 HBA devices -+ */ -+u16 -+_scsih_determine_hba_mpi_version_mpt2sas(struct pci_dev *pdev) -+{ -+ -+ switch (pdev->device) { -+ case MPI2_MFGPAGE_DEVID_SSS6200: -+ case MPI2_MFGPAGE_DEVID_SAS2004: -+ case MPI2_MFGPAGE_DEVID_SAS2008: -+ case MPI2_MFGPAGE_DEVID_SAS2108_1: -+ case MPI2_MFGPAGE_DEVID_SAS2108_2: -+ case MPI2_MFGPAGE_DEVID_SAS2108_3: -+ case MPI2_MFGPAGE_DEVID_SAS2116_1: -+ case MPI2_MFGPAGE_DEVID_SAS2116_2: -+ case MPI2_MFGPAGE_DEVID_SAS2208_1: -+ case MPI2_MFGPAGE_DEVID_SAS2208_2: -+ case MPI2_MFGPAGE_DEVID_SAS2208_3: -+ case MPI2_MFGPAGE_DEVID_SAS2208_4: -+ case MPI2_MFGPAGE_DEVID_SAS2208_5: -+ case MPI2_MFGPAGE_DEVID_SAS2208_6: -+ case MPI2_MFGPAGE_DEVID_SAS2308_1: -+ case MPI2_MFGPAGE_DEVID_SAS2308_2: -+ case MPI2_MFGPAGE_DEVID_SAS2308_3: -+ return MPI2_VERSION; -+ case MPI25_MFGPAGE_DEVID_SAS3004: -+ case MPI25_MFGPAGE_DEVID_SAS3008: -+ case MPI25_MFGPAGE_DEVID_SAS3108_1: -+ case MPI25_MFGPAGE_DEVID_SAS3108_2: -+ case MPI25_MFGPAGE_DEVID_SAS3108_5: -+ case MPI25_MFGPAGE_DEVID_SAS3108_6: -+ return MPI25_VERSION; -+ case MPI26_MFGPAGE_DEVID_SAS3216: -+ case MPI26_MFGPAGE_DEVID_SAS3224: -+ case MPI26_MFGPAGE_DEVID_SAS3316_1: -+ case MPI26_MFGPAGE_DEVID_SAS3316_2: -+ case MPI26_MFGPAGE_DEVID_SAS3316_3: -+ case MPI26_MFGPAGE_DEVID_SAS3316_4: -+ case MPI26_MFGPAGE_DEVID_SAS3324_1: -+ case MPI26_MFGPAGE_DEVID_SAS3324_2: -+ case MPI26_MFGPAGE_DEVID_SAS3324_3: -+ case MPI26_MFGPAGE_DEVID_SAS3324_4: -+ return MPI26_VERSION; -+ } -+ return 0; -+} -+ -+/** -+ * _scsih_probe_mpt2sas - attach and add scsi host -+ * @pdev: PCI device struct -+ * @id: pci device id -+ * -+ * Returns 0 success, anything else error. -+ */ -+int -+_scsih_probe_mpt2sas(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ struct Scsi_Host *shost = NULL; -+ int rv; -+ u16 hba_mpi_version; -+ -+ /* Determine in which MPI version class this pci device belongs */ -+ hba_mpi_version = _scsih_determine_hba_mpi_version_mpt2sas(pdev); -+ if (hba_mpi_version == 0) -+ return -ENODEV; -+ -+ switch (hba_mpi_version) { -+ case MPI2_VERSION: -+ /* Use mpt2sas driver host template for SAS 2.0 HBA's */ -+ shost = scsi_host_alloc(&mpt2sas_driver_template_mpt2sas, -+ sizeof(struct MPT3SAS_ADAPTER)); -+ if (!shost) -+ return -ENODEV; -+ ioc = shost_priv(shost); -+ memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); -+ ioc->hba_mpi_version_belonged = hba_mpi_version; -+ ioc->id = mpt2_ids++; -+ sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME); -+ if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) { -+ ioc->is_warpdrive = 1; -+ ioc->hide_ir_msg = 1; -+ } else -+ ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ /* Use mpt3sas driver host template for SAS 3.0 HBA's */ -+ shost = scsi_host_alloc(&mpt3sas_driver_template_mpt2sas, -+ sizeof(struct MPT3SAS_ADAPTER)); -+ if (!shost) -+ return -ENODEV; -+ ioc = shost_priv(shost); -+ memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); -+ ioc->hba_mpi_version_belonged = hba_mpi_version; -+ ioc->id = mpt3_ids++; -+ sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME); -+ if ((ioc->hba_mpi_version_belonged == MPI25_VERSION && -+ pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION) || -+ (ioc->hba_mpi_version_belonged == MPI26_VERSION)) -+ ioc->msix96_vector = 1; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ INIT_LIST_HEAD(&ioc->list); -+ spin_lock(&gioc_lock_mpt2sas); -+ list_add_tail(&ioc->list, &mpt2sas_ioc_list); -+ spin_unlock(&gioc_lock_mpt2sas); -+ ioc->shost = shost; -+ ioc->pdev = pdev; -+ ioc->scsi_io_cb_idx = scsi_io_cb_idx; -+ ioc->tm_cb_idx = tm_cb_idx; -+ ioc->ctl_cb_idx = ctl_cb_idx; -+ ioc->base_cb_idx = base_cb_idx; -+ ioc->port_enable_cb_idx = port_enable_cb_idx; -+ ioc->transport_cb_idx = transport_cb_idx; -+ ioc->scsih_cb_idx = scsih_cb_idx; -+ ioc->config_cb_idx = config_cb_idx; -+ ioc->tm_tr_cb_idx = tm_tr_cb_idx; -+ ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx; -+ ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; -+ ioc->logging_level = logging_level; -+ ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; -+ /* misc semaphores and spin locks */ -+ mutex_init(&ioc->reset_in_progress_mutex); -+ /* initializing pci_access_mutex lock */ -+ mutex_init(&ioc->pci_access_mutex); -+ spin_lock_init(&ioc->ioc_reset_in_progress_lock); -+ spin_lock_init(&ioc->scsi_lookup_lock); -+ spin_lock_init(&ioc->sas_device_lock); -+ spin_lock_init(&ioc->sas_node_lock); -+ spin_lock_init(&ioc->fw_event_lock); -+ spin_lock_init(&ioc->raid_device_lock); -+ spin_lock_init(&ioc->diag_trigger_lock); -+ -+ INIT_LIST_HEAD(&ioc->sas_device_list); -+ INIT_LIST_HEAD(&ioc->sas_device_init_list); -+ INIT_LIST_HEAD(&ioc->sas_expander_list); -+ INIT_LIST_HEAD(&ioc->fw_event_list); -+ INIT_LIST_HEAD(&ioc->raid_device_list); -+ INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); -+ INIT_LIST_HEAD(&ioc->delayed_tr_list); -+ INIT_LIST_HEAD(&ioc->delayed_sc_list); -+ INIT_LIST_HEAD(&ioc->delayed_event_ack_list); -+ INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); -+ INIT_LIST_HEAD(&ioc->reply_queue_list); -+ -+ sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id); -+ -+ /* init shost parameters */ -+ shost->max_cmd_len = 32; -+ shost->max_lun = max_lun; -+ shost->transportt = mpt2sas_transport_template; -+ shost->unique_id = ioc->id; -+ -+ if (max_sectors != 0xFFFF) { -+ if (max_sectors < 64) { -+ shost->max_sectors = 64; -+ pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ -+ "for max_sectors, range is 64 to 32767. Assigning " -+ "value of 64.\n", ioc->name, max_sectors); -+ } else if (max_sectors > 32767) { -+ shost->max_sectors = 32767; -+ pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ -+ "for max_sectors, range is 64 to 32767. Assigning " -+ "default value of 32767.\n", ioc->name, -+ max_sectors); -+ } else { -+ shost->max_sectors = max_sectors & 0xFFFE; -+ pr_info(MPT3SAS_FMT -+ "The max_sectors value is set to %d\n", -+ ioc->name, shost->max_sectors); -+ } -+ } -+ -+ /* register EEDP capabilities with SCSI layer */ -+ if (prot_mask > 0) -+ scsi_host_set_prot(shost, prot_mask); -+ else -+ scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION -+ | SHOST_DIF_TYPE2_PROTECTION -+ | SHOST_DIF_TYPE3_PROTECTION); -+ -+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); -+ -+ /* event thread */ -+ snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), -+ "fw_event_%s%d", ioc->driver_name, ioc->id); -+ ioc->firmware_event_thread = alloc_ordered_workqueue( -+ ioc->firmware_event_name, WQ_MEM_RECLAIM); -+ if (!ioc->firmware_event_thread) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rv = -ENODEV; -+ goto out_thread_fail; -+ } -+ -+ ioc->is_driver_loading = 1; -+ if ((mpt2sas_base_attach(ioc))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rv = -ENODEV; -+ goto out_attach_fail; -+ } -+ -+ if (ioc->is_warpdrive) { -+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) -+ ioc->hide_drives = 0; -+ else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) -+ ioc->hide_drives = 1; -+ else { -+ if (mpt2sas_get_num_volumes(ioc)) -+ ioc->hide_drives = 1; -+ else -+ ioc->hide_drives = 0; -+ } -+ } else -+ ioc->hide_drives = 0; -+ -+ rv = scsi_add_host(shost, &pdev->dev); -+ if (rv) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_add_shost_fail; -+ } -+ -+ scsi_scan_host(shost); -+ return 0; -+out_add_shost_fail: -+ mpt2sas_base_detach(ioc); -+ out_attach_fail: -+ destroy_workqueue(ioc->firmware_event_thread); -+ out_thread_fail: -+ spin_lock(&gioc_lock_mpt2sas); -+ list_del(&ioc->list); -+ spin_unlock(&gioc_lock_mpt2sas); -+ scsi_host_put(shost); -+ return rv; -+} -+ -+#ifdef CONFIG_PM -+/** -+ * scsih_suspend_mpt2sas - power management suspend main entry point -+ * @pdev: PCI device struct -+ * @state: PM state change to (usually PCI_D3) -+ * -+ * Returns 0 success, anything else error. -+ */ -+int -+scsih_suspend_mpt2sas(struct pci_dev *pdev, pm_message_t state) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ pci_power_t device_state; -+ -+ mpt2sas_base_stop_watchdog(ioc); -+ flush_scheduled_work(); -+ scsi_block_requests(shost); -+ device_state = pci_choose_state(pdev, state); -+ pr_info(MPT3SAS_FMT -+ "pdev=0x%p, slot=%s, entering operating state [D%d]\n", -+ ioc->name, pdev, pci_name(pdev), device_state); -+ -+ pci_save_state(pdev); -+ mpt2sas_base_free_resources(ioc); -+ pci_set_power_state(pdev, device_state); -+ return 0; -+} -+ -+/** -+ * scsih_resume_mpt2sas - power management resume main entry point -+ * @pdev: PCI device struct -+ * -+ * Returns 0 success, anything else error. -+ */ -+int -+scsih_resume_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ pci_power_t device_state = pdev->current_state; -+ int r; -+ -+ pr_info(MPT3SAS_FMT -+ "pdev=0x%p, slot=%s, previous operating state [D%d]\n", -+ ioc->name, pdev, pci_name(pdev), device_state); -+ -+ pci_set_power_state(pdev, PCI_D0); -+ pci_enable_wake(pdev, PCI_D0, 0); -+ pci_restore_state(pdev); -+ ioc->pdev = pdev; -+ r = mpt2sas_base_map_resources(ioc); -+ if (r) -+ return r; -+ -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET); -+ scsi_unblock_requests(shost); -+ mpt2sas_base_start_watchdog(ioc); -+ return 0; -+} -+#endif /* CONFIG_PM */ -+ -+/** -+ * scsih_pci_error_detected_mpt2sas - Called when a PCI error is detected. -+ * @pdev: PCI device struct -+ * @state: PCI channel state -+ * -+ * Description: Called when a PCI error is detected. -+ * -+ * Return value: -+ * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT -+ */ -+pci_ers_result_t -+scsih_pci_error_detected_mpt2sas(struct pci_dev *pdev, pci_channel_state_t state) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ pr_info(MPT3SAS_FMT "PCI error: detected callback, state(%d)!!\n", -+ ioc->name, state); -+ -+ switch (state) { -+ case pci_channel_io_normal: -+ return PCI_ERS_RESULT_CAN_RECOVER; -+ case pci_channel_io_frozen: -+ /* Fatal error, prepare for slot reset */ -+ ioc->pci_error_recovery = 1; -+ scsi_block_requests(ioc->shost); -+ mpt2sas_base_stop_watchdog(ioc); -+ mpt2sas_base_free_resources(ioc); -+ return PCI_ERS_RESULT_NEED_RESET; -+ case pci_channel_io_perm_failure: -+ /* Permanent error, prepare for device removal */ -+ ioc->pci_error_recovery = 1; -+ mpt2sas_base_stop_watchdog(ioc); -+ _scsih_flush_running_cmds(ioc); -+ return PCI_ERS_RESULT_DISCONNECT; -+ } -+ return PCI_ERS_RESULT_NEED_RESET; -+} -+ -+/** -+ * scsih_pci_slot_reset_mpt2sas - Called when PCI slot has been reset. -+ * @pdev: PCI device struct -+ * -+ * Description: This routine is called by the pci error recovery -+ * code after the PCI slot has been reset, just before we -+ * should resume normal operations. -+ */ -+pci_ers_result_t -+scsih_pci_slot_reset_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int rc; -+ -+ pr_info(MPT3SAS_FMT "PCI error: slot reset callback!!\n", -+ ioc->name); -+ -+ ioc->pci_error_recovery = 0; -+ ioc->pdev = pdev; -+ pci_restore_state(pdev); -+ rc = mpt2sas_base_map_resources(ioc); -+ if (rc) -+ return PCI_ERS_RESULT_DISCONNECT; -+ -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ -+ pr_warn(MPT3SAS_FMT "hard reset: %s\n", ioc->name, -+ (rc == 0) ? "success" : "failed"); -+ -+ if (!rc) -+ return PCI_ERS_RESULT_RECOVERED; -+ else -+ return PCI_ERS_RESULT_DISCONNECT; -+} -+ -+/** -+ * scsih_pci_resume_mpt2sas() - resume normal ops after PCI reset -+ * @pdev: pointer to PCI device -+ * -+ * Called when the error recovery driver tells us that its -+ * OK to resume normal operation. Use completion to allow -+ * halted scsi ops to resume. -+ */ -+void -+scsih_pci_resume_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ pr_info(MPT3SAS_FMT "PCI error: resume callback!!\n", ioc->name); -+ -+ pci_cleanup_aer_uncorrect_error_status(pdev); -+ mpt2sas_base_start_watchdog(ioc); -+ scsi_unblock_requests(ioc->shost); -+} -+ -+/** -+ * scsih_pci_mmio_enabled_mpt2sas - Enable MMIO and dump debug registers -+ * @pdev: pointer to PCI device -+ */ -+pci_ers_result_t -+scsih_pci_mmio_enabled_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ pr_info(MPT3SAS_FMT "PCI error: mmio enabled callback!!\n", -+ ioc->name); -+ -+ /* TODO - dump whatever for debugging purposes */ -+ -+ /* This called only if scsih_pci_error_detected_mpt2sas returns -+ * PCI_ERS_RESULT_CAN_RECOVER. Read/write to the device still -+ * works, no need to reset slot. -+ */ -+ return PCI_ERS_RESULT_RECOVERED; -+} -+ -+/* -+ * The pci device ids are defined in mpi/mpi2_cnfg.h. -+ */ -+static const struct pci_device_id mpt2sas_pci_table[] = { -+#ifdef MPT2SAS_SCSI -+ /* Spitfire ~ 2004 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Falcon ~ 2008 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Liberator ~ 2108 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Meteor ~ 2116 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Thunderbolt ~ 2208 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Mustang ~ 2308 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* SSS6200 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, -+ PCI_ANY_ID, PCI_ANY_ID }, -+#else -+ /* Fury ~ 3004 and 3008 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Invader ~ 3108 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Cutlass ~ 3216 and 3224 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Intruder ~ 3316 and 3324 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_4, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_4, -+ PCI_ANY_ID, PCI_ANY_ID }, -+#endif /* MPT2SAS_SCSI */ -+ {0} /* Terminating entry */ -+}; -+MODULE_DEVICE_TABLE(pci, mpt2sas_pci_table); -+ -+static struct pci_error_handlers _mpt2sas_err_handler = { -+ .error_detected = scsih_pci_error_detected_mpt2sas, -+ .mmio_enabled = scsih_pci_mmio_enabled_mpt2sas, -+ .slot_reset = scsih_pci_slot_reset_mpt2sas, -+ .resume = scsih_pci_resume_mpt2sas, -+}; -+ -+static struct pci_driver mpt3sas_driver = { -+#ifdef MPT2SAS_SCSI -+ .name = MPT2SAS_DRIVER_NAME, -+#else -+ .name = MPT3SAS_DRIVER_NAME, -+#endif /* MPT2SAS_SCSI */ -+ .id_table = mpt2sas_pci_table, -+ .probe = _scsih_probe_mpt2sas, -+ .remove = scsih_remove_mpt2sas, -+ .shutdown = scsih_shutdown_mpt2sas, -+ .err_handler = &_mpt2sas_err_handler, -+#ifdef CONFIG_PM -+ .suspend = scsih_suspend_mpt2sas, -+ .resume = scsih_resume_mpt2sas, -+#endif -+}; -+ -+/** -+ * scsih_init_mpt2sas - main entry point for this driver. -+ * -+ * Returns 0 success, anything else error. -+ */ -+int -+scsih_init_mpt2sas(void) -+{ -+ mpt2_ids = 0; -+ mpt3_ids = 0; -+ -+ mpt2sas_base_initialize_callback_handler(); -+ -+ /* queuecommand callback hander */ -+ scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done); -+ -+ /* task managment callback handler */ -+ tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done); -+ -+ /* base internal commands callback handler */ -+ base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done); -+ port_enable_cb_idx = mpt2sas_base_register_callback_handler( -+ mpt2sas_port_enable_done); -+ -+ /* transport internal commands callback handler */ -+ transport_cb_idx = mpt2sas_base_register_callback_handler( -+ mpt2sas_transport_done); -+ -+ /* scsih internal commands callback handler */ -+ scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done); -+ -+ /* configuration page API internal commands callback handler */ -+ config_cb_idx = mpt2sas_base_register_callback_handler( -+ mpt2sas_config_done); -+ -+ /* ctl module callback handler */ -+ ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done); -+ -+ tm_tr_cb_idx = mpt2sas_base_register_callback_handler( -+ _scsih_tm_tr_complete); -+ -+ tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler( -+ _scsih_tm_volume_tr_complete); -+ -+ tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler( -+ _scsih_sas_control_complete); -+ -+ return 0; -+} -+ -+/** -+ * scsih_exit_mpt2sas - exit point for this driver (when it is a module). -+ * -+ * Returns 0 success, anything else error. -+ */ -+void -+scsih_exit_mpt2sas(void) -+{ -+ -+ mpt2sas_base_release_callback_handler(scsi_io_cb_idx); -+ mpt2sas_base_release_callback_handler(tm_cb_idx); -+ mpt2sas_base_release_callback_handler(base_cb_idx); -+ mpt2sas_base_release_callback_handler(port_enable_cb_idx); -+ mpt2sas_base_release_callback_handler(transport_cb_idx); -+ mpt2sas_base_release_callback_handler(scsih_cb_idx); -+ mpt2sas_base_release_callback_handler(config_cb_idx); -+ mpt2sas_base_release_callback_handler(ctl_cb_idx); -+ -+ mpt2sas_base_release_callback_handler(tm_tr_cb_idx); -+ mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx); -+ mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); -+ -+/* raid transport support */ -+#ifdef MPT2SAS_SCSI -+ raid_class_release(mpt2sas_raid_template_mpt2sas); -+#else -+ raid_class_release(mpt3sas_raid_template_mpt2sas); -+#endif /* MPT2SAS_SCSI */ -+ sas_release_transport(mpt2sas_transport_template); -+} -+ -+/** -+ * _mpt2sas_init - main entry point for this driver. -+ * -+ * Returns 0 success, anything else error. -+ */ -+static int __init -+_mpt2sas_init(void) -+{ -+ int error; -+ -+#ifdef MPT2SAS_SCSI -+ pr_info("%s version %s loaded\n", MPT2SAS_DRIVER_NAME, -+ MPT2SAS_DRIVER_VERSION); -+#else -+ pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME, -+ MPT3SAS_DRIVER_VERSION); -+#endif /* MPT2SAS_SCSI */ -+ -+ mpt2sas_transport_template = -+ sas_attach_transport(&mpt2sas_transport_functions); -+ if (!mpt2sas_transport_template) -+ return -ENODEV; -+ -+#ifdef MPT2SAS_SCSI -+ mpt2sas_raid_template_mpt2sas = raid_class_attach(&mpt2sas_raid_functions); -+ if (!mpt2sas_raid_template_mpt2sas) { -+ sas_release_transport(mpt2sas_transport_template); -+ return -ENODEV; -+ } -+#else -+ mpt3sas_raid_template_mpt2sas = raid_class_attach(&mpt3sas_raid_functions); -+ if (!mpt3sas_raid_template_mpt2sas) { -+ sas_release_transport(mpt2sas_transport_template); -+ return -ENODEV; -+ } -+#endif /* MPT2SAS_SCSI */ -+ -+ error = scsih_init_mpt2sas(); -+ if (error) { -+ scsih_exit_mpt2sas(); -+ return error; -+ } -+ -+ -+#ifdef MPT2SAS_SCSI -+ mpt2sas_ctl_init(1); -+#else -+ mpt2sas_ctl_init(2); -+#endif /* MPT2SAS_SCSI */ -+ -+ error = pci_register_driver(&mpt3sas_driver); -+ if (error) -+ scsih_exit_mpt2sas(); -+ -+ return error; -+} -+ -+/** -+ * _mpt2sas_exit - exit point for this driver (when it is a module). -+ * -+ */ -+static void __exit -+_mpt2sas_exit(void) -+{ -+ pr_info("mpt3sas version %s unloading\n", -+ MPT3SAS_DRIVER_VERSION); -+ -+ pci_unregister_driver(&mpt3sas_driver); -+ -+#ifdef MPT2SAS_SCSI -+ mpt2sas_ctl_exit(1); -+#else -+ mpt2sas_ctl_exit(2); -+#endif /* MPT2SAS_SCSI */ -+ -+ scsih_exit_mpt2sas(); -+} -+ -+module_init(_mpt2sas_init); -+module_exit(_mpt2sas_exit); -diff --git a/drivers/scsi/mpt2sas/mpt3sas_transport.c b/drivers/scsi/mpt2sas/mpt3sas_transport.c -new file mode 100644 -index 0000000..690afa5 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_transport.c -@@ -0,0 +1,2138 @@ -+/* -+ * SAS Transport Layer for MPT (Message Passing Technology) based controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+/** -+ * _transport_sas_node_find_by_sas_address - sas node search -+ * @ioc: per adapter object -+ * @sas_address: sas address of expander or sas host -+ * Context: Calling function should acquire ioc->sas_node_lock. -+ * -+ * Search for either hba phys or expander device based on handle, then returns -+ * the sas_node object. -+ */ -+static struct _sas_node * -+_transport_sas_node_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ if (ioc->sas_hba.sas_address == sas_address) -+ return &ioc->sas_hba; -+ else -+ return mpt2sas_scsih_expander_find_by_sas_address(ioc, -+ sas_address); -+} -+ -+/** -+ * _transport_convert_phy_link_rate - -+ * @link_rate: link rate returned from mpt firmware -+ * -+ * Convert link_rate from mpi fusion into sas_transport form. -+ */ -+static enum sas_linkrate -+_transport_convert_phy_link_rate(u8 link_rate) -+{ -+ enum sas_linkrate rc; -+ -+ switch (link_rate) { -+ case MPI2_SAS_NEG_LINK_RATE_1_5: -+ rc = SAS_LINK_RATE_1_5_GBPS; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_3_0: -+ rc = SAS_LINK_RATE_3_0_GBPS; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_6_0: -+ rc = SAS_LINK_RATE_6_0_GBPS; -+ break; -+ case MPI25_SAS_NEG_LINK_RATE_12_0: -+ rc = SAS_LINK_RATE_12_0_GBPS; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED: -+ rc = SAS_PHY_DISABLED; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED: -+ rc = SAS_LINK_RATE_FAILED; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR: -+ rc = SAS_SATA_PORT_SELECTOR; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS: -+ rc = SAS_PHY_RESET_IN_PROGRESS; -+ break; -+ -+ default: -+ case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE: -+ case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE: -+ rc = SAS_LINK_RATE_UNKNOWN; -+ break; -+ } -+ return rc; -+} -+ -+/** -+ * _transport_set_identify - set identify for phys and end devices -+ * @ioc: per adapter object -+ * @handle: device handle -+ * @identify: sas identify info -+ * -+ * Populates sas identify info. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_set_identify(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ struct sas_identify *identify) -+{ -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u32 device_info; -+ u32 ioc_status; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -ENXIO; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT -+ "handle(0x%04x), ioc_status(0x%04x)\nfailure at %s:%d/%s()!\n", -+ ioc->name, handle, ioc_status, -+ __FILE__, __LINE__, __func__); -+ return -EIO; -+ } -+ -+ memset(identify, 0, sizeof(struct sas_identify)); -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ -+ /* sas_address */ -+ identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ -+ /* phy number of the parent device this device is linked to */ -+ identify->phy_identifier = sas_device_pg0.PhyNum; -+ -+ /* device_type */ -+ switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { -+ case MPI2_SAS_DEVICE_INFO_NO_DEVICE: -+ identify->device_type = SAS_PHY_UNUSED; -+ break; -+ case MPI2_SAS_DEVICE_INFO_END_DEVICE: -+ identify->device_type = SAS_END_DEVICE; -+ break; -+ case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER: -+ identify->device_type = SAS_EDGE_EXPANDER_DEVICE; -+ break; -+ case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER: -+ identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; -+ break; -+ } -+ -+ /* initiator_port_protocols */ -+ if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR) -+ identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR) -+ identify->initiator_port_protocols |= SAS_PROTOCOL_STP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR) -+ identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST) -+ identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; -+ -+ /* target_port_protocols */ -+ if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) -+ identify->target_port_protocols |= SAS_PROTOCOL_SSP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) -+ identify->target_port_protocols |= SAS_PROTOCOL_STP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) -+ identify->target_port_protocols |= SAS_PROTOCOL_SMP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -+ identify->target_port_protocols |= SAS_PROTOCOL_SATA; -+ -+ return 0; -+} -+ -+/** -+ * mpt2sas_transport_done - internal transport layer callback handler. -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Callback handler when sending internal generated transport cmds. -+ * The callback index passed is `ioc->transport_cb_idx` -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (ioc->transport_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->transport_cmds.smid != smid) -+ return 1; -+ ioc->transport_cmds.status |= MPT3_CMD_COMPLETE; -+ if (mpi_reply) { -+ memcpy(ioc->transport_cmds.reply, mpi_reply, -+ mpi_reply->MsgLength*4); -+ ioc->transport_cmds.status |= MPT3_CMD_REPLY_VALID; -+ } -+ ioc->transport_cmds.status &= ~MPT3_CMD_PENDING; -+ complete(&ioc->transport_cmds.done); -+ return 1; -+} -+ -+/* report manufacture request structure */ -+struct rep_manu_request { -+ u8 smp_frame_type; -+ u8 function; -+ u8 reserved; -+ u8 request_length; -+}; -+ -+/* report manufacture reply structure */ -+struct rep_manu_reply { -+ u8 smp_frame_type; /* 0x41 */ -+ u8 function; /* 0x01 */ -+ u8 function_result; -+ u8 response_length; -+ u16 expander_change_count; -+ u8 reserved0[2]; -+ u8 sas_format; -+ u8 reserved2[3]; -+ u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; -+ u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; -+ u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; -+ u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; -+ u16 component_id; -+ u8 component_revision_id; -+ u8 reserved3; -+ u8 vendor_specific[8]; -+}; -+ -+/** -+ * transport_expander_report_manufacture - obtain SMP report_manufacture -+ * @ioc: per adapter object -+ * @sas_address: expander sas address -+ * @edev: the sas_expander_device object -+ * -+ * Fills in the sas_expander_device object when SMP port is created. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address, struct sas_expander_device *edev) -+{ -+ Mpi2SmpPassthroughRequest_t *mpi_request; -+ Mpi2SmpPassthroughReply_t *mpi_reply; -+ struct rep_manu_reply *manufacture_reply; -+ struct rep_manu_request *manufacture_request; -+ int rc; -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ void *psge; -+ u8 issue_reset = 0; -+ void *data_out = NULL; -+ dma_addr_t data_out_dma; -+ dma_addr_t data_in_dma; -+ size_t data_in_sz; -+ size_t data_out_sz; -+ u16 wait_state_count; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ mutex_lock(&ioc->transport_cmds.mutex); -+ -+ if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->transport_cmds.status = MPT3_CMD_PENDING; -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->transport_cmds.smid = smid; -+ -+ data_out_sz = sizeof(struct rep_manu_request); -+ data_in_sz = sizeof(struct rep_manu_reply); -+ data_out = pci_alloc_consistent(ioc->pdev, data_out_sz + data_in_sz, -+ &data_out_dma); -+ -+ if (!data_out) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ rc = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ -+ data_in_dma = data_out_dma + sizeof(struct rep_manu_request); -+ -+ manufacture_request = data_out; -+ manufacture_request->smp_frame_type = 0x40; -+ manufacture_request->function = 1; -+ manufacture_request->reserved = 0; -+ manufacture_request->request_length = 0; -+ -+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; -+ mpi_request->PhysicalPort = 0xFF; -+ mpi_request->SASAddress = cpu_to_le64(sas_address); -+ mpi_request->RequestDataLength = cpu_to_le16(data_out_sz); -+ psge = &mpi_request->SGL; -+ -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, -+ data_in_sz); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "report_manufacture - send to sas_addr(0x%016llx)\n", -+ ioc->name, (unsigned long long)sas_address)); -+ init_completion(&ioc->transport_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, -+ 10*HZ); -+ -+ if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SmpPassthroughRequest_t)/4); -+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "report_manufacture - complete\n", ioc->name)); -+ -+ if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { -+ u8 *tmp; -+ -+ mpi_reply = ioc->transport_cmds.reply; -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "report_manufacture - reply data transfer size(%d)\n", -+ ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); -+ -+ if (le16_to_cpu(mpi_reply->ResponseDataLength) != -+ sizeof(struct rep_manu_reply)) -+ goto out; -+ -+ manufacture_reply = data_out + sizeof(struct rep_manu_request); -+ strncpy(edev->vendor_id, manufacture_reply->vendor_id, -+ SAS_EXPANDER_VENDOR_ID_LEN); -+ strncpy(edev->product_id, manufacture_reply->product_id, -+ SAS_EXPANDER_PRODUCT_ID_LEN); -+ strncpy(edev->product_rev, manufacture_reply->product_rev, -+ SAS_EXPANDER_PRODUCT_REV_LEN); -+ edev->level = manufacture_reply->sas_format & 1; -+ if (edev->level) { -+ strncpy(edev->component_vendor_id, -+ manufacture_reply->component_vendor_id, -+ SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); -+ tmp = (u8 *)&manufacture_reply->component_id; -+ edev->component_id = tmp[0] << 8 | tmp[1]; -+ edev->component_revision_id = -+ manufacture_reply->component_revision_id; -+ } -+ } else -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "report_manufacture - no reply\n", ioc->name)); -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ out: -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ if (data_out) -+ pci_free_consistent(ioc->pdev, data_out_sz + data_in_sz, -+ data_out, data_out_dma); -+ -+ mutex_unlock(&ioc->transport_cmds.mutex); -+ return rc; -+} -+ -+ -+/** -+ * _transport_delete_port - helper function to removing a port -+ * @ioc: per adapter object -+ * @mpt2sas_port: mpt3sas per port object -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_delete_port(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_port *mpt2sas_port) -+{ -+ u64 sas_address = mpt2sas_port->remote_identify.sas_address; -+ enum sas_device_type device_type = -+ mpt2sas_port->remote_identify.device_type; -+ -+ dev_printk(KERN_INFO, &mpt2sas_port->port->dev, -+ "remove: sas_addr(0x%016llx)\n", -+ (unsigned long long) sas_address); -+ -+ ioc->logging_level |= MPT_DEBUG_TRANSPORT; -+ if (device_type == SAS_END_DEVICE) -+ mpt2sas_device_remove_by_sas_address(ioc, sas_address); -+ else if (device_type == SAS_EDGE_EXPANDER_DEVICE || -+ device_type == SAS_FANOUT_EXPANDER_DEVICE) -+ mpt2sas_expander_remove(ioc, sas_address); -+ ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; -+} -+ -+/** -+ * _transport_delete_phy - helper function to removing single phy from port -+ * @ioc: per adapter object -+ * @mpt2sas_port: mpt3sas per port object -+ * @mpt2sas_phy: mpt3sas per phy object -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_delete_phy(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy) -+{ -+ u64 sas_address = mpt2sas_port->remote_identify.sas_address; -+ -+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, -+ "remove: sas_addr(0x%016llx), phy(%d)\n", -+ (unsigned long long) sas_address, mpt2sas_phy->phy_id); -+ -+ list_del(&mpt2sas_phy->port_siblings); -+ mpt2sas_port->num_phys--; -+ sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); -+ mpt2sas_phy->phy_belongs_to_port = 0; -+} -+ -+/** -+ * _transport_add_phy - helper function to adding single phy to port -+ * @ioc: per adapter object -+ * @mpt2sas_port: mpt3sas per port object -+ * @mpt2sas_phy: mpt3sas per phy object -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_add_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port, -+ struct _sas_phy *mpt2sas_phy) -+{ -+ u64 sas_address = mpt2sas_port->remote_identify.sas_address; -+ -+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, -+ "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) -+ sas_address, mpt2sas_phy->phy_id); -+ -+ list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list); -+ mpt2sas_port->num_phys++; -+ sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy); -+ mpt2sas_phy->phy_belongs_to_port = 1; -+} -+ -+/** -+ * _transport_add_phy_to_an_existing_port - adding new phy to existing port -+ * @ioc: per adapter object -+ * @sas_node: sas node object (either expander or sas host) -+ * @mpt2sas_phy: mpt3sas per phy object -+ * @sas_address: sas address of device/expander were phy needs to be added to -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, -+ u64 sas_address) -+{ -+ struct _sas_port *mpt2sas_port; -+ struct _sas_phy *phy_srch; -+ -+ if (mpt2sas_phy->phy_belongs_to_port == 1) -+ return; -+ -+ list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, -+ port_list) { -+ if (mpt2sas_port->remote_identify.sas_address != -+ sas_address) -+ continue; -+ list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, -+ port_siblings) { -+ if (phy_srch == mpt2sas_phy) -+ return; -+ } -+ _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy); -+ return; -+ } -+ -+} -+ -+/** -+ * _transport_del_phy_from_an_existing_port - delete phy from existing port -+ * @ioc: per adapter object -+ * @sas_node: sas node object (either expander or sas host) -+ * @mpt2sas_phy: mpt3sas per phy object -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy) -+{ -+ struct _sas_port *mpt2sas_port, *next; -+ struct _sas_phy *phy_srch; -+ -+ if (mpt2sas_phy->phy_belongs_to_port == 0) -+ return; -+ -+ list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, -+ port_list) { -+ list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, -+ port_siblings) { -+ if (phy_srch != mpt2sas_phy) -+ continue; -+ -+ if (mpt2sas_port->num_phys == 1) -+ _transport_delete_port(ioc, mpt2sas_port); -+ else -+ _transport_delete_phy(ioc, mpt2sas_port, -+ mpt2sas_phy); -+ return; -+ } -+ } -+} -+ -+/** -+ * _transport_sanity_check - sanity check when adding a new port -+ * @ioc: per adapter object -+ * @sas_node: sas node object (either expander or sas host) -+ * @sas_address: sas address of device being added -+ * -+ * See the explanation above from _transport_delete_duplicate_port -+ */ -+static void -+_transport_sanity_check(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, -+ u64 sas_address) -+{ -+ int i; -+ -+ for (i = 0; i < sas_node->num_phys; i++) { -+ if (sas_node->phy[i].remote_identify.sas_address != sas_address) -+ continue; -+ if (sas_node->phy[i].phy_belongs_to_port == 1) -+ _transport_del_phy_from_an_existing_port(ioc, sas_node, -+ &sas_node->phy[i]); -+ } -+} -+ -+/** -+ * mpt2sas_transport_port_add - insert port to the list -+ * @ioc: per adapter object -+ * @handle: handle of attached device -+ * @sas_address: sas address of parent expander or sas host -+ * Context: This function will acquire ioc->sas_node_lock. -+ * -+ * Adding new port object to the sas_node->sas_port_list. -+ * -+ * Returns mpt2sas_port. -+ */ -+struct _sas_port * -+mpt2sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u64 sas_address) -+{ -+ struct _sas_phy *mpt2sas_phy, *next; -+ struct _sas_port *mpt2sas_port; -+ unsigned long flags; -+ struct _sas_node *sas_node; -+ struct sas_rphy *rphy; -+ struct _sas_device *sas_device = NULL; -+ int i; -+ struct sas_port *port; -+ -+ mpt2sas_port = kzalloc(sizeof(struct _sas_port), -+ GFP_KERNEL); -+ if (!mpt2sas_port) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return NULL; -+ } -+ -+ INIT_LIST_HEAD(&mpt2sas_port->port_list); -+ INIT_LIST_HEAD(&mpt2sas_port->phy_list); -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ if (!sas_node) { -+ pr_err(MPT3SAS_FMT -+ "%s: Could not find parent sas_address(0x%016llx)!\n", -+ ioc->name, __func__, (unsigned long long)sas_address); -+ goto out_fail; -+ } -+ -+ if ((_transport_set_identify(ioc, handle, -+ &mpt2sas_port->remote_identify))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_fail; -+ } -+ -+ if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_fail; -+ } -+ -+ _transport_sanity_check(ioc, sas_node, -+ mpt2sas_port->remote_identify.sas_address); -+ -+ for (i = 0; i < sas_node->num_phys; i++) { -+ if (sas_node->phy[i].remote_identify.sas_address != -+ mpt2sas_port->remote_identify.sas_address) -+ continue; -+ list_add_tail(&sas_node->phy[i].port_siblings, -+ &mpt2sas_port->phy_list); -+ mpt2sas_port->num_phys++; -+ } -+ -+ if (!mpt2sas_port->num_phys) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_fail; -+ } -+ -+ port = sas_port_alloc_num(sas_node->parent_dev); -+ if ((sas_port_add(port))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_fail; -+ } -+ -+ list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, -+ port_siblings) { -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &port->dev, -+ "add: handle(0x%04x), sas_addr(0x%016llx), phy(%d)\n", -+ handle, (unsigned long long) -+ mpt2sas_port->remote_identify.sas_address, -+ mpt2sas_phy->phy_id); -+ sas_port_add_phy(port, mpt2sas_phy->phy); -+ mpt2sas_phy->phy_belongs_to_port = 1; -+ } -+ -+ mpt2sas_port->port = port; -+ if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) -+ rphy = sas_end_device_alloc(port); -+ else -+ rphy = sas_expander_alloc(port, -+ mpt2sas_port->remote_identify.device_type); -+ -+ rphy->identify = mpt2sas_port->remote_identify; -+ -+ if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) { -+ sas_device = mpt2sas_get_sdev_by_addr(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ if (!sas_device) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__)); -+ goto out_fail; -+ } -+ sas_device->pend_sas_rphy_add = 1; -+ } -+ -+ if ((sas_rphy_add(rphy))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ } -+ -+ if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) { -+ sas_device->pend_sas_rphy_add = 0; -+ sas_device_put(sas_device); -+ } -+ -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &rphy->dev, -+ "add: handle(0x%04x), sas_addr(0x%016llx)\n", -+ handle, (unsigned long long) -+ mpt2sas_port->remote_identify.sas_address); -+ mpt2sas_port->rphy = rphy; -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ /* fill in report manufacture */ -+ if (mpt2sas_port->remote_identify.device_type == -+ MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || -+ mpt2sas_port->remote_identify.device_type == -+ MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) -+ _transport_expander_report_manufacture(ioc, -+ mpt2sas_port->remote_identify.sas_address, -+ rphy_to_expander_device(rphy)); -+ return mpt2sas_port; -+ -+ out_fail: -+ list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list, -+ port_siblings) -+ list_del(&mpt2sas_phy->port_siblings); -+ kfree(mpt2sas_port); -+ return NULL; -+} -+ -+/** -+ * mpt2sas_transport_port_remove - remove port from the list -+ * @ioc: per adapter object -+ * @sas_address: sas address of attached device -+ * @sas_address_parent: sas address of parent expander or sas host -+ * Context: This function will acquire ioc->sas_node_lock. -+ * -+ * Removing object and freeing associated memory from the -+ * ioc->sas_port_list. -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, -+ u64 sas_address_parent) -+{ -+ int i; -+ unsigned long flags; -+ struct _sas_port *mpt2sas_port, *next; -+ struct _sas_node *sas_node; -+ u8 found = 0; -+ struct _sas_phy *mpt2sas_phy, *next_phy; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_node = _transport_sas_node_find_by_sas_address(ioc, -+ sas_address_parent); -+ if (!sas_node) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return; -+ } -+ list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, -+ port_list) { -+ if (mpt2sas_port->remote_identify.sas_address != sas_address) -+ continue; -+ found = 1; -+ list_del(&mpt2sas_port->port_list); -+ goto out; -+ } -+ out: -+ if (!found) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return; -+ } -+ -+ for (i = 0; i < sas_node->num_phys; i++) { -+ if (sas_node->phy[i].remote_identify.sas_address == sas_address) -+ memset(&sas_node->phy[i].remote_identify, 0 , -+ sizeof(struct sas_identify)); -+ } -+ -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ list_for_each_entry_safe(mpt2sas_phy, next_phy, -+ &mpt2sas_port->phy_list, port_siblings) { -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &mpt2sas_port->port->dev, -+ "remove: sas_addr(0x%016llx), phy(%d)\n", -+ (unsigned long long) -+ mpt2sas_port->remote_identify.sas_address, -+ mpt2sas_phy->phy_id); -+ mpt2sas_phy->phy_belongs_to_port = 0; -+ sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); -+ list_del(&mpt2sas_phy->port_siblings); -+ } -+ sas_port_delete(mpt2sas_port->port); -+ kfree(mpt2sas_port); -+} -+ -+/** -+ * mpt2sas_transport_add_host_phy - report sas_host phy to transport -+ * @ioc: per adapter object -+ * @mpt2sas_phy: mpt3sas per phy object -+ * @phy_pg0: sas phy page 0 -+ * @parent_dev: parent device class object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy -+ *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev) -+{ -+ struct sas_phy *phy; -+ int phy_index = mpt2sas_phy->phy_id; -+ -+ -+ INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); -+ phy = sas_phy_alloc(parent_dev, phy_index); -+ if (!phy) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ if ((_transport_set_identify(ioc, mpt2sas_phy->handle, -+ &mpt2sas_phy->identify))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_phy_free(phy); -+ return -1; -+ } -+ phy->identify = mpt2sas_phy->identify; -+ mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle); -+ if (mpt2sas_phy->attached_handle) -+ _transport_set_identify(ioc, mpt2sas_phy->attached_handle, -+ &mpt2sas_phy->remote_identify); -+ phy->identify.phy_identifier = mpt2sas_phy->phy_id; -+ phy->negotiated_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); -+ phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( -+ phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( -+ phy_pg0.HwLinkRate >> 4); -+ phy->minimum_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.ProgrammedLinkRate >> 4); -+ -+ if ((sas_phy_add(phy))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_phy_free(phy); -+ return -1; -+ } -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &phy->dev, -+ "add: handle(0x%04x), sas_addr(0x%016llx)\n" -+ "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", -+ mpt2sas_phy->handle, (unsigned long long) -+ mpt2sas_phy->identify.sas_address, -+ mpt2sas_phy->attached_handle, -+ (unsigned long long) -+ mpt2sas_phy->remote_identify.sas_address); -+ mpt2sas_phy->phy = phy; -+ return 0; -+} -+ -+ -+/** -+ * mpt2sas_transport_add_expander_phy - report expander phy to transport -+ * @ioc: per adapter object -+ * @mpt2sas_phy: mpt3sas per phy object -+ * @expander_pg1: expander page 1 -+ * @parent_dev: parent device class object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy -+ *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, -+ struct device *parent_dev) -+{ -+ struct sas_phy *phy; -+ int phy_index = mpt2sas_phy->phy_id; -+ -+ INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); -+ phy = sas_phy_alloc(parent_dev, phy_index); -+ if (!phy) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ if ((_transport_set_identify(ioc, mpt2sas_phy->handle, -+ &mpt2sas_phy->identify))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_phy_free(phy); -+ return -1; -+ } -+ phy->identify = mpt2sas_phy->identify; -+ mpt2sas_phy->attached_handle = -+ le16_to_cpu(expander_pg1.AttachedDevHandle); -+ if (mpt2sas_phy->attached_handle) -+ _transport_set_identify(ioc, mpt2sas_phy->attached_handle, -+ &mpt2sas_phy->remote_identify); -+ phy->identify.phy_identifier = mpt2sas_phy->phy_id; -+ phy->negotiated_linkrate = _transport_convert_phy_link_rate( -+ expander_pg1.NegotiatedLinkRate & -+ MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); -+ phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( -+ expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( -+ expander_pg1.HwLinkRate >> 4); -+ phy->minimum_linkrate = _transport_convert_phy_link_rate( -+ expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate = _transport_convert_phy_link_rate( -+ expander_pg1.ProgrammedLinkRate >> 4); -+ -+ if ((sas_phy_add(phy))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_phy_free(phy); -+ return -1; -+ } -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &phy->dev, -+ "add: handle(0x%04x), sas_addr(0x%016llx)\n" -+ "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", -+ mpt2sas_phy->handle, (unsigned long long) -+ mpt2sas_phy->identify.sas_address, -+ mpt2sas_phy->attached_handle, -+ (unsigned long long) -+ mpt2sas_phy->remote_identify.sas_address); -+ mpt2sas_phy->phy = phy; -+ return 0; -+} -+ -+/** -+ * mpt2sas_transport_update_links - refreshing phy link changes -+ * @ioc: per adapter object -+ * @sas_address: sas address of parent expander or sas host -+ * @handle: attached device handle -+ * @phy_numberv: phy number -+ * @link_rate: new link rate -+ * -+ * Returns nothing. -+ */ -+void -+mpt2sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) -+{ -+ unsigned long flags; -+ struct _sas_node *sas_node; -+ struct _sas_phy *mpt2sas_phy; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); -+ if (!sas_node) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return; -+ } -+ -+ mpt2sas_phy = &sas_node->phy[phy_number]; -+ mpt2sas_phy->attached_handle = handle; -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { -+ _transport_set_identify(ioc, handle, -+ &mpt2sas_phy->remote_identify); -+ _transport_add_phy_to_an_existing_port(ioc, sas_node, -+ mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address); -+ } else -+ memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct -+ sas_identify)); -+ -+ if (mpt2sas_phy->phy) -+ mpt2sas_phy->phy->negotiated_linkrate = -+ _transport_convert_phy_link_rate(link_rate); -+ -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, -+ "refresh: parent sas_addr(0x%016llx),\n" -+ "\tlink_rate(0x%02x), phy(%d)\n" -+ "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", -+ (unsigned long long)sas_address, -+ link_rate, phy_number, handle, (unsigned long long) -+ mpt2sas_phy->remote_identify.sas_address); -+} -+ -+static inline void * -+phy_to_ioc(struct sas_phy *phy) -+{ -+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); -+ return shost_priv(shost); -+} -+ -+static inline void * -+rphy_to_ioc(struct sas_rphy *rphy) -+{ -+ struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); -+ return shost_priv(shost); -+} -+ -+/* report phy error log structure */ -+struct phy_error_log_request { -+ u8 smp_frame_type; /* 0x40 */ -+ u8 function; /* 0x11 */ -+ u8 allocated_response_length; -+ u8 request_length; /* 02 */ -+ u8 reserved_1[5]; -+ u8 phy_identifier; -+ u8 reserved_2[2]; -+}; -+ -+/* report phy error log reply structure */ -+struct phy_error_log_reply { -+ u8 smp_frame_type; /* 0x41 */ -+ u8 function; /* 0x11 */ -+ u8 function_result; -+ u8 response_length; -+ __be16 expander_change_count; -+ u8 reserved_1[3]; -+ u8 phy_identifier; -+ u8 reserved_2[2]; -+ __be32 invalid_dword; -+ __be32 running_disparity_error; -+ __be32 loss_of_dword_sync; -+ __be32 phy_reset_problem; -+}; -+ -+/** -+ * _transport_get_expander_phy_error_log - return expander counters -+ * @ioc: per adapter object -+ * @phy: The sas phy object -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ */ -+static int -+_transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, -+ struct sas_phy *phy) -+{ -+ Mpi2SmpPassthroughRequest_t *mpi_request; -+ Mpi2SmpPassthroughReply_t *mpi_reply; -+ struct phy_error_log_request *phy_error_log_request; -+ struct phy_error_log_reply *phy_error_log_reply; -+ int rc; -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ void *psge; -+ u8 issue_reset = 0; -+ void *data_out = NULL; -+ dma_addr_t data_out_dma; -+ u32 sz; -+ u16 wait_state_count; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ mutex_lock(&ioc->transport_cmds.mutex); -+ -+ if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->transport_cmds.status = MPT3_CMD_PENDING; -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->transport_cmds.smid = smid; -+ -+ sz = sizeof(struct phy_error_log_request) + -+ sizeof(struct phy_error_log_reply); -+ data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); -+ if (!data_out) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ rc = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ -+ rc = -EINVAL; -+ memset(data_out, 0, sz); -+ phy_error_log_request = data_out; -+ phy_error_log_request->smp_frame_type = 0x40; -+ phy_error_log_request->function = 0x11; -+ phy_error_log_request->request_length = 2; -+ phy_error_log_request->allocated_response_length = 0; -+ phy_error_log_request->phy_identifier = phy->number; -+ -+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; -+ mpi_request->PhysicalPort = 0xFF; -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); -+ mpi_request->RequestDataLength = -+ cpu_to_le16(sizeof(struct phy_error_log_request)); -+ psge = &mpi_request->SGL; -+ -+ ioc->build_sg(ioc, psge, data_out_dma, -+ sizeof(struct phy_error_log_request), -+ data_out_dma + sizeof(struct phy_error_log_request), -+ sizeof(struct phy_error_log_reply)); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - send to sas_addr(0x%016llx), phy(%d)\n", -+ ioc->name, (unsigned long long)phy->identify.sas_address, -+ phy->number)); -+ init_completion(&ioc->transport_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, -+ 10*HZ); -+ -+ if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SmpPassthroughRequest_t)/4); -+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - complete\n", ioc->name)); -+ -+ if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { -+ -+ mpi_reply = ioc->transport_cmds.reply; -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - reply data transfer size(%d)\n", -+ ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); -+ -+ if (le16_to_cpu(mpi_reply->ResponseDataLength) != -+ sizeof(struct phy_error_log_reply)) -+ goto out; -+ -+ phy_error_log_reply = data_out + -+ sizeof(struct phy_error_log_request); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - function_result(%d)\n", -+ ioc->name, phy_error_log_reply->function_result)); -+ -+ phy->invalid_dword_count = -+ be32_to_cpu(phy_error_log_reply->invalid_dword); -+ phy->running_disparity_error_count = -+ be32_to_cpu(phy_error_log_reply->running_disparity_error); -+ phy->loss_of_dword_sync_count = -+ be32_to_cpu(phy_error_log_reply->loss_of_dword_sync); -+ phy->phy_reset_problem_count = -+ be32_to_cpu(phy_error_log_reply->phy_reset_problem); -+ rc = 0; -+ } else -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - no reply\n", ioc->name)); -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ out: -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ if (data_out) -+ pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); -+ -+ mutex_unlock(&ioc->transport_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * _transport_get_linkerrors - return phy counters for both hba and expanders -+ * @phy: The sas phy object -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ */ -+static int -+_transport_get_linkerrors(struct sas_phy *phy) -+{ -+ struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); -+ unsigned long flags; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasPhyPage1_t phy_pg1; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ if (_transport_sas_node_find_by_sas_address(ioc, -+ phy->identify.sas_address) == NULL) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return -EINVAL; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) -+ return _transport_get_expander_phy_error_log(ioc, phy); -+ -+ /* get hba phy error logs */ -+ if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, -+ phy->number))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -ENXIO; -+ } -+ -+ if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) -+ pr_info(MPT3SAS_FMT -+ "phy(%d), ioc_status (0x%04x), loginfo(0x%08x)\n", -+ ioc->name, phy->number, -+ le16_to_cpu(mpi_reply.IOCStatus), -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ -+ phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount); -+ phy->running_disparity_error_count = -+ le32_to_cpu(phy_pg1.RunningDisparityErrorCount); -+ phy->loss_of_dword_sync_count = -+ le32_to_cpu(phy_pg1.LossDwordSynchCount); -+ phy->phy_reset_problem_count = -+ le32_to_cpu(phy_pg1.PhyResetProblemCount); -+ return 0; -+} -+ -+/** -+ * _transport_get_enclosure_identifier - -+ * @phy: The sas phy object -+ * -+ * Obtain the enclosure logical id for an expander. -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) -+{ -+ struct MPT3SAS_ADAPTER *ioc = rphy_to_ioc(rphy); -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ int rc; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ rphy->identify.sas_address); -+ if (sas_device) { -+ *identifier = sas_device->enclosure_logical_id; -+ rc = 0; -+ sas_device_put(sas_device); -+ } else { -+ *identifier = 0; -+ rc = -ENXIO; -+ } -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ return rc; -+} -+ -+/** -+ * _transport_get_bay_identifier - -+ * @phy: The sas phy object -+ * -+ * Returns the slot id for a device that resides inside an enclosure. -+ */ -+static int -+_transport_get_bay_identifier(struct sas_rphy *rphy) -+{ -+ struct MPT3SAS_ADAPTER *ioc = rphy_to_ioc(rphy); -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ int rc; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ rphy->identify.sas_address); -+ if (sas_device) { -+ rc = sas_device->slot; -+ sas_device_put(sas_device); -+ } else { -+ rc = -ENXIO; -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ return rc; -+} -+ -+/* phy control request structure */ -+struct phy_control_request { -+ u8 smp_frame_type; /* 0x40 */ -+ u8 function; /* 0x91 */ -+ u8 allocated_response_length; -+ u8 request_length; /* 0x09 */ -+ u16 expander_change_count; -+ u8 reserved_1[3]; -+ u8 phy_identifier; -+ u8 phy_operation; -+ u8 reserved_2[13]; -+ u64 attached_device_name; -+ u8 programmed_min_physical_link_rate; -+ u8 programmed_max_physical_link_rate; -+ u8 reserved_3[6]; -+}; -+ -+/* phy control reply structure */ -+struct phy_control_reply { -+ u8 smp_frame_type; /* 0x41 */ -+ u8 function; /* 0x11 */ -+ u8 function_result; -+ u8 response_length; -+}; -+ -+#define SMP_PHY_CONTROL_LINK_RESET (0x01) -+#define SMP_PHY_CONTROL_HARD_RESET (0x02) -+#define SMP_PHY_CONTROL_DISABLE (0x03) -+ -+/** -+ * _transport_expander_phy_control - expander phy control -+ * @ioc: per adapter object -+ * @phy: The sas phy object -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ */ -+static int -+_transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, -+ struct sas_phy *phy, u8 phy_operation) -+{ -+ Mpi2SmpPassthroughRequest_t *mpi_request; -+ Mpi2SmpPassthroughReply_t *mpi_reply; -+ struct phy_control_request *phy_control_request; -+ struct phy_control_reply *phy_control_reply; -+ int rc; -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ void *psge; -+ u8 issue_reset = 0; -+ void *data_out = NULL; -+ dma_addr_t data_out_dma; -+ u32 sz; -+ u16 wait_state_count; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ mutex_lock(&ioc->transport_cmds.mutex); -+ -+ if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->transport_cmds.status = MPT3_CMD_PENDING; -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->transport_cmds.smid = smid; -+ -+ sz = sizeof(struct phy_control_request) + -+ sizeof(struct phy_control_reply); -+ data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); -+ if (!data_out) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ rc = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ -+ rc = -EINVAL; -+ memset(data_out, 0, sz); -+ phy_control_request = data_out; -+ phy_control_request->smp_frame_type = 0x40; -+ phy_control_request->function = 0x91; -+ phy_control_request->request_length = 9; -+ phy_control_request->allocated_response_length = 0; -+ phy_control_request->phy_identifier = phy->number; -+ phy_control_request->phy_operation = phy_operation; -+ phy_control_request->programmed_min_physical_link_rate = -+ phy->minimum_linkrate << 4; -+ phy_control_request->programmed_max_physical_link_rate = -+ phy->maximum_linkrate << 4; -+ -+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; -+ mpi_request->PhysicalPort = 0xFF; -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); -+ mpi_request->RequestDataLength = -+ cpu_to_le16(sizeof(struct phy_error_log_request)); -+ psge = &mpi_request->SGL; -+ -+ ioc->build_sg(ioc, psge, data_out_dma, -+ sizeof(struct phy_control_request), -+ data_out_dma + sizeof(struct phy_control_request), -+ sizeof(struct phy_control_reply)); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", -+ ioc->name, (unsigned long long)phy->identify.sas_address, -+ phy->number, phy_operation)); -+ init_completion(&ioc->transport_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, -+ 10*HZ); -+ -+ if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SmpPassthroughRequest_t)/4); -+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - complete\n", ioc->name)); -+ -+ if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { -+ -+ mpi_reply = ioc->transport_cmds.reply; -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - reply data transfer size(%d)\n", -+ ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); -+ -+ if (le16_to_cpu(mpi_reply->ResponseDataLength) != -+ sizeof(struct phy_control_reply)) -+ goto out; -+ -+ phy_control_reply = data_out + -+ sizeof(struct phy_control_request); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - function_result(%d)\n", -+ ioc->name, phy_control_reply->function_result)); -+ -+ rc = 0; -+ } else -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - no reply\n", ioc->name)); -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ out: -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ if (data_out) -+ pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); -+ -+ mutex_unlock(&ioc->transport_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * _transport_phy_reset - -+ * @phy: The sas phy object -+ * @hard_reset: -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_phy_reset(struct sas_phy *phy, int hard_reset) -+{ -+ struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); -+ Mpi2SasIoUnitControlReply_t mpi_reply; -+ Mpi2SasIoUnitControlRequest_t mpi_request; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ if (_transport_sas_node_find_by_sas_address(ioc, -+ phy->identify.sas_address) == NULL) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return -EINVAL; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ /* handle expander phys */ -+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) -+ return _transport_expander_phy_control(ioc, phy, -+ (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET : -+ SMP_PHY_CONTROL_LINK_RESET); -+ -+ /* handle hba phys */ -+ memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; -+ mpi_request.Operation = hard_reset ? -+ MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET; -+ mpi_request.PhyNum = phy->number; -+ -+ if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -ENXIO; -+ } -+ -+ if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) -+ pr_info(MPT3SAS_FMT -+ "phy(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, phy->number, le16_to_cpu(mpi_reply.IOCStatus), -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ -+ return 0; -+} -+ -+/** -+ * _transport_phy_enable - enable/disable phys -+ * @phy: The sas phy object -+ * @enable: enable phy when true -+ * -+ * Only support sas_host direct attached phys. -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_phy_enable(struct sas_phy *phy, int enable) -+{ -+ struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); -+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; -+ Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u16 sz; -+ int rc = 0; -+ unsigned long flags; -+ int i, discovery_active; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ if (_transport_sas_node_find_by_sas_address(ioc, -+ phy->identify.sas_address) == NULL) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return -EINVAL; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ /* handle expander phys */ -+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) -+ return _transport_expander_phy_control(ioc, phy, -+ (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET : -+ SMP_PHY_CONTROL_DISABLE); -+ -+ /* handle hba phys */ -+ -+ /* read sas_iounit page 0 */ -+ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit0PhyData_t)); -+ sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENOMEM; -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, -+ sas_iounit_pg0, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENXIO; -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -EIO; -+ goto out; -+ } -+ -+ /* unable to enable/disable phys when when discovery is active */ -+ for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) { -+ if (sas_iounit_pg0->PhyData[i].PortFlags & -+ MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) { -+ pr_err(MPT3SAS_FMT "discovery is active on " \ -+ "port = %d, phy = %d: unable to enable/disable " -+ "phys, try again later!\n", ioc->name, -+ sas_iounit_pg0->PhyData[i].Port, i); -+ discovery_active = 1; -+ } -+ } -+ -+ if (discovery_active) { -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ /* read sas_iounit page 1 */ -+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit1PhyData_t)); -+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg1) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENOMEM; -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, -+ sas_iounit_pg1, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENXIO; -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -EIO; -+ goto out; -+ } -+ -+ /* copy Port/PortFlags/PhyFlags from page 0 */ -+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) { -+ sas_iounit_pg1->PhyData[i].Port = -+ sas_iounit_pg0->PhyData[i].Port; -+ sas_iounit_pg1->PhyData[i].PortFlags = -+ (sas_iounit_pg0->PhyData[i].PortFlags & -+ MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG); -+ sas_iounit_pg1->PhyData[i].PhyFlags = -+ (sas_iounit_pg0->PhyData[i].PhyFlags & -+ (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED + -+ MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)); -+ } -+ -+ if (enable) -+ sas_iounit_pg1->PhyData[phy->number].PhyFlags -+ &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; -+ else -+ sas_iounit_pg1->PhyData[phy->number].PhyFlags -+ |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; -+ -+ mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); -+ -+ /* link reset */ -+ if (enable) -+ _transport_phy_reset(phy, 0); -+ -+ out: -+ kfree(sas_iounit_pg1); -+ kfree(sas_iounit_pg0); -+ return rc; -+} -+ -+/** -+ * _transport_phy_speed - set phy min/max link rates -+ * @phy: The sas phy object -+ * @rates: rates defined in sas_phy_linkrates -+ * -+ * Only support sas_host direct attached phys. -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) -+{ -+ struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); -+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; -+ Mpi2SasPhyPage0_t phy_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u16 sz; -+ int i; -+ int rc = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ if (_transport_sas_node_find_by_sas_address(ioc, -+ phy->identify.sas_address) == NULL) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return -EINVAL; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ if (!rates->minimum_linkrate) -+ rates->minimum_linkrate = phy->minimum_linkrate; -+ else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) -+ rates->minimum_linkrate = phy->minimum_linkrate_hw; -+ -+ if (!rates->maximum_linkrate) -+ rates->maximum_linkrate = phy->maximum_linkrate; -+ else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) -+ rates->maximum_linkrate = phy->maximum_linkrate_hw; -+ -+ /* handle expander phys */ -+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) { -+ phy->minimum_linkrate = rates->minimum_linkrate; -+ phy->maximum_linkrate = rates->maximum_linkrate; -+ return _transport_expander_phy_control(ioc, phy, -+ SMP_PHY_CONTROL_LINK_RESET); -+ } -+ -+ /* handle hba phys */ -+ -+ /* sas_iounit page 1 */ -+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit1PhyData_t)); -+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg1) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENOMEM; -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, -+ sas_iounit_pg1, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENXIO; -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -EIO; -+ goto out; -+ } -+ -+ for (i = 0; i < ioc->sas_hba.num_phys; i++) { -+ if (phy->number != i) { -+ sas_iounit_pg1->PhyData[i].MaxMinLinkRate = -+ (ioc->sas_hba.phy[i].phy->minimum_linkrate + -+ (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); -+ } else { -+ sas_iounit_pg1->PhyData[i].MaxMinLinkRate = -+ (rates->minimum_linkrate + -+ (rates->maximum_linkrate << 4)); -+ } -+ } -+ -+ if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, -+ sz)) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENXIO; -+ goto out; -+ } -+ -+ /* link reset */ -+ _transport_phy_reset(phy, 0); -+ -+ /* read phy page 0, then update the rates in the sas transport phy */ -+ if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, -+ phy->number)) { -+ phy->minimum_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.ProgrammedLinkRate >> 4); -+ phy->negotiated_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.NegotiatedLinkRate & -+ MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); -+ } -+ -+ out: -+ kfree(sas_iounit_pg1); -+ return rc; -+} -+ -+/** -+ * _transport_smp_handler - transport portal for smp passthru -+ * @shost: shost object -+ * @rphy: sas transport rphy object -+ * @req: -+ * -+ * This used primarily for smp_utils. -+ * Example: -+ * smp_rep_general /sys/class/bsg/expander-5:0 -+ */ -+static int -+_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, -+ struct request *req) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ Mpi2SmpPassthroughRequest_t *mpi_request; -+ Mpi2SmpPassthroughReply_t *mpi_reply; -+ int rc, i; -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ void *psge; -+ u8 issue_reset = 0; -+ dma_addr_t dma_addr_in = 0; -+ dma_addr_t dma_addr_out = 0; -+ dma_addr_t pci_dma_in = 0; -+ dma_addr_t pci_dma_out = 0; -+ void *pci_addr_in = NULL; -+ void *pci_addr_out = NULL; -+ u16 wait_state_count; -+ struct request *rsp = req->next_rq; -+ struct bio_vec *bvec = NULL; -+ -+ if (!rsp) { -+ pr_err(MPT3SAS_FMT "%s: the smp response space is missing\n", -+ ioc->name, __func__); -+ return -EINVAL; -+ } -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); -+ if (rc) -+ return rc; -+ -+ if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name, -+ __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->transport_cmds.status = MPT3_CMD_PENDING; -+ -+ /* Check if the request is split across multiple segments */ -+ if (req->bio->bi_vcnt > 1) { -+ u32 offset = 0; -+ -+ /* Allocate memory and copy the request */ -+ pci_addr_out = pci_alloc_consistent(ioc->pdev, -+ blk_rq_bytes(req), &pci_dma_out); -+ if (!pci_addr_out) { -+ pr_info(MPT3SAS_FMT "%s(): PCI Addr out = NULL\n", -+ ioc->name, __func__); -+ rc = -ENOMEM; -+ goto out; -+ } -+ -+ bio_for_each_segment(bvec, req->bio, i) { -+ memcpy(pci_addr_out + offset, -+ page_address(bvec->bv_page) + bvec->bv_offset, -+ bvec->bv_len); -+ offset += bvec->bv_len; -+ } -+ } else { -+ dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), -+ blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); -+ if (pci_dma_mapping_error(ioc->pdev, dma_addr_out)) { -+ pr_info(MPT3SAS_FMT "%s(): DMA Addr out = NULL\n", -+ ioc->name, __func__); -+ rc = -ENOMEM; -+ goto free_pci; -+ } -+ } -+ -+ /* Check if the response needs to be populated across -+ * multiple segments */ -+ if (rsp->bio->bi_vcnt > 1) { -+ pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), -+ &pci_dma_in); -+ if (!pci_addr_in) { -+ pr_info(MPT3SAS_FMT "%s(): PCI Addr in = NULL\n", -+ ioc->name, __func__); -+ rc = -ENOMEM; -+ goto unmap; -+ } -+ } else { -+ dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), -+ blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); -+ if (pci_dma_mapping_error(ioc->pdev, dma_addr_in)) { -+ pr_info(MPT3SAS_FMT "%s(): DMA Addr in = NULL\n", -+ ioc->name, __func__); -+ rc = -ENOMEM; -+ goto unmap; -+ } -+ } -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto unmap; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto unmap; -+ } -+ -+ rc = 0; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->transport_cmds.smid = smid; -+ -+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; -+ mpi_request->PhysicalPort = 0xFF; -+ mpi_request->SASAddress = (rphy) ? -+ cpu_to_le64(rphy->identify.sas_address) : -+ cpu_to_le64(ioc->sas_hba.sas_address); -+ mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); -+ psge = &mpi_request->SGL; -+ -+ if (req->bio->bi_vcnt > 1) -+ ioc->build_sg(ioc, psge, pci_dma_out, (blk_rq_bytes(req) - 4), -+ pci_dma_in, (blk_rq_bytes(rsp) + 4)); -+ else -+ ioc->build_sg(ioc, psge, dma_addr_out, (blk_rq_bytes(req) - 4), -+ dma_addr_in, (blk_rq_bytes(rsp) + 4)); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - sending smp request\n", ioc->name, __func__)); -+ -+ init_completion(&ioc->transport_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, -+ 10*HZ); -+ -+ if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s : timeout\n", -+ __func__, ioc->name); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SmpPassthroughRequest_t)/4); -+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - complete\n", ioc->name, __func__)); -+ -+ if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { -+ -+ mpi_reply = ioc->transport_cmds.reply; -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - reply data transfer size(%d)\n", -+ ioc->name, __func__, -+ le16_to_cpu(mpi_reply->ResponseDataLength))); -+ -+ memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); -+ req->sense_len = sizeof(*mpi_reply); -+ req->resid_len = 0; -+ rsp->resid_len -= -+ le16_to_cpu(mpi_reply->ResponseDataLength); -+ -+ /* check if the resp needs to be copied from the allocated -+ * pci mem */ -+ if (rsp->bio->bi_vcnt > 1) { -+ u32 offset = 0; -+ u32 bytes_to_copy = -+ le16_to_cpu(mpi_reply->ResponseDataLength); -+ bio_for_each_segment(bvec, rsp->bio, i) { -+ if (bytes_to_copy <= bvec->bv_len) { -+ memcpy(page_address(bvec->bv_page) + -+ bvec->bv_offset, pci_addr_in + -+ offset, bytes_to_copy); -+ break; -+ } else { -+ memcpy(page_address(bvec->bv_page) + -+ bvec->bv_offset, pci_addr_in + -+ offset, bvec->bv_len); -+ bytes_to_copy -= bvec->bv_len; -+ } -+ offset += bvec->bv_len; -+ } -+ } -+ } else { -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - no reply\n", ioc->name, __func__)); -+ rc = -ENXIO; -+ } -+ -+ issue_host_reset: -+ if (issue_reset) { -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ rc = -ETIMEDOUT; -+ } -+ -+ unmap: -+ if (dma_addr_out) -+ pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req), -+ PCI_DMA_BIDIRECTIONAL); -+ if (dma_addr_in) -+ pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), -+ PCI_DMA_BIDIRECTIONAL); -+ -+ free_pci: -+ if (pci_addr_out) -+ pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out, -+ pci_dma_out); -+ -+ if (pci_addr_in) -+ pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in, -+ pci_dma_in); -+ -+ out: -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_unlock(&ioc->transport_cmds.mutex); -+ return rc; -+} -+ -+struct sas_function_template mpt2sas_transport_functions = { -+ .get_linkerrors = _transport_get_linkerrors, -+ .get_enclosure_identifier = _transport_get_enclosure_identifier, -+ .get_bay_identifier = _transport_get_bay_identifier, -+ .phy_reset = _transport_phy_reset, -+ .phy_enable = _transport_phy_enable, -+ .set_phy_speed = _transport_phy_speed, -+ .smp_handler = _transport_smp_handler, -+}; -+ -+struct scsi_transport_template *mpt2sas_transport_template; -diff --git a/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c -new file mode 100644 -index 0000000..d5038ec ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c -@@ -0,0 +1,434 @@ -+/* -+ * This module provides common API to set Diagnostic trigger for MPT -+ * (Message Passing Technology) based controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+/** -+ * _mpt2sas_raise_sigio - notifiy app -+ * @ioc: per adapter object -+ * @event_data: -+ */ -+static void -+_mpt2sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) -+{ -+ Mpi2EventNotificationReply_t *mpi_reply; -+ u16 sz, event_data_sz; -+ unsigned long flags; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", -+ ioc->name, __func__)); -+ -+ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + -+ sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4; -+ mpi_reply = kzalloc(sz, GFP_KERNEL); -+ if (!mpi_reply) -+ goto out; -+ mpi_reply->Event = cpu_to_le16(MPI3_EVENT_DIAGNOSTIC_TRIGGER_FIRED); -+ event_data_sz = (sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4) / 4; -+ mpi_reply->EventDataLength = cpu_to_le16(event_data_sz); -+ memcpy(&mpi_reply->EventData, event_data, -+ sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: add to driver event log\n", -+ ioc->name, __func__)); -+ mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); -+ kfree(mpi_reply); -+ out: -+ -+ /* clearing the diag_trigger_active flag */ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: clearing diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ ioc->diag_trigger_active = 0; -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_process_trigger_data - process the event data for the trigger -+ * @ioc: per adapter object -+ * @event_data: -+ */ -+void -+mpt2sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) -+{ -+ u8 issue_reset = 0; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", -+ ioc->name, __func__)); -+ -+ /* release the diag buffer trace */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: release trace diag buffer\n", ioc->name, __func__)); -+ mpt2sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, -+ &issue_reset); -+ } -+ -+ _mpt2sas_raise_sigio(ioc, event_data); -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_trigger_master - Master trigger handler -+ * @ioc: per adapter object -+ * @trigger_bitmask: -+ * -+ */ -+void -+mpt2sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask) -+{ -+ struct SL_WH_TRIGGERS_EVENT_DATA_T event_data; -+ unsigned long flags; -+ u8 found_match = 0; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ -+ if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT || -+ trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET) -+ goto by_pass_checks; -+ -+ /* check to see if trace buffers are currently registered */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ /* check to see if trace buffers are currently released */ -+ if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ by_pass_checks: -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter - trigger_bitmask = 0x%08x\n", -+ ioc->name, __func__, trigger_bitmask)); -+ -+ /* don't send trigger if an trigger is currently active */ -+ if (ioc->diag_trigger_active) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ goto out; -+ } -+ -+ /* check for the trigger condition */ -+ if (ioc->diag_trigger_master.MasterData & trigger_bitmask) { -+ found_match = 1; -+ ioc->diag_trigger_active = 1; -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ } -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ if (!found_match) -+ goto out; -+ -+ memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ event_data.trigger_type = MPT3SAS_TRIGGER_MASTER; -+ event_data.u.master.MasterData = trigger_bitmask; -+ -+ if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT || -+ trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET) -+ _mpt2sas_raise_sigio(ioc, &event_data); -+ else -+ mpt2sas_send_trigger_data_event(ioc, &event_data); -+ -+ out: -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_trigger_event - Event trigger handler -+ * @ioc: per adapter object -+ * @event: -+ * @log_entry_qualifier: -+ * -+ */ -+void -+mpt2sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event, -+ u16 log_entry_qualifier) -+{ -+ struct SL_WH_TRIGGERS_EVENT_DATA_T event_data; -+ struct SL_WH_EVENT_TRIGGER_T *event_trigger; -+ int i; -+ unsigned long flags; -+ u8 found_match; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ -+ /* check to see if trace buffers are currently registered */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ /* check to see if trace buffers are currently released */ -+ if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n", -+ ioc->name, __func__, event, log_entry_qualifier)); -+ -+ /* don't send trigger if an trigger is currently active */ -+ if (ioc->diag_trigger_active) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ goto out; -+ } -+ -+ /* check for the trigger condition */ -+ event_trigger = ioc->diag_trigger_event.EventTriggerEntry; -+ for (i = 0 , found_match = 0; i < ioc->diag_trigger_event.ValidEntries -+ && !found_match; i++, event_trigger++) { -+ if (event_trigger->EventValue != event) -+ continue; -+ if (event == MPI2_EVENT_LOG_ENTRY_ADDED) { -+ if (event_trigger->LogEntryQualifier == -+ log_entry_qualifier) -+ found_match = 1; -+ continue; -+ } -+ found_match = 1; -+ ioc->diag_trigger_active = 1; -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ } -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ if (!found_match) -+ goto out; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ event_data.trigger_type = MPT3SAS_TRIGGER_EVENT; -+ event_data.u.event.EventValue = event; -+ event_data.u.event.LogEntryQualifier = log_entry_qualifier; -+ mpt2sas_send_trigger_data_event(ioc, &event_data); -+ out: -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_trigger_scsi - SCSI trigger handler -+ * @ioc: per adapter object -+ * @sense_key: -+ * @asc: -+ * @ascq: -+ * -+ */ -+void -+mpt2sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc, -+ u8 ascq) -+{ -+ struct SL_WH_TRIGGERS_EVENT_DATA_T event_data; -+ struct SL_WH_SCSI_TRIGGER_T *scsi_trigger; -+ int i; -+ unsigned long flags; -+ u8 found_match; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ -+ /* check to see if trace buffers are currently registered */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ /* check to see if trace buffers are currently released */ -+ if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n", -+ ioc->name, __func__, sense_key, asc, ascq)); -+ -+ /* don't send trigger if an trigger is currently active */ -+ if (ioc->diag_trigger_active) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ goto out; -+ } -+ -+ /* check for the trigger condition */ -+ scsi_trigger = ioc->diag_trigger_scsi.SCSITriggerEntry; -+ for (i = 0 , found_match = 0; i < ioc->diag_trigger_scsi.ValidEntries -+ && !found_match; i++, scsi_trigger++) { -+ if (scsi_trigger->SenseKey != sense_key) -+ continue; -+ if (!(scsi_trigger->ASC == 0xFF || scsi_trigger->ASC == asc)) -+ continue; -+ if (!(scsi_trigger->ASCQ == 0xFF || scsi_trigger->ASCQ == ascq)) -+ continue; -+ found_match = 1; -+ ioc->diag_trigger_active = 1; -+ } -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ if (!found_match) -+ goto out; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ event_data.trigger_type = MPT3SAS_TRIGGER_SCSI; -+ event_data.u.scsi.SenseKey = sense_key; -+ event_data.u.scsi.ASC = asc; -+ event_data.u.scsi.ASCQ = ascq; -+ mpt2sas_send_trigger_data_event(ioc, &event_data); -+ out: -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_trigger_mpi - MPI trigger handler -+ * @ioc: per adapter object -+ * @ioc_status: -+ * @loginfo: -+ * -+ */ -+void -+mpt2sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo) -+{ -+ struct SL_WH_TRIGGERS_EVENT_DATA_T event_data; -+ struct SL_WH_MPI_TRIGGER_T *mpi_trigger; -+ int i; -+ unsigned long flags; -+ u8 found_match; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ -+ /* check to see if trace buffers are currently registered */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ /* check to see if trace buffers are currently released */ -+ if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n", -+ ioc->name, __func__, ioc_status, loginfo)); -+ -+ /* don't send trigger if an trigger is currently active */ -+ if (ioc->diag_trigger_active) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ goto out; -+ } -+ -+ /* check for the trigger condition */ -+ mpi_trigger = ioc->diag_trigger_mpi.MPITriggerEntry; -+ for (i = 0 , found_match = 0; i < ioc->diag_trigger_mpi.ValidEntries -+ && !found_match; i++, mpi_trigger++) { -+ if (mpi_trigger->IOCStatus != ioc_status) -+ continue; -+ if (!(mpi_trigger->IocLogInfo == 0xFFFFFFFF || -+ mpi_trigger->IocLogInfo == loginfo)) -+ continue; -+ found_match = 1; -+ ioc->diag_trigger_active = 1; -+ } -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ if (!found_match) -+ goto out; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ event_data.trigger_type = MPT3SAS_TRIGGER_MPI; -+ event_data.u.mpi.IOCStatus = ioc_status; -+ event_data.u.mpi.IocLogInfo = loginfo; -+ mpt2sas_send_trigger_data_event(ioc, &event_data); -+ out: -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -diff --git a/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h b/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h -new file mode 100644 -index 0000000..6586a46 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h -@@ -0,0 +1,194 @@ -+/* -+ * This is the Fusion MPT base driver providing common API layer interface -+ * to set Diagnostic triggers for MPT (Message Passing Technology) based -+ * controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ /* Diagnostic Trigger Configuration Data Structures */ -+ -+#ifndef MPT3SAS_TRIGGER_DIAG_H_INCLUDED -+#define MPT3SAS_TRIGGER_DIAG_H_INCLUDED -+ -+/* limitation on number of entries */ -+#define NUM_VALID_ENTRIES (20) -+ -+/* trigger types */ -+#define MPT3SAS_TRIGGER_MASTER (1) -+#define MPT3SAS_TRIGGER_EVENT (2) -+#define MPT3SAS_TRIGGER_SCSI (3) -+#define MPT3SAS_TRIGGER_MPI (4) -+ -+/* trigger names */ -+#define MASTER_TRIGGER_FILE_NAME "diag_trigger_master" -+#define EVENT_TRIGGERS_FILE_NAME "diag_trigger_event" -+#define SCSI_TRIGGERS_FILE_NAME "diag_trigger_scsi" -+#define MPI_TRIGGER_FILE_NAME "diag_trigger_mpi" -+ -+/* master trigger bitmask */ -+#define MASTER_TRIGGER_FW_FAULT (0x00000001) -+#define MASTER_TRIGGER_ADAPTER_RESET (0x00000002) -+#define MASTER_TRIGGER_TASK_MANAGMENT (0x00000004) -+#define MASTER_TRIGGER_DEVICE_REMOVAL (0x00000008) -+ -+/* fake firmware event for tigger */ -+#define MPI3_EVENT_DIAGNOSTIC_TRIGGER_FIRED (0x6E) -+ -+/** -+ * MasterTrigger is a single U32 passed to/from sysfs. -+ * -+ * Bit Flags (enables) include: -+ * 1. FW Faults -+ * 2. Adapter Reset issued by driver -+ * 3. TMs -+ * 4. Device Remove Event sent by FW -+ */ -+ -+struct SL_WH_MASTER_TRIGGER_T { -+ uint32_t MasterData; -+}; -+ -+/** -+ * struct SL_WH_EVENT_TRIGGER_T - Definition of an event trigger element -+ * @EventValue: Event Code to trigger on -+ * @LogEntryQualifier: Type of FW event that logged (Log Entry Added Event only) -+ * -+ * Defines an event that should induce a DIAG_TRIGGER driver event if observed. -+ */ -+struct SL_WH_EVENT_TRIGGER_T { -+ uint16_t EventValue; -+ uint16_t LogEntryQualifier; -+}; -+ -+/** -+ * struct SL_WH_EVENT_TRIGGERS_T - Structure passed to/from sysfs containing a -+ * list of Event Triggers to be monitored for. -+ * @ValidEntries: Number of _SL_WH_EVENT_TRIGGER_T structures contained in this -+ * structure. -+ * @EventTriggerEntry: List of Event trigger elements. -+ * -+ * This binary structure is transferred via sysfs to get/set Event Triggers -+ * in the Linux Driver. -+ */ -+ -+struct SL_WH_EVENT_TRIGGERS_T { -+ uint32_t ValidEntries; -+ struct SL_WH_EVENT_TRIGGER_T EventTriggerEntry[NUM_VALID_ENTRIES]; -+}; -+ -+/** -+ * struct SL_WH_SCSI_TRIGGER_T - Definition of a SCSI trigger element -+ * @ASCQ: Additional Sense Code Qualifier. Can be specific or 0xFF for -+ * wildcard. -+ * @ASC: Additional Sense Code. Can be specific or 0xFF for wildcard -+ * @SenseKey: SCSI Sense Key -+ * -+ * Defines a sense key (single or many variants) that should induce a -+ * DIAG_TRIGGER driver event if observed. -+ */ -+struct SL_WH_SCSI_TRIGGER_T { -+ U8 ASCQ; -+ U8 ASC; -+ U8 SenseKey; -+ U8 Reserved; -+}; -+ -+/** -+ * struct SL_WH_SCSI_TRIGGERS_T - Structure passed to/from sysfs containing a -+ * list of SCSI sense codes that should trigger a DIAG_SERVICE event when -+ * observed. -+ * @ValidEntries: Number of _SL_WH_SCSI_TRIGGER_T structures contained in this -+ * structure. -+ * @SCSITriggerEntry: List of SCSI Sense Code trigger elements. -+ * -+ * This binary structure is transferred via sysfs to get/set SCSI Sense Code -+ * Triggers in the Linux Driver. -+ */ -+struct SL_WH_SCSI_TRIGGERS_T { -+ uint32_t ValidEntries; -+ struct SL_WH_SCSI_TRIGGER_T SCSITriggerEntry[NUM_VALID_ENTRIES]; -+}; -+ -+/** -+ * struct SL_WH_MPI_TRIGGER_T - Definition of an MPI trigger element -+ * @IOCStatus: MPI IOCStatus -+ * @IocLogInfo: MPI IocLogInfo. Can be specific or 0xFFFFFFFF for wildcard -+ * -+ * Defines a MPI IOCStatus/IocLogInfo pair that should induce a DIAG_TRIGGER -+ * driver event if observed. -+ */ -+struct SL_WH_MPI_TRIGGER_T { -+ uint16_t IOCStatus; -+ uint16_t Reserved; -+ uint32_t IocLogInfo; -+}; -+ -+/** -+ * struct SL_WH_MPI_TRIGGERS_T - Structure passed to/from sysfs containing a -+ * list of MPI IOCStatus/IocLogInfo pairs that should trigger a DIAG_SERVICE -+ * event when observed. -+ * @ValidEntries: Number of _SL_WH_MPI_TRIGGER_T structures contained in this -+ * structure. -+ * @MPITriggerEntry: List of MPI IOCStatus/IocLogInfo trigger elements. -+ * -+ * This binary structure is transferred via sysfs to get/set MPI Error Triggers -+ * in the Linux Driver. -+ */ -+struct SL_WH_MPI_TRIGGERS_T { -+ uint32_t ValidEntries; -+ struct SL_WH_MPI_TRIGGER_T MPITriggerEntry[NUM_VALID_ENTRIES]; -+}; -+ -+/** -+ * struct SL_WH_TRIGGERS_EVENT_DATA_T - event data for trigger -+ * @trigger_type: trigger type (see MPT3SAS_TRIGGER_XXXX) -+ * @u: trigger condition that caused trigger to be sent -+ */ -+struct SL_WH_TRIGGERS_EVENT_DATA_T { -+ uint32_t trigger_type; -+ union { -+ struct SL_WH_MASTER_TRIGGER_T master; -+ struct SL_WH_EVENT_TRIGGER_T event; -+ struct SL_WH_SCSI_TRIGGER_T scsi; -+ struct SL_WH_MPI_TRIGGER_T mpi; -+ } u; -+}; -+#endif /* MPT3SAS_TRIGGER_DIAG_H_INCLUDED */ -diff --git a/drivers/scsi/mpt2sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt2sas/mpt3sas_warpdrive.c -new file mode 100644 -index 0000000..2542263 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_warpdrive.c -@@ -0,0 +1,344 @@ -+/* -+ * Scsi Host Layer for MPT (Message Passing Technology) based controllers -+ * -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2015 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program. -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+/** -+ * _warpdrive_disable_ddio - Disable direct I/O for all the volumes -+ * @ioc: per adapter object -+ */ -+static void -+_warpdrive_disable_ddio(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2RaidVolPage1_t vol_pg1; -+ Mpi2ConfigReply_t mpi_reply; -+ struct _raid_device *raid_device; -+ u16 handle; -+ u16 ioc_status; -+ unsigned long flags; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) -+ break; -+ handle = le16_to_cpu(vol_pg1.DevHandle); -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ if (raid_device) -+ raid_device->direct_io_enabled = 0; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ } -+ return; -+} -+ -+ -+/** -+ * mpt2sas_get_num_volumes - Get number of volumes in the ioc -+ * @ioc: per adapter object -+ */ -+u8 -+mpt2sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2RaidVolPage1_t vol_pg1; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 handle; -+ u8 vol_cnt = 0; -+ u16 ioc_status; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) -+ break; -+ vol_cnt++; -+ handle = le16_to_cpu(vol_pg1.DevHandle); -+ } -+ return vol_cnt; -+} -+ -+ -+/** -+ * mpt2sas_init_warpdrive_properties - Set properties for warpdrive direct I/O. -+ * @ioc: per adapter object -+ * @raid_device: the raid_device object -+ */ -+void -+mpt2sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device) -+{ -+ Mpi2RaidVolPage0_t *vol_pg0; -+ Mpi2RaidPhysDiskPage0_t pd_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 sz; -+ u8 num_pds, count; -+ unsigned long stripe_sz, block_sz; -+ u8 stripe_exp, block_exp; -+ u64 dev_max_lba; -+ -+ if (!ioc->is_warpdrive) -+ return; -+ -+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "globally as drives are exposed\n", ioc->name); -+ return; -+ } -+ if (mpt2sas_get_num_volumes(ioc) > 1) { -+ _warpdrive_disable_ddio(ioc); -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "globally as number of drives > 1\n", ioc->name); -+ return; -+ } -+ if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, -+ &num_pds)) || !num_pds) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "Failure in computing number of drives\n", ioc->name); -+ return; -+ } -+ -+ sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * -+ sizeof(Mpi2RaidVol0PhysDisk_t)); -+ vol_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!vol_pg0) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "Memory allocation failure for RVPG0\n", ioc->name); -+ return; -+ } -+ -+ if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, -+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "Failure in retrieving RVPG0\n", ioc->name); -+ kfree(vol_pg0); -+ return; -+ } -+ -+ /* -+ * WARPDRIVE:If number of physical disks in a volume exceeds the max pds -+ * assumed for WARPDRIVE, disable direct I/O -+ */ -+ if (num_pds > MPT_MAX_WARPDRIVE_PDS) { -+ pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "for the drive with handle(0x%04x): num_mem=%d, " -+ "max_mem_allowed=%d\n", ioc->name, raid_device->handle, -+ num_pds, MPT_MAX_WARPDRIVE_PDS); -+ kfree(vol_pg0); -+ return; -+ } -+ for (count = 0; count < num_pds; count++) { -+ if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, -+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, -+ vol_pg0->PhysDisk[count].PhysDiskNum) || -+ pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " -+ "disabled for the drive with handle(0x%04x) member" -+ "handle retrieval failed for member number=%d\n", -+ ioc->name, raid_device->handle, -+ vol_pg0->PhysDisk[count].PhysDiskNum); -+ goto out_error; -+ } -+ /* Disable direct I/O if member drive lba exceeds 4 bytes */ -+ dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); -+ if (dev_max_lba >> 32) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " -+ "disabled for the drive with handle(0x%04x) member" -+ " handle (0x%04x) unsupported max lba 0x%016llx\n", -+ ioc->name, raid_device->handle, -+ le16_to_cpu(pd_pg0.DevHandle), -+ (unsigned long long)dev_max_lba); -+ goto out_error; -+ } -+ -+ raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); -+ } -+ -+ /* -+ * Assumption for WD: Direct I/O is not supported if the volume is -+ * not RAID0 -+ */ -+ if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "for the drive with handle(0x%04x): type=%d, " -+ "s_sz=%uK, blk_size=%u\n", ioc->name, -+ raid_device->handle, raid_device->volume_type, -+ (le32_to_cpu(vol_pg0->StripeSize) * -+ le16_to_cpu(vol_pg0->BlockSize)) / 1024, -+ le16_to_cpu(vol_pg0->BlockSize)); -+ goto out_error; -+ } -+ -+ stripe_sz = le32_to_cpu(vol_pg0->StripeSize); -+ stripe_exp = find_first_bit(&stripe_sz, 32); -+ if (stripe_exp == 32) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "for the drive with handle(0x%04x) invalid stripe sz %uK\n", -+ ioc->name, raid_device->handle, -+ (le32_to_cpu(vol_pg0->StripeSize) * -+ le16_to_cpu(vol_pg0->BlockSize)) / 1024); -+ goto out_error; -+ } -+ raid_device->stripe_exponent = stripe_exp; -+ block_sz = le16_to_cpu(vol_pg0->BlockSize); -+ block_exp = find_first_bit(&block_sz, 16); -+ if (block_exp == 16) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "for the drive with handle(0x%04x) invalid block sz %u\n", -+ ioc->name, raid_device->handle, -+ le16_to_cpu(vol_pg0->BlockSize)); -+ goto out_error; -+ } -+ raid_device->block_exponent = block_exp; -+ raid_device->direct_io_enabled = 1; -+ -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive" -+ " with handle(0x%04x)\n", ioc->name, raid_device->handle); -+ /* -+ * WARPDRIVE: Though the following fields are not used for direct IO, -+ * stored for future purpose: -+ */ -+ raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); -+ raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); -+ raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); -+ -+ -+ kfree(vol_pg0); -+ return; -+ -+out_error: -+ raid_device->direct_io_enabled = 0; -+ for (count = 0; count < num_pds; count++) -+ raid_device->pd_handle[count] = 0; -+ kfree(vol_pg0); -+ return; -+} -+ -+/** -+ * mpt2sas_scsi_direct_io_get - returns direct io flag -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns the smid stored scmd pointer. -+ */ -+inline u8 -+mpt2sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return ioc->scsi_lookup[smid - 1].direct_io; -+} -+ -+/** -+ * mpt2sas_scsi_direct_io_set - sets direct io flag -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @direct_io: Zero or non-zero value to set in the direct_io flag -+ * -+ * Returns Nothing. -+ */ -+inline void -+mpt2sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io) -+{ -+ ioc->scsi_lookup[smid - 1].direct_io = direct_io; -+} -+ -+/** -+ * mpt2sas_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O -+ * @ioc: per adapter object -+ * @scmd: pointer to scsi command object -+ * @raid_device: pointer to raid device data structure -+ * @mpi_request: pointer to the SCSI_IO reqest message frame -+ * @smid: system request message index -+ * -+ * Returns nothing -+ */ -+void -+mpt2sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, -+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, -+ u16 smid) -+{ -+ sector_t v_lba, p_lba, stripe_off, column, io_size; -+ u32 stripe_sz, stripe_exp; -+ u8 num_pds, cmd = scmd->cmnd[0]; -+ -+ if (cmd != READ_10 && cmd != WRITE_10 && -+ cmd != READ_16 && cmd != WRITE_16) -+ return; -+ -+ if (cmd == READ_10 || cmd == WRITE_10) -+ v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]); -+ else -+ v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]); -+ -+ io_size = scsi_bufflen(scmd) >> raid_device->block_exponent; -+ -+ if (v_lba + io_size - 1 > raid_device->max_lba) -+ return; -+ -+ stripe_sz = raid_device->stripe_sz; -+ stripe_exp = raid_device->stripe_exponent; -+ stripe_off = v_lba & (stripe_sz - 1); -+ -+ /* Return unless IO falls within a stripe */ -+ if (stripe_off + io_size > stripe_sz) -+ return; -+ -+ num_pds = raid_device->num_pds; -+ p_lba = v_lba >> stripe_exp; -+ column = sector_div(p_lba, num_pds); -+ p_lba = (p_lba << stripe_exp) + stripe_off; -+ mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]); -+ -+ if (cmd == READ_10 || cmd == WRITE_10) -+ put_unaligned_be32(lower_32_bits(p_lba), -+ &mpi_request->CDB.CDB32[2]); -+ else -+ put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]); -+ -+ mpt2sas_scsi_direct_io_set(ioc, smid, 1); -+} -diff --git a/drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c b/drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c -new file mode 100644 -index 0000000..7852050 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c -@@ -0,0 +1,4 @@ -+#define MPT2SAS_SCSI -+/* This directive is used to create the mpt2sas driver from the mpt3sas sources */ -+ -+#include "mpt3sas_scsih.c" -diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig -index 5743420..9aa67e2 100644 ---- a/drivers/scsi/mpt3sas/Kconfig -+++ b/drivers/scsi/mpt3sas/Kconfig -@@ -40,14 +40,6 @@ - # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - # USA. - --config SCSI_MPT2SAS -- tristate "LSI MPT Fusion SAS 2.0 Device Driver" -- depends on PCI && SCSI -- select SCSI_SAS_ATTRS -- select RAID_ATTRS -- ---help--- -- This driver supports PCI-Express SAS 6Gb/s Host Adapters. -- - config SCSI_MPT3SAS - tristate "LSI MPT Fusion SAS 3.0 Device Driver" - depends on PCI && SCSI -@@ -56,18 +48,6 @@ config SCSI_MPT3SAS - ---help--- - This driver supports PCI-Express SAS 12Gb/s Host Adapters. - --config SCSI_MPT2SAS_MAX_SGE -- int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)" -- depends on PCI && SCSI && SCSI_MPT3SAS -- default "128" -- range 16 256 -- ---help--- -- This option allows you to specify the maximum number of scatter- -- gather entries per I/O. The driver default is 128, which matches -- MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this -- can be 256. However, it may decreased down to 16. Decreasing this -- parameter will reduce memory requirements on a per controller instance. -- - config SCSI_MPT3SAS_MAX_SGE - int "LSI MPT Fusion SAS 3.0 Max number of SG Entries (16 - 256)" - depends on PCI && SCSI && SCSI_MPT3SAS -diff --git a/drivers/scsi/mpt3sas/Makefile b/drivers/scsi/mpt3sas/Makefile -index 0b90877..450b84b 100644 ---- a/drivers/scsi/mpt3sas/Makefile -+++ b/drivers/scsi/mpt3sas/Makefile -@@ -1,6 +1,5 @@ - # mpt2-3sas makefile - --obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o - obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas.o - - obj-m += mpt3sas.o -@@ -12,11 +11,3 @@ mpt3sas-y += mpt3sas_base.o \ - mpt3sas_trigger_diag.o \ - mpt3sas_warpdrive.o - --obj-m += mpt2sas.o --mpt2sas-y += mpt3sas_base.o \ -- mpt3sas_config.o \ -- wrapper_mpt3sas_scsih.o \ -- mpt3sas_transport.o \ -- mpt3sas_ctl.o \ -- mpt3sas_trigger_diag.o \ -- mpt3sas_warpdrive.o --- -1.8.3.1 - diff --git a/kernel/kernel-rt/centos/patches/kernel-3.10.0-x86_64-rt.config.tis_extra b/kernel/kernel-rt/centos/patches/kernel-3.10.0-x86_64-rt.config.tis_extra index 46300ed46..eade7c017 100644 --- a/kernel/kernel-rt/centos/patches/kernel-3.10.0-x86_64-rt.config.tis_extra +++ b/kernel/kernel-rt/centos/patches/kernel-3.10.0-x86_64-rt.config.tis_extra @@ -24,8 +24,9 @@ CONFIG_SCSI_PMCRAID=y CONFIG_SCSI_HPSA=y CONFIG_MEGARAID_SAS=y CONFIG_SCSI_SMARTPQI=y -CONFIG_SCSI_MPT2SAS=y -CONFIG_SCSI_MPT3SAS=y +# These two will only build as modules +CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_MPT3SAS=m CONFIG_SCSI_VIRTIO=y CONFIG_FUSION_SAS=y CONFIG_SCSI_AIC94XX=y diff --git a/kernel/kernel-std/centos/build_srpm.data b/kernel/kernel-std/centos/build_srpm.data index dab446664..2ed119b61 100644 --- a/kernel/kernel-std/centos/build_srpm.data +++ b/kernel/kernel-std/centos/build_srpm.data @@ -1,4 +1,4 @@ COPY_LIST="files/*" -TIS_PATCH_VER=2 +TIS_PATCH_VER=3 BUILD_IS_BIG=11 BUILD_IS_SLOW=12 diff --git a/kernel/kernel-std/centos/meta_patches/Compile-issues.patch b/kernel/kernel-std/centos/meta_patches/Compile-issues.patch index 0af3a1c7e..24689d64f 100644 --- a/kernel/kernel-std/centos/meta_patches/Compile-issues.patch +++ b/kernel/kernel-std/centos/meta_patches/Compile-issues.patch @@ -1,7 +1,7 @@ -From f9a5a49c9daac827d94cd562c0c6f100388fd798 Mon Sep 17 00:00:00 2001 -Message-Id: -In-Reply-To: -References: +From 6c41acf7c1a4f5f3437e474505193bb353d241e6 Mon Sep 17 00:00:00 2001 +Message-Id: <6c41acf7c1a4f5f3437e474505193bb353d241e6.1584125537.git.Jim.Somerville@windriver.com> +In-Reply-To: <47c970e28e2adfd6483fa8d861eeb338492297bf.1584125537.git.Jim.Somerville@windriver.com> +References: <47c970e28e2adfd6483fa8d861eeb338492297bf.1584125537.git.Jim.Somerville@windriver.com> From: "zhao.shuai" Date: Tue, 6 Aug 2019 16:18:04 +0800 Subject: [PATCH 2/2] Compile issues @@ -13,10 +13,10 @@ Signed-off-by: Jim Somerville 1 file changed, 9 insertions(+) diff --git a/SPECS/kernel.spec b/SPECS/kernel.spec -index d5df4a4..1d765ed 100644 +index 012ddbd..6595a38 100644 --- a/SPECS/kernel.spec +++ b/SPECS/kernel.spec -@@ -497,6 +497,12 @@ Patch40027: epoll-fix-use-after-free-in-eventpoll_release_file.patch +@@ -496,6 +496,12 @@ Patch40027: epoll-fix-use-after-free-in-eventpoll_release_file.patch Patch40028: ipvs-fix-memory-leak-in-ip_vs_ctl.c.patch Patch40029: rh-ext4-release-leaked-posix-acl-in-ext4_acl_chmod.patch Patch40030: rh-ext4-release-leaked-posix-acl-in-ext4_xattr_set_a.patch @@ -29,7 +29,7 @@ index d5df4a4..1d765ed 100644 BuildRoot: %{_tmppath}/kernel-%{KVRA}-root -@@ -881,6 +887,9 @@ ApplyOptionalPatch epoll-fix-use-after-free-in-eventpoll_release_file.patch +@@ -879,6 +885,9 @@ ApplyOptionalPatch epoll-fix-use-after-free-in-eventpoll_release_file.patch ApplyOptionalPatch ipvs-fix-memory-leak-in-ip_vs_ctl.c.patch ApplyOptionalPatch rh-ext4-release-leaked-posix-acl-in-ext4_acl_chmod.patch ApplyOptionalPatch rh-ext4-release-leaked-posix-acl-in-ext4_xattr_set_a.patch diff --git a/kernel/kernel-std/centos/meta_patches/Kernel-source-patches-for-TiC.patch b/kernel/kernel-std/centos/meta_patches/Kernel-source-patches-for-TiC.patch index 171786f12..09e797dfb 100644 --- a/kernel/kernel-std/centos/meta_patches/Kernel-source-patches-for-TiC.patch +++ b/kernel/kernel-std/centos/meta_patches/Kernel-source-patches-for-TiC.patch @@ -1,5 +1,5 @@ -From ac67546ccbecd3ee18145be31d87d7253048adda Mon Sep 17 00:00:00 2001 -Message-Id: +From 47c970e28e2adfd6483fa8d861eeb338492297bf Mon Sep 17 00:00:00 2001 +Message-Id: <47c970e28e2adfd6483fa8d861eeb338492297bf.1584125537.git.Jim.Somerville@windriver.com> From: "zhao.shuai" Date: Mon, 5 Aug 2019 17:55:01 +0800 Subject: [PATCH 1/2] Kernel-source-patches-for-TiC @@ -8,14 +8,14 @@ Signed-off-by: zhao.shuai Signed-off-by: Jim Somerville Signed-off-by: Robin Lu --- - SPECS/kernel.spec | 66 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 66 insertions(+) + SPECS/kernel.spec | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 64 insertions(+) diff --git a/SPECS/kernel.spec b/SPECS/kernel.spec -index e42177e..d5df4a4 100644 +index 0b2ff2e..012ddbd 100644 --- a/SPECS/kernel.spec +++ b/SPECS/kernel.spec -@@ -463,6 +463,41 @@ Patch1002: debrand-rh-i686-cpu.patch +@@ -463,6 +463,40 @@ Patch1002: debrand-rh-i686-cpu.patch Source30000: kernel-3.10.0-x86_64.config.tis_extra Source30001: ima_signing_key.pub @@ -31,7 +31,6 @@ index e42177e..d5df4a4 100644 +Patch40009: memblock-introduce-memblock_alloc_range.patch +Patch40010: cma-add-placement-specifier-for-cma-kernel-parameter.patch +Patch40011: x86-enable-DMA-CMA-with-swiotlb.patch -+Patch40012: Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch +Patch40013: Enable-building-kernel-with-CONFIG_BLK_DEV_NBD.patch +Patch40014: x86-make-dma_alloc_coherent-return-zeroed-memory-if-.patch +Patch40016: Porting-Cacheinfo-from-Kernel-4.10.17.patch @@ -57,7 +56,7 @@ index e42177e..d5df4a4 100644 BuildRoot: %{_tmppath}/kernel-%{KVRA}-root %description -@@ -816,6 +851,37 @@ ApplyOptionalPatch debrand-single-cpu.patch +@@ -816,6 +850,36 @@ ApplyOptionalPatch debrand-single-cpu.patch ApplyOptionalPatch debrand-rh_taint.patch ApplyOptionalPatch debrand-rh-i686-cpu.patch @@ -73,7 +72,6 @@ index e42177e..d5df4a4 100644 +ApplyOptionalPatch memblock-introduce-memblock_alloc_range.patch +ApplyOptionalPatch cma-add-placement-specifier-for-cma-kernel-parameter.patch +ApplyOptionalPatch x86-enable-DMA-CMA-with-swiotlb.patch -+ApplyOptionalPatch Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch +ApplyOptionalPatch Enable-building-kernel-with-CONFIG_BLK_DEV_NBD.patch +ApplyOptionalPatch x86-make-dma_alloc_coherent-return-zeroed-memory-if-.patch +ApplyOptionalPatch Porting-Cacheinfo-from-Kernel-4.10.17.patch diff --git a/kernel/kernel-std/centos/patches/Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch b/kernel/kernel-std/centos/patches/Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch deleted file mode 100644 index bc7daba9c..000000000 --- a/kernel/kernel-std/centos/patches/Enable-building-mpt2sas-and-mpt3sas-as-builtin-for-C.patch +++ /dev/null @@ -1,34236 +0,0 @@ -From 90a9ed3030882fdaf1bf8c7b9f17e47821f20700 Mon Sep 17 00:00:00 2001 -Message-Id: <90a9ed3030882fdaf1bf8c7b9f17e47821f20700.1527544850.git.Jim.Somerville@windriver.com> -In-Reply-To: -References: -From: Chris Friesen -Date: Mon, 9 Jan 2017 15:03:00 -0500 -Subject: [PATCH 12/26] Enable building mpt2sas and mpt3sas as builtin for - CentOS 7.3 - -In CentOS 7.3 the upstream mpt2sas/mpt3sas drivers are built from -essentially the same codebase with a flag defined to give the mpt2sas -behaviour. This is purely a problem in 7.3 due to how they have mangled -the drivers. More recently in the Linux kernel these have been merged -into a single driver, while previously in 7.2 they were two totally -separate drivers. - -The 7.3 code works fine when building as modules, but when building as -builtin it gives problems because KBUILD_MODNAME is not defined for files -that are included in multiple drivers. - -The workaround is to move the mpt2sas driver into its own directory, -copying the whole mpt3sas codebase into it. This required a number of -changes after duplicating the codebase: - -1) Add knowledge of the new "mpt2sas" directory to from drivers/scsi/Kconfig -and drivers/scsi/Makefile. - -2) Remove mention of mpt2sas from drivers/scsi/mpt3sas/Kconfig and -drivers/scsi/mpt3sas/Makefile. - -3) Remove mention of mpt3sas from drivers/scsi/mpt2sas/Kconfig and -drivers/scsi/mpt2sas/Makefile. - -4) In the mpt2sas directory, all functions/variables with "mpt3sas" in -the name which did not already have an mpt2sas equivalent were renamed -to instead use "mpt2sas". Thus "_mpt3sas_init" became "_mpt2sas_init". - -5) All other symbols that collided between the two modules were renamed -in the mpt2sas driver by appending "_mpt2sas". This included ones with -"mpt2sas" already in the name, so "mpt2sas_raid_template" became -"mpt2sas_raid_template_mpt2sas". (While the version in the mpt3sas -driver remained "mpt2sas_raid_template".) - -Signed-off-by: Jim Somerville ---- - drivers/scsi/Kconfig | 1 + - drivers/scsi/Makefile | 1 + - drivers/scsi/mpt2sas/Kconfig | 61 + - drivers/scsi/mpt2sas/Makefile | 12 + - drivers/scsi/mpt2sas/mpi/mpi2.h | 1243 ++++ - drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 3493 ++++++++++ - drivers/scsi/mpt2sas/mpi/mpi2_init.h | 581 ++ - drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 1860 +++++ - drivers/scsi/mpt2sas/mpi/mpi2_raid.h | 355 + - drivers/scsi/mpt2sas/mpi/mpi2_sas.h | 303 + - drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 483 ++ - drivers/scsi/mpt2sas/mpi/mpi2_type.h | 57 + - drivers/scsi/mpt2sas/mpt3sas_base.c | 5713 ++++++++++++++++ - drivers/scsi/mpt2sas/mpt3sas_base.h | 1462 ++++ - drivers/scsi/mpt2sas/mpt3sas_config.c | 1716 +++++ - drivers/scsi/mpt2sas/mpt3sas_ctl.c | 3483 ++++++++++ - drivers/scsi/mpt2sas/mpt3sas_ctl.h | 423 ++ - drivers/scsi/mpt2sas/mpt3sas_debug.h | 206 + - drivers/scsi/mpt2sas/mpt3sas_scsih.c | 9356 ++++++++++++++++++++++++++ - drivers/scsi/mpt2sas/mpt3sas_transport.c | 2138 ++++++ - drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c | 434 ++ - drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h | 194 + - drivers/scsi/mpt2sas/mpt3sas_warpdrive.c | 344 + - drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c | 4 + - drivers/scsi/mpt3sas/Kconfig | 20 - - drivers/scsi/mpt3sas/Makefile | 9 - - 26 files changed, 33923 insertions(+), 29 deletions(-) - create mode 100644 drivers/scsi/mpt2sas/Kconfig - create mode 100644 drivers/scsi/mpt2sas/Makefile - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_init.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_ioc.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_raid.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_sas.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_tool.h - create mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_type.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_base.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_base.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_config.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_ctl.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_ctl.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_debug.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_scsih.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_transport.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h - create mode 100644 drivers/scsi/mpt2sas/mpt3sas_warpdrive.c - create mode 100644 drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c - -diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig -index 4cb0e23..4d79408 100644 ---- a/drivers/scsi/Kconfig -+++ b/drivers/scsi/Kconfig -@@ -599,6 +599,7 @@ config SCSI_ARCMSR - module will be called arcmsr (modprobe arcmsr). - - source "drivers/scsi/megaraid/Kconfig.megaraid" -+source "drivers/scsi/mpt2sas/Kconfig" - source "drivers/scsi/mpt3sas/Kconfig" - source "drivers/scsi/smartpqi/Kconfig" - source "drivers/scsi/ufs/Kconfig" -diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile -index 95aed68..1a08fca 100644 ---- a/drivers/scsi/Makefile -+++ b/drivers/scsi/Makefile -@@ -109,6 +109,7 @@ obj-$(CONFIG_CXLFLASH) += cxlflash/ - obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o - obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ - obj-$(CONFIG_MEGARAID_SAS) += megaraid/ -+obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/ - obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas/ - obj-$(CONFIG_SCSI_UFSHCD) += ufs/ - obj-$(CONFIG_SCSI_ACARD) += atp870u.o -diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig -new file mode 100644 -index 0000000..a53ee73 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/Kconfig -@@ -0,0 +1,61 @@ -+# -+# Kernel configuration file for the MPT2SAS -+# -+# This code is based on drivers/scsi/mpt3sas/Kconfig -+# Copyright (C) 2012-2014 LSI Corporation -+# (mailto:DL-MPTFusionLinux@lsi.com) -+ -+# This program is free software; you can redistribute it and/or -+# modify it under the terms of the GNU General Public License -+# as published by the Free Software Foundation; either version 2 -+# of the License, or (at your option) any later version. -+ -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+ -+# NO WARRANTY -+# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+# solely responsible for determining the appropriateness of using and -+# distributing the Program and assumes all risks associated with its -+# exercise of rights under this Agreement, including but not limited to -+# the risks and costs of program errors, damage to or loss of data, -+# programs or equipment, and unavailability or interruption of operations. -+ -+# DISCLAIMER OF LIABILITY -+# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+# USA. -+ -+config SCSI_MPT2SAS -+ tristate "LSI MPT Fusion SAS 2.0 Device Driver" -+ depends on PCI && SCSI -+ select SCSI_SAS_ATTRS -+ select RAID_ATTRS -+ ---help--- -+ This driver supports PCI-Express SAS 6Gb/s Host Adapters. -+ -+config SCSI_MPT2SAS_MAX_SGE -+ int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)" -+ depends on PCI && SCSI && SCSI_MPT2SAS -+ default "128" -+ range 16 256 -+ ---help--- -+ This option allows you to specify the maximum number of scatter- -+ gather entries per I/O. The driver default is 128, which matches -+ MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this -+ can be 256. However, it may decreased down to 16. Decreasing this -+ parameter will reduce memory requirements on a per controller instance. -diff --git a/drivers/scsi/mpt2sas/Makefile b/drivers/scsi/mpt2sas/Makefile -new file mode 100644 -index 0000000..5706ea4 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/Makefile -@@ -0,0 +1,12 @@ -+# mpt2-3sas makefile -+ -+obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o -+ -+obj-m += mpt2sas.o -+mpt2sas-y += mpt3sas_base.o \ -+ mpt3sas_config.o \ -+ wrapper_mpt3sas_scsih.o \ -+ mpt3sas_transport.o \ -+ mpt3sas_ctl.o \ -+ mpt3sas_trigger_diag.o \ -+ mpt3sas_warpdrive.o -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h -new file mode 100644 -index 0000000..a9a659f ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h -@@ -0,0 +1,1243 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2.h -+ * Title: MPI Message independent structures and definitions -+ * including System Interface Register Set and -+ * scatter/gather formats. -+ * Creation Date: June 21, 2006 -+ * -+ * mpi2.h Version: 02.00.42 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Moved ReplyPostHostIndex register to offset 0x6C of the -+ * MPI2_SYSTEM_INTERFACE_REGS and modified the define for -+ * MPI2_REPLY_POST_HOST_INDEX_OFFSET. -+ * Added union of request descriptors. -+ * Added union of reply descriptors. -+ * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added define for MPI2_VERSION_02_00. -+ * Fixed the size of the FunctionDependent5 field in the -+ * MPI2_DEFAULT_REPLY structure. -+ * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Removed the MPI-defined Fault Codes and extended the -+ * product specific codes up to 0xEFFF. -+ * Added a sixth key value for the WriteSequence register -+ * and changed the flush value to 0x0. -+ * Added message function codes for Diagnostic Buffer Post -+ * and Diagnsotic Release. -+ * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED -+ * Moved MPI2_VERSION_UNION from mpi2_ioc.h. -+ * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added #defines for marking a reply descriptor as unused. -+ * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Moved LUN field defines from mpi2_init.h. -+ * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. -+ * In all request and reply descriptors, replaced VF_ID -+ * field with MSIxIndex field. -+ * Removed DevHandle field from -+ * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those -+ * bytes reserved. -+ * Added RAID Accelerator functionality. -+ * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added MSI-x index mask and shift for Reply Post Host -+ * Index register. -+ * Added function code for Host Based Discovery Action. -+ * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. -+ * Added defines for product-specific range of message -+ * function codes, 0xF0 to 0xFF. -+ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added alternative defines for the SGE Direction bit. -+ * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. -+ * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. -+ * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Incorporating additions for MPI v2.5. -+ * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added Hard Reset delay timings. -+ * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET. -+ * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT -+ * 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 11-18-14 02.00.36 Updated copyright information. -+ * Bumped MPI2_HEADER_VERSION_UNIT. -+ * 03-16-15 02.00.37 Bumped MPI2_HEADER_VERSION_UNIT. -+ * Added Scratchpad registers to -+ * MPI2_SYSTEM_INTERFACE_REGS. -+ * Added MPI2_DIAG_SBR_RELOAD. -+ * 03-19-15 02.00.38 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 05-25-15 02.00.39 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 08-25-15 02.00.40 Bumped MPI2_HEADER_VERSION_UNIT. -+ * 12-15-15 02.00.41 Bumped MPI_HEADER_VERSION_UNIT -+ * 01-01-16 02.00.42 Bumped MPI_HEADER_VERSION_UNIT -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_H -+#define MPI2_H -+ -+/***************************************************************************** -+* -+* MPI Version Definitions -+* -+*****************************************************************************/ -+ -+#define MPI2_VERSION_MAJOR_MASK (0xFF00) -+#define MPI2_VERSION_MAJOR_SHIFT (8) -+#define MPI2_VERSION_MINOR_MASK (0x00FF) -+#define MPI2_VERSION_MINOR_SHIFT (0) -+ -+/*major version for all MPI v2.x */ -+#define MPI2_VERSION_MAJOR (0x02) -+ -+/*minor version for MPI v2.0 compatible products */ -+#define MPI2_VERSION_MINOR (0x00) -+#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ -+ MPI2_VERSION_MINOR) -+#define MPI2_VERSION_02_00 (0x0200) -+ -+/*minor version for MPI v2.5 compatible products */ -+#define MPI25_VERSION_MINOR (0x05) -+#define MPI25_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ -+ MPI25_VERSION_MINOR) -+#define MPI2_VERSION_02_05 (0x0205) -+ -+/*minor version for MPI v2.6 compatible products */ -+#define MPI26_VERSION_MINOR (0x06) -+#define MPI26_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ -+ MPI26_VERSION_MINOR) -+#define MPI2_VERSION_02_06 (0x0206) -+ -+/*Unit and Dev versioning for this MPI header set */ -+#define MPI2_HEADER_VERSION_UNIT (0x2A) -+#define MPI2_HEADER_VERSION_DEV (0x00) -+#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) -+#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) -+#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) -+#define MPI2_HEADER_VERSION_DEV_SHIFT (0) -+#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \ -+ MPI2_HEADER_VERSION_DEV) -+ -+/***************************************************************************** -+* -+* IOC State Definitions -+* -+*****************************************************************************/ -+ -+#define MPI2_IOC_STATE_RESET (0x00000000) -+#define MPI2_IOC_STATE_READY (0x10000000) -+#define MPI2_IOC_STATE_OPERATIONAL (0x20000000) -+#define MPI2_IOC_STATE_FAULT (0x40000000) -+ -+#define MPI2_IOC_STATE_MASK (0xF0000000) -+#define MPI2_IOC_STATE_SHIFT (28) -+ -+/*Fault state range for prodcut specific codes */ -+#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000) -+#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF) -+ -+/***************************************************************************** -+* -+* System Interface Register Definitions -+* -+*****************************************************************************/ -+ -+typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS { -+ U32 Doorbell; /*0x00 */ -+ U32 WriteSequence; /*0x04 */ -+ U32 HostDiagnostic; /*0x08 */ -+ U32 Reserved1; /*0x0C */ -+ U32 DiagRWData; /*0x10 */ -+ U32 DiagRWAddressLow; /*0x14 */ -+ U32 DiagRWAddressHigh; /*0x18 */ -+ U32 Reserved2[5]; /*0x1C */ -+ U32 HostInterruptStatus; /*0x30 */ -+ U32 HostInterruptMask; /*0x34 */ -+ U32 DCRData; /*0x38 */ -+ U32 DCRAddress; /*0x3C */ -+ U32 Reserved3[2]; /*0x40 */ -+ U32 ReplyFreeHostIndex; /*0x48 */ -+ U32 Reserved4[8]; /*0x4C */ -+ U32 ReplyPostHostIndex; /*0x6C */ -+ U32 Reserved5; /*0x70 */ -+ U32 HCBSize; /*0x74 */ -+ U32 HCBAddressLow; /*0x78 */ -+ U32 HCBAddressHigh; /*0x7C */ -+ U32 Reserved6[12]; /*0x80 */ -+ U32 Scratchpad[4]; /*0xB0 */ -+ U32 RequestDescriptorPostLow; /*0xC0 */ -+ U32 RequestDescriptorPostHigh; /*0xC4 */ -+ U32 AtomicRequestDescriptorPost;/*0xC8 */ -+ U32 Reserved7[13]; /*0xCC */ -+} MPI2_SYSTEM_INTERFACE_REGS, -+ *PTR_MPI2_SYSTEM_INTERFACE_REGS, -+ Mpi2SystemInterfaceRegs_t, -+ *pMpi2SystemInterfaceRegs_t; -+ -+/* -+ *Defines for working with the Doorbell register. -+ */ -+#define MPI2_DOORBELL_OFFSET (0x00000000) -+ -+/*IOC --> System values */ -+#define MPI2_DOORBELL_USED (0x08000000) -+#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000) -+#define MPI2_DOORBELL_WHO_INIT_SHIFT (24) -+#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF) -+#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF) -+ -+/*System --> IOC values */ -+#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000) -+#define MPI2_DOORBELL_FUNCTION_SHIFT (24) -+#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) -+#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16) -+ -+/* -+ *Defines for the WriteSequence register -+ */ -+#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) -+#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F) -+#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) -+#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) -+#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) -+#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) -+#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) -+#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) -+#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) -+ -+/* -+ *Defines for the HostDiagnostic register -+ */ -+#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008) -+ -+#define MPI2_DIAG_SBR_RELOAD (0x00002000) -+ -+#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800) -+#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000) -+#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800) -+ -+#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) -+#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200) -+#define MPI2_DIAG_HCB_MODE (0x00000100) -+#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080) -+#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040) -+#define MPI2_DIAG_RESET_HISTORY (0x00000020) -+#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010) -+#define MPI2_DIAG_RESET_ADAPTER (0x00000004) -+#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002) -+ -+/* -+ *Offsets for DiagRWData and address -+ */ -+#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010) -+#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014) -+#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018) -+ -+/* -+ *Defines for the HostInterruptStatus register -+ */ -+#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) -+#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000) -+#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS -+#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000) -+#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008) -+#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001) -+#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS -+ -+/* -+ *Defines for the HostInterruptMask register -+ */ -+#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034) -+#define MPI2_HIM_RESET_IRQ_MASK (0x40000000) -+#define MPI2_HIM_REPLY_INT_MASK (0x00000008) -+#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK -+#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001) -+#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK -+ -+/* -+ *Offsets for DCRData and address -+ */ -+#define MPI2_DCR_DATA_OFFSET (0x00000038) -+#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C) -+ -+/* -+ *Offset for the Reply Free Queue -+ */ -+#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) -+ -+/* -+ *Defines for the Reply Descriptor Post Queue -+ */ -+#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) -+#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) -+#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) -+#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) -+#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /*MPI v2.5 only*/ -+ -+ -+/* -+ *Defines for the HCBSize and address -+ */ -+#define MPI2_HCB_SIZE_OFFSET (0x00000074) -+#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000) -+#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001) -+ -+#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078) -+#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C) -+ -+/* -+ *Offsets for the Scratchpad registers -+ */ -+#define MPI26_SCRATCHPAD0_OFFSET (0x000000B0) -+#define MPI26_SCRATCHPAD1_OFFSET (0x000000B4) -+#define MPI26_SCRATCHPAD2_OFFSET (0x000000B8) -+#define MPI26_SCRATCHPAD3_OFFSET (0x000000BC) -+ -+/* -+ *Offsets for the Request Descriptor Post Queue -+ */ -+#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0) -+#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4) -+#define MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET (0x000000C8) -+ -+/*Hard Reset delay timings */ -+#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000) -+#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC (255000) -+#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC (256000) -+ -+/***************************************************************************** -+* -+* Message Descriptors -+* -+*****************************************************************************/ -+ -+/*Request Descriptors */ -+ -+/*Default Request Descriptor */ -+typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 DescriptorTypeDependent; /*0x06 */ -+} MPI2_DEFAULT_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR, -+ Mpi2DefaultRequestDescriptor_t, -+ *pMpi2DefaultRequestDescriptor_t; -+ -+/*defines for the RequestFlags field */ -+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x1E) -+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_RSHIFT (1) -+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) -+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) -+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) -+#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) -+#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A) -+#define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO (0x0C) -+ -+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) -+ -+/*High Priority Request Descriptor */ -+typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 Reserved1; /*0x06 */ -+} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, -+ Mpi2HighPriorityRequestDescriptor_t, -+ *pMpi2HighPriorityRequestDescriptor_t; -+ -+/*SCSI IO Request Descriptor */ -+typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 DevHandle; /*0x06 */ -+} MPI2_SCSI_IO_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR, -+ Mpi2SCSIIORequestDescriptor_t, -+ *pMpi2SCSIIORequestDescriptor_t; -+ -+/*SCSI Target Request Descriptor */ -+typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 IoIndex; /*0x06 */ -+} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, -+ Mpi2SCSITargetRequestDescriptor_t, -+ *pMpi2SCSITargetRequestDescriptor_t; -+ -+/*RAID Accelerator Request Descriptor */ -+typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 LMID; /*0x04 */ -+ U16 Reserved; /*0x06 */ -+} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, -+ *PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, -+ Mpi2RAIDAcceleratorRequestDescriptor_t, -+ *pMpi2RAIDAcceleratorRequestDescriptor_t; -+ -+/*Fast Path SCSI IO Request Descriptor */ -+typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR -+ MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR, -+ *PTR_MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR, -+ Mpi25FastPathSCSIIORequestDescriptor_t, -+ *pMpi25FastPathSCSIIORequestDescriptor_t; -+ -+/*union of Request Descriptors */ -+typedef union _MPI2_REQUEST_DESCRIPTOR_UNION { -+ MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; -+ MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; -+ MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; -+ MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; -+ MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; -+ MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR FastPathSCSIIO; -+ U64 Words; -+} MPI2_REQUEST_DESCRIPTOR_UNION, -+ *PTR_MPI2_REQUEST_DESCRIPTOR_UNION, -+ Mpi2RequestDescriptorUnion_t, -+ *pMpi2RequestDescriptorUnion_t; -+ -+/*Atomic Request Descriptors */ -+ -+/* -+ * All Atomic Request Descriptors have the same format, so the following -+ * structure is used for all Atomic Request Descriptors: -+ * Atomic Default Request Descriptor -+ * Atomic High Priority Request Descriptor -+ * Atomic SCSI IO Request Descriptor -+ * Atomic SCSI Target Request Descriptor -+ * Atomic RAID Accelerator Request Descriptor -+ * Atomic Fast Path SCSI IO Request Descriptor -+ */ -+ -+/*Atomic Request Descriptor */ -+typedef struct _MPI26_ATOMIC_REQUEST_DESCRIPTOR { -+ U8 RequestFlags; /* 0x00 */ -+ U8 MSIxIndex; /* 0x01 */ -+ U16 SMID; /* 0x02 */ -+} MPI26_ATOMIC_REQUEST_DESCRIPTOR, -+ *PTR_MPI26_ATOMIC_REQUEST_DESCRIPTOR, -+ Mpi26AtomicRequestDescriptor_t, -+ *pMpi26AtomicRequestDescriptor_t; -+ -+/*for the RequestFlags field, use the same -+ *defines as MPI2_DEFAULT_REQUEST_DESCRIPTOR -+ */ -+ -+/*Reply Descriptors */ -+ -+/*Default Reply Descriptor */ -+typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 DescriptorTypeDependent1; /*0x02 */ -+ U32 DescriptorTypeDependent2; /*0x04 */ -+} MPI2_DEFAULT_REPLY_DESCRIPTOR, -+ *PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR, -+ Mpi2DefaultReplyDescriptor_t, -+ *pMpi2DefaultReplyDescriptor_t; -+ -+/*defines for the ReplyFlags field */ -+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) -+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) -+#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) -+#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) -+#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) -+#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05) -+#define MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS (0x06) -+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) -+ -+/*values for marking a reply descriptor as unused */ -+#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) -+#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF) -+ -+/*Address Reply Descriptor */ -+typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U32 ReplyFrameAddress; /*0x04 */ -+} MPI2_ADDRESS_REPLY_DESCRIPTOR, -+ *PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, -+ Mpi2AddressReplyDescriptor_t, -+ *pMpi2AddressReplyDescriptor_t; -+ -+#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00) -+ -+/*SCSI IO Success Reply Descriptor */ -+typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U16 TaskTag; /*0x04 */ -+ U16 Reserved1; /*0x06 */ -+} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, -+ *PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, -+ Mpi2SCSIIOSuccessReplyDescriptor_t, -+ *pMpi2SCSIIOSuccessReplyDescriptor_t; -+ -+/*TargetAssist Success Reply Descriptor */ -+typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U8 SequenceNumber; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 IoIndex; /*0x06 */ -+} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, -+ *PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, -+ Mpi2TargetAssistSuccessReplyDescriptor_t, -+ *pMpi2TargetAssistSuccessReplyDescriptor_t; -+ -+/*Target Command Buffer Reply Descriptor */ -+typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U8 VP_ID; /*0x02 */ -+ U8 Flags; /*0x03 */ -+ U16 InitiatorDevHandle; /*0x04 */ -+ U16 IoIndex; /*0x06 */ -+} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, -+ *PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, -+ Mpi2TargetCommandBufferReplyDescriptor_t, -+ *pMpi2TargetCommandBufferReplyDescriptor_t; -+ -+/*defines for Flags field */ -+#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F) -+ -+/*RAID Accelerator Success Reply Descriptor */ -+typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { -+ U8 ReplyFlags; /*0x00 */ -+ U8 MSIxIndex; /*0x01 */ -+ U16 SMID; /*0x02 */ -+ U32 Reserved; /*0x04 */ -+} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, -+ *PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, -+ Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, -+ *pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; -+ -+/*Fast Path SCSI IO Success Reply Descriptor */ -+typedef MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR -+ MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, -+ *PTR_MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, -+ Mpi25FastPathSCSIIOSuccessReplyDescriptor_t, -+ *pMpi25FastPathSCSIIOSuccessReplyDescriptor_t; -+ -+/*union of Reply Descriptors */ -+typedef union _MPI2_REPLY_DESCRIPTORS_UNION { -+ MPI2_DEFAULT_REPLY_DESCRIPTOR Default; -+ MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; -+ MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; -+ MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; -+ MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; -+ MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; -+ MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR FastPathSCSIIOSuccess; -+ U64 Words; -+} MPI2_REPLY_DESCRIPTORS_UNION, -+ *PTR_MPI2_REPLY_DESCRIPTORS_UNION, -+ Mpi2ReplyDescriptorsUnion_t, -+ *pMpi2ReplyDescriptorsUnion_t; -+ -+/***************************************************************************** -+* -+* Message Functions -+* -+*****************************************************************************/ -+ -+#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) -+#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) -+#define MPI2_FUNCTION_IOC_INIT (0x02) -+#define MPI2_FUNCTION_IOC_FACTS (0x03) -+#define MPI2_FUNCTION_CONFIG (0x04) -+#define MPI2_FUNCTION_PORT_FACTS (0x05) -+#define MPI2_FUNCTION_PORT_ENABLE (0x06) -+#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) -+#define MPI2_FUNCTION_EVENT_ACK (0x08) -+#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) -+#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) -+#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) -+#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) -+#define MPI2_FUNCTION_FW_UPLOAD (0x12) -+#define MPI2_FUNCTION_RAID_ACTION (0x15) -+#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) -+#define MPI2_FUNCTION_TOOLBOX (0x17) -+#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) -+#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) -+#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) -+#define MPI2_FUNCTION_IO_UNIT_CONTROL (0x1B) -+#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) -+#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) -+#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) -+#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) -+#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) -+#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) -+#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) -+#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) -+#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) -+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) -+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) -+ -+/*Doorbell functions */ -+#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) -+#define MPI2_FUNCTION_HANDSHAKE (0x42) -+ -+/***************************************************************************** -+* -+* IOC Status Values -+* -+*****************************************************************************/ -+ -+/*mask for IOCStatus status value */ -+#define MPI2_IOCSTATUS_MASK (0x7FFF) -+ -+/**************************************************************************** -+* Common IOCStatus values for all replies -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_SUCCESS (0x0000) -+#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001) -+#define MPI2_IOCSTATUS_BUSY (0x0002) -+#define MPI2_IOCSTATUS_INVALID_SGL (0x0003) -+#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004) -+#define MPI2_IOCSTATUS_INVALID_VPID (0x0005) -+#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) -+#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007) -+#define MPI2_IOCSTATUS_INVALID_STATE (0x0008) -+#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) -+#define MPI2_IOCSTATUS_INSUFFICIENT_POWER (0x000A) -+ -+/**************************************************************************** -+* Config IOCStatus values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) -+#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) -+#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) -+#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) -+#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) -+#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) -+ -+/**************************************************************************** -+* SCSI IO Reply -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) -+#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) -+#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) -+#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) -+#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) -+#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) -+#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) -+#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) -+#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) -+#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) -+#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) -+#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) -+ -+/**************************************************************************** -+* For use by SCSI Initiator and SCSI Target end-to-end data protection -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) -+#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) -+#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) -+ -+/**************************************************************************** -+* SCSI Target values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) -+#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063) -+#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) -+#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) -+#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) -+#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) -+#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) -+#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) -+#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) -+#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) -+ -+/**************************************************************************** -+* Serial Attached SCSI values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) -+#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) -+ -+/**************************************************************************** -+* Diagnostic Buffer Post / Diagnostic Release values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) -+ -+/**************************************************************************** -+* RAID Accelerator values -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0) -+ -+/**************************************************************************** -+* IOCStatus flag to indicate that log info is available -+****************************************************************************/ -+ -+#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) -+ -+/**************************************************************************** -+* IOCLogInfo Types -+****************************************************************************/ -+ -+#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000) -+#define MPI2_IOCLOGINFO_TYPE_SHIFT (28) -+#define MPI2_IOCLOGINFO_TYPE_NONE (0x0) -+#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1) -+#define MPI2_IOCLOGINFO_TYPE_FC (0x2) -+#define MPI2_IOCLOGINFO_TYPE_SAS (0x3) -+#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4) -+#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) -+ -+/***************************************************************************** -+* -+* Standard Message Structures -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+*Request Message Header for all request messages -+****************************************************************************/ -+ -+typedef struct _MPI2_REQUEST_HEADER { -+ U16 FunctionDependent1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 FunctionDependent2; /*0x04 */ -+ U8 FunctionDependent3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+} MPI2_REQUEST_HEADER, *PTR_MPI2_REQUEST_HEADER, -+ MPI2RequestHeader_t, *pMPI2RequestHeader_t; -+ -+/**************************************************************************** -+* Default Reply -+****************************************************************************/ -+ -+typedef struct _MPI2_DEFAULT_REPLY { -+ U16 FunctionDependent1; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 FunctionDependent2; /*0x04 */ -+ U8 FunctionDependent3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U16 FunctionDependent5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_DEFAULT_REPLY, *PTR_MPI2_DEFAULT_REPLY, -+ MPI2DefaultReply_t, *pMPI2DefaultReply_t; -+ -+/*common version structure/union used in messages and configuration pages */ -+ -+typedef struct _MPI2_VERSION_STRUCT { -+ U8 Dev; /*0x00 */ -+ U8 Unit; /*0x01 */ -+ U8 Minor; /*0x02 */ -+ U8 Major; /*0x03 */ -+} MPI2_VERSION_STRUCT; -+ -+typedef union _MPI2_VERSION_UNION { -+ MPI2_VERSION_STRUCT Struct; -+ U32 Word; -+} MPI2_VERSION_UNION; -+ -+/*LUN field defines, common to many structures */ -+#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) -+#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) -+#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) -+#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) -+#define MPI2_LUN_LEVEL_1_WORD (0xFF00) -+#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00) -+ -+/***************************************************************************** -+* -+* Fusion-MPT MPI Scatter Gather Elements -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* MPI Simple Element structures -+****************************************************************************/ -+ -+typedef struct _MPI2_SGE_SIMPLE32 { -+ U32 FlagsLength; -+ U32 Address; -+} MPI2_SGE_SIMPLE32, *PTR_MPI2_SGE_SIMPLE32, -+ Mpi2SGESimple32_t, *pMpi2SGESimple32_t; -+ -+typedef struct _MPI2_SGE_SIMPLE64 { -+ U32 FlagsLength; -+ U64 Address; -+} MPI2_SGE_SIMPLE64, *PTR_MPI2_SGE_SIMPLE64, -+ Mpi2SGESimple64_t, *pMpi2SGESimple64_t; -+ -+typedef struct _MPI2_SGE_SIMPLE_UNION { -+ U32 FlagsLength; -+ union { -+ U32 Address32; -+ U64 Address64; -+ } u; -+} MPI2_SGE_SIMPLE_UNION, -+ *PTR_MPI2_SGE_SIMPLE_UNION, -+ Mpi2SGESimpleUnion_t, -+ *pMpi2SGESimpleUnion_t; -+ -+/**************************************************************************** -+* MPI Chain Element structures - for MPI v2.0 products only -+****************************************************************************/ -+ -+typedef struct _MPI2_SGE_CHAIN32 { -+ U16 Length; -+ U8 NextChainOffset; -+ U8 Flags; -+ U32 Address; -+} MPI2_SGE_CHAIN32, *PTR_MPI2_SGE_CHAIN32, -+ Mpi2SGEChain32_t, *pMpi2SGEChain32_t; -+ -+typedef struct _MPI2_SGE_CHAIN64 { -+ U16 Length; -+ U8 NextChainOffset; -+ U8 Flags; -+ U64 Address; -+} MPI2_SGE_CHAIN64, *PTR_MPI2_SGE_CHAIN64, -+ Mpi2SGEChain64_t, *pMpi2SGEChain64_t; -+ -+typedef struct _MPI2_SGE_CHAIN_UNION { -+ U16 Length; -+ U8 NextChainOffset; -+ U8 Flags; -+ union { -+ U32 Address32; -+ U64 Address64; -+ } u; -+} MPI2_SGE_CHAIN_UNION, -+ *PTR_MPI2_SGE_CHAIN_UNION, -+ Mpi2SGEChainUnion_t, -+ *pMpi2SGEChainUnion_t; -+ -+/**************************************************************************** -+* MPI Transaction Context Element structures - for MPI v2.0 products only -+****************************************************************************/ -+ -+typedef struct _MPI2_SGE_TRANSACTION32 { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ U32 TransactionContext[1]; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION32, -+ *PTR_MPI2_SGE_TRANSACTION32, -+ Mpi2SGETransaction32_t, -+ *pMpi2SGETransaction32_t; -+ -+typedef struct _MPI2_SGE_TRANSACTION64 { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ U32 TransactionContext[2]; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION64, -+ *PTR_MPI2_SGE_TRANSACTION64, -+ Mpi2SGETransaction64_t, -+ *pMpi2SGETransaction64_t; -+ -+typedef struct _MPI2_SGE_TRANSACTION96 { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ U32 TransactionContext[3]; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION96, *PTR_MPI2_SGE_TRANSACTION96, -+ Mpi2SGETransaction96_t, *pMpi2SGETransaction96_t; -+ -+typedef struct _MPI2_SGE_TRANSACTION128 { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ U32 TransactionContext[4]; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION128, *PTR_MPI2_SGE_TRANSACTION128, -+ Mpi2SGETransaction_t128, *pMpi2SGETransaction_t128; -+ -+typedef struct _MPI2_SGE_TRANSACTION_UNION { -+ U8 Reserved; -+ U8 ContextSize; -+ U8 DetailsLength; -+ U8 Flags; -+ union { -+ U32 TransactionContext32[1]; -+ U32 TransactionContext64[2]; -+ U32 TransactionContext96[3]; -+ U32 TransactionContext128[4]; -+ } u; -+ U32 TransactionDetails[1]; -+} MPI2_SGE_TRANSACTION_UNION, -+ *PTR_MPI2_SGE_TRANSACTION_UNION, -+ Mpi2SGETransactionUnion_t, -+ *pMpi2SGETransactionUnion_t; -+ -+/**************************************************************************** -+* MPI SGE union for IO SGL's - for MPI v2.0 products only -+****************************************************************************/ -+ -+typedef struct _MPI2_MPI_SGE_IO_UNION { -+ union { -+ MPI2_SGE_SIMPLE_UNION Simple; -+ MPI2_SGE_CHAIN_UNION Chain; -+ } u; -+} MPI2_MPI_SGE_IO_UNION, *PTR_MPI2_MPI_SGE_IO_UNION, -+ Mpi2MpiSGEIOUnion_t, *pMpi2MpiSGEIOUnion_t; -+ -+/**************************************************************************** -+* MPI SGE union for SGL's with Simple and Transaction elements - for MPI v2.0 products only -+****************************************************************************/ -+ -+typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION { -+ union { -+ MPI2_SGE_SIMPLE_UNION Simple; -+ MPI2_SGE_TRANSACTION_UNION Transaction; -+ } u; -+} MPI2_SGE_TRANS_SIMPLE_UNION, -+ *PTR_MPI2_SGE_TRANS_SIMPLE_UNION, -+ Mpi2SGETransSimpleUnion_t, -+ *pMpi2SGETransSimpleUnion_t; -+ -+/**************************************************************************** -+* All MPI SGE types union -+****************************************************************************/ -+ -+typedef struct _MPI2_MPI_SGE_UNION { -+ union { -+ MPI2_SGE_SIMPLE_UNION Simple; -+ MPI2_SGE_CHAIN_UNION Chain; -+ MPI2_SGE_TRANSACTION_UNION Transaction; -+ } u; -+} MPI2_MPI_SGE_UNION, *PTR_MPI2_MPI_SGE_UNION, -+ Mpi2MpiSgeUnion_t, *pMpi2MpiSgeUnion_t; -+ -+/**************************************************************************** -+* MPI SGE field definition and masks -+****************************************************************************/ -+ -+/*Flags field bit definitions */ -+ -+#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80) -+#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40) -+#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) -+#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08) -+#define MPI2_SGE_FLAGS_DIRECTION (0x04) -+#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02) -+#define MPI2_SGE_FLAGS_END_OF_LIST (0x01) -+ -+#define MPI2_SGE_FLAGS_SHIFT (24) -+ -+#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF) -+#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) -+ -+/*Element Type */ -+ -+#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) -+#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10) -+#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30) -+#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30) -+ -+/*Address location */ -+ -+#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00) -+ -+/*Direction */ -+ -+#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) -+#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) -+ -+#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST) -+#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC) -+ -+/*Address Size */ -+ -+#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) -+#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) -+ -+/*Context Size */ -+ -+#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00) -+#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02) -+#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04) -+#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06) -+ -+#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000) -+#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16) -+ -+/**************************************************************************** -+* MPI SGE operation Macros -+****************************************************************************/ -+ -+/*SIMPLE FlagsLength manipulations... */ -+#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT) -+#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> \ -+ MPI2_SGE_FLAGS_SHIFT) -+#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK) -+#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK) -+ -+#define MPI2_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_SGE_SET_FLAGS(f) | \ -+ MPI2_SGE_LENGTH(l)) -+ -+#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength) -+#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength) -+#define MPI2_pSGE_SET_FLAGS_LENGTH(psg, f, l) ((psg)->FlagsLength = \ -+ MPI2_SGE_SET_FLAGS_LENGTH(f, l)) -+ -+/*CAUTION - The following are READ-MODIFY-WRITE! */ -+#define MPI2_pSGE_SET_FLAGS(psg, f) ((psg)->FlagsLength |= \ -+ MPI2_SGE_SET_FLAGS(f)) -+#define MPI2_pSGE_SET_LENGTH(psg, l) ((psg)->FlagsLength |= \ -+ MPI2_SGE_LENGTH(l)) -+ -+#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> \ -+ MPI2_SGE_CHAIN_OFFSET_SHIFT) -+ -+/***************************************************************************** -+* -+* Fusion-MPT IEEE Scatter Gather Elements -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* IEEE Simple Element structures -+****************************************************************************/ -+ -+/*MPI2_IEEE_SGE_SIMPLE32 is for MPI v2.0 products only */ -+typedef struct _MPI2_IEEE_SGE_SIMPLE32 { -+ U32 Address; -+ U32 FlagsLength; -+} MPI2_IEEE_SGE_SIMPLE32, *PTR_MPI2_IEEE_SGE_SIMPLE32, -+ Mpi2IeeeSgeSimple32_t, *pMpi2IeeeSgeSimple32_t; -+ -+typedef struct _MPI2_IEEE_SGE_SIMPLE64 { -+ U64 Address; -+ U32 Length; -+ U16 Reserved1; -+ U8 Reserved2; -+ U8 Flags; -+} MPI2_IEEE_SGE_SIMPLE64, *PTR_MPI2_IEEE_SGE_SIMPLE64, -+ Mpi2IeeeSgeSimple64_t, *pMpi2IeeeSgeSimple64_t; -+ -+typedef union _MPI2_IEEE_SGE_SIMPLE_UNION { -+ MPI2_IEEE_SGE_SIMPLE32 Simple32; -+ MPI2_IEEE_SGE_SIMPLE64 Simple64; -+} MPI2_IEEE_SGE_SIMPLE_UNION, -+ *PTR_MPI2_IEEE_SGE_SIMPLE_UNION, -+ Mpi2IeeeSgeSimpleUnion_t, -+ *pMpi2IeeeSgeSimpleUnion_t; -+ -+/**************************************************************************** -+* IEEE Chain Element structures -+****************************************************************************/ -+ -+/*MPI2_IEEE_SGE_CHAIN32 is for MPI v2.0 products only */ -+typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32; -+ -+/*MPI2_IEEE_SGE_CHAIN64 is for MPI v2.0 products only */ -+typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64; -+ -+typedef union _MPI2_IEEE_SGE_CHAIN_UNION { -+ MPI2_IEEE_SGE_CHAIN32 Chain32; -+ MPI2_IEEE_SGE_CHAIN64 Chain64; -+} MPI2_IEEE_SGE_CHAIN_UNION, -+ *PTR_MPI2_IEEE_SGE_CHAIN_UNION, -+ Mpi2IeeeSgeChainUnion_t, -+ *pMpi2IeeeSgeChainUnion_t; -+ -+/*MPI25_IEEE_SGE_CHAIN64 is for MPI v2.5 and later */ -+typedef struct _MPI25_IEEE_SGE_CHAIN64 { -+ U64 Address; -+ U32 Length; -+ U16 Reserved1; -+ U8 NextChainOffset; -+ U8 Flags; -+} MPI25_IEEE_SGE_CHAIN64, -+ *PTR_MPI25_IEEE_SGE_CHAIN64, -+ Mpi25IeeeSgeChain64_t, -+ *pMpi25IeeeSgeChain64_t; -+ -+/**************************************************************************** -+* All IEEE SGE types union -+****************************************************************************/ -+ -+/*MPI2_IEEE_SGE_UNION is for MPI v2.0 products only */ -+typedef struct _MPI2_IEEE_SGE_UNION { -+ union { -+ MPI2_IEEE_SGE_SIMPLE_UNION Simple; -+ MPI2_IEEE_SGE_CHAIN_UNION Chain; -+ } u; -+} MPI2_IEEE_SGE_UNION, *PTR_MPI2_IEEE_SGE_UNION, -+ Mpi2IeeeSgeUnion_t, *pMpi2IeeeSgeUnion_t; -+ -+/**************************************************************************** -+* IEEE SGE union for IO SGL's -+****************************************************************************/ -+ -+typedef union _MPI25_SGE_IO_UNION { -+ MPI2_IEEE_SGE_SIMPLE64 IeeeSimple; -+ MPI25_IEEE_SGE_CHAIN64 IeeeChain; -+} MPI25_SGE_IO_UNION, *PTR_MPI25_SGE_IO_UNION, -+ Mpi25SGEIOUnion_t, *pMpi25SGEIOUnion_t; -+ -+/**************************************************************************** -+* IEEE SGE field definitions and masks -+****************************************************************************/ -+ -+/*Flags field bit definitions */ -+ -+#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80) -+#define MPI25_IEEE_SGE_FLAGS_END_OF_LIST (0x40) -+ -+#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24) -+ -+#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF) -+ -+/*Element Type */ -+ -+#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00) -+#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) -+ -+/*Next Segment Format */ -+ -+#define MPI26_IEEE_SGE_FLAGS_NSF_MASK (0x1C) -+#define MPI26_IEEE_SGE_FLAGS_NSF_MPI_IEEE (0x00) -+ -+/*Data Location Address Space */ -+ -+#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) -+#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) -+#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) -+#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) -+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) -+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03) -+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \ -+ (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) -+#define MPI26_IEEE_SGE_FLAGS_IOCCTL_ADDR (0x02) -+ -+/**************************************************************************** -+* IEEE SGE operation Macros -+****************************************************************************/ -+ -+/*SIMPLE FlagsLength manipulations... */ -+#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT) -+#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) \ -+ >> MPI2_IEEE32_SGE_FLAGS_SHIFT) -+#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK) -+ -+#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) |\ -+ MPI2_IEEE32_SGE_LENGTH(l)) -+ -+#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) \ -+ MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength) -+#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) \ -+ MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength) -+#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg, f, l) ((psg)->FlagsLength = \ -+ MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l)) -+ -+/*CAUTION - The following are READ-MODIFY-WRITE! */ -+#define MPI2_IEEE32_pSGE_SET_FLAGS(psg, f) ((psg)->FlagsLength |= \ -+ MPI2_IEEE32_SGE_SET_FLAGS(f)) -+#define MPI2_IEEE32_pSGE_SET_LENGTH(psg, l) ((psg)->FlagsLength |= \ -+ MPI2_IEEE32_SGE_LENGTH(l)) -+ -+/***************************************************************************** -+* -+* Fusion-MPT MPI/IEEE Scatter Gather Unions -+* -+*****************************************************************************/ -+ -+typedef union _MPI2_SIMPLE_SGE_UNION { -+ MPI2_SGE_SIMPLE_UNION MpiSimple; -+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; -+} MPI2_SIMPLE_SGE_UNION, *PTR_MPI2_SIMPLE_SGE_UNION, -+ Mpi2SimpleSgeUntion_t, *pMpi2SimpleSgeUntion_t; -+ -+typedef union _MPI2_SGE_IO_UNION { -+ MPI2_SGE_SIMPLE_UNION MpiSimple; -+ MPI2_SGE_CHAIN_UNION MpiChain; -+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; -+ MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; -+} MPI2_SGE_IO_UNION, *PTR_MPI2_SGE_IO_UNION, -+ Mpi2SGEIOUnion_t, *pMpi2SGEIOUnion_t; -+ -+/**************************************************************************** -+* -+* Values for SGLFlags field, used in many request messages with an SGL -+* -+****************************************************************************/ -+ -+/*values for MPI SGL Data Location Address Space subfield */ -+#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C) -+#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00) -+#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04) -+#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) -+#define MPI26_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) -+#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C) -+/*values for SGL Type subfield */ -+#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03) -+#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00) -+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01) -+#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02) -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -new file mode 100644 -index 0000000..95356a8 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h -@@ -0,0 +1,3493 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_cnfg.h -+ * Title: MPI Configuration messages and pages -+ * Creation Date: November 10, 2006 -+ * -+ * mpi2_cnfg.h Version: 02.00.35 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. -+ * Added Manufacturing Page 11. -+ * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE -+ * define. -+ * 06-26-07 02.00.02 Adding generic structure for product-specific -+ * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. -+ * Rework of BIOS Page 2 configuration page. -+ * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the -+ * forms. -+ * Added configuration pages IOC Page 8 and Driver -+ * Persistent Mapping Page 0. -+ * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated -+ * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, -+ * RAID Physical Disk Pages 0 and 1, RAID Configuration -+ * Page 0). -+ * Added new value for AccessStatus field of SAS Device -+ * Page 0 (_SATA_NEEDS_INITIALIZATION). -+ * 10-31-07 02.00.04 Added missing SEPDevHandle field to -+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. -+ * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for -+ * NVDATA. -+ * Modified IOC Page 7 to use masks and added field for -+ * SASBroadcastPrimitiveMasks. -+ * Added MPI2_CONFIG_PAGE_BIOS_4. -+ * Added MPI2_CONFIG_PAGE_LOG_0. -+ * 02-29-08 02.00.06 Modified various names to make them 32-character unique. -+ * Added SAS Device IDs. -+ * Updated Integrated RAID configuration pages including -+ * Manufacturing Page 4, IOC Page 6, and RAID Configuration -+ * Page 0. -+ * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. -+ * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. -+ * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. -+ * Added missing MaxNumRoutedSasAddresses field to -+ * MPI2_CONFIG_PAGE_EXPANDER_0. -+ * Added SAS Port Page 0. -+ * Modified structure layout for -+ * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. -+ * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use -+ * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. -+ * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF -+ * to 0x000000FF. -+ * Added two new values for the Physical Disk Coercion Size -+ * bits in the Flags field of Manufacturing Page 4. -+ * Added product-specific Manufacturing pages 16 to 31. -+ * Modified Flags bits for controlling write cache on SATA -+ * drives in IO Unit Page 1. -+ * Added new bit to AdditionalControlFlags of SAS IO Unit -+ * Page 1 to control Invalid Topology Correction. -+ * Added additional defines for RAID Volume Page 0 -+ * VolumeStatusFlags field. -+ * Modified meaning of RAID Volume Page 0 VolumeSettings -+ * define for auto-configure of hot-swap drives. -+ * Added SupportedPhysDisks field to RAID Volume Page 1 and -+ * added related defines. -+ * Added PhysDiskAttributes field (and related defines) to -+ * RAID Physical Disk Page 0. -+ * Added MPI2_SAS_PHYINFO_PHY_VACANT define. -+ * Added three new DiscoveryStatus bits for SAS IO Unit -+ * Page 0 and SAS Expander Page 0. -+ * Removed multiplexing information from SAS IO Unit pages. -+ * Added BootDeviceWaitTime field to SAS IO Unit Page 4. -+ * Removed Zone Address Resolved bit from PhyInfo and from -+ * Expander Page 0 Flags field. -+ * Added two new AccessStatus values to SAS Device Page 0 -+ * for indicating routing problems. Added 3 reserved words -+ * to this page. -+ * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. -+ * Inserted missing reserved field into structure for IOC -+ * Page 6. -+ * Added more pending task bits to RAID Volume Page 0 -+ * VolumeStatusFlags defines. -+ * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. -+ * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 -+ * and SAS Expander Page 0 to flag a downstream initiator -+ * when in simplified routing mode. -+ * Removed SATA Init Failure defines for DiscoveryStatus -+ * fields of SAS IO Unit Page 0 and SAS Expander Page 0. -+ * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. -+ * Added PortGroups, DmaGroup, and ControlGroup fields to -+ * SAS Device Page 0. -+ * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO -+ * Unit Page 6. -+ * Added expander reduced functionality data to SAS -+ * Expander Page 0. -+ * Added SAS PHY Page 2 and SAS PHY Page 3. -+ * 07-30-09 02.00.12 Added IO Unit Page 7. -+ * Added new device ids. -+ * Added SAS IO Unit Page 5. -+ * Added partial and slumber power management capable flags -+ * to SAS Device Page 0 Flags field. -+ * Added PhyInfo defines for power condition. -+ * Added Ethernet configuration pages. -+ * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. -+ * Added SAS PHY Page 4 structure and defines. -+ * 02-10-10 02.00.14 Modified the comments for the configuration page -+ * structures that contain an array of data. The host -+ * should use the "count" field in the page data (e.g. the -+ * NumPhys field) to determine the number of valid elements -+ * in the array. -+ * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. -+ * Added PowerManagementCapabilities to IO Unit Page 7. -+ * Added PortWidthModGroup field to -+ * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. -+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. -+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. -+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. -+ * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT -+ * define. -+ * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. -+ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. -+ * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) -+ * defines. -+ * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to -+ * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for -+ * the Pinout field. -+ * Added BoardTemperature and BoardTemperatureUnits fields -+ * to MPI2_CONFIG_PAGE_IO_UNIT_7. -+ * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define -+ * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. -+ * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. -+ * Added IO Unit Page 8, IO Unit Page 9, -+ * and IO Unit Page 10. -+ * Added SASNotifyPrimitiveMasks field to -+ * MPI2_CONFIG_PAGE_IOC_7. -+ * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). -+ * 05-25-11 02.00.20 Cleaned up a few comments. -+ * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities -+ * for PCIe link as obsolete. -+ * Added SpinupFlags field containing a Disable Spin-up bit -+ * to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of SAS IO -+ * Unit Page 4. -+ * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT. -+ * Added UEFIVersion field to BIOS Page 1 and defined new -+ * BiosOptions bits. -+ * Incorporating additions for MPI v2.5. -+ * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER. -+ * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID. -+ * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as -+ * obsolete for MPI v2.5 and later. -+ * Added some defines for 12G SAS speeds. -+ * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK. -+ * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to -+ * match the specification. -+ * 08-19-13 02.00.26 Added reserved words to MPI2_CONFIG_PAGE_IO_UNIT_7 for -+ * future use. -+ * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for -+ * MPI2_CONFIG_PAGE_MAN_7. -+ * Added EnclosureLevel and ConnectorName fields to -+ * MPI2_CONFIG_PAGE_SAS_DEV_0. -+ * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for -+ * MPI2_CONFIG_PAGE_SAS_DEV_0. -+ * Added EnclosureLevel field to -+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. -+ * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for -+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. -+ * 01-08-14 02.00.28 Added more defines for the BiosOptions field of -+ * MPI2_CONFIG_PAGE_BIOS_1. -+ * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and -+ * more defines for the BiosOptions field. -+ * 11-18-14 02.00.30 Updated copyright information. -+ * Added MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG. -+ * Added AdapterOrderAux fields to BIOS Page 3. -+ * 03-16-15 02.00.31 Updated for MPI v2.6. -+ * Added Flags field to IO Unit Page 7. -+ * Added new SAS Phy Event codes -+ * 05-25-15 02.00.33 Added more defines for the BiosOptions field of -+ * MPI2_CONFIG_PAGE_BIOS_1. -+ * 08-25-15 02.00.34 Bumped Header Version. -+ * 12-18-15 02.00.35 Added SATADeviceWaitTime to SAS IO Unit Page 4. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_CNFG_H -+#define MPI2_CNFG_H -+ -+/***************************************************************************** -+* Configuration Page Header and defines -+*****************************************************************************/ -+ -+/*Config Page Header */ -+typedef struct _MPI2_CONFIG_PAGE_HEADER { -+ U8 PageVersion; /*0x00 */ -+ U8 PageLength; /*0x01 */ -+ U8 PageNumber; /*0x02 */ -+ U8 PageType; /*0x03 */ -+} MPI2_CONFIG_PAGE_HEADER, *PTR_MPI2_CONFIG_PAGE_HEADER, -+ Mpi2ConfigPageHeader_t, *pMpi2ConfigPageHeader_t; -+ -+typedef union _MPI2_CONFIG_PAGE_HEADER_UNION { -+ MPI2_CONFIG_PAGE_HEADER Struct; -+ U8 Bytes[4]; -+ U16 Word16[2]; -+ U32 Word32; -+} MPI2_CONFIG_PAGE_HEADER_UNION, *PTR_MPI2_CONFIG_PAGE_HEADER_UNION, -+ Mpi2ConfigPageHeaderUnion, *pMpi2ConfigPageHeaderUnion; -+ -+/*Extended Config Page Header */ -+typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER { -+ U8 PageVersion; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 PageNumber; /*0x02 */ -+ U8 PageType; /*0x03 */ -+ U16 ExtPageLength; /*0x04 */ -+ U8 ExtPageType; /*0x06 */ -+ U8 Reserved2; /*0x07 */ -+} MPI2_CONFIG_EXTENDED_PAGE_HEADER, -+ *PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER, -+ Mpi2ConfigExtendedPageHeader_t, -+ *pMpi2ConfigExtendedPageHeader_t; -+ -+typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION { -+ MPI2_CONFIG_PAGE_HEADER Struct; -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext; -+ U8 Bytes[8]; -+ U16 Word16[4]; -+ U32 Word32[2]; -+} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, -+ *PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION, -+ Mpi2ConfigPageExtendedHeaderUnion, -+ *pMpi2ConfigPageExtendedHeaderUnion; -+ -+ -+/*PageType field values */ -+#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) -+#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) -+#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) -+#define MPI2_CONFIG_PAGEATTR_MASK (0xF0) -+ -+#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00) -+#define MPI2_CONFIG_PAGETYPE_IOC (0x01) -+#define MPI2_CONFIG_PAGETYPE_BIOS (0x02) -+#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08) -+#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09) -+#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) -+#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F) -+#define MPI2_CONFIG_PAGETYPE_MASK (0x0F) -+ -+#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF) -+ -+ -+/*ExtPageType field values */ -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) -+#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14) -+#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) -+#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) -+#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) -+#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) -+#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) -+#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) -+ -+ -+/***************************************************************************** -+* PageAddress defines -+*****************************************************************************/ -+ -+/*RAID Volume PageAddress format */ -+#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -+#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000) -+ -+#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF) -+ -+ -+/*RAID Physical Disk PageAddress format */ -+#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000) -+#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000) -+#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000) -+ -+#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) -+#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF) -+ -+ -+/*SAS Expander PageAddress format */ -+#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000) -+#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000) -+#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000) -+ -+#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF) -+#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000) -+#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16) -+ -+ -+/*SAS Device PageAddress format */ -+#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -+#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000) -+ -+#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF) -+ -+ -+/*SAS PHY PageAddress format */ -+#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000) -+#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000) -+ -+#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) -+#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF) -+ -+ -+/*SAS Port PageAddress format */ -+#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000) -+#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000) -+ -+#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF) -+ -+ -+/*SAS Enclosure PageAddress format */ -+#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -+#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000) -+ -+#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF) -+ -+ -+/*RAID Configuration PageAddress format */ -+#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000) -+#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000) -+#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000) -+ -+#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF) -+ -+ -+/*Driver Persistent Mapping PageAddress format */ -+#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000) -+ -+#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000) -+#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16) -+#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) -+ -+ -+/*Ethernet PageAddress format */ -+#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) -+#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) -+ -+#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) -+ -+ -+/**************************************************************************** -+* Configuration messages -+****************************************************************************/ -+ -+/*Configuration Request Message */ -+typedef struct _MPI2_CONFIG_REQUEST { -+ U8 Action; /*0x00 */ -+ U8 SGLFlags; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 ExtPageLength; /*0x04 */ -+ U8 ExtPageType; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U8 Reserved2; /*0x0C */ -+ U8 ProxyVF_ID; /*0x0D */ -+ U16 Reserved4; /*0x0E */ -+ U32 Reserved3; /*0x10 */ -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x14 */ -+ U32 PageAddress; /*0x18 */ -+ MPI2_SGE_IO_UNION PageBufferSGE; /*0x1C */ -+} MPI2_CONFIG_REQUEST, *PTR_MPI2_CONFIG_REQUEST, -+ Mpi2ConfigRequest_t, *pMpi2ConfigRequest_t; -+ -+/*values for the Action field */ -+#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00) -+#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) -+#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) -+#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03) -+#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) -+#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) -+#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) -+#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) -+ -+/*use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+ -+/*Config Reply Message */ -+typedef struct _MPI2_CONFIG_REPLY { -+ U8 Action; /*0x00 */ -+ U8 SGLFlags; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 ExtPageLength; /*0x04 */ -+ U8 ExtPageType; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U16 Reserved2; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x14 */ -+} MPI2_CONFIG_REPLY, *PTR_MPI2_CONFIG_REPLY, -+ Mpi2ConfigReply_t, *pMpi2ConfigReply_t; -+ -+ -+ -+/***************************************************************************** -+* -+* C o n f i g u r a t i o n P a g e s -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* Manufacturing Config pages -+****************************************************************************/ -+ -+#define MPI2_MFGPAGE_VENDORID_LSI (0x1000) -+ -+/*MPI v2.0 SAS products */ -+#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070) -+#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072) -+#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074) -+#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076) -+#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) -+#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) -+#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) -+ -+#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E) -+ -+#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) -+#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) -+#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) -+#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) -+#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) -+#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) -+#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) -+#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) -+#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) -+ -+/*MPI v2.5 SAS products */ -+#define MPI25_MFGPAGE_DEVID_SAS3004 (0x0096) -+#define MPI25_MFGPAGE_DEVID_SAS3008 (0x0097) -+#define MPI25_MFGPAGE_DEVID_SAS3108_1 (0x0090) -+#define MPI25_MFGPAGE_DEVID_SAS3108_2 (0x0091) -+#define MPI25_MFGPAGE_DEVID_SAS3108_5 (0x0094) -+#define MPI25_MFGPAGE_DEVID_SAS3108_6 (0x0095) -+ -+/* MPI v2.6 SAS Products */ -+#define MPI26_MFGPAGE_DEVID_SAS3216 (0x00C9) -+#define MPI26_MFGPAGE_DEVID_SAS3224 (0x00C4) -+#define MPI26_MFGPAGE_DEVID_SAS3316_1 (0x00C5) -+#define MPI26_MFGPAGE_DEVID_SAS3316_2 (0x00C6) -+#define MPI26_MFGPAGE_DEVID_SAS3316_3 (0x00C7) -+#define MPI26_MFGPAGE_DEVID_SAS3316_4 (0x00C8) -+#define MPI26_MFGPAGE_DEVID_SAS3324_1 (0x00C0) -+#define MPI26_MFGPAGE_DEVID_SAS3324_2 (0x00C1) -+#define MPI26_MFGPAGE_DEVID_SAS3324_3 (0x00C2) -+#define MPI26_MFGPAGE_DEVID_SAS3324_4 (0x00C3) -+ -+/*Manufacturing Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 ChipName[16]; /*0x04 */ -+ U8 ChipRevision[8]; /*0x14 */ -+ U8 BoardName[16]; /*0x1C */ -+ U8 BoardAssembly[16]; /*0x2C */ -+ U8 BoardTracerNumber[16]; /*0x3C */ -+} MPI2_CONFIG_PAGE_MAN_0, -+ *PTR_MPI2_CONFIG_PAGE_MAN_0, -+ Mpi2ManufacturingPage0_t, -+ *pMpi2ManufacturingPage0_t; -+ -+#define MPI2_MANUFACTURING0_PAGEVERSION (0x00) -+ -+ -+/*Manufacturing Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 VPD[256]; /*0x04 */ -+} MPI2_CONFIG_PAGE_MAN_1, -+ *PTR_MPI2_CONFIG_PAGE_MAN_1, -+ Mpi2ManufacturingPage1_t, -+ *pMpi2ManufacturingPage1_t; -+ -+#define MPI2_MANUFACTURING1_PAGEVERSION (0x00) -+ -+ -+typedef struct _MPI2_CHIP_REVISION_ID { -+ U16 DeviceID; /*0x00 */ -+ U8 PCIRevisionID; /*0x02 */ -+ U8 Reserved; /*0x03 */ -+} MPI2_CHIP_REVISION_ID, *PTR_MPI2_CHIP_REVISION_ID, -+ Mpi2ChipRevisionId_t, *pMpi2ChipRevisionId_t; -+ -+ -+/*Manufacturing Page 2 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check Header.PageLength at runtime. -+ */ -+#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS -+#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_2 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ MPI2_CHIP_REVISION_ID ChipId; /*0x04 */ -+ U32 -+ HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/*0x08 */ -+} MPI2_CONFIG_PAGE_MAN_2, -+ *PTR_MPI2_CONFIG_PAGE_MAN_2, -+ Mpi2ManufacturingPage2_t, -+ *pMpi2ManufacturingPage2_t; -+ -+#define MPI2_MANUFACTURING2_PAGEVERSION (0x00) -+ -+ -+/*Manufacturing Page 3 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check Header.PageLength at runtime. -+ */ -+#ifndef MPI2_MAN_PAGE_3_INFO_WORDS -+#define MPI2_MAN_PAGE_3_INFO_WORDS (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_3 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ MPI2_CHIP_REVISION_ID ChipId; /*0x04 */ -+ U32 -+ Info[MPI2_MAN_PAGE_3_INFO_WORDS];/*0x08 */ -+} MPI2_CONFIG_PAGE_MAN_3, -+ *PTR_MPI2_CONFIG_PAGE_MAN_3, -+ Mpi2ManufacturingPage3_t, -+ *pMpi2ManufacturingPage3_t; -+ -+#define MPI2_MANUFACTURING3_PAGEVERSION (0x00) -+ -+ -+/*Manufacturing Page 4 */ -+ -+typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS { -+ U8 PowerSaveFlags; /*0x00 */ -+ U8 InternalOperationsSleepTime; /*0x01 */ -+ U8 InternalOperationsRunTime; /*0x02 */ -+ U8 HostIdleTime; /*0x03 */ -+} MPI2_MANPAGE4_PWR_SAVE_SETTINGS, -+ *PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS, -+ Mpi2ManPage4PwrSaveSettings_t, -+ *pMpi2ManPage4PwrSaveSettings_t; -+ -+/*defines for the PowerSaveFlags field */ -+#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03) -+#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00) -+#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01) -+#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02) -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_4 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Flags; /*0x08 */ -+ U8 InquirySize; /*0x0C */ -+ U8 Reserved2; /*0x0D */ -+ U16 Reserved3; /*0x0E */ -+ U8 InquiryData[56]; /*0x10 */ -+ U32 RAID0VolumeSettings; /*0x48 */ -+ U32 RAID1EVolumeSettings; /*0x4C */ -+ U32 RAID1VolumeSettings; /*0x50 */ -+ U32 RAID10VolumeSettings; /*0x54 */ -+ U32 Reserved4; /*0x58 */ -+ U32 Reserved5; /*0x5C */ -+ MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /*0x60 */ -+ U8 MaxOCEDisks; /*0x64 */ -+ U8 ResyncRate; /*0x65 */ -+ U16 DataScrubDuration; /*0x66 */ -+ U8 MaxHotSpares; /*0x68 */ -+ U8 MaxPhysDisksPerVol; /*0x69 */ -+ U8 MaxPhysDisks; /*0x6A */ -+ U8 MaxVolumes; /*0x6B */ -+} MPI2_CONFIG_PAGE_MAN_4, -+ *PTR_MPI2_CONFIG_PAGE_MAN_4, -+ Mpi2ManufacturingPage4_t, -+ *pMpi2ManufacturingPage4_t; -+ -+#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A) -+ -+/*Manufacturing Page 4 Flags field */ -+#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000) -+#define MPI2_MANPAGE4_METADATA_512MB (0x00000000) -+ -+#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000) -+#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000) -+#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000) -+ -+#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00) -+#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000) -+#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400) -+#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800) -+#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00) -+ -+#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300) -+#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000) -+#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100) -+#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200) -+ -+#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080) -+#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040) -+#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020) -+#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010) -+#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008) -+#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004) -+#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002) -+#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001) -+ -+ -+/*Manufacturing Page 5 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES -+#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_MANUFACTURING5_ENTRY { -+ U64 WWID; /*0x00 */ -+ U64 DeviceName; /*0x08 */ -+} MPI2_MANUFACTURING5_ENTRY, -+ *PTR_MPI2_MANUFACTURING5_ENTRY, -+ Mpi2Manufacturing5Entry_t, -+ *pMpi2Manufacturing5Entry_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_5 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumPhys; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U32 Reserved3; /*0x08 */ -+ U32 Reserved4; /*0x0C */ -+ MPI2_MANUFACTURING5_ENTRY -+ Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/*0x08 */ -+} MPI2_CONFIG_PAGE_MAN_5, -+ *PTR_MPI2_CONFIG_PAGE_MAN_5, -+ Mpi2ManufacturingPage5_t, -+ *pMpi2ManufacturingPage5_t; -+ -+#define MPI2_MANUFACTURING5_PAGEVERSION (0x03) -+ -+ -+/*Manufacturing Page 6 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_6 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 ProductSpecificInfo;/*0x04 */ -+} MPI2_CONFIG_PAGE_MAN_6, -+ *PTR_MPI2_CONFIG_PAGE_MAN_6, -+ Mpi2ManufacturingPage6_t, -+ *pMpi2ManufacturingPage6_t; -+ -+#define MPI2_MANUFACTURING6_PAGEVERSION (0x00) -+ -+ -+/*Manufacturing Page 7 */ -+ -+typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO { -+ U32 Pinout; /*0x00 */ -+ U8 Connector[16]; /*0x04 */ -+ U8 Location; /*0x14 */ -+ U8 ReceptacleID; /*0x15 */ -+ U16 Slot; /*0x16 */ -+ U32 Reserved2; /*0x18 */ -+} MPI2_MANPAGE7_CONNECTOR_INFO, -+ *PTR_MPI2_MANPAGE7_CONNECTOR_INFO, -+ Mpi2ManPage7ConnectorInfo_t, -+ *pMpi2ManPage7ConnectorInfo_t; -+ -+/*defines for the Pinout field */ -+#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00) -+#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) -+ -+#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) -+#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) -+#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) -+#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) -+#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) -+#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) -+#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) -+#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) -+#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) -+#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) -+#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) -+#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) -+#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) -+#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) -+#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) -+ -+/*defines for the Location field */ -+#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) -+#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02) -+#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04) -+#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08) -+#define MPI2_MANPAGE7_LOCATION_AUTO (0x10) -+#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20) -+#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX -+#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_7 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U32 Flags; /*0x0C */ -+ U8 EnclosureName[16]; /*0x10 */ -+ U8 NumPhys; /*0x20 */ -+ U8 Reserved3; /*0x21 */ -+ U16 Reserved4; /*0x22 */ -+ MPI2_MANPAGE7_CONNECTOR_INFO -+ ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /*0x24 */ -+} MPI2_CONFIG_PAGE_MAN_7, -+ *PTR_MPI2_CONFIG_PAGE_MAN_7, -+ Mpi2ManufacturingPage7_t, -+ *pMpi2ManufacturingPage7_t; -+ -+#define MPI2_MANUFACTURING7_PAGEVERSION (0x01) -+ -+/*defines for the Flags field */ -+#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008) -+#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002) -+#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) -+ -+ -+/* -+ *Generic structure to use for product-specific manufacturing pages -+ *(currently Manufacturing Page 8 through Manufacturing Page 31). -+ */ -+ -+typedef struct _MPI2_CONFIG_PAGE_MAN_PS { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 ProductSpecificInfo;/*0x04 */ -+} MPI2_CONFIG_PAGE_MAN_PS, -+ *PTR_MPI2_CONFIG_PAGE_MAN_PS, -+ Mpi2ManufacturingPagePS_t, -+ *pMpi2ManufacturingPagePS_t; -+ -+#define MPI2_MANUFACTURING8_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING9_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING10_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING11_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING12_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING13_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING14_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING15_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING16_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING17_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING18_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING19_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING20_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING21_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING22_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING23_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING24_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING25_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING26_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING27_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING28_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING29_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING30_PAGEVERSION (0x00) -+#define MPI2_MANUFACTURING31_PAGEVERSION (0x00) -+ -+ -+/**************************************************************************** -+* IO Unit Config Pages -+****************************************************************************/ -+ -+/*IO Unit Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U64 UniqueValue; /*0x04 */ -+ MPI2_VERSION_UNION NvdataVersionDefault; /*0x08 */ -+ MPI2_VERSION_UNION NvdataVersionPersistent; /*0x0A */ -+} MPI2_CONFIG_PAGE_IO_UNIT_0, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_0, -+ Mpi2IOUnitPage0_t, *pMpi2IOUnitPage0_t; -+ -+#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02) -+ -+ -+/*IO Unit Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Flags; /*0x04 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_1, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_1, -+ Mpi2IOUnitPage1_t, *pMpi2IOUnitPage1_t; -+ -+#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) -+ -+/*IO Unit Page 1 Flags defines */ -+#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000) -+#define MPI25_IOUNITPAGE1_NEW_DEVICE_FAST_PATH_DISABLE (0x00002000) -+#define MPI25_IOUNITPAGE1_DISABLE_FAST_PATH (0x00001000) -+#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) -+#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) -+#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9) -+#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) -+#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) -+#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) -+#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) -+#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) -+#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) -+#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) -+ -+ -+/*IO Unit Page 3 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for GPIOCount at runtime. -+ */ -+#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX -+#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 GPIOCount; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U16 -+ GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/*0x08 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_3, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_3, -+ Mpi2IOUnitPage3_t, *pMpi2IOUnitPage3_t; -+ -+#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01) -+ -+/*defines for IO Unit Page 3 GPIOVal field */ -+#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC) -+#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2) -+#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000) -+#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001) -+ -+ -+/*IO Unit Page 5 */ -+ -+/* -+ *Upper layer code (drivers, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumDmaEngines at runtime. -+ */ -+#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES -+#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U64 -+ RaidAcceleratorBufferBaseAddress; /*0x04 */ -+ U64 -+ RaidAcceleratorBufferSize; /*0x0C */ -+ U64 -+ RaidAcceleratorControlBaseAddress; /*0x14 */ -+ U8 RAControlSize; /*0x1C */ -+ U8 NumDmaEngines; /*0x1D */ -+ U8 RAMinControlSize; /*0x1E */ -+ U8 RAMaxControlSize; /*0x1F */ -+ U32 Reserved1; /*0x20 */ -+ U32 Reserved2; /*0x24 */ -+ U32 Reserved3; /*0x28 */ -+ U32 -+ DmaEngineCapabilities[MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /*0x2C */ -+} MPI2_CONFIG_PAGE_IO_UNIT_5, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, -+ Mpi2IOUnitPage5_t, *pMpi2IOUnitPage5_t; -+ -+#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00) -+ -+/*defines for IO Unit Page 5 DmaEngineCapabilities field */ -+#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFFFF0000) -+#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16) -+ -+#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008) -+#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004) -+#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002) -+#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001) -+ -+ -+/*IO Unit Page 6 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U16 Flags; /*0x04 */ -+ U8 RAHostControlSize; /*0x06 */ -+ U8 Reserved0; /*0x07 */ -+ U64 -+ RaidAcceleratorHostControlBaseAddress; /*0x08 */ -+ U32 Reserved1; /*0x10 */ -+ U32 Reserved2; /*0x14 */ -+ U32 Reserved3; /*0x18 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_6, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, -+ Mpi2IOUnitPage6_t, *pMpi2IOUnitPage6_t; -+ -+#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00) -+ -+/*defines for IO Unit Page 6 Flags field */ -+#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) -+ -+ -+/*IO Unit Page 7 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 CurrentPowerMode; /*0x04 */ -+ U8 PreviousPowerMode; /*0x05 */ -+ U8 PCIeWidth; /*0x06 */ -+ U8 PCIeSpeed; /*0x07 */ -+ U32 ProcessorState; /*0x08 */ -+ U32 -+ PowerManagementCapabilities; /*0x0C */ -+ U16 IOCTemperature; /*0x10 */ -+ U8 -+ IOCTemperatureUnits; /*0x12 */ -+ U8 IOCSpeed; /*0x13 */ -+ U16 BoardTemperature; /*0x14 */ -+ U8 -+ BoardTemperatureUnits; /*0x16 */ -+ U8 Reserved3; /*0x17 */ -+ U32 BoardPowerRequirement; /*0x18 */ -+ U32 PCISlotPowerAllocation; /*0x1C */ -+/* reserved prior to MPI v2.6 */ -+ U8 Flags; /* 0x20 */ -+ U8 Reserved6; /* 0x21 */ -+ U16 Reserved7; /* 0x22 */ -+ U32 Reserved8; /* 0x24 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_7, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, -+ Mpi2IOUnitPage7_t, *pMpi2IOUnitPage7_t; -+ -+#define MPI2_IOUNITPAGE7_PAGEVERSION (0x05) -+ -+/*defines for IO Unit Page 7 CurrentPowerMode and PreviousPowerMode fields */ -+#define MPI25_IOUNITPAGE7_PM_INIT_MASK (0xC0) -+#define MPI25_IOUNITPAGE7_PM_INIT_UNAVAILABLE (0x00) -+#define MPI25_IOUNITPAGE7_PM_INIT_HOST (0x40) -+#define MPI25_IOUNITPAGE7_PM_INIT_IO_UNIT (0x80) -+#define MPI25_IOUNITPAGE7_PM_INIT_PCIE_DPA (0xC0) -+ -+#define MPI25_IOUNITPAGE7_PM_MODE_MASK (0x07) -+#define MPI25_IOUNITPAGE7_PM_MODE_UNAVAILABLE (0x00) -+#define MPI25_IOUNITPAGE7_PM_MODE_UNKNOWN (0x01) -+#define MPI25_IOUNITPAGE7_PM_MODE_FULL_POWER (0x04) -+#define MPI25_IOUNITPAGE7_PM_MODE_REDUCED_POWER (0x05) -+#define MPI25_IOUNITPAGE7_PM_MODE_STANDBY (0x06) -+ -+ -+/*defines for IO Unit Page 7 PCIeWidth field */ -+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) -+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) -+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) -+#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) -+ -+/*defines for IO Unit Page 7 PCIeSpeed field */ -+#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) -+#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) -+#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) -+ -+/*defines for IO Unit Page 7 ProcessorState field */ -+#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) -+#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) -+ -+#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) -+#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) -+#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) -+ -+/*defines for IO Unit Page 7 PowerManagementCapabilities field */ -+#define MPI25_IOUNITPAGE7_PMCAP_DPA_FULL_PWR_MODE (0x00400000) -+#define MPI25_IOUNITPAGE7_PMCAP_DPA_REDUCED_PWR_MODE (0x00200000) -+#define MPI25_IOUNITPAGE7_PMCAP_DPA_STANDBY_MODE (0x00100000) -+#define MPI25_IOUNITPAGE7_PMCAP_HOST_FULL_PWR_MODE (0x00040000) -+#define MPI25_IOUNITPAGE7_PMCAP_HOST_REDUCED_PWR_MODE (0x00020000) -+#define MPI25_IOUNITPAGE7_PMCAP_HOST_STANDBY_MODE (0x00010000) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_FULL_PWR_MODE (0x00004000) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_REDUCED_PWR_MODE (0x00002000) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_STANDBY_MODE (0x00001000) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_12_5_PCT_IOCSPEED (0x00000400) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_25_0_PCT_IOCSPEED (0x00000200) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_50_0_PCT_IOCSPEED (0x00000100) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_12_5_PCT_IOCSPEED (0x00000040) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_25_0_PCT_IOCSPEED (0x00000020) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_50_0_PCT_IOCSPEED (0x00000010) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_WIDTH_CHANGE_PCIE (0x00000008) -+#define MPI2_IOUNITPAGE7_PMCAP_HOST_SPEED_CHANGE_PCIE (0x00000004) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_WIDTH_CHANGE_PCIE (0x00000002) -+#define MPI25_IOUNITPAGE7_PMCAP_IO_SPEED_CHANGE_PCIE (0x00000001) -+ -+/*obsolete names for the PowerManagementCapabilities bits (above) */ -+#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) -+#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) -+#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) -+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /*obsolete */ -+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /*obsolete */ -+ -+ -+/*defines for IO Unit Page 7 IOCTemperatureUnits field */ -+#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) -+#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) -+#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) -+ -+/*defines for IO Unit Page 7 IOCSpeed field */ -+#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) -+#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) -+#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) -+#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) -+ -+/*defines for IO Unit Page 7 BoardTemperatureUnits field */ -+#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) -+#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) -+#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) -+ -+/* defines for IO Unit Page 7 Flags field */ -+#define MPI2_IOUNITPAGE7_FLAG_CABLE_POWER_EXC (0x01) -+ -+/*IO Unit Page 8 */ -+ -+#define MPI2_IOUNIT8_NUM_THRESHOLDS (4) -+ -+typedef struct _MPI2_IOUNIT8_SENSOR { -+ U16 Flags; /*0x00 */ -+ U16 Reserved1; /*0x02 */ -+ U16 -+ Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /*0x04 */ -+ U32 Reserved2; /*0x0C */ -+ U32 Reserved3; /*0x10 */ -+ U32 Reserved4; /*0x14 */ -+} MPI2_IOUNIT8_SENSOR, *PTR_MPI2_IOUNIT8_SENSOR, -+ Mpi2IOUnit8Sensor_t, *pMpi2IOUnit8Sensor_t; -+ -+/*defines for IO Unit Page 8 Sensor Flags field */ -+#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008) -+#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004) -+#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002) -+#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumSensors at runtime. -+ */ -+#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES -+#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U8 NumSensors; /*0x0C */ -+ U8 PollingInterval; /*0x0D */ -+ U16 Reserved3; /*0x0E */ -+ MPI2_IOUNIT8_SENSOR -+ Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/*0x10 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_8, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, -+ Mpi2IOUnitPage8_t, *pMpi2IOUnitPage8_t; -+ -+#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00) -+ -+ -+/*IO Unit Page 9 */ -+ -+typedef struct _MPI2_IOUNIT9_SENSOR { -+ U16 CurrentTemperature; /*0x00 */ -+ U16 Reserved1; /*0x02 */ -+ U8 Flags; /*0x04 */ -+ U8 Reserved2; /*0x05 */ -+ U16 Reserved3; /*0x06 */ -+ U32 Reserved4; /*0x08 */ -+ U32 Reserved5; /*0x0C */ -+} MPI2_IOUNIT9_SENSOR, *PTR_MPI2_IOUNIT9_SENSOR, -+ Mpi2IOUnit9Sensor_t, *pMpi2IOUnit9Sensor_t; -+ -+/*defines for IO Unit Page 9 Sensor Flags field */ -+#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumSensors at runtime. -+ */ -+#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES -+#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U8 NumSensors; /*0x0C */ -+ U8 Reserved4; /*0x0D */ -+ U16 Reserved3; /*0x0E */ -+ MPI2_IOUNIT9_SENSOR -+ Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/*0x10 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_9, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, -+ Mpi2IOUnitPage9_t, *pMpi2IOUnitPage9_t; -+ -+#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00) -+ -+ -+/*IO Unit Page 10 */ -+ -+typedef struct _MPI2_IOUNIT10_FUNCTION { -+ U8 CreditPercent; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+} MPI2_IOUNIT10_FUNCTION, -+ *PTR_MPI2_IOUNIT10_FUNCTION, -+ Mpi2IOUnit10Function_t, -+ *pMpi2IOUnit10Function_t; -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumFunctions at runtime. -+ */ -+#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES -+#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumFunctions; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U32 Reserved3; /*0x08 */ -+ U32 Reserved4; /*0x0C */ -+ MPI2_IOUNIT10_FUNCTION -+ Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/*0x10 */ -+} MPI2_CONFIG_PAGE_IO_UNIT_10, -+ *PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, -+ Mpi2IOUnitPage10_t, *pMpi2IOUnitPage10_t; -+ -+#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01) -+ -+ -+/* IO Unit Page 11 (for MPI v2.6 and later) */ -+ -+typedef struct _MPI26_IOUNIT11_SPINUP_GROUP { -+ U8 MaxTargetSpinup; /* 0x00 */ -+ U8 SpinupDelay; /* 0x01 */ -+ U8 SpinupFlags; /* 0x02 */ -+ U8 Reserved1; /* 0x03 */ -+} MPI26_IOUNIT11_SPINUP_GROUP, -+ *PTR_MPI26_IOUNIT11_SPINUP_GROUP, -+ Mpi26IOUnit11SpinupGroup_t, -+ *pMpi26IOUnit11SpinupGroup_t; -+ -+/* defines for IO Unit Page 11 SpinupFlags */ -+#define MPI26_IOUNITPAGE11_SPINUP_DISABLE_FLAG (0x01) -+ -+ -+/* -+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ * four and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI26_IOUNITPAGE11_PHY_MAX -+#define MPI26_IOUNITPAGE11_PHY_MAX (4) -+#endif -+ -+typedef struct _MPI26_CONFIG_PAGE_IO_UNIT_11 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ MPI26_IOUNIT11_SPINUP_GROUP SpinupGroupParameters[4]; /*0x08 */ -+ U32 Reserved2; /*0x18 */ -+ U32 Reserved3; /*0x1C */ -+ U32 Reserved4; /*0x20 */ -+ U8 BootDeviceWaitTime; /*0x24 */ -+ U8 Reserved5; /*0x25 */ -+ U16 Reserved6; /*0x26 */ -+ U8 NumPhys; /*0x28 */ -+ U8 PEInitialSpinupDelay; /*0x29 */ -+ U8 PEReplyDelay; /*0x2A */ -+ U8 Flags; /*0x2B */ -+ U8 PHY[MPI26_IOUNITPAGE11_PHY_MAX];/*0x2C */ -+} MPI26_CONFIG_PAGE_IO_UNIT_11, -+ *PTR_MPI26_CONFIG_PAGE_IO_UNIT_11, -+ Mpi26IOUnitPage11_t, -+ *pMpi26IOUnitPage11_t; -+ -+#define MPI26_IOUNITPAGE11_PAGEVERSION (0x00) -+ -+/* defines for Flags field */ -+#define MPI26_IOUNITPAGE11_FLAGS_AUTO_PORTENABLE (0x01) -+ -+/* defines for PHY field */ -+#define MPI26_IOUNITPAGE11_PHY_SPINUP_GROUP_MASK (0x03) -+ -+ -+ -+ -+ -+ -+/**************************************************************************** -+* IOC Config Pages -+****************************************************************************/ -+ -+/*IOC Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U16 VendorID; /*0x0C */ -+ U16 DeviceID; /*0x0E */ -+ U8 RevisionID; /*0x10 */ -+ U8 Reserved3; /*0x11 */ -+ U16 Reserved4; /*0x12 */ -+ U32 ClassCode; /*0x14 */ -+ U16 SubsystemVendorID; /*0x18 */ -+ U16 SubsystemID; /*0x1A */ -+} MPI2_CONFIG_PAGE_IOC_0, -+ *PTR_MPI2_CONFIG_PAGE_IOC_0, -+ Mpi2IOCPage0_t, *pMpi2IOCPage0_t; -+ -+#define MPI2_IOCPAGE0_PAGEVERSION (0x02) -+ -+ -+/*IOC Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Flags; /*0x04 */ -+ U32 CoalescingTimeout; /*0x08 */ -+ U8 CoalescingDepth; /*0x0C */ -+ U8 PCISlotNum; /*0x0D */ -+ U8 PCIBusNum; /*0x0E */ -+ U8 PCIDomainSegment; /*0x0F */ -+ U32 Reserved1; /*0x10 */ -+ U32 Reserved2; /*0x14 */ -+} MPI2_CONFIG_PAGE_IOC_1, -+ *PTR_MPI2_CONFIG_PAGE_IOC_1, -+ Mpi2IOCPage1_t, *pMpi2IOCPage1_t; -+ -+#define MPI2_IOCPAGE1_PAGEVERSION (0x05) -+ -+/*defines for IOC Page 1 Flags field */ -+#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001) -+ -+#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) -+#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF) -+#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF) -+ -+/*IOC Page 6 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_6 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 -+ CapabilitiesFlags; /*0x04 */ -+ U8 MaxDrivesRAID0; /*0x08 */ -+ U8 MaxDrivesRAID1; /*0x09 */ -+ U8 -+ MaxDrivesRAID1E; /*0x0A */ -+ U8 -+ MaxDrivesRAID10; /*0x0B */ -+ U8 MinDrivesRAID0; /*0x0C */ -+ U8 MinDrivesRAID1; /*0x0D */ -+ U8 -+ MinDrivesRAID1E; /*0x0E */ -+ U8 -+ MinDrivesRAID10; /*0x0F */ -+ U32 Reserved1; /*0x10 */ -+ U8 -+ MaxGlobalHotSpares; /*0x14 */ -+ U8 MaxPhysDisks; /*0x15 */ -+ U8 MaxVolumes; /*0x16 */ -+ U8 MaxConfigs; /*0x17 */ -+ U8 MaxOCEDisks; /*0x18 */ -+ U8 Reserved2; /*0x19 */ -+ U16 Reserved3; /*0x1A */ -+ U32 -+ SupportedStripeSizeMapRAID0; /*0x1C */ -+ U32 -+ SupportedStripeSizeMapRAID1E; /*0x20 */ -+ U32 -+ SupportedStripeSizeMapRAID10; /*0x24 */ -+ U32 Reserved4; /*0x28 */ -+ U32 Reserved5; /*0x2C */ -+ U16 -+ DefaultMetadataSize; /*0x30 */ -+ U16 Reserved6; /*0x32 */ -+ U16 -+ MaxBadBlockTableEntries; /*0x34 */ -+ U16 Reserved7; /*0x36 */ -+ U32 -+ IRNvsramVersion; /*0x38 */ -+} MPI2_CONFIG_PAGE_IOC_6, -+ *PTR_MPI2_CONFIG_PAGE_IOC_6, -+ Mpi2IOCPage6_t, *pMpi2IOCPage6_t; -+ -+#define MPI2_IOCPAGE6_PAGEVERSION (0x05) -+ -+/*defines for IOC Page 6 CapabilitiesFlags */ -+#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020) -+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010) -+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008) -+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004) -+#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002) -+#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) -+ -+ -+/*IOC Page 7 */ -+ -+#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4) -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_7 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 -+ EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/*0x08 */ -+ U16 SASBroadcastPrimitiveMasks; /*0x18 */ -+ U16 SASNotifyPrimitiveMasks; /*0x1A */ -+ U32 Reserved3; /*0x1C */ -+} MPI2_CONFIG_PAGE_IOC_7, -+ *PTR_MPI2_CONFIG_PAGE_IOC_7, -+ Mpi2IOCPage7_t, *pMpi2IOCPage7_t; -+ -+#define MPI2_IOCPAGE7_PAGEVERSION (0x02) -+ -+ -+/*IOC Page 8 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_IOC_8 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumDevsPerEnclosure; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U16 MaxPersistentEntries; /*0x08 */ -+ U16 MaxNumPhysicalMappedIDs; /*0x0A */ -+ U16 Flags; /*0x0C */ -+ U16 Reserved3; /*0x0E */ -+ U16 IRVolumeMappingFlags; /*0x10 */ -+ U16 Reserved4; /*0x12 */ -+ U32 Reserved5; /*0x14 */ -+} MPI2_CONFIG_PAGE_IOC_8, -+ *PTR_MPI2_CONFIG_PAGE_IOC_8, -+ Mpi2IOCPage8_t, *pMpi2IOCPage8_t; -+ -+#define MPI2_IOCPAGE8_PAGEVERSION (0x00) -+ -+/*defines for IOC Page 8 Flags field */ -+#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020) -+#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010) -+ -+#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E) -+#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000) -+#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002) -+ -+#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001) -+#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000) -+ -+/*defines for IOC Page 8 IRVolumeMappingFlags */ -+#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003) -+#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000) -+#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001) -+ -+ -+/**************************************************************************** -+* BIOS Config Pages -+****************************************************************************/ -+ -+/*BIOS Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_BIOS_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 BiosOptions; /*0x04 */ -+ U32 IOCSettings; /*0x08 */ -+ U8 SSUTimeout; /*0x0C */ -+ U8 Reserved1; /*0x0D */ -+ U16 Reserved2; /*0x0E */ -+ U32 DeviceSettings; /*0x10 */ -+ U16 NumberOfDevices; /*0x14 */ -+ U16 UEFIVersion; /*0x16 */ -+ U16 IOTimeoutBlockDevicesNonRM; /*0x18 */ -+ U16 IOTimeoutSequential; /*0x1A */ -+ U16 IOTimeoutOther; /*0x1C */ -+ U16 IOTimeoutBlockDevicesRM; /*0x1E */ -+} MPI2_CONFIG_PAGE_BIOS_1, -+ *PTR_MPI2_CONFIG_PAGE_BIOS_1, -+ Mpi2BiosPage1_t, *pMpi2BiosPage1_t; -+ -+#define MPI2_BIOSPAGE1_PAGEVERSION (0x07) -+ -+/*values for BIOS Page 1 BiosOptions field */ -+#define MPI2_BIOSPAGE1_OPTIONS_BOOT_LIST_ADD_ALT_BOOT_DEVICE (0x00008000) -+#define MPI2_BIOSPAGE1_OPTIONS_ADVANCED_CONFIG (0x00004000) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800) -+#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300) -+#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000) -+#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100) -+#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200) -+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0) -+#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006) -+#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000) -+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002) -+#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004) -+ -+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) -+ -+/*values for BIOS Page 1 IOCSettings field */ -+#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) -+#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) -+#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) -+ -+#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) -+#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) -+#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) -+#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) -+ -+#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) -+#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) -+#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) -+#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) -+#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) -+ -+#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) -+ -+/*values for BIOS Page 1 DeviceSettings field */ -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010) -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) -+#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) -+ -+/*defines for BIOS Page 1 UEFIVersion field */ -+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00) -+#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8) -+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF) -+#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0) -+ -+ -+ -+/*BIOS Page 2 */ -+ -+typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER { -+ U32 Reserved1; /*0x00 */ -+ U32 Reserved2; /*0x04 */ -+ U32 Reserved3; /*0x08 */ -+ U32 Reserved4; /*0x0C */ -+ U32 Reserved5; /*0x10 */ -+ U32 Reserved6; /*0x14 */ -+} MPI2_BOOT_DEVICE_ADAPTER_ORDER, -+ *PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER, -+ Mpi2BootDeviceAdapterOrder_t, -+ *pMpi2BootDeviceAdapterOrder_t; -+ -+typedef struct _MPI2_BOOT_DEVICE_SAS_WWID { -+ U64 SASAddress; /*0x00 */ -+ U8 LUN[8]; /*0x08 */ -+ U32 Reserved1; /*0x10 */ -+ U32 Reserved2; /*0x14 */ -+} MPI2_BOOT_DEVICE_SAS_WWID, -+ *PTR_MPI2_BOOT_DEVICE_SAS_WWID, -+ Mpi2BootDeviceSasWwid_t, -+ *pMpi2BootDeviceSasWwid_t; -+ -+typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT { -+ U64 EnclosureLogicalID; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+ U16 SlotNumber; /*0x10 */ -+ U16 Reserved3; /*0x12 */ -+ U32 Reserved4; /*0x14 */ -+} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, -+ *PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, -+ Mpi2BootDeviceEnclosureSlot_t, -+ *pMpi2BootDeviceEnclosureSlot_t; -+ -+typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME { -+ U64 DeviceName; /*0x00 */ -+ U8 LUN[8]; /*0x08 */ -+ U32 Reserved1; /*0x10 */ -+ U32 Reserved2; /*0x14 */ -+} MPI2_BOOT_DEVICE_DEVICE_NAME, -+ *PTR_MPI2_BOOT_DEVICE_DEVICE_NAME, -+ Mpi2BootDeviceDeviceName_t, -+ *pMpi2BootDeviceDeviceName_t; -+ -+typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE { -+ MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder; -+ MPI2_BOOT_DEVICE_SAS_WWID SasWwid; -+ MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot; -+ MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName; -+} MPI2_BIOSPAGE2_BOOT_DEVICE, -+ *PTR_MPI2_BIOSPAGE2_BOOT_DEVICE, -+ Mpi2BiosPage2BootDevice_t, -+ *pMpi2BiosPage2BootDevice_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_BIOS_2 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U32 Reserved3; /*0x0C */ -+ U32 Reserved4; /*0x10 */ -+ U32 Reserved5; /*0x14 */ -+ U32 Reserved6; /*0x18 */ -+ U8 ReqBootDeviceForm; /*0x1C */ -+ U8 Reserved7; /*0x1D */ -+ U16 Reserved8; /*0x1E */ -+ MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /*0x20 */ -+ U8 ReqAltBootDeviceForm; /*0x38 */ -+ U8 Reserved9; /*0x39 */ -+ U16 Reserved10; /*0x3A */ -+ MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /*0x3C */ -+ U8 CurrentBootDeviceForm; /*0x58 */ -+ U8 Reserved11; /*0x59 */ -+ U16 Reserved12; /*0x5A */ -+ MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /*0x58 */ -+} MPI2_CONFIG_PAGE_BIOS_2, *PTR_MPI2_CONFIG_PAGE_BIOS_2, -+ Mpi2BiosPage2_t, *pMpi2BiosPage2_t; -+ -+#define MPI2_BIOSPAGE2_PAGEVERSION (0x04) -+ -+/*values for BIOS Page 2 BootDeviceForm fields */ -+#define MPI2_BIOSPAGE2_FORM_MASK (0x0F) -+#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00) -+#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05) -+#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) -+#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07) -+ -+ -+/*BIOS Page 3 */ -+ -+#define MPI2_BIOSPAGE3_NUM_ADAPTER (4) -+ -+typedef struct _MPI2_ADAPTER_INFO { -+ U8 PciBusNumber; /*0x00 */ -+ U8 PciDeviceAndFunctionNumber; /*0x01 */ -+ U16 AdapterFlags; /*0x02 */ -+} MPI2_ADAPTER_INFO, *PTR_MPI2_ADAPTER_INFO, -+ Mpi2AdapterInfo_t, *pMpi2AdapterInfo_t; -+ -+#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) -+#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) -+ -+typedef struct _MPI2_ADAPTER_ORDER_AUX { -+ U64 WWID; /* 0x00 */ -+ U32 Reserved1; /* 0x08 */ -+ U32 Reserved2; /* 0x0C */ -+} MPI2_ADAPTER_ORDER_AUX, *PTR_MPI2_ADAPTER_ORDER_AUX, -+ Mpi2AdapterOrderAux_t, *pMpi2AdapterOrderAux_t; -+ -+ -+typedef struct _MPI2_CONFIG_PAGE_BIOS_3 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U32 GlobalFlags; /*0x04 */ -+ U32 BiosVersion; /*0x08 */ -+ MPI2_ADAPTER_INFO AdapterOrder[MPI2_BIOSPAGE3_NUM_ADAPTER]; -+ U32 Reserved1; /*0x1C */ -+ MPI2_ADAPTER_ORDER_AUX AdapterOrderAux[MPI2_BIOSPAGE3_NUM_ADAPTER]; -+} MPI2_CONFIG_PAGE_BIOS_3, -+ *PTR_MPI2_CONFIG_PAGE_BIOS_3, -+ Mpi2BiosPage3_t, *pMpi2BiosPage3_t; -+ -+#define MPI2_BIOSPAGE3_PAGEVERSION (0x01) -+ -+/*values for BIOS Page 3 GlobalFlags */ -+#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002) -+#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004) -+#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010) -+ -+#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) -+#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) -+#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020) -+#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) -+ -+ -+/*BIOS Page 4 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES -+#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) -+#endif -+ -+typedef struct _MPI2_BIOS4_ENTRY { -+ U64 ReassignmentWWID; /*0x00 */ -+ U64 ReassignmentDeviceName; /*0x08 */ -+} MPI2_BIOS4_ENTRY, *PTR_MPI2_BIOS4_ENTRY, -+ Mpi2MBios4Entry_t, *pMpi2Bios4Entry_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_BIOS_4 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumPhys; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ MPI2_BIOS4_ENTRY -+ Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /*0x08 */ -+} MPI2_CONFIG_PAGE_BIOS_4, *PTR_MPI2_CONFIG_PAGE_BIOS_4, -+ Mpi2BiosPage4_t, *pMpi2BiosPage4_t; -+ -+#define MPI2_BIOSPAGE4_PAGEVERSION (0x01) -+ -+ -+/**************************************************************************** -+* RAID Volume Config Pages -+****************************************************************************/ -+ -+/*RAID Volume Page 0 */ -+ -+typedef struct _MPI2_RAIDVOL0_PHYS_DISK { -+ U8 RAIDSetNum; /*0x00 */ -+ U8 PhysDiskMap; /*0x01 */ -+ U8 PhysDiskNum; /*0x02 */ -+ U8 Reserved; /*0x03 */ -+} MPI2_RAIDVOL0_PHYS_DISK, *PTR_MPI2_RAIDVOL0_PHYS_DISK, -+ Mpi2RaidVol0PhysDisk_t, *pMpi2RaidVol0PhysDisk_t; -+ -+/*defines for the PhysDiskMap field */ -+#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01) -+#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02) -+ -+typedef struct _MPI2_RAIDVOL0_SETTINGS { -+ U16 Settings; /*0x00 */ -+ U8 HotSparePool; /*0x01 */ -+ U8 Reserved; /*0x02 */ -+} MPI2_RAIDVOL0_SETTINGS, *PTR_MPI2_RAIDVOL0_SETTINGS, -+ Mpi2RaidVol0Settings_t, -+ *pMpi2RaidVol0Settings_t; -+ -+/*RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */ -+#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01) -+#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02) -+#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04) -+#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08) -+#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10) -+#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20) -+#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40) -+#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80) -+ -+/*RAID Volume Page 0 VolumeSettings defines */ -+#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008) -+#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004) -+ -+#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003) -+#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000) -+#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001) -+#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhysDisks at runtime. -+ */ -+#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX -+#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U16 DevHandle; /*0x04 */ -+ U8 VolumeState; /*0x06 */ -+ U8 VolumeType; /*0x07 */ -+ U32 VolumeStatusFlags; /*0x08 */ -+ MPI2_RAIDVOL0_SETTINGS VolumeSettings; /*0x0C */ -+ U64 MaxLBA; /*0x10 */ -+ U32 StripeSize; /*0x18 */ -+ U16 BlockSize; /*0x1C */ -+ U16 Reserved1; /*0x1E */ -+ U8 SupportedPhysDisks;/*0x20 */ -+ U8 ResyncRate; /*0x21 */ -+ U16 DataScrubDuration; /*0x22 */ -+ U8 NumPhysDisks; /*0x24 */ -+ U8 Reserved2; /*0x25 */ -+ U8 Reserved3; /*0x26 */ -+ U8 InactiveStatus; /*0x27 */ -+ MPI2_RAIDVOL0_PHYS_DISK -+ PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /*0x28 */ -+} MPI2_CONFIG_PAGE_RAID_VOL_0, -+ *PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, -+ Mpi2RaidVolPage0_t, *pMpi2RaidVolPage0_t; -+ -+#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A) -+ -+/*values for RAID VolumeState */ -+#define MPI2_RAID_VOL_STATE_MISSING (0x00) -+#define MPI2_RAID_VOL_STATE_FAILED (0x01) -+#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02) -+#define MPI2_RAID_VOL_STATE_ONLINE (0x03) -+#define MPI2_RAID_VOL_STATE_DEGRADED (0x04) -+#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05) -+ -+/*values for RAID VolumeType */ -+#define MPI2_RAID_VOL_TYPE_RAID0 (0x00) -+#define MPI2_RAID_VOL_TYPE_RAID1E (0x01) -+#define MPI2_RAID_VOL_TYPE_RAID1 (0x02) -+#define MPI2_RAID_VOL_TYPE_RAID10 (0x05) -+#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF) -+ -+/*values for RAID Volume Page 0 VolumeStatusFlags field */ -+#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080) -+#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) -+#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) -+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) -+#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010) -+#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008) -+#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004) -+#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002) -+#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001) -+ -+/*values for RAID Volume Page 0 SupportedPhysDisks field */ -+#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08) -+#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04) -+#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02) -+#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01) -+ -+/*values for RAID Volume Page 0 InactiveStatus field */ -+#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) -+#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01) -+#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02) -+#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03) -+#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04) -+#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05) -+#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06) -+ -+ -+/*RAID Volume Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U16 DevHandle; /*0x04 */ -+ U16 Reserved0; /*0x06 */ -+ U8 GUID[24]; /*0x08 */ -+ U8 Name[16]; /*0x20 */ -+ U64 WWID; /*0x30 */ -+ U32 Reserved1; /*0x38 */ -+ U32 Reserved2; /*0x3C */ -+} MPI2_CONFIG_PAGE_RAID_VOL_1, -+ *PTR_MPI2_CONFIG_PAGE_RAID_VOL_1, -+ Mpi2RaidVolPage1_t, *pMpi2RaidVolPage1_t; -+ -+#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03) -+ -+ -+/**************************************************************************** -+* RAID Physical Disk Config Pages -+****************************************************************************/ -+ -+/*RAID Physical Disk Page 0 */ -+ -+typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS { -+ U16 Reserved1; /*0x00 */ -+ U8 HotSparePool; /*0x02 */ -+ U8 Reserved2; /*0x03 */ -+} MPI2_RAIDPHYSDISK0_SETTINGS, -+ *PTR_MPI2_RAIDPHYSDISK0_SETTINGS, -+ Mpi2RaidPhysDisk0Settings_t, -+ *pMpi2RaidPhysDisk0Settings_t; -+ -+/*use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */ -+ -+typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA { -+ U8 VendorID[8]; /*0x00 */ -+ U8 ProductID[16]; /*0x08 */ -+ U8 ProductRevLevel[4]; /*0x18 */ -+ U8 SerialNum[32]; /*0x1C */ -+} MPI2_RAIDPHYSDISK0_INQUIRY_DATA, -+ *PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA, -+ Mpi2RaidPhysDisk0InquiryData_t, -+ *pMpi2RaidPhysDisk0InquiryData_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U16 DevHandle; /*0x04 */ -+ U8 Reserved1; /*0x06 */ -+ U8 PhysDiskNum; /*0x07 */ -+ MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+ MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /*0x10 */ -+ U32 Reserved3; /*0x4C */ -+ U8 PhysDiskState; /*0x50 */ -+ U8 OfflineReason; /*0x51 */ -+ U8 IncompatibleReason; /*0x52 */ -+ U8 PhysDiskAttributes; /*0x53 */ -+ U32 PhysDiskStatusFlags;/*0x54 */ -+ U64 DeviceMaxLBA; /*0x58 */ -+ U64 HostMaxLBA; /*0x60 */ -+ U64 CoercedMaxLBA; /*0x68 */ -+ U16 BlockSize; /*0x70 */ -+ U16 Reserved5; /*0x72 */ -+ U32 Reserved6; /*0x74 */ -+} MPI2_CONFIG_PAGE_RD_PDISK_0, -+ *PTR_MPI2_CONFIG_PAGE_RD_PDISK_0, -+ Mpi2RaidPhysDiskPage0_t, -+ *pMpi2RaidPhysDiskPage0_t; -+ -+#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05) -+ -+/*PhysDiskState defines */ -+#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00) -+#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01) -+#define MPI2_RAID_PD_STATE_OFFLINE (0x02) -+#define MPI2_RAID_PD_STATE_ONLINE (0x03) -+#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04) -+#define MPI2_RAID_PD_STATE_DEGRADED (0x05) -+#define MPI2_RAID_PD_STATE_REBUILDING (0x06) -+#define MPI2_RAID_PD_STATE_OPTIMAL (0x07) -+ -+/*OfflineReason defines */ -+#define MPI2_PHYSDISK0_ONLINE (0x00) -+#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01) -+#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03) -+#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04) -+#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05) -+#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06) -+#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF) -+ -+/*IncompatibleReason defines */ -+#define MPI2_PHYSDISK0_COMPATIBLE (0x00) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06) -+#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) -+ -+/*PhysDiskAttributes defines */ -+#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C) -+#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) -+#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) -+ -+#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03) -+#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) -+#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) -+ -+/*PhysDiskStatusFlags defines */ -+#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040) -+#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020) -+#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010) -+#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000) -+#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008) -+#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004) -+#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002) -+#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001) -+ -+ -+/*RAID Physical Disk Page 1 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhysDiskPaths at runtime. -+ */ -+#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX -+#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) -+#endif -+ -+typedef struct _MPI2_RAIDPHYSDISK1_PATH { -+ U16 DevHandle; /*0x00 */ -+ U16 Reserved1; /*0x02 */ -+ U64 WWID; /*0x04 */ -+ U64 OwnerWWID; /*0x0C */ -+ U8 OwnerIdentifier; /*0x14 */ -+ U8 Reserved2; /*0x15 */ -+ U16 Flags; /*0x16 */ -+} MPI2_RAIDPHYSDISK1_PATH, *PTR_MPI2_RAIDPHYSDISK1_PATH, -+ Mpi2RaidPhysDisk1Path_t, -+ *pMpi2RaidPhysDisk1Path_t; -+ -+/*RAID Physical Disk Page 1 Physical Disk Path Flags field defines */ -+#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004) -+#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) -+#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001) -+ -+typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 { -+ MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ -+ U8 NumPhysDiskPaths; /*0x04 */ -+ U8 PhysDiskNum; /*0x05 */ -+ U16 Reserved1; /*0x06 */ -+ U32 Reserved2; /*0x08 */ -+ MPI2_RAIDPHYSDISK1_PATH -+ PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/*0x0C */ -+} MPI2_CONFIG_PAGE_RD_PDISK_1, -+ *PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, -+ Mpi2RaidPhysDiskPage1_t, -+ *pMpi2RaidPhysDiskPage1_t; -+ -+#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02) -+ -+ -+/**************************************************************************** -+* values for fields used by several types of SAS Config Pages -+****************************************************************************/ -+ -+/*values for NegotiatedLinkRates fields */ -+#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0) -+#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4) -+#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F) -+/*link rates used for Negotiated Physical and Logical Link Rate */ -+#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00) -+#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01) -+#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02) -+#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) -+#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) -+#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) -+#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06) -+#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) -+#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) -+#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) -+#define MPI25_SAS_NEG_LINK_RATE_12_0 (0x0B) -+ -+ -+/*values for AttachedPhyInfo fields */ -+#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040) -+#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020) -+#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010) -+ -+#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F) -+#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000) -+#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001) -+#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002) -+#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003) -+#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004) -+#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005) -+#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006) -+#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007) -+#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008) -+ -+ -+/*values for PhyInfo fields */ -+#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) -+ -+#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) -+#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27) -+#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) -+#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) -+#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) -+ -+#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) -+#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) -+#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) -+#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000) -+#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000) -+#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000) -+ -+#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000) -+#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000) -+#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000) -+#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000) -+#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000) -+#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000) -+#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000) -+#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000) -+#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000) -+#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000) -+ -+#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000) -+#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000) -+#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000) -+#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000) -+ -+#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) -+#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) -+ -+#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) -+#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000) -+#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) -+#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020) -+ -+ -+/*values for SAS ProgrammedLinkRate fields */ -+#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0) -+#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) -+#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80) -+#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90) -+#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0) -+#define MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0) -+#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F) -+#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) -+#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08) -+#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09) -+#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A) -+#define MPI25_SAS_PRATE_MIN_RATE_12_0 (0x0B) -+ -+ -+/*values for SAS HwLinkRate fields */ -+#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0) -+#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80) -+#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90) -+#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0) -+#define MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0) -+#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F) -+#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08) -+#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09) -+#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A) -+#define MPI25_SAS_HWRATE_MIN_RATE_12_0 (0x0B) -+ -+ -+ -+/**************************************************************************** -+* SAS IO Unit Config Pages -+****************************************************************************/ -+ -+/*SAS IO Unit Page 0 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA { -+ U8 Port; /*0x00 */ -+ U8 PortFlags; /*0x01 */ -+ U8 PhyFlags; /*0x02 */ -+ U8 NegotiatedLinkRate; /*0x03 */ -+ U32 ControllerPhyDeviceInfo;/*0x04 */ -+ U16 AttachedDevHandle; /*0x08 */ -+ U16 ControllerDevHandle; /*0x0A */ -+ U32 DiscoveryStatus; /*0x0C */ -+ U32 Reserved; /*0x10 */ -+} MPI2_SAS_IO_UNIT0_PHY_DATA, -+ *PTR_MPI2_SAS_IO_UNIT0_PHY_DATA, -+ Mpi2SasIOUnit0PhyData_t, -+ *pMpi2SasIOUnit0PhyData_t; -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT0_PHY_MAX -+#define MPI2_SAS_IOUNIT0_PHY_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1;/*0x08 */ -+ U8 NumPhys; /*0x0C */ -+ U8 Reserved2;/*0x0D */ -+ U16 Reserved3;/*0x0E */ -+ MPI2_SAS_IO_UNIT0_PHY_DATA -+ PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /*0x10 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_0, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, -+ Mpi2SasIOUnitPage0_t, *pMpi2SasIOUnitPage0_t; -+ -+#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05) -+ -+/*values for SAS IO Unit Page 0 PortFlags */ -+#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08) -+#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01) -+ -+/*values for SAS IO Unit Page 0 PhyFlags */ -+#define MPI2_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT (0x40) -+#define MPI2_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT (0x20) -+#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10) -+#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) -+ -+/*use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -+ -+/*see mpi2_sas.h for values for -+ *SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ -+ -+/*values for SAS IO Unit Page 0 DiscoveryStatus */ -+#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -+#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000) -+#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000) -+#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -+#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000) -+#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -+#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -+#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000) -+#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -+#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) -+#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400) -+#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) -+#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100) -+#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080) -+#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040) -+#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020) -+#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010) -+#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004) -+#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002) -+#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001) -+ -+ -+/*SAS IO Unit Page 1 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA { -+ U8 Port; /*0x00 */ -+ U8 PortFlags; /*0x01 */ -+ U8 PhyFlags; /*0x02 */ -+ U8 MaxMinLinkRate; /*0x03 */ -+ U32 ControllerPhyDeviceInfo; /*0x04 */ -+ U16 MaxTargetPortConnectTime; /*0x08 */ -+ U16 Reserved1; /*0x0A */ -+} MPI2_SAS_IO_UNIT1_PHY_DATA, -+ *PTR_MPI2_SAS_IO_UNIT1_PHY_DATA, -+ Mpi2SasIOUnit1PhyData_t, -+ *pMpi2SasIOUnit1PhyData_t; -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT1_PHY_MAX -+#define MPI2_SAS_IOUNIT1_PHY_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U16 -+ ControlFlags; /*0x08 */ -+ U16 -+ SASNarrowMaxQueueDepth; /*0x0A */ -+ U16 -+ AdditionalControlFlags; /*0x0C */ -+ U16 -+ SASWideMaxQueueDepth; /*0x0E */ -+ U8 -+ NumPhys; /*0x10 */ -+ U8 -+ SATAMaxQDepth; /*0x11 */ -+ U8 -+ ReportDeviceMissingDelay; /*0x12 */ -+ U8 -+ IODeviceMissingDelay; /*0x13 */ -+ MPI2_SAS_IO_UNIT1_PHY_DATA -+ PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /*0x14 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_1, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, -+ Mpi2SasIOUnitPage1_t, *pMpi2SasIOUnitPage1_t; -+ -+#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09) -+ -+/*values for SAS IO Unit Page 1 ControlFlags */ -+#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) -+ -+#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600) -+#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) -+#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0) -+#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1) -+#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2) -+ -+#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) -+#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) -+#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008) -+#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) -+#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) -+#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) -+ -+/*values for SAS IO Unit Page 1 AdditionalControlFlags */ -+#define MPI2_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT (0x0100) -+#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) -+#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) -+#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020) -+#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) -+#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) -+#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) -+#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) -+#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) -+ -+/*defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ -+#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) -+#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80) -+ -+/*values for SAS IO Unit Page 1 PortFlags */ -+#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) -+ -+/*values for SAS IO Unit Page 1 PhyFlags */ -+#define MPI2_SASIOUNIT1_PHYFLAGS_INIT_PERSIST_CONNECT (0x40) -+#define MPI2_SASIOUNIT1_PHYFLAGS_TARG_PERSIST_CONNECT (0x20) -+#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) -+#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) -+ -+/*values for SAS IO Unit Page 1 MaxMinLinkRate */ -+#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) -+#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) -+#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) -+#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0) -+#define MPI25_SASIOUNIT1_MAX_RATE_12_0 (0xB0) -+#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F) -+#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08) -+#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09) -+#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A) -+#define MPI25_SASIOUNIT1_MIN_RATE_12_0 (0x0B) -+ -+/*see mpi2_sas.h for values for -+ *SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ -+ -+ -+/*SAS IO Unit Page 4 (for MPI v2.5 and earlier) */ -+ -+typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP { -+ U8 MaxTargetSpinup; /*0x00 */ -+ U8 SpinupDelay; /*0x01 */ -+ U8 SpinupFlags; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+} MPI2_SAS_IOUNIT4_SPINUP_GROUP, -+ *PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, -+ Mpi2SasIOUnit4SpinupGroup_t, -+ *pMpi2SasIOUnit4SpinupGroup_t; -+/*defines for SAS IO Unit Page 4 SpinupFlags */ -+#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01) -+ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT4_PHY_MAX -+#define MPI2_SAS_IOUNIT4_PHY_MAX (4) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header;/*0x00 */ -+ MPI2_SAS_IOUNIT4_SPINUP_GROUP -+ SpinupGroupParameters[4]; /*0x08 */ -+ U32 -+ Reserved1; /*0x18 */ -+ U32 -+ Reserved2; /*0x1C */ -+ U32 -+ Reserved3; /*0x20 */ -+ U8 -+ BootDeviceWaitTime; /*0x24 */ -+ U8 -+ SATADeviceWaitTime; /*0x25 */ -+ U16 -+ Reserved5; /*0x26 */ -+ U8 -+ NumPhys; /*0x28 */ -+ U8 -+ PEInitialSpinupDelay; /*0x29 */ -+ U8 -+ PEReplyDelay; /*0x2A */ -+ U8 -+ Flags; /*0x2B */ -+ U8 -+ PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /*0x2C */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_4, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4, -+ Mpi2SasIOUnitPage4_t, *pMpi2SasIOUnitPage4_t; -+ -+#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02) -+ -+/*defines for Flags field */ -+#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01) -+ -+/*defines for PHY field */ -+#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) -+ -+ -+/*SAS IO Unit Page 5 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { -+ U8 ControlFlags; /*0x00 */ -+ U8 PortWidthModGroup; /*0x01 */ -+ U16 InactivityTimerExponent; /*0x02 */ -+ U8 SATAPartialTimeout; /*0x04 */ -+ U8 Reserved2; /*0x05 */ -+ U8 SATASlumberTimeout; /*0x06 */ -+ U8 Reserved3; /*0x07 */ -+ U8 SASPartialTimeout; /*0x08 */ -+ U8 Reserved4; /*0x09 */ -+ U8 SASSlumberTimeout; /*0x0A */ -+ U8 Reserved5; /*0x0B */ -+} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, -+ *PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, -+ Mpi2SasIOUnit5PhyPmSettings_t, -+ *pMpi2SasIOUnit5PhyPmSettings_t; -+ -+/*defines for ControlFlags field */ -+#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) -+#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) -+#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) -+#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) -+ -+/*defines for PortWidthModeGroup field */ -+#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) -+ -+/*defines for InactivityTimerExponent field */ -+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) -+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) -+#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) -+#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) -+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) -+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) -+#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) -+#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) -+ -+#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) -+#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) -+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) -+#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) -+#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) -+#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) -+#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) -+#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhys at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT5_PHY_MAX -+#define MPI2_SAS_IOUNIT5_PHY_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U8 NumPhys; /*0x08 */ -+ U8 Reserved1;/*0x09 */ -+ U16 Reserved2;/*0x0A */ -+ U32 Reserved3;/*0x0C */ -+ MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS -+ SASPhyPowerManagementSettings[MPI2_SAS_IOUNIT5_PHY_MAX];/*0x10 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_5, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, -+ Mpi2SasIOUnitPage5_t, *pMpi2SasIOUnitPage5_t; -+ -+#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) -+ -+ -+/*SAS IO Unit Page 6 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { -+ U8 CurrentStatus; /*0x00 */ -+ U8 CurrentModulation; /*0x01 */ -+ U8 CurrentUtilization; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+ U32 Reserved2; /*0x04 */ -+} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, -+ *PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, -+ Mpi2SasIOUnit6PortWidthModGroupStatus_t, -+ *pMpi2SasIOUnit6PortWidthModGroupStatus_t; -+ -+/*defines for CurrentStatus field */ -+#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) -+#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) -+#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) -+#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) -+#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) -+#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) -+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) -+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) -+ -+/*defines for CurrentModulation field */ -+#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) -+#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) -+#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) -+#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumGroups at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX -+#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+ U8 NumGroups; /*0x10 */ -+ U8 Reserved3; /*0x11 */ -+ U16 Reserved4; /*0x12 */ -+ MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS -+ PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /*0x14 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_6, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, -+ Mpi2SasIOUnitPage6_t, *pMpi2SasIOUnitPage6_t; -+ -+#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) -+ -+ -+/*SAS IO Unit Page 7 */ -+ -+typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { -+ U8 Flags; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U8 Threshold75Pct; /*0x04 */ -+ U8 Threshold50Pct; /*0x05 */ -+ U8 Threshold25Pct; /*0x06 */ -+ U8 Reserved3; /*0x07 */ -+} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, -+ *PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, -+ Mpi2SasIOUnit7PortWidthModGroupSettings_t, -+ *pMpi2SasIOUnit7PortWidthModGroupSettings_t; -+ -+/*defines for Flags field */ -+#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) -+ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumGroups at runtime. -+ */ -+#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX -+#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U8 SamplingInterval; /*0x08 */ -+ U8 WindowLength; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U32 Reserved2; /*0x0C */ -+ U32 Reserved3; /*0x10 */ -+ U8 NumGroups; /*0x14 */ -+ U8 Reserved4; /*0x15 */ -+ U16 Reserved5; /*0x16 */ -+ MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS -+ PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX];/*0x18 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_7, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, -+ Mpi2SasIOUnitPage7_t, *pMpi2SasIOUnitPage7_t; -+ -+#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) -+ -+ -+/*SAS IO Unit Page 8 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U32 -+ PowerManagementCapabilities; /*0x0C */ -+ U8 -+ TxRxSleepStatus; /*0x10 */ -+ U8 -+ Reserved2; /*0x11 */ -+ U16 -+ Reserved3; /*0x12 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT_8, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, -+ Mpi2SasIOUnitPage8_t, *pMpi2SasIOUnitPage8_t; -+ -+#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) -+ -+/*defines for PowerManagementCapabilities field */ -+#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000) -+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800) -+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400) -+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200) -+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002) -+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001) -+ -+/*defines for TxRxSleepStatus field */ -+#define MPI25_SASIOUNIT8_TXRXSLEEP_UNSUPPORTED (0x00) -+#define MPI25_SASIOUNIT8_TXRXSLEEP_DISENGAGED (0x01) -+#define MPI25_SASIOUNIT8_TXRXSLEEP_ACTIVE (0x02) -+#define MPI25_SASIOUNIT8_TXRXSLEEP_SHUTDOWN (0x03) -+ -+ -+ -+/*SAS IO Unit Page 16 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U64 -+ TimeStamp; /*0x08 */ -+ U32 -+ Reserved1; /*0x10 */ -+ U32 -+ Reserved2; /*0x14 */ -+ U32 -+ FastPathPendedRequests; /*0x18 */ -+ U32 -+ FastPathUnPendedRequests; /*0x1C */ -+ U32 -+ FastPathHostRequestStarts; /*0x20 */ -+ U32 -+ FastPathFirmwareRequestStarts; /*0x24 */ -+ U32 -+ FastPathHostCompletions; /*0x28 */ -+ U32 -+ FastPathFirmwareCompletions; /*0x2C */ -+ U32 -+ NonFastPathRequestStarts; /*0x30 */ -+ U32 -+ NonFastPathHostCompletions; /*0x30 */ -+} MPI2_CONFIG_PAGE_SASIOUNIT16, -+ *PTR_MPI2_CONFIG_PAGE_SASIOUNIT16, -+ Mpi2SasIOUnitPage16_t, *pMpi2SasIOUnitPage16_t; -+ -+#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00) -+ -+ -+/**************************************************************************** -+* SAS Expander Config Pages -+****************************************************************************/ -+ -+/*SAS Expander Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U8 -+ PhysicalPort; /*0x08 */ -+ U8 -+ ReportGenLength; /*0x09 */ -+ U16 -+ EnclosureHandle; /*0x0A */ -+ U64 -+ SASAddress; /*0x0C */ -+ U32 -+ DiscoveryStatus; /*0x14 */ -+ U16 -+ DevHandle; /*0x18 */ -+ U16 -+ ParentDevHandle; /*0x1A */ -+ U16 -+ ExpanderChangeCount; /*0x1C */ -+ U16 -+ ExpanderRouteIndexes; /*0x1E */ -+ U8 -+ NumPhys; /*0x20 */ -+ U8 -+ SASLevel; /*0x21 */ -+ U16 -+ Flags; /*0x22 */ -+ U16 -+ STPBusInactivityTimeLimit; /*0x24 */ -+ U16 -+ STPMaxConnectTimeLimit; /*0x26 */ -+ U16 -+ STP_SMP_NexusLossTime; /*0x28 */ -+ U16 -+ MaxNumRoutedSasAddresses; /*0x2A */ -+ U64 -+ ActiveZoneManagerSASAddress;/*0x2C */ -+ U16 -+ ZoneLockInactivityLimit; /*0x34 */ -+ U16 -+ Reserved1; /*0x36 */ -+ U8 -+ TimeToReducedFunc; /*0x38 */ -+ U8 -+ InitialTimeToReducedFunc; /*0x39 */ -+ U8 -+ MaxReducedFuncTime; /*0x3A */ -+ U8 -+ Reserved2; /*0x3B */ -+} MPI2_CONFIG_PAGE_EXPANDER_0, -+ *PTR_MPI2_CONFIG_PAGE_EXPANDER_0, -+ Mpi2ExpanderPage0_t, *pMpi2ExpanderPage0_t; -+ -+#define MPI2_SASEXPANDER0_PAGEVERSION (0x06) -+ -+/*values for SAS Expander Page 0 DiscoveryStatus field */ -+#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -+#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000) -+#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000) -+#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -+#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000) -+#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -+#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -+#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000) -+#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -+#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) -+#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400) -+#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200) -+#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100) -+#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080) -+#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040) -+#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020) -+#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010) -+#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004) -+#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002) -+#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) -+ -+/*values for SAS Expander Page 0 Flags field */ -+#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000) -+#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000) -+#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) -+#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) -+#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200) -+#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100) -+#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080) -+#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010) -+#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004) -+#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002) -+#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001) -+ -+ -+/*SAS Expander Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U8 -+ PhysicalPort; /*0x08 */ -+ U8 -+ Reserved1; /*0x09 */ -+ U16 -+ Reserved2; /*0x0A */ -+ U8 -+ NumPhys; /*0x0C */ -+ U8 -+ Phy; /*0x0D */ -+ U16 -+ NumTableEntriesProgrammed; /*0x0E */ -+ U8 -+ ProgrammedLinkRate; /*0x10 */ -+ U8 -+ HwLinkRate; /*0x11 */ -+ U16 -+ AttachedDevHandle; /*0x12 */ -+ U32 -+ PhyInfo; /*0x14 */ -+ U32 -+ AttachedDeviceInfo; /*0x18 */ -+ U16 -+ ExpanderDevHandle; /*0x1C */ -+ U8 -+ ChangeCount; /*0x1E */ -+ U8 -+ NegotiatedLinkRate; /*0x1F */ -+ U8 -+ PhyIdentifier; /*0x20 */ -+ U8 -+ AttachedPhyIdentifier; /*0x21 */ -+ U8 -+ Reserved3; /*0x22 */ -+ U8 -+ DiscoveryInfo; /*0x23 */ -+ U32 -+ AttachedPhyInfo; /*0x24 */ -+ U8 -+ ZoneGroup; /*0x28 */ -+ U8 -+ SelfConfigStatus; /*0x29 */ -+ U16 -+ Reserved4; /*0x2A */ -+} MPI2_CONFIG_PAGE_EXPANDER_1, -+ *PTR_MPI2_CONFIG_PAGE_EXPANDER_1, -+ Mpi2ExpanderPage1_t, *pMpi2ExpanderPage1_t; -+ -+#define MPI2_SASEXPANDER1_PAGEVERSION (0x02) -+ -+/*use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ -+ -+/*use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ -+ -+/*use MPI2_SAS_PHYINFO_ for the PhyInfo field */ -+ -+/*see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines -+ *used for the AttachedDeviceInfo field */ -+ -+/*use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -+ -+/*values for SAS Expander Page 1 DiscoveryInfo field */ -+#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) -+#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) -+#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) -+ -+/*use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ -+ -+ -+/**************************************************************************** -+* SAS Device Config Pages -+****************************************************************************/ -+ -+/*SAS Device Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U16 -+ Slot; /*0x08 */ -+ U16 -+ EnclosureHandle; /*0x0A */ -+ U64 -+ SASAddress; /*0x0C */ -+ U16 -+ ParentDevHandle; /*0x14 */ -+ U8 -+ PhyNum; /*0x16 */ -+ U8 -+ AccessStatus; /*0x17 */ -+ U16 -+ DevHandle; /*0x18 */ -+ U8 -+ AttachedPhyIdentifier; /*0x1A */ -+ U8 -+ ZoneGroup; /*0x1B */ -+ U32 -+ DeviceInfo; /*0x1C */ -+ U16 -+ Flags; /*0x20 */ -+ U8 -+ PhysicalPort; /*0x22 */ -+ U8 -+ MaxPortConnections; /*0x23 */ -+ U64 -+ DeviceName; /*0x24 */ -+ U8 -+ PortGroups; /*0x2C */ -+ U8 -+ DmaGroup; /*0x2D */ -+ U8 -+ ControlGroup; /*0x2E */ -+ U8 -+ EnclosureLevel; /*0x2F */ -+ U32 -+ ConnectorName[4]; /*0x30 */ -+ U32 -+ Reserved3; /*0x34 */ -+} MPI2_CONFIG_PAGE_SAS_DEV_0, -+ *PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, -+ Mpi2SasDevicePage0_t, -+ *pMpi2SasDevicePage0_t; -+ -+#define MPI2_SASDEVICE0_PAGEVERSION (0x09) -+ -+/*values for SAS Device Page 0 AccessStatus field */ -+#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) -+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) -+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) -+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) -+#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) -+#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05) -+#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06) -+#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07) -+/*specific values for SATA Init failures */ -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) -+#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) -+ -+/*see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ -+ -+/*values for SAS Device Page 0 Flags field */ -+#define MPI2_SAS_DEVICE0_FLAGS_UNAUTHORIZED_DEVICE (0x8000) -+#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH (0x4000) -+#define MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE (0x2000) -+#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) -+#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) -+#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) -+#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) -+#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) -+#define MPI2_SAS_DEVICE0_FLAGS_PERSIST_CAPABLE (0x0004) -+#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002) -+#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) -+ -+ -+/*SAS Device Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U64 -+ SASAddress; /*0x0C */ -+ U32 -+ Reserved2; /*0x14 */ -+ U16 -+ DevHandle; /*0x18 */ -+ U16 -+ Reserved3; /*0x1A */ -+ U8 -+ InitialRegDeviceFIS[20];/*0x1C */ -+} MPI2_CONFIG_PAGE_SAS_DEV_1, -+ *PTR_MPI2_CONFIG_PAGE_SAS_DEV_1, -+ Mpi2SasDevicePage1_t, -+ *pMpi2SasDevicePage1_t; -+ -+#define MPI2_SASDEVICE1_PAGEVERSION (0x01) -+ -+ -+/**************************************************************************** -+* SAS PHY Config Pages -+****************************************************************************/ -+ -+/*SAS PHY Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U16 -+ OwnerDevHandle; /*0x08 */ -+ U16 -+ Reserved1; /*0x0A */ -+ U16 -+ AttachedDevHandle; /*0x0C */ -+ U8 -+ AttachedPhyIdentifier; /*0x0E */ -+ U8 -+ Reserved2; /*0x0F */ -+ U32 -+ AttachedPhyInfo; /*0x10 */ -+ U8 -+ ProgrammedLinkRate; /*0x14 */ -+ U8 -+ HwLinkRate; /*0x15 */ -+ U8 -+ ChangeCount; /*0x16 */ -+ U8 -+ Flags; /*0x17 */ -+ U32 -+ PhyInfo; /*0x18 */ -+ U8 -+ NegotiatedLinkRate; /*0x1C */ -+ U8 -+ Reserved3; /*0x1D */ -+ U16 -+ Reserved4; /*0x1E */ -+} MPI2_CONFIG_PAGE_SAS_PHY_0, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_0, -+ Mpi2SasPhyPage0_t, *pMpi2SasPhyPage0_t; -+ -+#define MPI2_SASPHY0_PAGEVERSION (0x03) -+ -+/*use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ -+ -+/*use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ -+ -+/*use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ -+ -+/*values for SAS PHY Page 0 Flags field */ -+#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) -+ -+/*use MPI2_SAS_PHYINFO_ for the PhyInfo field */ -+ -+/*use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -+ -+ -+/*SAS PHY Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U32 -+ InvalidDwordCount; /*0x0C */ -+ U32 -+ RunningDisparityErrorCount; /*0x10 */ -+ U32 -+ LossDwordSynchCount; /*0x14 */ -+ U32 -+ PhyResetProblemCount; /*0x18 */ -+} MPI2_CONFIG_PAGE_SAS_PHY_1, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_1, -+ Mpi2SasPhyPage1_t, *pMpi2SasPhyPage1_t; -+ -+#define MPI2_SASPHY1_PAGEVERSION (0x01) -+ -+ -+/*SAS PHY Page 2 */ -+ -+typedef struct _MPI2_SASPHY2_PHY_EVENT { -+ U8 PhyEventCode; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 PhyEventInfo; /*0x04 */ -+} MPI2_SASPHY2_PHY_EVENT, *PTR_MPI2_SASPHY2_PHY_EVENT, -+ Mpi2SasPhy2PhyEvent_t, *pMpi2SasPhy2PhyEvent_t; -+ -+/*use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ -+ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhyEvents at runtime. -+ */ -+#ifndef MPI2_SASPHY2_PHY_EVENT_MAX -+#define MPI2_SASPHY2_PHY_EVENT_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U8 -+ NumPhyEvents; /*0x0C */ -+ U8 -+ Reserved2; /*0x0D */ -+ U16 -+ Reserved3; /*0x0E */ -+ MPI2_SASPHY2_PHY_EVENT -+ PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; /*0x10 */ -+} MPI2_CONFIG_PAGE_SAS_PHY_2, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, -+ Mpi2SasPhyPage2_t, -+ *pMpi2SasPhyPage2_t; -+ -+#define MPI2_SASPHY2_PAGEVERSION (0x00) -+ -+ -+/*SAS PHY Page 3 */ -+ -+typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { -+ U8 PhyEventCode; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U8 CounterType; /*0x04 */ -+ U8 ThresholdWindow; /*0x05 */ -+ U8 TimeUnits; /*0x06 */ -+ U8 Reserved3; /*0x07 */ -+ U32 EventThreshold; /*0x08 */ -+ U16 ThresholdFlags; /*0x0C */ -+ U16 Reserved4; /*0x0E */ -+} MPI2_SASPHY3_PHY_EVENT_CONFIG, -+ *PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, -+ Mpi2SasPhy3PhyEventConfig_t, -+ *pMpi2SasPhy3PhyEventConfig_t; -+ -+/*values for PhyEventCode field */ -+#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00) -+#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) -+#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) -+#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) -+#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) -+#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) -+#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06) -+#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) -+#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) -+#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) -+#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) -+#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) -+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) -+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) -+#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27) -+#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28) -+#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) -+#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A) -+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) -+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) -+#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) -+#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) -+#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) -+#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) -+#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) -+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) -+#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) -+#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) -+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2) -+ -+/*Following codes are product specific and in MPI v2.6 and later */ -+#define MPI2_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME (0xD3) -+#define MPI2_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME (0xD4) -+#define MPI2_SASPHY3_EVENT_CODE_LCCONN_TIME (0xD5) -+#define MPI2_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT (0xD6) -+#define MPI2_SASPHY3_EVENT_CODE_SATA_TX_START (0xD7) -+#define MPI2_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT (0xD8) -+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN (0xD9) -+#define MPI2_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE (0xDA) -+#define MPI2_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xDB) -+#define MPI2_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE (0xDC) -+ -+ -+/*values for the CounterType field */ -+#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) -+#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01) -+#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) -+ -+/*values for the TimeUnits field */ -+#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) -+#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) -+#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) -+#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) -+ -+/*values for the ThresholdFlags field */ -+#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002) -+#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumPhyEvents at runtime. -+ */ -+#ifndef MPI2_SASPHY3_PHY_EVENT_MAX -+#define MPI2_SASPHY3_PHY_EVENT_MAX (1) -+#endif -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U8 -+ NumPhyEvents; /*0x0C */ -+ U8 -+ Reserved2; /*0x0D */ -+ U16 -+ Reserved3; /*0x0E */ -+ MPI2_SASPHY3_PHY_EVENT_CONFIG -+ PhyEventConfig[MPI2_SASPHY3_PHY_EVENT_MAX]; /*0x10 */ -+} MPI2_CONFIG_PAGE_SAS_PHY_3, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, -+ Mpi2SasPhyPage3_t, *pMpi2SasPhyPage3_t; -+ -+#define MPI2_SASPHY3_PAGEVERSION (0x00) -+ -+ -+/*SAS PHY Page 4 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U16 -+ Reserved1; /*0x08 */ -+ U8 -+ Reserved2; /*0x0A */ -+ U8 -+ Flags; /*0x0B */ -+ U8 -+ InitialFrame[28]; /*0x0C */ -+} MPI2_CONFIG_PAGE_SAS_PHY_4, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, -+ Mpi2SasPhyPage4_t, *pMpi2SasPhyPage4_t; -+ -+#define MPI2_SASPHY4_PAGEVERSION (0x00) -+ -+/*values for the Flags field */ -+#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) -+#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) -+ -+ -+ -+ -+/**************************************************************************** -+* SAS Port Config Pages -+****************************************************************************/ -+ -+/*SAS Port Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U8 -+ PortNumber; /*0x08 */ -+ U8 -+ PhysicalPort; /*0x09 */ -+ U8 -+ PortWidth; /*0x0A */ -+ U8 -+ PhysicalPortWidth; /*0x0B */ -+ U8 -+ ZoneGroup; /*0x0C */ -+ U8 -+ Reserved1; /*0x0D */ -+ U16 -+ Reserved2; /*0x0E */ -+ U64 -+ SASAddress; /*0x10 */ -+ U32 -+ DeviceInfo; /*0x18 */ -+ U32 -+ Reserved3; /*0x1C */ -+ U32 -+ Reserved4; /*0x20 */ -+} MPI2_CONFIG_PAGE_SAS_PORT_0, -+ *PTR_MPI2_CONFIG_PAGE_SAS_PORT_0, -+ Mpi2SasPortPage0_t, *pMpi2SasPortPage0_t; -+ -+#define MPI2_SASPORT0_PAGEVERSION (0x00) -+ -+/*see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */ -+ -+ -+/**************************************************************************** -+* SAS Enclosure Config Pages -+****************************************************************************/ -+ -+/*SAS Enclosure Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved1; /*0x08 */ -+ U64 -+ EnclosureLogicalID; /*0x0C */ -+ U16 -+ Flags; /*0x14 */ -+ U16 -+ EnclosureHandle; /*0x16 */ -+ U16 -+ NumSlots; /*0x18 */ -+ U16 -+ StartSlot; /*0x1A */ -+ U8 -+ Reserved2; /*0x1C */ -+ U8 -+ EnclosureLevel; /*0x1D */ -+ U16 -+ SEPDevHandle; /*0x1E */ -+ U32 -+ Reserved3; /*0x20 */ -+ U32 -+ Reserved4; /*0x24 */ -+} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, -+ *PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, -+ Mpi2SasEnclosurePage0_t, *pMpi2SasEnclosurePage0_t; -+ -+#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04) -+ -+/*values for SAS Enclosure Page 0 Flags field */ -+#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) -+#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) -+ -+ -+/**************************************************************************** -+* Log Config Page -+****************************************************************************/ -+ -+/*Log Page 0 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumLogEntries at runtime. -+ */ -+#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES -+#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) -+#endif -+ -+#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) -+ -+typedef struct _MPI2_LOG_0_ENTRY { -+ U64 TimeStamp; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U16 LogSequence; /*0x0C */ -+ U16 LogEntryQualifier; /*0x0E */ -+ U8 VP_ID; /*0x10 */ -+ U8 VF_ID; /*0x11 */ -+ U16 Reserved2; /*0x12 */ -+ U8 -+ LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/*0x14 */ -+} MPI2_LOG_0_ENTRY, *PTR_MPI2_LOG_0_ENTRY, -+ Mpi2Log0Entry_t, *pMpi2Log0Entry_t; -+ -+/*values for Log Page 0 LogEntry LogEntryQualifier field */ -+#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000) -+#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001) -+#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002) -+#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000) -+#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF) -+ -+typedef struct _MPI2_CONFIG_PAGE_LOG_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+ U16 NumLogEntries;/*0x10 */ -+ U16 Reserved3; /*0x12 */ -+ MPI2_LOG_0_ENTRY -+ LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /*0x14 */ -+} MPI2_CONFIG_PAGE_LOG_0, *PTR_MPI2_CONFIG_PAGE_LOG_0, -+ Mpi2LogPage0_t, *pMpi2LogPage0_t; -+ -+#define MPI2_LOG_0_PAGEVERSION (0x02) -+ -+ -+/**************************************************************************** -+* RAID Config Page -+****************************************************************************/ -+ -+/*RAID Page 0 */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check the value returned for NumElements at runtime. -+ */ -+#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS -+#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) -+#endif -+ -+typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT { -+ U16 ElementFlags; /*0x00 */ -+ U16 VolDevHandle; /*0x02 */ -+ U8 HotSparePool; /*0x04 */ -+ U8 PhysDiskNum; /*0x05 */ -+ U16 PhysDiskDevHandle; /*0x06 */ -+} MPI2_RAIDCONFIG0_CONFIG_ELEMENT, -+ *PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT, -+ Mpi2RaidConfig0ConfigElement_t, -+ *pMpi2RaidConfig0ConfigElement_t; -+ -+/*values for the ElementFlags field */ -+#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F) -+#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000) -+#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001) -+#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002) -+#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003) -+ -+ -+typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U8 NumHotSpares; /*0x08 */ -+ U8 NumPhysDisks; /*0x09 */ -+ U8 NumVolumes; /*0x0A */ -+ U8 ConfigNum; /*0x0B */ -+ U32 Flags; /*0x0C */ -+ U8 ConfigGUID[24]; /*0x10 */ -+ U32 Reserved1; /*0x28 */ -+ U8 NumElements; /*0x2C */ -+ U8 Reserved2; /*0x2D */ -+ U16 Reserved3; /*0x2E */ -+ MPI2_RAIDCONFIG0_CONFIG_ELEMENT -+ ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /*0x30 */ -+} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, -+ *PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, -+ Mpi2RaidConfigurationPage0_t, -+ *pMpi2RaidConfigurationPage0_t; -+ -+#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00) -+ -+/*values for RAID Configuration Page 0 Flags field */ -+#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001) -+ -+ -+/**************************************************************************** -+* Driver Persistent Mapping Config Pages -+****************************************************************************/ -+ -+/*Driver Persistent Mapping Page 0 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY { -+ U64 PhysicalIdentifier; /*0x00 */ -+ U16 MappingInformation; /*0x08 */ -+ U16 DeviceIndex; /*0x0A */ -+ U32 PhysicalBitsMapping; /*0x0C */ -+ U32 Reserved1; /*0x10 */ -+} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, -+ *PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, -+ Mpi2DriverMap0Entry_t, *pMpi2DriverMap0Entry_t; -+ -+typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /*0x08 */ -+} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, -+ *PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, -+ Mpi2DriverMappingPage0_t, *pMpi2DriverMappingPage0_t; -+ -+#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00) -+ -+/*values for Driver Persistent Mapping Page 0 MappingInformation field */ -+#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0) -+#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4) -+#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) -+ -+ -+/**************************************************************************** -+* Ethernet Config Pages -+****************************************************************************/ -+ -+/*Ethernet Page 0 */ -+ -+/*IP address (union of IPv4 and IPv6) */ -+typedef union _MPI2_ETHERNET_IP_ADDR { -+ U32 IPv4Addr; -+ U32 IPv6Addr[4]; -+} MPI2_ETHERNET_IP_ADDR, *PTR_MPI2_ETHERNET_IP_ADDR, -+ Mpi2EthernetIpAddr_t, *pMpi2EthernetIpAddr_t; -+ -+#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) -+ -+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ -+ U8 NumInterfaces; /*0x08 */ -+ U8 Reserved0; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U32 Status; /*0x0C */ -+ U8 MediaState; /*0x10 */ -+ U8 Reserved2; /*0x11 */ -+ U16 Reserved3; /*0x12 */ -+ U8 MacAddress[6]; /*0x14 */ -+ U8 Reserved4; /*0x1A */ -+ U8 Reserved5; /*0x1B */ -+ MPI2_ETHERNET_IP_ADDR IpAddress; /*0x1C */ -+ MPI2_ETHERNET_IP_ADDR SubnetMask; /*0x2C */ -+ MPI2_ETHERNET_IP_ADDR GatewayIpAddress;/*0x3C */ -+ MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /*0x4C */ -+ MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /*0x5C */ -+ MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /*0x6C */ -+ U8 -+ HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/*0x7C */ -+} MPI2_CONFIG_PAGE_ETHERNET_0, -+ *PTR_MPI2_CONFIG_PAGE_ETHERNET_0, -+ Mpi2EthernetPage0_t, *pMpi2EthernetPage0_t; -+ -+#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) -+ -+/*values for Ethernet Page 0 Status field */ -+#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) -+#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) -+#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) -+#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) -+#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) -+#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) -+#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) -+#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) -+#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) -+#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) -+#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) -+#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) -+ -+/*values for Ethernet Page 0 MediaState field */ -+#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) -+#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) -+#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) -+ -+#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) -+#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) -+#define MPI2_ETHPG0_MS_10MBIT (0x01) -+#define MPI2_ETHPG0_MS_100MBIT (0x02) -+#define MPI2_ETHPG0_MS_1GBIT (0x03) -+ -+ -+/*Ethernet Page 1 */ -+ -+typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ Reserved0; /*0x08 */ -+ U32 -+ Flags; /*0x0C */ -+ U8 -+ MediaState; /*0x10 */ -+ U8 -+ Reserved1; /*0x11 */ -+ U16 -+ Reserved2; /*0x12 */ -+ U8 -+ MacAddress[6]; /*0x14 */ -+ U8 -+ Reserved3; /*0x1A */ -+ U8 -+ Reserved4; /*0x1B */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticIpAddress; /*0x1C */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticSubnetMask; /*0x2C */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticGatewayIpAddress; /*0x3C */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticDNS1IpAddress; /*0x4C */ -+ MPI2_ETHERNET_IP_ADDR -+ StaticDNS2IpAddress; /*0x5C */ -+ U32 -+ Reserved5; /*0x6C */ -+ U32 -+ Reserved6; /*0x70 */ -+ U32 -+ Reserved7; /*0x74 */ -+ U32 -+ Reserved8; /*0x78 */ -+ U8 -+ HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/*0x7C */ -+} MPI2_CONFIG_PAGE_ETHERNET_1, -+ *PTR_MPI2_CONFIG_PAGE_ETHERNET_1, -+ Mpi2EthernetPage1_t, *pMpi2EthernetPage1_t; -+ -+#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) -+ -+/*values for Ethernet Page 1 Flags field */ -+#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) -+#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) -+#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) -+#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) -+#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) -+#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) -+#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) -+#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) -+#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) -+ -+/*values for Ethernet Page 1 MediaState field */ -+#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) -+#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) -+#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) -+ -+#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) -+#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) -+#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) -+#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) -+#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) -+ -+ -+/**************************************************************************** -+* Extended Manufacturing Config Pages -+****************************************************************************/ -+ -+/* -+ *Generic structure to use for product-specific extended manufacturing pages -+ *(currently Extended Manufacturing Page 40 through Extended Manufacturing -+ *Page 60). -+ */ -+ -+typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { -+ MPI2_CONFIG_EXTENDED_PAGE_HEADER -+ Header; /*0x00 */ -+ U32 -+ ProductSpecificInfo; /*0x08 */ -+} MPI2_CONFIG_PAGE_EXT_MAN_PS, -+ *PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, -+ Mpi2ExtManufacturingPagePS_t, -+ *pMpi2ExtManufacturingPagePS_t; -+ -+/*PageVersion should be provided by product-specific code */ -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h -new file mode 100644 -index 0000000..bba56b6 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h -@@ -0,0 +1,581 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_init.h -+ * Title: MPI SCSI initiator mode messages and structures -+ * Creation Date: June 23, 2006 -+ * -+ * mpi2_init.h Version: 02.00.20 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. -+ * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. -+ * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. -+ * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. -+ * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. -+ * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO -+ * Control field Task Attribute flags. -+ * Moved LUN field defines to mpi2.h becasue they are -+ * common to many structures. -+ * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to -+ * Query Asynchronous Event. -+ * Defined two new bits in the SlotStatus field of the SCSI -+ * Enclosure Processor Request and Reply. -+ * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for -+ * both SCSI IO Error Reply and SCSI Task Management Reply. -+ * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. -+ * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. -+ * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. -+ * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. -+ * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. -+ * 11-18-11 02.00.12 Incorporating additions for MPI v2.5. -+ * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command -+ * Priority to match SAM-4. -+ * Added EEDPErrorOffset to MPI2_SCSI_IO_REPLY. -+ * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION. -+ * 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY, -+ * replacing the Reserved4 field. -+ * 11-18-14 02.00.16 Updated copyright information. -+ * 03-16-15 02.00.17 Updated for MPI v2.6. -+ * Added MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH. -+ * Added MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF and -+ * MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF. -+ * 08-26-15 02.00.18 Added SCSITASKMGMT_MSGFLAGS for Target Reset. -+ * 12-18-15 02.00.19 Added EEDPObservedValue added to SCSI IO Reply message. -+ * 01-04-16 02.00.20 Modified EEDP reported values in SCSI IO Reply message. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_INIT_H -+#define MPI2_INIT_H -+ -+/***************************************************************************** -+* -+* SCSI Initiator Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* SCSI IO messages and associated structures -+****************************************************************************/ -+ -+typedef struct _MPI2_SCSI_IO_CDB_EEDP32 { -+ U8 CDB[20]; /*0x00 */ -+ U32 PrimaryReferenceTag; /*0x14 */ -+ U16 PrimaryApplicationTag; /*0x18 */ -+ U16 PrimaryApplicationTagMask; /*0x1A */ -+ U32 TransferLength; /*0x1C */ -+} MPI2_SCSI_IO_CDB_EEDP32, *PTR_MPI2_SCSI_IO_CDB_EEDP32, -+ Mpi2ScsiIoCdbEedp32_t, *pMpi2ScsiIoCdbEedp32_t; -+ -+/*MPI v2.0 CDB field */ -+typedef union _MPI2_SCSI_IO_CDB_UNION { -+ U8 CDB32[32]; -+ MPI2_SCSI_IO_CDB_EEDP32 EEDP32; -+ MPI2_SGE_SIMPLE_UNION SGE; -+} MPI2_SCSI_IO_CDB_UNION, *PTR_MPI2_SCSI_IO_CDB_UNION, -+ Mpi2ScsiIoCdb_t, *pMpi2ScsiIoCdb_t; -+ -+/*MPI v2.0 SCSI IO Request Message */ -+typedef struct _MPI2_SCSI_IO_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U32 SenseBufferLowAddress; /*0x0C */ -+ U16 SGLFlags; /*0x10 */ -+ U8 SenseBufferLength; /*0x12 */ -+ U8 Reserved4; /*0x13 */ -+ U8 SGLOffset0; /*0x14 */ -+ U8 SGLOffset1; /*0x15 */ -+ U8 SGLOffset2; /*0x16 */ -+ U8 SGLOffset3; /*0x17 */ -+ U32 SkipCount; /*0x18 */ -+ U32 DataLength; /*0x1C */ -+ U32 BidirectionalDataLength; /*0x20 */ -+ U16 IoFlags; /*0x24 */ -+ U16 EEDPFlags; /*0x26 */ -+ U32 EEDPBlockSize; /*0x28 */ -+ U32 SecondaryReferenceTag; /*0x2C */ -+ U16 SecondaryApplicationTag; /*0x30 */ -+ U16 ApplicationTagTranslationMask; /*0x32 */ -+ U8 LUN[8]; /*0x34 */ -+ U32 Control; /*0x3C */ -+ MPI2_SCSI_IO_CDB_UNION CDB; /*0x40 */ -+ -+#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /*typically this is left undefined */ -+ MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion; -+#endif -+ -+ MPI2_SGE_IO_UNION SGL; /*0x60 */ -+ -+} MPI2_SCSI_IO_REQUEST, *PTR_MPI2_SCSI_IO_REQUEST, -+ Mpi2SCSIIORequest_t, *pMpi2SCSIIORequest_t; -+ -+/*SCSI IO MsgFlags bits */ -+ -+/*MsgFlags for SenseBufferAddressSpace */ -+#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C) -+#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00) -+#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04) -+#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08) -+#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C) -+#define MPI26_SCSIIO_MSGFLAGS_IOCCTL_SENSE_ADDR (0x08) -+ -+/*SCSI IO SGLFlags bits */ -+ -+/*base values for Data Location Address Space */ -+#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C) -+#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00) -+#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04) -+#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08) -+#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) -+ -+/*base values for Type */ -+#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03) -+#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00) -+#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01) -+#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02) -+ -+/*shift values for each sub-field */ -+#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12) -+#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8) -+#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) -+#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) -+ -+/*number of SGLOffset fields */ -+#define MPI2_SCSIIO_NUM_SGLOFFSETS (4) -+ -+/*SCSI IO IoFlags bits */ -+ -+/*Large CDB Address Space */ -+#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000) -+#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000) -+#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000) -+#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000) -+#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000) -+ -+#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) -+#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) -+#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400) -+#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200) -+#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) -+ -+/*SCSI IO EEDPFlags bits */ -+ -+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) -+#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000) -+#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000) -+#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000) -+ -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) -+ -+#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) -+ -+#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007) -+#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001) -+#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) -+#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) -+#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006) -+#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007) -+ -+/*SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */ -+ -+/*SCSI IO Control bits */ -+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000) -+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) -+ -+#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) -+#define MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION (24) -+#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) -+#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) -+#define MPI2_SCSIIO_CONTROL_READ (0x02000000) -+#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000) -+ -+#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800) -+#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11) -+/*alternate name for the previous field; called Command Priority in SAM-4 */ -+#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK (0x00007800) -+#define MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT (11) -+ -+#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) -+#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000) -+#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100) -+#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200) -+#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400) -+ -+#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0) -+#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000) -+#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040) -+#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080) -+ -+/*MPI v2.5 CDB field */ -+typedef union _MPI25_SCSI_IO_CDB_UNION { -+ U8 CDB32[32]; -+ MPI2_SCSI_IO_CDB_EEDP32 EEDP32; -+ MPI2_IEEE_SGE_SIMPLE64 SGE; -+} MPI25_SCSI_IO_CDB_UNION, *PTR_MPI25_SCSI_IO_CDB_UNION, -+ Mpi25ScsiIoCdb_t, *pMpi25ScsiIoCdb_t; -+ -+/*MPI v2.5/2.6 SCSI IO Request Message */ -+typedef struct _MPI25_SCSI_IO_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U32 SenseBufferLowAddress; /*0x0C */ -+ U8 DMAFlags; /*0x10 */ -+ U8 Reserved5; /*0x11 */ -+ U8 SenseBufferLength; /*0x12 */ -+ U8 Reserved4; /*0x13 */ -+ U8 SGLOffset0; /*0x14 */ -+ U8 SGLOffset1; /*0x15 */ -+ U8 SGLOffset2; /*0x16 */ -+ U8 SGLOffset3; /*0x17 */ -+ U32 SkipCount; /*0x18 */ -+ U32 DataLength; /*0x1C */ -+ U32 BidirectionalDataLength; /*0x20 */ -+ U16 IoFlags; /*0x24 */ -+ U16 EEDPFlags; /*0x26 */ -+ U16 EEDPBlockSize; /*0x28 */ -+ U16 Reserved6; /*0x2A */ -+ U32 SecondaryReferenceTag; /*0x2C */ -+ U16 SecondaryApplicationTag; /*0x30 */ -+ U16 ApplicationTagTranslationMask; /*0x32 */ -+ U8 LUN[8]; /*0x34 */ -+ U32 Control; /*0x3C */ -+ MPI25_SCSI_IO_CDB_UNION CDB; /*0x40 */ -+ -+#ifdef MPI25_SCSI_IO_VENDOR_UNIQUE_REGION /*typically this is left undefined */ -+ MPI25_SCSI_IO_VENDOR_UNIQUE VendorRegion; -+#endif -+ -+ MPI25_SGE_IO_UNION SGL; /*0x60 */ -+ -+} MPI25_SCSI_IO_REQUEST, *PTR_MPI25_SCSI_IO_REQUEST, -+ Mpi25SCSIIORequest_t, *pMpi25SCSIIORequest_t; -+ -+/*use MPI2_SCSIIO_MSGFLAGS_ defines for the MsgFlags field */ -+ -+/*Defines for the DMAFlags field -+ * Each setting affects 4 SGLS, from SGL0 to SGL3. -+ * D = Data -+ * C = Cache DIF -+ * I = Interleaved -+ * H = Host DIF -+ */ -+#define MPI25_SCSIIO_DMAFLAGS_OP_MASK (0x0F) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_D (0x00) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_C (0x01) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_D_I (0x02) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_C (0x03) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_C_I (0x04) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_D_I_I (0x05) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_C (0x06) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_C_I (0x07) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_C_I_I (0x08) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_I_I_I (0x09) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_D (0x0A) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_C (0x0B) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_D_I (0x0C) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_C (0x0D) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_C_I (0x0E) -+#define MPI25_SCSIIO_DMAFLAGS_OP_D_H_I_I (0x0F) -+ -+/*number of SGLOffset fields */ -+#define MPI25_SCSIIO_NUM_SGLOFFSETS (4) -+ -+/*defines for the IoFlags field */ -+#define MPI25_SCSIIO_IOFLAGS_IO_PATH_MASK (0xC000) -+#define MPI25_SCSIIO_IOFLAGS_NORMAL_PATH (0x0000) -+#define MPI25_SCSIIO_IOFLAGS_FAST_PATH (0x4000) -+ -+#define MPI26_SCSIIO_IOFLAGS_ESCAPE_PASSTHROUGH (0x2000) -+#define MPI25_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) -+#define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) -+#define MPI26_SCSIIO_IOFLAGS_PORT_REQUEST (0x0400) -+#define MPI25_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) -+ -+/*MPI v2.5 defines for the EEDPFlags bits */ -+/*use MPI2_SCSIIO_EEDPFLAGS_ defines for the other EEDPFlags bits */ -+#define MPI25_SCSIIO_EEDPFLAGS_ESCAPE_MODE_MASK (0x00C0) -+#define MPI25_SCSIIO_EEDPFLAGS_COMPATIBLE_MODE (0x0000) -+#define MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE (0x0040) -+#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE (0x0080) -+#define MPI25_SCSIIO_EEDPFLAGS_APPTAG_REFTAG_DISABLE_MODE (0x00C0) -+ -+#define MPI25_SCSIIO_EEDPFLAGS_HOST_GUARD_METHOD_MASK (0x0030) -+#define MPI25_SCSIIO_EEDPFLAGS_T10_CRC_HOST_GUARD (0x0000) -+#define MPI25_SCSIIO_EEDPFLAGS_IP_CHKSUM_HOST_GUARD (0x0010) -+ -+/*use MPI2_LUN_ defines from mpi2.h for the LUN field */ -+ -+/*use MPI2_SCSIIO_CONTROL_ defines for the Control field */ -+ -+/*NOTE: The SCSI IO Reply is nearly the same for MPI 2.0 and MPI 2.5, so -+ * MPI2_SCSI_IO_REPLY is used for both. -+ */ -+ -+/*SCSI IO Error Reply Message */ -+typedef struct _MPI2_SCSI_IO_REPLY { -+ U16 DevHandle; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U8 SCSIStatus; /*0x0C */ -+ U8 SCSIState; /*0x0D */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 TransferCount; /*0x14 */ -+ U32 SenseCount; /*0x18 */ -+ U32 ResponseInfo; /*0x1C */ -+ U16 TaskTag; /*0x20 */ -+ U16 SCSIStatusQualifier; /* 0x22 */ -+ U32 BidirectionalTransferCount; /*0x24 */ -+ /* MPI 2.5+ only; Reserved in MPI 2.0 */ -+ U32 EEDPErrorOffset; /* 0x28 */ -+ /* MPI 2.5+ only; Reserved in MPI 2.0 */ -+ U16 EEDPObservedAppTag; /* 0x2C */ -+ /* MPI 2.5+ only; Reserved in MPI 2.0 */ -+ U16 EEDPObservedGuard; /* 0x2E */ -+ /* MPI 2.5+ only; Reserved in MPI 2.0 */ -+ U32 EEDPObservedRefTag; /* 0x30 */ -+} MPI2_SCSI_IO_REPLY, *PTR_MPI2_SCSI_IO_REPLY, -+ Mpi2SCSIIOReply_t, *pMpi2SCSIIOReply_t; -+ -+/*SCSI IO Reply SCSIStatus values (SAM-4 status codes) */ -+ -+#define MPI2_SCSI_STATUS_GOOD (0x00) -+#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02) -+#define MPI2_SCSI_STATUS_CONDITION_MET (0x04) -+#define MPI2_SCSI_STATUS_BUSY (0x08) -+#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10) -+#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) -+#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18) -+#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /*obsolete */ -+#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28) -+#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30) -+#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40) -+ -+/*SCSI IO Reply SCSIState flags */ -+ -+#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10) -+#define MPI2_SCSI_STATE_TERMINATED (0x08) -+#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04) -+#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) -+#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) -+ -+/*masks and shifts for the ResponseInfo field */ -+ -+#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) -+#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) -+ -+#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) -+ -+/**************************************************************************** -+* SCSI Task Management messages -+****************************************************************************/ -+ -+/*SCSI Task Management Request Message */ -+typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Reserved1; /*0x04 */ -+ U8 TaskType; /*0x05 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U8 LUN[8]; /*0x0C */ -+ U32 Reserved4[7]; /*0x14 */ -+ U16 TaskMID; /*0x30 */ -+ U16 Reserved5; /*0x32 */ -+} MPI2_SCSI_TASK_MANAGE_REQUEST, -+ *PTR_MPI2_SCSI_TASK_MANAGE_REQUEST, -+ Mpi2SCSITaskManagementRequest_t, -+ *pMpi2SCSITaskManagementRequest_t; -+ -+/*TaskType values */ -+ -+#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) -+#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) -+#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) -+#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) -+#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) -+#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) -+#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) -+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) -+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) -+ -+/*obsolete TaskType name */ -+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \ -+ (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT) -+ -+/*MsgFlags bits */ -+ -+#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18) -+#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00) -+#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08) -+#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10) -+ -+#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) -+ -+/*SCSI Task Management Reply Message */ -+typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY { -+ U16 DevHandle; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 ResponseCode; /*0x04 */ -+ U8 TaskType; /*0x05 */ -+ U8 Reserved1; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U16 Reserved3; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 TerminationCount; /*0x14 */ -+ U32 ResponseInfo; /*0x18 */ -+} MPI2_SCSI_TASK_MANAGE_REPLY, -+ *PTR_MPI2_SCSI_TASK_MANAGE_REPLY, -+ Mpi2SCSITaskManagementReply_t, *pMpi2SCSIManagementReply_t; -+ -+/*ResponseCode values */ -+ -+#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) -+#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) -+#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) -+#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) -+#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) -+#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) -+#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) -+#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) -+ -+/*masks and shifts for the ResponseInfo field */ -+ -+#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) -+#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) -+#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) -+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) -+#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) -+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) -+#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) -+#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) -+ -+/**************************************************************************** -+* SCSI Enclosure Processor messages -+****************************************************************************/ -+ -+/*SCSI Enclosure Processor Request Message */ -+typedef struct _MPI2_SEP_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Action; /*0x04 */ -+ U8 Flags; /*0x05 */ -+ U8 Reserved1; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U32 SlotStatus; /*0x0C */ -+ U32 Reserved3; /*0x10 */ -+ U32 Reserved4; /*0x14 */ -+ U32 Reserved5; /*0x18 */ -+ U16 Slot; /*0x1C */ -+ U16 EnclosureHandle; /*0x1E */ -+} MPI2_SEP_REQUEST, *PTR_MPI2_SEP_REQUEST, -+ Mpi2SepRequest_t, *pMpi2SepRequest_t; -+ -+/*Action defines */ -+#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00) -+#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01) -+ -+/*Flags defines */ -+#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00) -+#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01) -+ -+/*SlotStatus defines */ -+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_OFF (0x00080000) -+#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) -+#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) -+#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) -+#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) -+#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) -+#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) -+#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) -+#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) -+#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) -+#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) -+ -+/*SCSI Enclosure Processor Reply Message */ -+typedef struct _MPI2_SEP_REPLY { -+ U16 DevHandle; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Action; /*0x04 */ -+ U8 Flags; /*0x05 */ -+ U8 Reserved1; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U16 Reserved3; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 SlotStatus; /*0x14 */ -+ U32 Reserved4; /*0x18 */ -+ U16 Slot; /*0x1C */ -+ U16 EnclosureHandle; /*0x1E */ -+} MPI2_SEP_REPLY, *PTR_MPI2_SEP_REPLY, -+ Mpi2SepReply_t, *pMpi2SepReply_t; -+ -+/*SlotStatus defines */ -+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_OFF (0x00080000) -+#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) -+#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) -+#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) -+#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) -+#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) -+#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) -+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) -+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) -+#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) -+#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h -new file mode 100644 -index 0000000..8bae305 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h -@@ -0,0 +1,1860 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_ioc.h -+ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages -+ * Creation Date: October 11, 2006 -+ * -+ * mpi2_ioc.h Version: 02.00.27 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to -+ * MaxTargets. -+ * Added TotalImageSize field to FWDownload Request. -+ * Added reserved words to FWUpload Request. -+ * 06-26-07 02.00.02 Added IR Configuration Change List Event. -+ * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit -+ * request and replaced it with -+ * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. -+ * Replaced the MinReplyQueueDepth field of the IOCFacts -+ * reply with MaxReplyDescriptorPostQueueDepth. -+ * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum -+ * depth for the Reply Descriptor Post Queue. -+ * Added SASAddress field to Initiator Device Table -+ * Overflow Event data. -+ * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING -+ * for SAS Initiator Device Status Change Event data. -+ * Modified Reason Code defines for SAS Topology Change -+ * List Event data, including adding a bit for PHY Vacant -+ * status, and adding a mask for the Reason Code. -+ * Added define for -+ * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. -+ * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. -+ * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of -+ * the IOCFacts Reply. -+ * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. -+ * Moved MPI2_VERSION_UNION to mpi2.h. -+ * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks -+ * instead of enables, and added SASBroadcastPrimitiveMasks -+ * field. -+ * Added Log Entry Added Event and related structure. -+ * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. -+ * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. -+ * Added MaxVolumes and MaxPersistentEntries fields to -+ * IOCFacts reply. -+ * Added ProtocalFlags and IOCCapabilities fields to -+ * MPI2_FW_IMAGE_HEADER. -+ * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. -+ * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to -+ * a U16 (from a U32). -+ * Removed extra 's' from EventMasks name. -+ * 06-27-08 02.00.08 Fixed an offset in a comment. -+ * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. -+ * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and -+ * renamed MinReplyFrameSize to ReplyFrameSize. -+ * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. -+ * Added two new RAIDOperation values for Integrated RAID -+ * Operations Status Event data. -+ * Added four new IR Configuration Change List Event data -+ * ReasonCode values. -+ * Added two new ReasonCode defines for SAS Device Status -+ * Change Event data. -+ * Added three new DiscoveryStatus bits for the SAS -+ * Discovery event data. -+ * Added Multiplexing Status Change bit to the PhyStatus -+ * field of the SAS Topology Change List event data. -+ * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. -+ * BootFlags are now product-specific. -+ * Added defines for the indivdual signature bytes -+ * for MPI2_INIT_IMAGE_FOOTER. -+ * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. -+ * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR -+ * define. -+ * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE -+ * define. -+ * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. -+ * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. -+ * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. -+ * Added two new reason codes for SAS Device Status Change -+ * Event. -+ * Added new event: SAS PHY Counter. -+ * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. -+ * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. -+ * Added new product id family for 2208. -+ * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. -+ * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. -+ * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. -+ * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. -+ * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. -+ * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. -+ * Added Host Based Discovery Phy Event data. -+ * Added defines for ProductID Product field -+ * (MPI2_FW_HEADER_PID_). -+ * Modified values for SAS ProductID Family -+ * (MPI2_FW_HEADER_PID_FAMILY_). -+ * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. -+ * Added PowerManagementControl Request structures and -+ * defines. -+ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. -+ * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. -+ * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. -+ * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added -+ * SASNotifyPrimitiveMasks field to -+ * MPI2_EVENT_NOTIFICATION_REQUEST. -+ * Added Temperature Threshold Event. -+ * Added Host Message Event. -+ * Added Send Host Message request and reply. -+ * 05-25-11 02.00.18 For Extended Image Header, added -+ * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and -+ * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. -+ * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. -+ * 08-24-11 02.00.19 Added PhysicalPort field to -+ * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. -+ * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. -+ * 11-18-11 02.00.20 Incorporating additions for MPI v2.5. -+ * 03-29-12 02.00.21 Added a product specific range to event values. -+ * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE. -+ * Added ElapsedSeconds field to -+ * MPI2_EVENT_DATA_IR_OPERATION_STATUS. -+ * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE -+ * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY. -+ * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. -+ * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. -+ * Added Encrypted Hash Extended Image. -+ * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. -+ * 11-18-14 02.00.25 Updated copyright information. -+ * 03-16-15 02.00.26 Updated for MPI v2.6. -+ * Added MPI2_EVENT_ACTIVE_CABLE_EXCEPTION and -+ * MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT. -+ * Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and -+ * MPI26_FW_HEADER_PID_FAMILY_3516_SAS. -+ * Added MPI26_CTRL_OP_SHUTDOWN. -+ * 08-25-15 02.00.27 Added IC ARCH Class based signature defines -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_IOC_H -+#define MPI2_IOC_H -+ -+/***************************************************************************** -+* -+* IOC Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* IOCInit message -+****************************************************************************/ -+ -+/*IOCInit Request message */ -+typedef struct _MPI2_IOC_INIT_REQUEST { -+ U8 WhoInit; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 MsgVersion; /*0x0C */ -+ U16 HeaderVersion; /*0x0E */ -+ U32 Reserved5; /*0x10 */ -+ U16 ConfigurationFlags; /* 0x14 */ -+ U8 HostPageSize; /*0x16 */ -+ U8 HostMSIxVectors; /*0x17 */ -+ U16 Reserved8; /*0x18 */ -+ U16 SystemRequestFrameSize; /*0x1A */ -+ U16 ReplyDescriptorPostQueueDepth; /*0x1C */ -+ U16 ReplyFreeQueueDepth; /*0x1E */ -+ U32 SenseBufferAddressHigh; /*0x20 */ -+ U32 SystemReplyAddressHigh; /*0x24 */ -+ U64 SystemRequestFrameBaseAddress; /*0x28 */ -+ U64 ReplyDescriptorPostQueueAddress; /*0x30 */ -+ U64 ReplyFreeQueueAddress; /*0x38 */ -+ U64 TimeStamp; /*0x40 */ -+} MPI2_IOC_INIT_REQUEST, *PTR_MPI2_IOC_INIT_REQUEST, -+ Mpi2IOCInitRequest_t, *pMpi2IOCInitRequest_t; -+ -+/*WhoInit values */ -+#define MPI2_WHOINIT_NOT_INITIALIZED (0x00) -+#define MPI2_WHOINIT_SYSTEM_BIOS (0x01) -+#define MPI2_WHOINIT_ROM_BIOS (0x02) -+#define MPI2_WHOINIT_PCI_PEER (0x03) -+#define MPI2_WHOINIT_HOST_DRIVER (0x04) -+#define MPI2_WHOINIT_MANUFACTURER (0x05) -+ -+/* MsgFlags */ -+#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01) -+ -+ -+/*MsgVersion */ -+#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00) -+#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8) -+#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF) -+#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0) -+ -+/*HeaderVersion */ -+#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00) -+#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8) -+#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF) -+#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0) -+ -+/*minimum depth for a Reply Descriptor Post Queue */ -+#define MPI2_RDPQ_DEPTH_MIN (16) -+ -+/* Reply Descriptor Post Queue Array Entry */ -+typedef struct _MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { -+ U64 RDPQBaseAddress; /* 0x00 */ -+ U32 Reserved1; /* 0x08 */ -+ U32 Reserved2; /* 0x0C */ -+} MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, -+*PTR_MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, -+Mpi2IOCInitRDPQArrayEntry, *pMpi2IOCInitRDPQArrayEntry; -+ -+ -+/*IOCInit Reply message */ -+typedef struct _MPI2_IOC_INIT_REPLY { -+ U8 WhoInit; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_IOC_INIT_REPLY, *PTR_MPI2_IOC_INIT_REPLY, -+ Mpi2IOCInitReply_t, *pMpi2IOCInitReply_t; -+ -+/**************************************************************************** -+* IOCFacts message -+****************************************************************************/ -+ -+/*IOCFacts Request message */ -+typedef struct _MPI2_IOC_FACTS_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+} MPI2_IOC_FACTS_REQUEST, *PTR_MPI2_IOC_FACTS_REQUEST, -+ Mpi2IOCFactsRequest_t, *pMpi2IOCFactsRequest_t; -+ -+/*IOCFacts Reply message */ -+typedef struct _MPI2_IOC_FACTS_REPLY { -+ U16 MsgVersion; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 HeaderVersion; /*0x04 */ -+ U8 IOCNumber; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U16 IOCExceptions; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U8 MaxChainDepth; /*0x14 */ -+ U8 WhoInit; /*0x15 */ -+ U8 NumberOfPorts; /*0x16 */ -+ U8 MaxMSIxVectors; /*0x17 */ -+ U16 RequestCredit; /*0x18 */ -+ U16 ProductID; /*0x1A */ -+ U32 IOCCapabilities; /*0x1C */ -+ MPI2_VERSION_UNION FWVersion; /*0x20 */ -+ U16 IOCRequestFrameSize; /*0x24 */ -+ U16 IOCMaxChainSegmentSize; /*0x26 */ -+ U16 MaxInitiators; /*0x28 */ -+ U16 MaxTargets; /*0x2A */ -+ U16 MaxSasExpanders; /*0x2C */ -+ U16 MaxEnclosures; /*0x2E */ -+ U16 ProtocolFlags; /*0x30 */ -+ U16 HighPriorityCredit; /*0x32 */ -+ U16 MaxReplyDescriptorPostQueueDepth; /*0x34 */ -+ U8 ReplyFrameSize; /*0x36 */ -+ U8 MaxVolumes; /*0x37 */ -+ U16 MaxDevHandle; /*0x38 */ -+ U16 MaxPersistentEntries; /*0x3A */ -+ U16 MinDevHandle; /*0x3C */ -+ U8 CurrentHostPageSize; /* 0x3E */ -+ U8 Reserved4; /* 0x3F */ -+} MPI2_IOC_FACTS_REPLY, *PTR_MPI2_IOC_FACTS_REPLY, -+ Mpi2IOCFactsReply_t, *pMpi2IOCFactsReply_t; -+ -+/*MsgVersion */ -+#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) -+#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8) -+#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) -+#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0) -+ -+/*HeaderVersion */ -+#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00) -+#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8) -+#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF) -+#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0) -+ -+/*IOCExceptions */ -+#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200) -+#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100) -+ -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0) -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000) -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020) -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040) -+#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060) -+ -+#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) -+#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008) -+#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) -+#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) -+#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) -+ -+/*defines for WhoInit field are after the IOCInit Request */ -+ -+/*ProductID field uses MPI2_FW_HEADER_PID_ */ -+ -+/*IOCCapabilities */ -+#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000) -+#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000) -+#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE (0x00020000) -+#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) -+#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) -+#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) -+#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) -+#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000) -+#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800) -+#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) -+#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) -+#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) -+#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) -+#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) -+#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) -+#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) -+ -+/*ProtocolFlags */ -+#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) -+#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) -+ -+/**************************************************************************** -+* PortFacts message -+****************************************************************************/ -+ -+/*PortFacts Request message */ -+typedef struct _MPI2_PORT_FACTS_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 PortNumber; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+} MPI2_PORT_FACTS_REQUEST, *PTR_MPI2_PORT_FACTS_REQUEST, -+ Mpi2PortFactsRequest_t, *pMpi2PortFactsRequest_t; -+ -+/*PortFacts Reply message */ -+typedef struct _MPI2_PORT_FACTS_REPLY { -+ U16 Reserved1; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 PortNumber; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U16 Reserved4; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U8 Reserved5; /*0x14 */ -+ U8 PortType; /*0x15 */ -+ U16 Reserved6; /*0x16 */ -+ U16 MaxPostedCmdBuffers; /*0x18 */ -+ U16 Reserved7; /*0x1A */ -+} MPI2_PORT_FACTS_REPLY, *PTR_MPI2_PORT_FACTS_REPLY, -+ Mpi2PortFactsReply_t, *pMpi2PortFactsReply_t; -+ -+/*PortType values */ -+#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00) -+#define MPI2_PORTFACTS_PORTTYPE_FC (0x10) -+#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20) -+#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30) -+#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31) -+ -+/**************************************************************************** -+* PortEnable message -+****************************************************************************/ -+ -+/*PortEnable Request message */ -+typedef struct _MPI2_PORT_ENABLE_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Reserved2; /*0x04 */ -+ U8 PortFlags; /*0x05 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+} MPI2_PORT_ENABLE_REQUEST, *PTR_MPI2_PORT_ENABLE_REQUEST, -+ Mpi2PortEnableRequest_t, *pMpi2PortEnableRequest_t; -+ -+/*PortEnable Reply message */ -+typedef struct _MPI2_PORT_ENABLE_REPLY { -+ U16 Reserved1; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U8 Reserved2; /*0x04 */ -+ U8 PortFlags; /*0x05 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_PORT_ENABLE_REPLY, *PTR_MPI2_PORT_ENABLE_REPLY, -+ Mpi2PortEnableReply_t, *pMpi2PortEnableReply_t; -+ -+/**************************************************************************** -+* EventNotification message -+****************************************************************************/ -+ -+/*EventNotification Request message */ -+#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4) -+ -+typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 Reserved6; /*0x10 */ -+ U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; /*0x14 */ -+ U16 SASBroadcastPrimitiveMasks; /*0x24 */ -+ U16 SASNotifyPrimitiveMasks; /*0x26 */ -+ U32 Reserved8; /*0x28 */ -+} MPI2_EVENT_NOTIFICATION_REQUEST, -+ *PTR_MPI2_EVENT_NOTIFICATION_REQUEST, -+ Mpi2EventNotificationRequest_t, -+ *pMpi2EventNotificationRequest_t; -+ -+/*EventNotification Reply message */ -+typedef struct _MPI2_EVENT_NOTIFICATION_REPLY { -+ U16 EventDataLength; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 AckRequired; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U16 Reserved3; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U16 Event; /*0x14 */ -+ U16 Reserved4; /*0x16 */ -+ U32 EventContext; /*0x18 */ -+ U32 EventData[1]; /*0x1C */ -+} MPI2_EVENT_NOTIFICATION_REPLY, *PTR_MPI2_EVENT_NOTIFICATION_REPLY, -+ Mpi2EventNotificationReply_t, -+ *pMpi2EventNotificationReply_t; -+ -+/*AckRequired */ -+#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) -+#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) -+ -+/*Event */ -+#define MPI2_EVENT_LOG_DATA (0x0001) -+#define MPI2_EVENT_STATE_CHANGE (0x0002) -+#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) -+#define MPI2_EVENT_EVENT_CHANGE (0x000A) -+#define MPI2_EVENT_TASK_SET_FULL (0x000E) /*obsolete */ -+#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) -+#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) -+#define MPI2_EVENT_SAS_DISCOVERY (0x0016) -+#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017) -+#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018) -+#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019) -+#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C) -+#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D) -+#define MPI2_EVENT_IR_VOLUME (0x001E) -+#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) -+#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) -+#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) -+#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) -+#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) -+#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) -+#define MPI2_EVENT_SAS_QUIESCE (0x0025) -+#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026) -+#define MPI2_EVENT_TEMP_THRESHOLD (0x0027) -+#define MPI2_EVENT_HOST_MESSAGE (0x0028) -+#define MPI2_EVENT_POWER_PERFORMANCE_CHANGE (0x0029) -+#define MPI2_EVENT_ACTIVE_CABLE_EXCEPTION (0x0034) -+#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E) -+#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F) -+ -+/*Log Entry Added Event data */ -+ -+/*the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */ -+#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C) -+ -+typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED { -+ U64 TimeStamp; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U16 LogSequence; /*0x0C */ -+ U16 LogEntryQualifier; /*0x0E */ -+ U8 VP_ID; /*0x10 */ -+ U8 VF_ID; /*0x11 */ -+ U16 Reserved2; /*0x12 */ -+ U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH]; /*0x14 */ -+} MPI2_EVENT_DATA_LOG_ENTRY_ADDED, -+ *PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, -+ Mpi2EventDataLogEntryAdded_t, -+ *pMpi2EventDataLogEntryAdded_t; -+ -+/*GPIO Interrupt Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT { -+ U8 GPIONum; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+} MPI2_EVENT_DATA_GPIO_INTERRUPT, -+ *PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, -+ Mpi2EventDataGpioInterrupt_t, -+ *pMpi2EventDataGpioInterrupt_t; -+ -+/*Temperature Threshold Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_TEMPERATURE { -+ U16 Status; /*0x00 */ -+ U8 SensorNum; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+ U16 CurrentTemperature; /*0x04 */ -+ U16 Reserved2; /*0x06 */ -+ U32 Reserved3; /*0x08 */ -+ U32 Reserved4; /*0x0C */ -+} MPI2_EVENT_DATA_TEMPERATURE, -+ *PTR_MPI2_EVENT_DATA_TEMPERATURE, -+ Mpi2EventDataTemperature_t, *pMpi2EventDataTemperature_t; -+ -+/*Temperature Threshold Event data Status bits */ -+#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008) -+#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004) -+#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002) -+#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001) -+ -+/*Host Message Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE { -+ U8 SourceVF_ID; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 Reserved3; /*0x04 */ -+ U32 HostData[1]; /*0x08 */ -+} MPI2_EVENT_DATA_HOST_MESSAGE, *PTR_MPI2_EVENT_DATA_HOST_MESSAGE, -+ Mpi2EventDataHostMessage_t, *pMpi2EventDataHostMessage_t; -+ -+/*Power Performance Change Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_POWER_PERF_CHANGE { -+ U8 CurrentPowerMode; /*0x00 */ -+ U8 PreviousPowerMode; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+} MPI2_EVENT_DATA_POWER_PERF_CHANGE, -+ *PTR_MPI2_EVENT_DATA_POWER_PERF_CHANGE, -+ Mpi2EventDataPowerPerfChange_t, -+ *pMpi2EventDataPowerPerfChange_t; -+ -+/*defines for CurrentPowerMode and PreviousPowerMode fields */ -+#define MPI2_EVENT_PM_INIT_MASK (0xC0) -+#define MPI2_EVENT_PM_INIT_UNAVAILABLE (0x00) -+#define MPI2_EVENT_PM_INIT_HOST (0x40) -+#define MPI2_EVENT_PM_INIT_IO_UNIT (0x80) -+#define MPI2_EVENT_PM_INIT_PCIE_DPA (0xC0) -+ -+#define MPI2_EVENT_PM_MODE_MASK (0x07) -+#define MPI2_EVENT_PM_MODE_UNAVAILABLE (0x00) -+#define MPI2_EVENT_PM_MODE_UNKNOWN (0x01) -+#define MPI2_EVENT_PM_MODE_FULL_POWER (0x04) -+#define MPI2_EVENT_PM_MODE_REDUCED_POWER (0x05) -+#define MPI2_EVENT_PM_MODE_STANDBY (0x06) -+ -+/* Active Cable Exception Event data */ -+ -+typedef struct _MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT { -+ U32 ActiveCablePowerRequirement; /* 0x00 */ -+ U8 ReasonCode; /* 0x04 */ -+ U8 ReceptacleID; /* 0x05 */ -+ U16 Reserved1; /* 0x06 */ -+} MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT, -+ *PTR_MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT, -+ Mpi26EventDataActiveCableExcept_t, -+ *pMpi26EventDataActiveCableExcept_t; -+ -+/* defines for ReasonCode field */ -+#define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00) -+ -+/*Hard Reset Received Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED { -+ U8 Reserved1; /*0x00 */ -+ U8 Port; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+} MPI2_EVENT_DATA_HARD_RESET_RECEIVED, -+ *PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED, -+ Mpi2EventDataHardResetReceived_t, -+ *pMpi2EventDataHardResetReceived_t; -+ -+/*Task Set Full Event data */ -+/* this event is obsolete */ -+ -+typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL { -+ U16 DevHandle; /*0x00 */ -+ U16 CurrentDepth; /*0x02 */ -+} MPI2_EVENT_DATA_TASK_SET_FULL, *PTR_MPI2_EVENT_DATA_TASK_SET_FULL, -+ Mpi2EventDataTaskSetFull_t, *pMpi2EventDataTaskSetFull_t; -+ -+/*SAS Device Status Change Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE { -+ U16 TaskTag; /*0x00 */ -+ U8 ReasonCode; /*0x02 */ -+ U8 PhysicalPort; /*0x03 */ -+ U8 ASC; /*0x04 */ -+ U8 ASCQ; /*0x05 */ -+ U16 DevHandle; /*0x06 */ -+ U32 Reserved2; /*0x08 */ -+ U64 SASAddress; /*0x0C */ -+ U8 LUN[8]; /*0x14 */ -+} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, -+ *PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, -+ Mpi2EventDataSasDeviceStatusChange_t, -+ *pMpi2EventDataSasDeviceStatusChange_t; -+ -+/*SAS Device Status Change Event data ReasonCode values */ -+#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11) -+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12) -+ -+/*Integrated RAID Operation Status Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS { -+ U16 VolDevHandle; /*0x00 */ -+ U16 Reserved1; /*0x02 */ -+ U8 RAIDOperation; /*0x04 */ -+ U8 PercentComplete; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U32 ElapsedSeconds; /*0x08 */ -+} MPI2_EVENT_DATA_IR_OPERATION_STATUS, -+ *PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS, -+ Mpi2EventDataIrOperationStatus_t, -+ *pMpi2EventDataIrOperationStatus_t; -+ -+/*Integrated RAID Operation Status Event data RAIDOperation values */ -+#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00) -+#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01) -+#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02) -+#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03) -+#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04) -+ -+/*Integrated RAID Volume Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_IR_VOLUME { -+ U16 VolDevHandle; /*0x00 */ -+ U8 ReasonCode; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+ U32 NewValue; /*0x04 */ -+ U32 PreviousValue; /*0x08 */ -+} MPI2_EVENT_DATA_IR_VOLUME, *PTR_MPI2_EVENT_DATA_IR_VOLUME, -+ Mpi2EventDataIrVolume_t, *pMpi2EventDataIrVolume_t; -+ -+/*Integrated RAID Volume Event data ReasonCode values */ -+#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01) -+#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02) -+#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03) -+ -+/*Integrated RAID Physical Disk Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK { -+ U16 Reserved1; /*0x00 */ -+ U8 ReasonCode; /*0x02 */ -+ U8 PhysDiskNum; /*0x03 */ -+ U16 PhysDiskDevHandle; /*0x04 */ -+ U16 Reserved2; /*0x06 */ -+ U16 Slot; /*0x08 */ -+ U16 EnclosureHandle; /*0x0A */ -+ U32 NewValue; /*0x0C */ -+ U32 PreviousValue; /*0x10 */ -+} MPI2_EVENT_DATA_IR_PHYSICAL_DISK, -+ *PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK, -+ Mpi2EventDataIrPhysicalDisk_t, -+ *pMpi2EventDataIrPhysicalDisk_t; -+ -+/*Integrated RAID Physical Disk Event data ReasonCode values */ -+#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01) -+#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02) -+#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03) -+ -+/*Integrated RAID Configuration Change List Event data */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check NumElements at runtime. -+ */ -+#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT -+#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) -+#endif -+ -+typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT { -+ U16 ElementFlags; /*0x00 */ -+ U16 VolDevHandle; /*0x02 */ -+ U8 ReasonCode; /*0x04 */ -+ U8 PhysDiskNum; /*0x05 */ -+ U16 PhysDiskDevHandle; /*0x06 */ -+} MPI2_EVENT_IR_CONFIG_ELEMENT, *PTR_MPI2_EVENT_IR_CONFIG_ELEMENT, -+ Mpi2EventIrConfigElement_t, *pMpi2EventIrConfigElement_t; -+ -+/*IR Configuration Change List Event data ElementFlags values */ -+#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F) -+#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000) -+#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001) -+#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002) -+ -+/*IR Configuration Change List Event data ReasonCode values */ -+#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01) -+#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02) -+#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03) -+#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04) -+#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05) -+#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06) -+#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07) -+#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08) -+#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09) -+ -+typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST { -+ U8 NumElements; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 Reserved2; /*0x02 */ -+ U8 ConfigNum; /*0x03 */ -+ U32 Flags; /*0x04 */ -+ MPI2_EVENT_IR_CONFIG_ELEMENT -+ ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT];/*0x08 */ -+} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, -+ *PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, -+ Mpi2EventDataIrConfigChangeList_t, -+ *pMpi2EventDataIrConfigChangeList_t; -+ -+/*IR Configuration Change List Event data Flags values */ -+#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001) -+ -+/*SAS Discovery Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY { -+ U8 Flags; /*0x00 */ -+ U8 ReasonCode; /*0x01 */ -+ U8 PhysicalPort; /*0x02 */ -+ U8 Reserved1; /*0x03 */ -+ U32 DiscoveryStatus; /*0x04 */ -+} MPI2_EVENT_DATA_SAS_DISCOVERY, -+ *PTR_MPI2_EVENT_DATA_SAS_DISCOVERY, -+ Mpi2EventDataSasDiscovery_t, *pMpi2EventDataSasDiscovery_t; -+ -+/*SAS Discovery Event data Flags values */ -+#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02) -+#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01) -+ -+/*SAS Discovery Event data ReasonCode values */ -+#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01) -+#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02) -+ -+/*SAS Discovery Event data DiscoveryStatus values */ -+#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -+#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000) -+#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000) -+#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -+#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000) -+#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -+#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -+#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000) -+#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -+#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800) -+#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400) -+#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200) -+#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100) -+#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080) -+#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040) -+#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020) -+#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010) -+#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004) -+#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002) -+#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001) -+ -+/*SAS Broadcast Primitive Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE { -+ U8 PhyNum; /*0x00 */ -+ U8 Port; /*0x01 */ -+ U8 PortWidth; /*0x02 */ -+ U8 Primitive; /*0x03 */ -+} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, -+ *PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, -+ Mpi2EventDataSasBroadcastPrimitive_t, -+ *pMpi2EventDataSasBroadcastPrimitive_t; -+ -+/*defines for the Primitive field */ -+#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01) -+#define MPI2_EVENT_PRIMITIVE_SES (0x02) -+#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03) -+#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) -+#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05) -+#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06) -+#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) -+#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) -+ -+/*SAS Notify Primitive Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE { -+ U8 PhyNum; /*0x00 */ -+ U8 Port; /*0x01 */ -+ U8 Reserved1; /*0x02 */ -+ U8 Primitive; /*0x03 */ -+} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -+ *PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -+ Mpi2EventDataSasNotifyPrimitive_t, -+ *pMpi2EventDataSasNotifyPrimitive_t; -+ -+/*defines for the Primitive field */ -+#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01) -+#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02) -+#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03) -+#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04) -+ -+/*SAS Initiator Device Status Change Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE { -+ U8 ReasonCode; /*0x00 */ -+ U8 PhysicalPort; /*0x01 */ -+ U16 DevHandle; /*0x02 */ -+ U64 SASAddress; /*0x04 */ -+} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, -+ *PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, -+ Mpi2EventDataSasInitDevStatusChange_t, -+ *pMpi2EventDataSasInitDevStatusChange_t; -+ -+/*SAS Initiator Device Status Change event ReasonCode values */ -+#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01) -+#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02) -+ -+/*SAS Initiator Device Table Overflow Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW { -+ U16 MaxInit; /*0x00 */ -+ U16 CurrentInit; /*0x02 */ -+ U64 SASAddress; /*0x04 */ -+} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, -+ *PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, -+ Mpi2EventDataSasInitTableOverflow_t, -+ *pMpi2EventDataSasInitTableOverflow_t; -+ -+/*SAS Topology Change List Event data */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check NumEntries at runtime. -+ */ -+#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT -+#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) -+#endif -+ -+typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY { -+ U16 AttachedDevHandle; /*0x00 */ -+ U8 LinkRate; /*0x02 */ -+ U8 PhyStatus; /*0x03 */ -+} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, *PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY, -+ Mpi2EventSasTopoPhyEntry_t, *pMpi2EventSasTopoPhyEntry_t; -+ -+typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST { -+ U16 EnclosureHandle; /*0x00 */ -+ U16 ExpanderDevHandle; /*0x02 */ -+ U8 NumPhys; /*0x04 */ -+ U8 Reserved1; /*0x05 */ -+ U16 Reserved2; /*0x06 */ -+ U8 NumEntries; /*0x08 */ -+ U8 StartPhyNum; /*0x09 */ -+ U8 ExpStatus; /*0x0A */ -+ U8 PhysicalPort; /*0x0B */ -+ MPI2_EVENT_SAS_TOPO_PHY_ENTRY -+ PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /*0x0C */ -+} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, -+ *PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, -+ Mpi2EventDataSasTopologyChangeList_t, -+ *pMpi2EventDataSasTopologyChangeList_t; -+ -+/*values for the ExpStatus field */ -+#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) -+#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) -+#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) -+#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) -+#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) -+ -+/*defines for the LinkRate field */ -+#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0) -+#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4) -+#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F) -+#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0) -+ -+#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00) -+#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01) -+#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02) -+#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) -+#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) -+#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) -+#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06) -+#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) -+#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) -+#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) -+#define MPI25_EVENT_SAS_TOPO_LR_RATE_12_0 (0x0B) -+ -+/*values for the PhyStatus field */ -+#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80) -+#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10) -+/*values for the PhyStatus ReasonCode sub-field */ -+#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F) -+#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01) -+#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02) -+#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03) -+#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04) -+#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05) -+ -+/*SAS Enclosure Device Status Change Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE { -+ U16 EnclosureHandle; /*0x00 */ -+ U8 ReasonCode; /*0x02 */ -+ U8 PhysicalPort; /*0x03 */ -+ U64 EnclosureLogicalID; /*0x04 */ -+ U16 NumSlots; /*0x0C */ -+ U16 StartSlot; /*0x0E */ -+ U32 PhyBits; /*0x10 */ -+} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, -+ *PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, -+ Mpi2EventDataSasEnclDevStatusChange_t, -+ *pMpi2EventDataSasEnclDevStatusChange_t; -+ -+/*SAS Enclosure Device Status Change event ReasonCode values */ -+#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01) -+#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02) -+ -+/*SAS PHY Counter Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { -+ U64 TimeStamp; /*0x00 */ -+ U32 Reserved1; /*0x08 */ -+ U8 PhyEventCode; /*0x0C */ -+ U8 PhyNum; /*0x0D */ -+ U16 Reserved2; /*0x0E */ -+ U32 PhyEventInfo; /*0x10 */ -+ U8 CounterType; /*0x14 */ -+ U8 ThresholdWindow; /*0x15 */ -+ U8 TimeUnits; /*0x16 */ -+ U8 Reserved3; /*0x17 */ -+ U32 EventThreshold; /*0x18 */ -+ U16 ThresholdFlags; /*0x1C */ -+ U16 Reserved4; /*0x1E */ -+} MPI2_EVENT_DATA_SAS_PHY_COUNTER, -+ *PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, -+ Mpi2EventDataSasPhyCounter_t, -+ *pMpi2EventDataSasPhyCounter_t; -+ -+/*use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h -+ *for the PhyEventCode field */ -+ -+/*use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h -+ *for the CounterType field */ -+ -+/*use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h -+ *for the TimeUnits field */ -+ -+/*use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h -+ *for the ThresholdFlags field */ -+ -+/*SAS Quiesce Event data */ -+ -+typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE { -+ U8 ReasonCode; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 Reserved3; /*0x04 */ -+} MPI2_EVENT_DATA_SAS_QUIESCE, -+ *PTR_MPI2_EVENT_DATA_SAS_QUIESCE, -+ Mpi2EventDataSasQuiesce_t, *pMpi2EventDataSasQuiesce_t; -+ -+/*SAS Quiesce Event data ReasonCode values */ -+#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) -+#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) -+ -+/*Host Based Discovery Phy Event data */ -+ -+typedef struct _MPI2_EVENT_HBD_PHY_SAS { -+ U8 Flags; /*0x00 */ -+ U8 NegotiatedLinkRate; /*0x01 */ -+ U8 PhyNum; /*0x02 */ -+ U8 PhysicalPort; /*0x03 */ -+ U32 Reserved1; /*0x04 */ -+ U8 InitialFrame[28]; /*0x08 */ -+} MPI2_EVENT_HBD_PHY_SAS, *PTR_MPI2_EVENT_HBD_PHY_SAS, -+ Mpi2EventHbdPhySas_t, *pMpi2EventHbdPhySas_t; -+ -+/*values for the Flags field */ -+#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) -+#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) -+ -+/*use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h -+ *for the NegotiatedLinkRate field */ -+ -+typedef union _MPI2_EVENT_HBD_DESCRIPTOR { -+ MPI2_EVENT_HBD_PHY_SAS Sas; -+} MPI2_EVENT_HBD_DESCRIPTOR, *PTR_MPI2_EVENT_HBD_DESCRIPTOR, -+ Mpi2EventHbdDescriptor_t, *pMpi2EventHbdDescriptor_t; -+ -+typedef struct _MPI2_EVENT_DATA_HBD_PHY { -+ U8 DescriptorType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 Reserved3; /*0x04 */ -+ MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /*0x08 */ -+} MPI2_EVENT_DATA_HBD_PHY, *PTR_MPI2_EVENT_DATA_HBD_PHY, -+ Mpi2EventDataHbdPhy_t, -+ *pMpi2EventDataMpi2EventDataHbdPhy_t; -+ -+/*values for the DescriptorType field */ -+#define MPI2_EVENT_HBD_DT_SAS (0x01) -+ -+/**************************************************************************** -+* EventAck message -+****************************************************************************/ -+ -+/*EventAck Request message */ -+typedef struct _MPI2_EVENT_ACK_REQUEST { -+ U16 Reserved1; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Event; /*0x0C */ -+ U16 Reserved5; /*0x0E */ -+ U32 EventContext; /*0x10 */ -+} MPI2_EVENT_ACK_REQUEST, *PTR_MPI2_EVENT_ACK_REQUEST, -+ Mpi2EventAckRequest_t, *pMpi2EventAckRequest_t; -+ -+/*EventAck Reply message */ -+typedef struct _MPI2_EVENT_ACK_REPLY { -+ U16 Reserved1; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_EVENT_ACK_REPLY, *PTR_MPI2_EVENT_ACK_REPLY, -+ Mpi2EventAckReply_t, *pMpi2EventAckReply_t; -+ -+/**************************************************************************** -+* SendHostMessage message -+****************************************************************************/ -+ -+/*SendHostMessage Request message */ -+typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST { -+ U16 HostDataLength; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U8 Reserved4; /*0x0C */ -+ U8 DestVF_ID; /*0x0D */ -+ U16 Reserved5; /*0x0E */ -+ U32 Reserved6; /*0x10 */ -+ U32 Reserved7; /*0x14 */ -+ U32 Reserved8; /*0x18 */ -+ U32 Reserved9; /*0x1C */ -+ U32 Reserved10; /*0x20 */ -+ U32 HostData[1]; /*0x24 */ -+} MPI2_SEND_HOST_MESSAGE_REQUEST, -+ *PTR_MPI2_SEND_HOST_MESSAGE_REQUEST, -+ Mpi2SendHostMessageRequest_t, -+ *pMpi2SendHostMessageRequest_t; -+ -+/*SendHostMessage Reply message */ -+typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY { -+ U16 HostDataLength; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved1; /*0x04 */ -+ U8 Reserved2; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U16 Reserved4; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_SEND_HOST_MESSAGE_REPLY, *PTR_MPI2_SEND_HOST_MESSAGE_REPLY, -+ Mpi2SendHostMessageReply_t, *pMpi2SendHostMessageReply_t; -+ -+/**************************************************************************** -+* FWDownload message -+****************************************************************************/ -+ -+/*MPI v2.0 FWDownload Request message */ -+typedef struct _MPI2_FW_DOWNLOAD_REQUEST { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 TotalImageSize; /*0x0C */ -+ U32 Reserved5; /*0x10 */ -+ MPI2_MPI_SGE_UNION SGL; /*0x14 */ -+} MPI2_FW_DOWNLOAD_REQUEST, *PTR_MPI2_FW_DOWNLOAD_REQUEST, -+ Mpi2FWDownloadRequest, *pMpi2FWDownloadRequest; -+ -+#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01) -+ -+#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01) -+#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02) -+#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) -+#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) -+#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) -+#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) -+#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) -+#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -+#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C) -+#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) -+ -+/*MPI v2.0 FWDownload TransactionContext Element */ -+typedef struct _MPI2_FW_DOWNLOAD_TCSGE { -+ U8 Reserved1; /*0x00 */ -+ U8 ContextSize; /*0x01 */ -+ U8 DetailsLength; /*0x02 */ -+ U8 Flags; /*0x03 */ -+ U32 Reserved2; /*0x04 */ -+ U32 ImageOffset; /*0x08 */ -+ U32 ImageSize; /*0x0C */ -+} MPI2_FW_DOWNLOAD_TCSGE, *PTR_MPI2_FW_DOWNLOAD_TCSGE, -+ Mpi2FWDownloadTCSGE_t, *pMpi2FWDownloadTCSGE_t; -+ -+/*MPI v2.5 FWDownload Request message */ -+typedef struct _MPI25_FW_DOWNLOAD_REQUEST { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 TotalImageSize; /*0x0C */ -+ U32 Reserved5; /*0x10 */ -+ U32 Reserved6; /*0x14 */ -+ U32 ImageOffset; /*0x18 */ -+ U32 ImageSize; /*0x1C */ -+ MPI25_SGE_IO_UNION SGL; /*0x20 */ -+} MPI25_FW_DOWNLOAD_REQUEST, *PTR_MPI25_FW_DOWNLOAD_REQUEST, -+ Mpi25FWDownloadRequest, *pMpi25FWDownloadRequest; -+ -+/*FWDownload Reply message */ -+typedef struct _MPI2_FW_DOWNLOAD_REPLY { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_FW_DOWNLOAD_REPLY, *PTR_MPI2_FW_DOWNLOAD_REPLY, -+ Mpi2FWDownloadReply_t, *pMpi2FWDownloadReply_t; -+ -+/**************************************************************************** -+* FWUpload message -+****************************************************************************/ -+ -+/*MPI v2.0 FWUpload Request message */ -+typedef struct _MPI2_FW_UPLOAD_REQUEST { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 Reserved6; /*0x10 */ -+ MPI2_MPI_SGE_UNION SGL; /*0x14 */ -+} MPI2_FW_UPLOAD_REQUEST, *PTR_MPI2_FW_UPLOAD_REQUEST, -+ Mpi2FWUploadRequest_t, *pMpi2FWUploadRequest_t; -+ -+#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00) -+#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01) -+#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) -+#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) -+#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) -+#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) -+#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) -+#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09) -+#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A) -+#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -+#define MPI2_FW_UPLOAD_ITYPE_CBB_BACKUP (0x0D) -+ -+/*MPI v2.0 FWUpload TransactionContext Element */ -+typedef struct _MPI2_FW_UPLOAD_TCSGE { -+ U8 Reserved1; /*0x00 */ -+ U8 ContextSize; /*0x01 */ -+ U8 DetailsLength; /*0x02 */ -+ U8 Flags; /*0x03 */ -+ U32 Reserved2; /*0x04 */ -+ U32 ImageOffset; /*0x08 */ -+ U32 ImageSize; /*0x0C */ -+} MPI2_FW_UPLOAD_TCSGE, *PTR_MPI2_FW_UPLOAD_TCSGE, -+ Mpi2FWUploadTCSGE_t, *pMpi2FWUploadTCSGE_t; -+ -+/*MPI v2.5 FWUpload Request message */ -+typedef struct _MPI25_FW_UPLOAD_REQUEST { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 Reserved6; /*0x10 */ -+ U32 Reserved7; /*0x14 */ -+ U32 ImageOffset; /*0x18 */ -+ U32 ImageSize; /*0x1C */ -+ MPI25_SGE_IO_UNION SGL; /*0x20 */ -+} MPI25_FW_UPLOAD_REQUEST, *PTR_MPI25_FW_UPLOAD_REQUEST, -+ Mpi25FWUploadRequest_t, *pMpi25FWUploadRequest_t; -+ -+/*FWUpload Reply message */ -+typedef struct _MPI2_FW_UPLOAD_REPLY { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 ActualImageSize; /*0x14 */ -+} MPI2_FW_UPLOAD_REPLY, *PTR_MPI2_FW_UPLOAD_REPLY, -+ Mpi2FWUploadReply_t, *pMPi2FWUploadReply_t; -+ -+/*FW Image Header */ -+typedef struct _MPI2_FW_IMAGE_HEADER { -+ U32 Signature; /*0x00 */ -+ U32 Signature0; /*0x04 */ -+ U32 Signature1; /*0x08 */ -+ U32 Signature2; /*0x0C */ -+ MPI2_VERSION_UNION MPIVersion; /*0x10 */ -+ MPI2_VERSION_UNION FWVersion; /*0x14 */ -+ MPI2_VERSION_UNION NVDATAVersion; /*0x18 */ -+ MPI2_VERSION_UNION PackageVersion; /*0x1C */ -+ U16 VendorID; /*0x20 */ -+ U16 ProductID; /*0x22 */ -+ U16 ProtocolFlags; /*0x24 */ -+ U16 Reserved26; /*0x26 */ -+ U32 IOCCapabilities; /*0x28 */ -+ U32 ImageSize; /*0x2C */ -+ U32 NextImageHeaderOffset; /*0x30 */ -+ U32 Checksum; /*0x34 */ -+ U32 Reserved38; /*0x38 */ -+ U32 Reserved3C; /*0x3C */ -+ U32 Reserved40; /*0x40 */ -+ U32 Reserved44; /*0x44 */ -+ U32 Reserved48; /*0x48 */ -+ U32 Reserved4C; /*0x4C */ -+ U32 Reserved50; /*0x50 */ -+ U32 Reserved54; /*0x54 */ -+ U32 Reserved58; /*0x58 */ -+ U32 Reserved5C; /*0x5C */ -+ U32 BootFlags; /*0x60 */ -+ U32 FirmwareVersionNameWhat; /*0x64 */ -+ U8 FirmwareVersionName[32]; /*0x68 */ -+ U32 VendorNameWhat; /*0x88 */ -+ U8 VendorName[32]; /*0x8C */ -+ U32 PackageNameWhat; /*0x88 */ -+ U8 PackageName[32]; /*0x8C */ -+ U32 ReservedD0; /*0xD0 */ -+ U32 ReservedD4; /*0xD4 */ -+ U32 ReservedD8; /*0xD8 */ -+ U32 ReservedDC; /*0xDC */ -+ U32 ReservedE0; /*0xE0 */ -+ U32 ReservedE4; /*0xE4 */ -+ U32 ReservedE8; /*0xE8 */ -+ U32 ReservedEC; /*0xEC */ -+ U32 ReservedF0; /*0xF0 */ -+ U32 ReservedF4; /*0xF4 */ -+ U32 ReservedF8; /*0xF8 */ -+ U32 ReservedFC; /*0xFC */ -+} MPI2_FW_IMAGE_HEADER, *PTR_MPI2_FW_IMAGE_HEADER, -+ Mpi2FWImageHeader_t, *pMpi2FWImageHeader_t; -+ -+/*Signature field */ -+#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00) -+#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000) -+#define MPI2_FW_HEADER_SIGNATURE (0xEA000000) -+#define MPI26_FW_HEADER_SIGNATURE (0xEB000000) -+ -+/*Signature0 field */ -+#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04) -+#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A) -+/* Last byte is defined by architecture */ -+#define MPI26_FW_HEADER_SIGNATURE0_BASE (0x5AEAA500) -+#define MPI26_FW_HEADER_SIGNATURE0_ARC_0 (0x5A) -+#define MPI26_FW_HEADER_SIGNATURE0_ARC_1 (0x00) -+#define MPI26_FW_HEADER_SIGNATURE0_ARC_2 (0x01) -+/* legacy (0x5AEAA55A) */ -+#define MPI26_FW_HEADER_SIGNATURE0 \ -+ (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_0) -+#define MPI26_FW_HEADER_SIGNATURE0_3516 \ -+ (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_1) -+ -+/*Signature1 field */ -+#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08) -+#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5) -+#define MPI26_FW_HEADER_SIGNATURE1 (0xA55AEAA5) -+ -+/*Signature2 field */ -+#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C) -+#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA) -+#define MPI26_FW_HEADER_SIGNATURE2 (0x5AA55AEA) -+ -+/*defines for using the ProductID field */ -+#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) -+#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) -+ -+#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) -+#define MPI2_FW_HEADER_PID_PROD_A (0x0000) -+#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) -+#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) -+ -+#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) -+/*SAS ProductID Family bits */ -+#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) -+#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) -+#define MPI25_FW_HEADER_PID_FAMILY_3108_SAS (0x0021) -+#define MPI26_FW_HEADER_PID_FAMILY_3324_SAS (0x0028) -+#define MPI26_FW_HEADER_PID_FAMILY_3516_SAS (0x0031) -+ -+/*use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ -+ -+/*use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */ -+ -+#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C) -+#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30) -+#define MPI26_FW_HEADER_BOOTFLAGS_OFFSET (0x60) -+#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64) -+ -+#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840) -+ -+#define MPI2_FW_HEADER_SIZE (0x100) -+ -+/*Extended Image Header */ -+typedef struct _MPI2_EXT_IMAGE_HEADER { -+ U8 ImageType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 Checksum; /*0x04 */ -+ U32 ImageSize; /*0x08 */ -+ U32 NextImageHeaderOffset; /*0x0C */ -+ U32 PackageVersion; /*0x10 */ -+ U32 Reserved3; /*0x14 */ -+ U32 Reserved4; /*0x18 */ -+ U32 Reserved5; /*0x1C */ -+ U8 IdentifyString[32]; /*0x20 */ -+} MPI2_EXT_IMAGE_HEADER, *PTR_MPI2_EXT_IMAGE_HEADER, -+ Mpi2ExtImageHeader_t, *pMpi2ExtImageHeader_t; -+ -+/*useful offsets */ -+#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00) -+#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08) -+#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C) -+ -+#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40) -+ -+/*defines for the ImageType field */ -+#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) -+#define MPI2_EXT_IMAGE_TYPE_FW (0x01) -+#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) -+#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) -+#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) -+#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) -+#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) -+#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) -+#define MPI2_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09) -+#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) -+#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) -+ -+#define MPI2_EXT_IMAGE_TYPE_MAX (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) -+ -+/*FLASH Layout Extended Image Data */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check RegionsPerLayout at runtime. -+ */ -+#ifndef MPI2_FLASH_NUMBER_OF_REGIONS -+#define MPI2_FLASH_NUMBER_OF_REGIONS (1) -+#endif -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check NumberOfLayouts at runtime. -+ */ -+#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS -+#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) -+#endif -+ -+typedef struct _MPI2_FLASH_REGION { -+ U8 RegionType; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 RegionOffset; /*0x04 */ -+ U32 RegionSize; /*0x08 */ -+ U32 Reserved3; /*0x0C */ -+} MPI2_FLASH_REGION, *PTR_MPI2_FLASH_REGION, -+ Mpi2FlashRegion_t, *pMpi2FlashRegion_t; -+ -+typedef struct _MPI2_FLASH_LAYOUT { -+ U32 FlashSize; /*0x00 */ -+ U32 Reserved1; /*0x04 */ -+ U32 Reserved2; /*0x08 */ -+ U32 Reserved3; /*0x0C */ -+ MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS]; /*0x10 */ -+} MPI2_FLASH_LAYOUT, *PTR_MPI2_FLASH_LAYOUT, -+ Mpi2FlashLayout_t, *pMpi2FlashLayout_t; -+ -+typedef struct _MPI2_FLASH_LAYOUT_DATA { -+ U8 ImageRevision; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 SizeOfRegion; /*0x02 */ -+ U8 Reserved2; /*0x03 */ -+ U16 NumberOfLayouts; /*0x04 */ -+ U16 RegionsPerLayout; /*0x06 */ -+ U16 MinimumSectorAlignment; /*0x08 */ -+ U16 Reserved3; /*0x0A */ -+ U32 Reserved4; /*0x0C */ -+ MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS]; /*0x10 */ -+} MPI2_FLASH_LAYOUT_DATA, *PTR_MPI2_FLASH_LAYOUT_DATA, -+ Mpi2FlashLayoutData_t, *pMpi2FlashLayoutData_t; -+ -+/*defines for the RegionType field */ -+#define MPI2_FLASH_REGION_UNUSED (0x00) -+#define MPI2_FLASH_REGION_FIRMWARE (0x01) -+#define MPI2_FLASH_REGION_BIOS (0x02) -+#define MPI2_FLASH_REGION_NVDATA (0x03) -+#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05) -+#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06) -+#define MPI2_FLASH_REGION_CONFIG_1 (0x07) -+#define MPI2_FLASH_REGION_CONFIG_2 (0x08) -+#define MPI2_FLASH_REGION_MEGARAID (0x09) -+#define MPI2_FLASH_REGION_COMMON_BOOT_BLOCK (0x0A) -+#define MPI2_FLASH_REGION_INIT (MPI2_FLASH_REGION_COMMON_BOOT_BLOCK) -+#define MPI2_FLASH_REGION_CBB_BACKUP (0x0D) -+ -+/*ImageRevision */ -+#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00) -+ -+/*Supported Devices Extended Image Data */ -+ -+/* -+ *Host code (drivers, BIOS, utilities, etc.) should leave this define set to -+ *one and check NumberOfDevices at runtime. -+ */ -+#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES -+#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) -+#endif -+ -+typedef struct _MPI2_SUPPORTED_DEVICE { -+ U16 DeviceID; /*0x00 */ -+ U16 VendorID; /*0x02 */ -+ U16 DeviceIDMask; /*0x04 */ -+ U16 Reserved1; /*0x06 */ -+ U8 LowPCIRev; /*0x08 */ -+ U8 HighPCIRev; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U32 Reserved3; /*0x0C */ -+} MPI2_SUPPORTED_DEVICE, *PTR_MPI2_SUPPORTED_DEVICE, -+ Mpi2SupportedDevice_t, *pMpi2SupportedDevice_t; -+ -+typedef struct _MPI2_SUPPORTED_DEVICES_DATA { -+ U8 ImageRevision; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 NumberOfDevices; /*0x02 */ -+ U8 Reserved2; /*0x03 */ -+ U32 Reserved3; /*0x04 */ -+ MPI2_SUPPORTED_DEVICE -+ SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES];/*0x08 */ -+} MPI2_SUPPORTED_DEVICES_DATA, *PTR_MPI2_SUPPORTED_DEVICES_DATA, -+ Mpi2SupportedDevicesData_t, *pMpi2SupportedDevicesData_t; -+ -+/*ImageRevision */ -+#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00) -+ -+/*Init Extended Image Data */ -+ -+typedef struct _MPI2_INIT_IMAGE_FOOTER { -+ U32 BootFlags; /*0x00 */ -+ U32 ImageSize; /*0x04 */ -+ U32 Signature0; /*0x08 */ -+ U32 Signature1; /*0x0C */ -+ U32 Signature2; /*0x10 */ -+ U32 ResetVector; /*0x14 */ -+} MPI2_INIT_IMAGE_FOOTER, *PTR_MPI2_INIT_IMAGE_FOOTER, -+ Mpi2InitImageFooter_t, *pMpi2InitImageFooter_t; -+ -+/*defines for the BootFlags field */ -+#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00) -+ -+/*defines for the ImageSize field */ -+#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04) -+ -+/*defines for the Signature0 field */ -+#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08) -+#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA) -+ -+/*defines for the Signature1 field */ -+#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C) -+#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5) -+ -+/*defines for the Signature2 field */ -+#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10) -+#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A) -+ -+/*Signature fields as individual bytes */ -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A) -+ -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5) -+ -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA) -+#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A) -+ -+/*defines for the ResetVector field */ -+#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) -+ -+ -+/* Encrypted Hash Extended Image Data */ -+ -+typedef struct _MPI25_ENCRYPTED_HASH_ENTRY { -+ U8 HashImageType; /* 0x00 */ -+ U8 HashAlgorithm; /* 0x01 */ -+ U8 EncryptionAlgorithm; /* 0x02 */ -+ U8 Reserved1; /* 0x03 */ -+ U32 Reserved2; /* 0x04 */ -+ U32 EncryptedHash[1]; /* 0x08 */ /* variable length */ -+} MPI25_ENCRYPTED_HASH_ENTRY, *PTR_MPI25_ENCRYPTED_HASH_ENTRY, -+Mpi25EncryptedHashEntry_t, *pMpi25EncryptedHashEntry_t; -+ -+/* values for HashImageType */ -+#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00) -+#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01) -+#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02) -+ -+/* values for HashAlgorithm */ -+#define MPI25_HASH_ALGORITHM_UNUSED (0x00) -+#define MPI25_HASH_ALGORITHM_SHA256 (0x01) -+ -+/* values for EncryptionAlgorithm */ -+#define MPI25_ENCRYPTION_ALG_UNUSED (0x00) -+#define MPI25_ENCRYPTION_ALG_RSA256 (0x01) -+ -+typedef struct _MPI25_ENCRYPTED_HASH_DATA { -+ U8 ImageVersion; /* 0x00 */ -+ U8 NumHash; /* 0x01 */ -+ U16 Reserved1; /* 0x02 */ -+ U32 Reserved2; /* 0x04 */ -+ MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /* 0x08 */ -+} MPI25_ENCRYPTED_HASH_DATA, *PTR_MPI25_ENCRYPTED_HASH_DATA, -+Mpi25EncryptedHashData_t, *pMpi25EncryptedHashData_t; -+ -+ -+/**************************************************************************** -+* PowerManagementControl message -+****************************************************************************/ -+ -+/*PowerManagementControl Request message */ -+typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { -+ U8 Feature; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U8 Parameter1; /*0x0C */ -+ U8 Parameter2; /*0x0D */ -+ U8 Parameter3; /*0x0E */ -+ U8 Parameter4; /*0x0F */ -+ U32 Reserved5; /*0x10 */ -+ U32 Reserved6; /*0x14 */ -+} MPI2_PWR_MGMT_CONTROL_REQUEST, *PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, -+ Mpi2PwrMgmtControlRequest_t, *pMpi2PwrMgmtControlRequest_t; -+ -+/*defines for the Feature field */ -+#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) -+#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) -+#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /*obsolete */ -+#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) -+#define MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE (0x05) -+#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) -+#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) -+ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ -+/*Parameter1 contains a PHY number */ -+/*Parameter2 indicates power condition action using these defines */ -+#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) -+#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) -+#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) -+/*Parameter3 and Parameter4 are reserved */ -+ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION -+ * Feature */ -+/*Parameter1 contains SAS port width modulation group number */ -+/*Parameter2 indicates IOC action using these defines */ -+#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) -+#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) -+#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) -+/*Parameter3 indicates desired modulation level using these defines */ -+#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) -+#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) -+#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) -+#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) -+/*Parameter4 is reserved */ -+ -+/*this next set (_PCIE_LINK) is obsolete */ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ -+/*Parameter1 indicates desired PCIe link speed using these defines */ -+#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /*obsolete */ -+/*Parameter2 indicates desired PCIe link width using these defines */ -+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /*obsolete */ -+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /*obsolete */ -+/*Parameter3 and Parameter4 are reserved */ -+ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ -+/*Parameter1 indicates desired IOC hardware clock speed using these defines */ -+#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) -+#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) -+#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) -+#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) -+/*Parameter2, Parameter3, and Parameter4 are reserved */ -+ -+/*parameter usage for the MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE Feature*/ -+/*Parameter1 indicates host action regarding global power management mode */ -+#define MPI2_PM_CONTROL_PARAM1_TAKE_CONTROL (0x01) -+#define MPI2_PM_CONTROL_PARAM1_CHANGE_GLOBAL_MODE (0x02) -+#define MPI2_PM_CONTROL_PARAM1_RELEASE_CONTROL (0x03) -+/*Parameter2 indicates the requested global power management mode */ -+#define MPI2_PM_CONTROL_PARAM2_FULL_PWR_PERF (0x01) -+#define MPI2_PM_CONTROL_PARAM2_REDUCED_PWR_PERF (0x08) -+#define MPI2_PM_CONTROL_PARAM2_STANDBY (0x40) -+/*Parameter3 and Parameter4 are reserved */ -+ -+/*PowerManagementControl Reply message */ -+typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY { -+ U8 Feature; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_PWR_MGMT_CONTROL_REPLY, *PTR_MPI2_PWR_MGMT_CONTROL_REPLY, -+ Mpi2PwrMgmtControlReply_t, *pMpi2PwrMgmtControlReply_t; -+ -+/**************************************************************************** -+* IO Unit Control messages (MPI v2.6 and later only.) -+****************************************************************************/ -+ -+/* IO Unit Control Request Message */ -+typedef struct _MPI26_IOUNIT_CONTROL_REQUEST { -+ U8 Operation; /* 0x00 */ -+ U8 Reserved1; /* 0x01 */ -+ U8 ChainOffset; /* 0x02 */ -+ U8 Function; /* 0x03 */ -+ U16 DevHandle; /* 0x04 */ -+ U8 IOCParameter; /* 0x06 */ -+ U8 MsgFlags; /* 0x07 */ -+ U8 VP_ID; /* 0x08 */ -+ U8 VF_ID; /* 0x09 */ -+ U16 Reserved3; /* 0x0A */ -+ U16 Reserved4; /* 0x0C */ -+ U8 PhyNum; /* 0x0E */ -+ U8 PrimFlags; /* 0x0F */ -+ U32 Primitive; /* 0x10 */ -+ U8 LookupMethod; /* 0x14 */ -+ U8 Reserved5; /* 0x15 */ -+ U16 SlotNumber; /* 0x16 */ -+ U64 LookupAddress; /* 0x18 */ -+ U32 IOCParameterValue; /* 0x20 */ -+ U32 Reserved7; /* 0x24 */ -+ U32 Reserved8; /* 0x28 */ -+} MPI26_IOUNIT_CONTROL_REQUEST, -+ *PTR_MPI26_IOUNIT_CONTROL_REQUEST, -+ Mpi26IoUnitControlRequest_t, -+ *pMpi26IoUnitControlRequest_t; -+ -+/* values for the Operation field */ -+#define MPI26_CTRL_OP_CLEAR_ALL_PERSISTENT (0x02) -+#define MPI26_CTRL_OP_SAS_PHY_LINK_RESET (0x06) -+#define MPI26_CTRL_OP_SAS_PHY_HARD_RESET (0x07) -+#define MPI26_CTRL_OP_PHY_CLEAR_ERROR_LOG (0x08) -+#define MPI26_CTRL_OP_LINK_CLEAR_ERROR_LOG (0x09) -+#define MPI26_CTRL_OP_SAS_SEND_PRIMITIVE (0x0A) -+#define MPI26_CTRL_OP_FORCE_FULL_DISCOVERY (0x0B) -+#define MPI26_CTRL_OP_REMOVE_DEVICE (0x0D) -+#define MPI26_CTRL_OP_LOOKUP_MAPPING (0x0E) -+#define MPI26_CTRL_OP_SET_IOC_PARAMETER (0x0F) -+#define MPI26_CTRL_OP_ENABLE_FP_DEVICE (0x10) -+#define MPI26_CTRL_OP_DISABLE_FP_DEVICE (0x11) -+#define MPI26_CTRL_OP_ENABLE_FP_ALL (0x12) -+#define MPI26_CTRL_OP_DISABLE_FP_ALL (0x13) -+#define MPI26_CTRL_OP_DEV_ENABLE_NCQ (0x14) -+#define MPI26_CTRL_OP_DEV_DISABLE_NCQ (0x15) -+#define MPI26_CTRL_OP_SHUTDOWN (0x16) -+#define MPI26_CTRL_OP_DEV_ENABLE_PERSIST_CONNECTION (0x17) -+#define MPI26_CTRL_OP_DEV_DISABLE_PERSIST_CONNECTION (0x18) -+#define MPI26_CTRL_OP_DEV_CLOSE_PERSIST_CONNECTION (0x19) -+#define MPI26_CTRL_OP_PRODUCT_SPECIFIC_MIN (0x80) -+ -+/* values for the PrimFlags field */ -+#define MPI26_CTRL_PRIMFLAGS_SINGLE (0x08) -+#define MPI26_CTRL_PRIMFLAGS_TRIPLE (0x02) -+#define MPI26_CTRL_PRIMFLAGS_REDUNDANT (0x01) -+ -+/* values for the LookupMethod field */ -+#define MPI26_CTRL_LOOKUP_METHOD_WWID_ADDRESS (0x01) -+#define MPI26_CTRL_LOOKUP_METHOD_ENCLOSURE_SLOT (0x02) -+#define MPI26_CTRL_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) -+ -+ -+/* IO Unit Control Reply Message */ -+typedef struct _MPI26_IOUNIT_CONTROL_REPLY { -+ U8 Operation; /* 0x00 */ -+ U8 Reserved1; /* 0x01 */ -+ U8 MsgLength; /* 0x02 */ -+ U8 Function; /* 0x03 */ -+ U16 DevHandle; /* 0x04 */ -+ U8 IOCParameter; /* 0x06 */ -+ U8 MsgFlags; /* 0x07 */ -+ U8 VP_ID; /* 0x08 */ -+ U8 VF_ID; /* 0x09 */ -+ U16 Reserved3; /* 0x0A */ -+ U16 Reserved4; /* 0x0C */ -+ U16 IOCStatus; /* 0x0E */ -+ U32 IOCLogInfo; /* 0x10 */ -+} MPI26_IOUNIT_CONTROL_REPLY, -+ *PTR_MPI26_IOUNIT_CONTROL_REPLY, -+ Mpi26IoUnitControlReply_t, -+ *pMpi26IoUnitControlReply_t; -+ -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h -new file mode 100644 -index 0000000..1c0eeee ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h -@@ -0,0 +1,355 @@ -+/* -+ * Copyright 2000-2014 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_raid.h -+ * Title: MPI Integrated RAID messages and structures -+ * Creation Date: April 26, 2007 -+ * -+ * mpi2_raid.h Version: 02.00.11 -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 08-31-07 02.00.01 Modifications to RAID Action request and reply, -+ * including the Actions and ActionData. -+ * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. -+ * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that -+ * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT -+ * can be sized by the build environment. -+ * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of -+ * VolumeCreationFlags and marked the old one as obsolete. -+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. -+ * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with -+ * related structures and defines. -+ * Added product-specific range to RAID Action values. -+ * 11-18-11 02.00.07 Incorporating additions for MPI v2.5. -+ * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN. -+ * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR. -+ * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define. -+ * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI. -+ * 11-18-14 02.00.11 Updated copyright information. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_RAID_H -+#define MPI2_RAID_H -+ -+/***************************************************************************** -+* -+* Integrated RAID Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* RAID Action messages -+****************************************************************************/ -+ -+/* ActionDataWord defines for use with MPI2_RAID_ACTION_CREATE_VOLUME action */ -+#define MPI25_RAID_ACTION_ADATA_ALLOW_PI (0x80000000) -+ -+/*ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */ -+#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) -+#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001) -+ -+/*use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for -+ *MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ -+ -+/*ActionDataWord defines for use with -+ *MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */ -+#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001) -+ -+/*ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */ -+typedef struct _MPI2_RAID_ACTION_RATE_DATA { -+ U8 RateToChange; /*0x00 */ -+ U8 RateOrMode; /*0x01 */ -+ U16 DataScrubDuration; /*0x02 */ -+} MPI2_RAID_ACTION_RATE_DATA, *PTR_MPI2_RAID_ACTION_RATE_DATA, -+ Mpi2RaidActionRateData_t, *pMpi2RaidActionRateData_t; -+ -+#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00) -+#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01) -+#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02) -+ -+/*ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */ -+typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION { -+ U8 RAIDFunction; /*0x00 */ -+ U8 Flags; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+} MPI2_RAID_ACTION_START_RAID_FUNCTION, -+ *PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION, -+ Mpi2RaidActionStartRaidFunction_t, -+ *pMpi2RaidActionStartRaidFunction_t; -+ -+/*defines for the RAIDFunction field */ -+#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00) -+#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01) -+#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02) -+ -+/*defines for the Flags field */ -+#define MPI2_RAID_ACTION_START_NEW (0x00) -+#define MPI2_RAID_ACTION_START_RESUME (0x01) -+ -+/*ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */ -+typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION { -+ U8 RAIDFunction; /*0x00 */ -+ U8 Flags; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+} MPI2_RAID_ACTION_STOP_RAID_FUNCTION, -+ *PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION, -+ Mpi2RaidActionStopRaidFunction_t, -+ *pMpi2RaidActionStopRaidFunction_t; -+ -+/*defines for the RAIDFunction field */ -+#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00) -+#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01) -+#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02) -+ -+/*defines for the Flags field */ -+#define MPI2_RAID_ACTION_STOP_ABORT (0x00) -+#define MPI2_RAID_ACTION_STOP_PAUSE (0x01) -+ -+/*ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */ -+typedef struct _MPI2_RAID_ACTION_HOT_SPARE { -+ U8 HotSparePool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 DevHandle; /*0x02 */ -+} MPI2_RAID_ACTION_HOT_SPARE, *PTR_MPI2_RAID_ACTION_HOT_SPARE, -+ Mpi2RaidActionHotSpare_t, *pMpi2RaidActionHotSpare_t; -+ -+/*ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */ -+typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE { -+ U8 Flags; /*0x00 */ -+ U8 DeviceFirmwareUpdateModeTimeout; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+} MPI2_RAID_ACTION_FW_UPDATE_MODE, -+ *PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE, -+ Mpi2RaidActionFwUpdateMode_t, -+ *pMpi2RaidActionFwUpdateMode_t; -+ -+/*ActionDataWord defines for use with -+ *MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */ -+#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00) -+#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01) -+ -+typedef union _MPI2_RAID_ACTION_DATA { -+ U32 Word; -+ MPI2_RAID_ACTION_RATE_DATA Rates; -+ MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction; -+ MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction; -+ MPI2_RAID_ACTION_HOT_SPARE HotSpare; -+ MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode; -+} MPI2_RAID_ACTION_DATA, *PTR_MPI2_RAID_ACTION_DATA, -+ Mpi2RaidActionData_t, *pMpi2RaidActionData_t; -+ -+/*RAID Action Request Message */ -+typedef struct _MPI2_RAID_ACTION_REQUEST { -+ U8 Action; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 VolDevHandle; /*0x04 */ -+ U8 PhysDiskNum; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U32 Reserved3; /*0x0C */ -+ MPI2_RAID_ACTION_DATA ActionDataWord; /*0x10 */ -+ MPI2_SGE_SIMPLE_UNION ActionDataSGE; /*0x14 */ -+} MPI2_RAID_ACTION_REQUEST, *PTR_MPI2_RAID_ACTION_REQUEST, -+ Mpi2RaidActionRequest_t, *pMpi2RaidActionRequest_t; -+ -+/*RAID Action request Action values */ -+ -+#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01) -+#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02) -+#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03) -+#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04) -+#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05) -+#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A) -+#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B) -+#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F) -+#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11) -+#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) -+#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) -+#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18) -+#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19) -+#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C) -+#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D) -+#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E) -+#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20) -+#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21) -+#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22) -+#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23) -+#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN (0x24) -+#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80) -+#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF) -+ -+/*RAID Volume Creation Structure */ -+ -+/* -+ *The following define can be customized for the targeted product. -+ */ -+#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS -+#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1) -+#endif -+ -+typedef struct _MPI2_RAID_VOLUME_PHYSDISK { -+ U8 RAIDSetNum; /*0x00 */ -+ U8 PhysDiskMap; /*0x01 */ -+ U16 PhysDiskDevHandle; /*0x02 */ -+} MPI2_RAID_VOLUME_PHYSDISK, *PTR_MPI2_RAID_VOLUME_PHYSDISK, -+ Mpi2RaidVolumePhysDisk_t, *pMpi2RaidVolumePhysDisk_t; -+ -+/*defines for the PhysDiskMap field */ -+#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01) -+#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02) -+ -+typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT { -+ U8 NumPhysDisks; /*0x00 */ -+ U8 VolumeType; /*0x01 */ -+ U16 Reserved1; /*0x02 */ -+ U32 VolumeCreationFlags; /*0x04 */ -+ U32 VolumeSettings; /*0x08 */ -+ U8 Reserved2; /*0x0C */ -+ U8 ResyncRate; /*0x0D */ -+ U16 DataScrubDuration; /*0x0E */ -+ U64 VolumeMaxLBA; /*0x10 */ -+ U32 StripeSize; /*0x18 */ -+ U8 Name[16]; /*0x1C */ -+ MPI2_RAID_VOLUME_PHYSDISK -+ PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS]; /*0x2C */ -+} MPI2_RAID_VOLUME_CREATION_STRUCT, -+ *PTR_MPI2_RAID_VOLUME_CREATION_STRUCT, -+ Mpi2RaidVolumeCreationStruct_t, -+ *pMpi2RaidVolumeCreationStruct_t; -+ -+/*use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ -+ -+/*defines for the VolumeCreationFlags field */ -+#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000) -+#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) -+#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) -+#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) -+/*The following is an obsolete define. -+ *It must be shifted left 24 bits in order to set the proper bit. -+ */ -+#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) -+ -+/*RAID Online Capacity Expansion Structure */ -+ -+typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION { -+ U32 Flags; /*0x00 */ -+ U16 DevHandle0; /*0x04 */ -+ U16 Reserved1; /*0x06 */ -+ U16 DevHandle1; /*0x08 */ -+ U16 Reserved2; /*0x0A */ -+} MPI2_RAID_ONLINE_CAPACITY_EXPANSION, -+ *PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION, -+ Mpi2RaidOnlineCapacityExpansion_t, -+ *pMpi2RaidOnlineCapacityExpansion_t; -+ -+/*RAID Compatibility Input Structure */ -+ -+typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT { -+ U16 SourceDevHandle; /*0x00 */ -+ U16 CandidateDevHandle; /*0x02 */ -+ U32 Flags; /*0x04 */ -+ U32 Reserved1; /*0x08 */ -+ U32 Reserved2; /*0x0C */ -+} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -+ *PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -+ Mpi2RaidCompatibilityInputStruct_t, -+ *pMpi2RaidCompatibilityInputStruct_t; -+ -+/*defines for RAID Compatibility Structure Flags field */ -+#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002) -+#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001) -+ -+/*RAID Volume Indicator Structure */ -+ -+typedef struct _MPI2_RAID_VOL_INDICATOR { -+ U64 TotalBlocks; /*0x00 */ -+ U64 BlocksRemaining; /*0x08 */ -+ U32 Flags; /*0x10 */ -+ U32 ElapsedSeconds; /* 0x14 */ -+} MPI2_RAID_VOL_INDICATOR, *PTR_MPI2_RAID_VOL_INDICATOR, -+ Mpi2RaidVolIndicator_t, *pMpi2RaidVolIndicator_t; -+ -+/*defines for RAID Volume Indicator Flags field */ -+#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID (0x80000000) -+#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F) -+#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000) -+#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) -+#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) -+#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) -+#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) -+ -+/*RAID Compatibility Result Structure */ -+ -+typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT { -+ U8 State; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U16 Reserved2; /*0x02 */ -+ U32 GenericAttributes; /*0x04 */ -+ U32 OEMSpecificAttributes; /*0x08 */ -+ U32 Reserved3; /*0x0C */ -+ U32 Reserved4; /*0x10 */ -+} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -+ *PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -+ Mpi2RaidCompatibilityResultStruct_t, -+ *pMpi2RaidCompatibilityResultStruct_t; -+ -+/*defines for RAID Compatibility Result Structure State field */ -+#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00) -+#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01) -+ -+/*defines for RAID Compatibility Result Structure GenericAttributes field */ -+#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010) -+ -+#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C) -+#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008) -+#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004) -+ -+#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003) -+#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002) -+#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001) -+ -+/*RAID Action Reply ActionData union */ -+typedef union _MPI2_RAID_ACTION_REPLY_DATA { -+ U32 Word[6]; -+ MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; -+ U16 VolDevHandle; -+ U8 VolumeState; -+ U8 PhysDiskNum; -+ MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult; -+} MPI2_RAID_ACTION_REPLY_DATA, *PTR_MPI2_RAID_ACTION_REPLY_DATA, -+ Mpi2RaidActionReplyData_t, *pMpi2RaidActionReplyData_t; -+ -+/*use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for -+ *MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ -+ -+/*RAID Action Reply Message */ -+typedef struct _MPI2_RAID_ACTION_REPLY { -+ U8 Action; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 VolDevHandle; /*0x04 */ -+ U8 PhysDiskNum; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved2; /*0x0A */ -+ U16 Reserved3; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ MPI2_RAID_ACTION_REPLY_DATA ActionData; /*0x14 */ -+} MPI2_RAID_ACTION_REPLY, *PTR_MPI2_RAID_ACTION_REPLY, -+ Mpi2RaidActionReply_t, *pMpi2RaidActionReply_t; -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h -new file mode 100644 -index 0000000..c10c2c0 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h -@@ -0,0 +1,303 @@ -+/* -+ * Copyright 2000-2015 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_sas.h -+ * Title: MPI Serial Attached SCSI structures and definitions -+ * Creation Date: February 9, 2007 -+ * -+ * mpi2_sas.h Version: 02.00.10 -+ * -+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 -+ * prefix are for use only on MPI v2.5 products, and must not be used -+ * with MPI v2.0 products. Unless otherwise noted, names beginning with -+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products. -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit -+ * Control Request. -+ * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control -+ * Request. -+ * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST -+ * to MPI2_SGE_IO_UNION since it supports chained SGLs. -+ * 05-12-10 02.00.04 Modified some comments. -+ * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. -+ * 11-18-11 02.00.06 Incorporating additions for MPI v2.5. -+ * 07-10-12 02.00.07 Added MPI2_SATA_PT_SGE_UNION for use in the SATA -+ * Passthrough Request message. -+ * 08-19-13 02.00.08 Made MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL obsolete -+ * for anything newer than MPI v2.0. -+ * 11-18-14 02.00.09 Updated copyright information. -+ * 03-16-15 02.00.10 Updated for MPI v2.6. -+ * Added MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_SAS_H -+#define MPI2_SAS_H -+ -+/* -+ *Values for SASStatus. -+ */ -+#define MPI2_SASSTATUS_SUCCESS (0x00) -+#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01) -+#define MPI2_SASSTATUS_INVALID_FRAME (0x02) -+#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03) -+#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04) -+#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) -+#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) -+#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) -+#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) -+#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09) -+#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) -+#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) -+#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) -+#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) -+#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) -+#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) -+#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) -+#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11) -+#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12) -+#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) -+#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) -+ -+/* -+ *Values for the SAS DeviceInfo field used in SAS Device Status Change Event -+ *data and SAS Configuration pages. -+ */ -+#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000) -+#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) -+#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) -+#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) -+#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) -+#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200) -+#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) -+#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) -+#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) -+#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) -+#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) -+#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008) -+ -+#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) -+#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) -+#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001) -+#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) -+#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) -+ -+/***************************************************************************** -+* -+* SAS Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* SMP Passthrough messages -+****************************************************************************/ -+ -+/*SMP Passthrough Request Message */ -+typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST { -+ U8 PassthroughFlags; /*0x00 */ -+ U8 PhysicalPort; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 RequestDataLength; /*0x04 */ -+ U8 SGLFlags; /*0x06*//*MPI v2.0 only. Reserved on MPI v2.5*/ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U32 Reserved2; /*0x0C */ -+ U64 SASAddress; /*0x10 */ -+ U32 Reserved3; /*0x18 */ -+ U32 Reserved4; /*0x1C */ -+ MPI2_SIMPLE_SGE_UNION SGL;/*0x20 */ -+} MPI2_SMP_PASSTHROUGH_REQUEST, *PTR_MPI2_SMP_PASSTHROUGH_REQUEST, -+ Mpi2SmpPassthroughRequest_t, *pMpi2SmpPassthroughRequest_t; -+ -+/*values for PassthroughFlags field */ -+#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) -+ -+/*MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+/*SMP Passthrough Reply Message */ -+typedef struct _MPI2_SMP_PASSTHROUGH_REPLY { -+ U8 PassthroughFlags; /*0x00 */ -+ U8 PhysicalPort; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 ResponseDataLength; /*0x04 */ -+ U8 SGLFlags; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U8 Reserved2; /*0x0C */ -+ U8 SASStatus; /*0x0D */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 Reserved3; /*0x14 */ -+ U8 ResponseData[4]; /*0x18 */ -+} MPI2_SMP_PASSTHROUGH_REPLY, *PTR_MPI2_SMP_PASSTHROUGH_REPLY, -+ Mpi2SmpPassthroughReply_t, *pMpi2SmpPassthroughReply_t; -+ -+/*values for PassthroughFlags field */ -+#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) -+ -+/*values for SASStatus field are at the top of this file */ -+ -+/**************************************************************************** -+* SATA Passthrough messages -+****************************************************************************/ -+ -+typedef union _MPI2_SATA_PT_SGE_UNION { -+ MPI2_SGE_SIMPLE_UNION MpiSimple; /*MPI v2.0 only */ -+ MPI2_SGE_CHAIN_UNION MpiChain; /*MPI v2.0 only */ -+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; -+ MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; /*MPI v2.0 only */ -+ MPI25_IEEE_SGE_CHAIN64 IeeeChain64; /*MPI v2.5 only */ -+} MPI2_SATA_PT_SGE_UNION, *PTR_MPI2_SATA_PT_SGE_UNION, -+ Mpi2SataPTSGEUnion_t, *pMpi2SataPTSGEUnion_t; -+ -+/*SATA Passthrough Request Message */ -+typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST { -+ U16 DevHandle; /*0x00 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 PassthroughFlags; /*0x04 */ -+ U8 SGLFlags; /*0x06*//*MPI v2.0 only. Reserved on MPI v2.5*/ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U32 Reserved2; /*0x0C */ -+ U32 Reserved3; /*0x10 */ -+ U32 Reserved4; /*0x14 */ -+ U32 DataLength; /*0x18 */ -+ U8 CommandFIS[20]; /*0x1C */ -+ MPI2_SATA_PT_SGE_UNION SGL;/*0x30*//*MPI v2.5: IEEE 64 elements only*/ -+} MPI2_SATA_PASSTHROUGH_REQUEST, *PTR_MPI2_SATA_PASSTHROUGH_REQUEST, -+ Mpi2SataPassthroughRequest_t, -+ *pMpi2SataPassthroughRequest_t; -+ -+/*values for PassthroughFlags field */ -+#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_FPDMA (0x0040) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) -+#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) -+ -+/*MPI v2.0: use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+/*SATA Passthrough Reply Message */ -+typedef struct _MPI2_SATA_PASSTHROUGH_REPLY { -+ U16 DevHandle; /*0x00 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 PassthroughFlags; /*0x04 */ -+ U8 SGLFlags; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved1; /*0x0A */ -+ U8 Reserved2; /*0x0C */ -+ U8 SASStatus; /*0x0D */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U8 StatusFIS[20]; /*0x14 */ -+ U32 StatusControlRegisters; /*0x28 */ -+ U32 TransferCount; /*0x2C */ -+} MPI2_SATA_PASSTHROUGH_REPLY, *PTR_MPI2_SATA_PASSTHROUGH_REPLY, -+ Mpi2SataPassthroughReply_t, *pMpi2SataPassthroughReply_t; -+ -+/*values for SASStatus field are at the top of this file */ -+ -+/**************************************************************************** -+* SAS IO Unit Control messages -+* (MPI v2.5 and earlier only. -+* Replaced by IO Unit Control messages in MPI v2.6 and later.) -+****************************************************************************/ -+ -+/*SAS IO Unit Control Request Message */ -+typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST { -+ U8 Operation; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 DevHandle; /*0x04 */ -+ U8 IOCParameter; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U16 Reserved4; /*0x0C */ -+ U8 PhyNum; /*0x0E */ -+ U8 PrimFlags; /*0x0F */ -+ U32 Primitive; /*0x10 */ -+ U8 LookupMethod; /*0x14 */ -+ U8 Reserved5; /*0x15 */ -+ U16 SlotNumber; /*0x16 */ -+ U64 LookupAddress; /*0x18 */ -+ U32 IOCParameterValue; /*0x20 */ -+ U32 Reserved7; /*0x24 */ -+ U32 Reserved8; /*0x28 */ -+} MPI2_SAS_IOUNIT_CONTROL_REQUEST, -+ *PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST, -+ Mpi2SasIoUnitControlRequest_t, -+ *pMpi2SasIoUnitControlRequest_t; -+ -+/*values for the Operation field */ -+#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02) -+#define MPI2_SAS_OP_PHY_LINK_RESET (0x06) -+#define MPI2_SAS_OP_PHY_HARD_RESET (0x07) -+#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) -+#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A) -+#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) -+#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) /* MPI v2.0 only */ -+#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D) -+#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E) -+#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F) -+#define MPI25_SAS_OP_ENABLE_FP_DEVICE (0x10) -+#define MPI25_SAS_OP_DISABLE_FP_DEVICE (0x11) -+#define MPI25_SAS_OP_ENABLE_FP_ALL (0x12) -+#define MPI25_SAS_OP_DISABLE_FP_ALL (0x13) -+#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14) -+#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15) -+#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) -+ -+/*values for the PrimFlags field */ -+#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08) -+#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02) -+#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01) -+ -+/*values for the LookupMethod field */ -+#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01) -+#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02) -+#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) -+ -+/*SAS IO Unit Control Reply Message */ -+typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY { -+ U8 Operation; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 DevHandle; /*0x04 */ -+ U8 IOCParameter; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved3; /*0x0A */ -+ U16 Reserved4; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_SAS_IOUNIT_CONTROL_REPLY, -+ *PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY, -+ Mpi2SasIoUnitControlReply_t, *pMpi2SasIoUnitControlReply_t; -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h -new file mode 100644 -index 0000000..5f9289a ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h -@@ -0,0 +1,483 @@ -+/* -+ * Copyright 2000-2014 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_tool.h -+ * Title: MPI diagnostic tool structures and definitions -+ * Creation Date: March 26, 2007 -+ * -+ * mpi2_tool.h Version: 02.00.13 -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release -+ * structures and defines. -+ * 02-29-08 02.00.02 Modified various names to make them 32-character unique. -+ * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. -+ * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request -+ * and reply messages. -+ * Added MPI2_DIAG_BUF_TYPE_EXTENDED. -+ * Incremented MPI2_DIAG_BUF_TYPE_COUNT. -+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. -+ * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer -+ * Post Request. -+ * 05-25-11 02.00.07 Added Flags field and related defines to -+ * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. -+ * 11-18-11 02.00.08 Incorporating additions for MPI v2.5. -+ * 07-10-12 02.00.09 Add MPI v2.5 Toolbox Diagnostic CLI Tool Request -+ * message. -+ * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that -+ * it uses MPI Chain SGE as well as MPI Simple SGE. -+ * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. -+ * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC. -+ * 11-18-14 02.00.13 Updated copyright information. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_TOOL_H -+#define MPI2_TOOL_H -+ -+/***************************************************************************** -+* -+* Toolbox Messages -+* -+*****************************************************************************/ -+ -+/*defines for the Tools */ -+#define MPI2_TOOLBOX_CLEAN_TOOL (0x00) -+#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) -+#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) -+#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) -+#define MPI2_TOOLBOX_BEACON_TOOL (0x05) -+#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) -+#define MPI2_TOOLBOX_TEXT_DISPLAY_TOOL (0x07) -+ -+/**************************************************************************** -+* Toolbox reply -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_REPLY { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_TOOLBOX_REPLY, *PTR_MPI2_TOOLBOX_REPLY, -+ Mpi2ToolboxReply_t, *pMpi2ToolboxReply_t; -+ -+/**************************************************************************** -+* Toolbox Clean Tool request -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Flags; /*0x0C */ -+} MPI2_TOOLBOX_CLEAN_REQUEST, *PTR_MPI2_TOOLBOX_CLEAN_REQUEST, -+ Mpi2ToolboxCleanRequest_t, *pMpi2ToolboxCleanRequest_t; -+ -+/*values for the Flags field */ -+#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) -+#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) -+#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) -+#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) -+#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) -+#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000) -+#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) -+#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) -+#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) -+#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002) -+#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001) -+ -+/**************************************************************************** -+* Toolbox Memory Move request -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ MPI2_SGE_SIMPLE_UNION SGL; /*0x0C */ -+} MPI2_TOOLBOX_MEM_MOVE_REQUEST, *PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST, -+ Mpi2ToolboxMemMoveRequest_t, *pMpi2ToolboxMemMoveRequest_t; -+ -+/**************************************************************************** -+* Toolbox Diagnostic Data Upload request -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U8 SGLFlags; /*0x0C */ -+ U8 Reserved5; /*0x0D */ -+ U16 Reserved6; /*0x0E */ -+ U32 Flags; /*0x10 */ -+ U32 DataLength; /*0x14 */ -+ MPI2_SGE_SIMPLE_UNION SGL; /*0x18 */ -+} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -+ *PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -+ Mpi2ToolboxDiagDataUploadRequest_t, -+ *pMpi2ToolboxDiagDataUploadRequest_t; -+ -+/*use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER { -+ U32 DiagDataLength; /*00h */ -+ U8 FormatCode; /*04h */ -+ U8 Reserved1; /*05h */ -+ U16 Reserved2; /*06h */ -+} MPI2_DIAG_DATA_UPLOAD_HEADER, *PTR_MPI2_DIAG_DATA_UPLOAD_HEADER, -+ Mpi2DiagDataUploadHeader_t, *pMpi2DiagDataUploadHeader_t; -+ -+/**************************************************************************** -+* Toolbox ISTWI Read Write Tool -+****************************************************************************/ -+ -+/*Toolbox ISTWI Read Write Tool request message */ -+typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 Reserved6; /*0x10 */ -+ U8 DevIndex; /*0x14 */ -+ U8 Action; /*0x15 */ -+ U8 SGLFlags; /*0x16 */ -+ U8 Flags; /*0x17 */ -+ U16 TxDataLength; /*0x18 */ -+ U16 RxDataLength; /*0x1A */ -+ U32 Reserved8; /*0x1C */ -+ U32 Reserved9; /*0x20 */ -+ U32 Reserved10; /*0x24 */ -+ U32 Reserved11; /*0x28 */ -+ U32 Reserved12; /*0x2C */ -+ MPI2_SGE_SIMPLE_UNION SGL; /*0x30 */ -+} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, -+ *PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, -+ Mpi2ToolboxIstwiReadWriteRequest_t, -+ *pMpi2ToolboxIstwiReadWriteRequest_t; -+ -+/*values for the Action field */ -+#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01) -+#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02) -+#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03) -+#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10) -+#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) -+#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) -+ -+/*use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+/*values for the Flags field */ -+#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80) -+#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07) -+ -+/*Toolbox ISTWI Read Write Tool reply message */ -+typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U8 DevIndex; /*0x14 */ -+ U8 Action; /*0x15 */ -+ U8 IstwiStatus; /*0x16 */ -+ U8 Reserved6; /*0x17 */ -+ U16 TxDataCount; /*0x18 */ -+ U16 RxDataCount; /*0x1A */ -+} MPI2_TOOLBOX_ISTWI_REPLY, *PTR_MPI2_TOOLBOX_ISTWI_REPLY, -+ Mpi2ToolboxIstwiReply_t, *pMpi2ToolboxIstwiReply_t; -+ -+/**************************************************************************** -+* Toolbox Beacon Tool request -+****************************************************************************/ -+ -+typedef struct _MPI2_TOOLBOX_BEACON_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U8 Reserved5; /*0x0C */ -+ U8 PhysicalPort; /*0x0D */ -+ U8 Reserved6; /*0x0E */ -+ U8 Flags; /*0x0F */ -+} MPI2_TOOLBOX_BEACON_REQUEST, *PTR_MPI2_TOOLBOX_BEACON_REQUEST, -+ Mpi2ToolboxBeaconRequest_t, *pMpi2ToolboxBeaconRequest_t; -+ -+/*values for the Flags field */ -+#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00) -+#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01) -+ -+/**************************************************************************** -+* Toolbox Diagnostic CLI Tool -+****************************************************************************/ -+ -+#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C) -+ -+/*MPI v2.0 Toolbox Diagnostic CLI Tool request message */ -+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U8 SGLFlags; /*0x0C */ -+ U8 Reserved5; /*0x0D */ -+ U16 Reserved6; /*0x0E */ -+ U32 DataLength; /*0x10 */ -+ U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];/*0x14 */ -+ MPI2_MPI_SGE_IO_UNION SGL; /*0x70 */ -+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, -+ *PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, -+ Mpi2ToolboxDiagnosticCliRequest_t, -+ *pMpi2ToolboxDiagnosticCliRequest_t; -+ -+/*use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ -+ -+/*MPI v2.5 Toolbox Diagnostic CLI Tool request message */ -+typedef struct _MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U32 Reserved5; /*0x0C */ -+ U32 DataLength; /*0x10 */ -+ U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];/*0x14 */ -+ MPI25_SGE_IO_UNION SGL; /* 0x70 */ -+} MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, -+ *PTR_MPI25_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, -+ Mpi25ToolboxDiagnosticCliRequest_t, -+ *pMpi25ToolboxDiagnosticCliRequest_t; -+ -+/*Toolbox Diagnostic CLI Tool reply message */ -+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY { -+ U8 Tool; /*0x00 */ -+ U8 Reserved1; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 ReturnedDataLength; /*0x14 */ -+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, -+ *PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, -+ Mpi2ToolboxDiagnosticCliReply_t, -+ *pMpi2ToolboxDiagnosticCliReply_t; -+ -+ -+/**************************************************************************** -+* Toolbox Console Text Display Tool -+****************************************************************************/ -+ -+/* Toolbox Console Text Display Tool request message */ -+typedef struct _MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST { -+ U8 Tool; /* 0x00 */ -+ U8 Reserved1; /* 0x01 */ -+ U8 ChainOffset; /* 0x02 */ -+ U8 Function; /* 0x03 */ -+ U16 Reserved2; /* 0x04 */ -+ U8 Reserved3; /* 0x06 */ -+ U8 MsgFlags; /* 0x07 */ -+ U8 VP_ID; /* 0x08 */ -+ U8 VF_ID; /* 0x09 */ -+ U16 Reserved4; /* 0x0A */ -+ U8 Console; /* 0x0C */ -+ U8 Flags; /* 0x0D */ -+ U16 Reserved6; /* 0x0E */ -+ U8 TextToDisplay[4]; /* 0x10 */ -+} MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, -+*PTR_MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, -+Mpi2ToolboxTextDisplayRequest_t, -+*pMpi2ToolboxTextDisplayRequest_t; -+ -+/* defines for the Console field */ -+#define MPI2_TOOLBOX_CONSOLE_TYPE_MASK (0xF0) -+#define MPI2_TOOLBOX_CONSOLE_TYPE_DEFAULT (0x00) -+#define MPI2_TOOLBOX_CONSOLE_TYPE_UART (0x10) -+#define MPI2_TOOLBOX_CONSOLE_TYPE_ETHERNET (0x20) -+ -+#define MPI2_TOOLBOX_CONSOLE_NUMBER_MASK (0x0F) -+ -+/* defines for the Flags field */ -+#define MPI2_TOOLBOX_CONSOLE_FLAG_TIMESTAMP (0x01) -+ -+ -+ -+/***************************************************************************** -+* -+* Diagnostic Buffer Messages -+* -+*****************************************************************************/ -+ -+/**************************************************************************** -+* Diagnostic Buffer Post request -+****************************************************************************/ -+ -+typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST { -+ U8 ExtendedType; /*0x00 */ -+ U8 BufferType; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U64 BufferAddress; /*0x0C */ -+ U32 BufferLength; /*0x14 */ -+ U32 Reserved5; /*0x18 */ -+ U32 Reserved6; /*0x1C */ -+ U32 Flags; /*0x20 */ -+ U32 ProductSpecific[23]; /*0x24 */ -+} MPI2_DIAG_BUFFER_POST_REQUEST, *PTR_MPI2_DIAG_BUFFER_POST_REQUEST, -+ Mpi2DiagBufferPostRequest_t, *pMpi2DiagBufferPostRequest_t; -+ -+/*values for the ExtendedType field */ -+#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) -+ -+/*values for the BufferType field */ -+#define MPI2_DIAG_BUF_TYPE_TRACE (0x00) -+#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) -+#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) -+/*count of the number of buffer types */ -+#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) -+ -+/*values for the Flags field */ -+#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002) -+#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001) -+ -+/**************************************************************************** -+* Diagnostic Buffer Post reply -+****************************************************************************/ -+ -+typedef struct _MPI2_DIAG_BUFFER_POST_REPLY { -+ U8 ExtendedType; /*0x00 */ -+ U8 BufferType; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+ U32 TransferLength; /*0x14 */ -+} MPI2_DIAG_BUFFER_POST_REPLY, *PTR_MPI2_DIAG_BUFFER_POST_REPLY, -+ Mpi2DiagBufferPostReply_t, *pMpi2DiagBufferPostReply_t; -+ -+/**************************************************************************** -+* Diagnostic Release request -+****************************************************************************/ -+ -+typedef struct _MPI2_DIAG_RELEASE_REQUEST { -+ U8 Reserved1; /*0x00 */ -+ U8 BufferType; /*0x01 */ -+ U8 ChainOffset; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+} MPI2_DIAG_RELEASE_REQUEST, *PTR_MPI2_DIAG_RELEASE_REQUEST, -+ Mpi2DiagReleaseRequest_t, *pMpi2DiagReleaseRequest_t; -+ -+/**************************************************************************** -+* Diagnostic Buffer Post reply -+****************************************************************************/ -+ -+typedef struct _MPI2_DIAG_RELEASE_REPLY { -+ U8 Reserved1; /*0x00 */ -+ U8 BufferType; /*0x01 */ -+ U8 MsgLength; /*0x02 */ -+ U8 Function; /*0x03 */ -+ U16 Reserved2; /*0x04 */ -+ U8 Reserved3; /*0x06 */ -+ U8 MsgFlags; /*0x07 */ -+ U8 VP_ID; /*0x08 */ -+ U8 VF_ID; /*0x09 */ -+ U16 Reserved4; /*0x0A */ -+ U16 Reserved5; /*0x0C */ -+ U16 IOCStatus; /*0x0E */ -+ U32 IOCLogInfo; /*0x10 */ -+} MPI2_DIAG_RELEASE_REPLY, *PTR_MPI2_DIAG_RELEASE_REPLY, -+ Mpi2DiagReleaseReply_t, *pMpi2DiagReleaseReply_t; -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h -new file mode 100644 -index 0000000..92a81ab ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpi/mpi2_type.h -@@ -0,0 +1,57 @@ -+/* -+ * Copyright 2000-2014 Avago Technologies. All rights reserved. -+ * -+ * -+ * Name: mpi2_type.h -+ * Title: MPI basic type definitions -+ * Creation Date: August 16, 2006 -+ * -+ * mpi2_type.h Version: 02.00.01 -+ * -+ * Version History -+ * --------------- -+ * -+ * Date Version Description -+ * -------- -------- ------------------------------------------------------ -+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. -+ * 11-18-14 02.00.01 Updated copyright information. -+ * -------------------------------------------------------------------------- -+ */ -+ -+#ifndef MPI2_TYPE_H -+#define MPI2_TYPE_H -+ -+/******************************************************************************* -+ * Define * if it hasn't already been defined. By default -+ * * is defined to be a near pointer. MPI2_POINTER can be defined as -+ * a far pointer by defining * as "far *" before this header file is -+ * included. -+ */ -+ -+/* the basic types may have already been included by mpi_type.h */ -+#ifndef MPI_TYPE_H -+/***************************************************************************** -+* -+* Basic Types -+* -+*****************************************************************************/ -+ -+typedef u8 U8; -+typedef __le16 U16; -+typedef __le32 U32; -+typedef __le64 U64 __attribute__ ((aligned(4))); -+ -+/***************************************************************************** -+* -+* Pointer Types -+* -+*****************************************************************************/ -+ -+typedef U8 *PU8; -+typedef U16 *PU16; -+typedef U32 *PU32; -+typedef U64 *PU64; -+ -+#endif -+ -+#endif -diff --git a/drivers/scsi/mpt2sas/mpt3sas_base.c b/drivers/scsi/mpt2sas/mpt3sas_base.c -new file mode 100644 -index 0000000..224bf9d ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_base.c -@@ -0,0 +1,5713 @@ -+/* -+ * This is the Fusion MPT base driver providing common API layer interface -+ * for access to MPT (Message Passing Technology) firmware. -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#include "mpt3sas_base.h" -+ -+static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; -+ -+ -+#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ -+ -+ /* maximum controller queue depth */ -+#define MAX_HBA_QUEUE_DEPTH 30000 -+#define MAX_CHAIN_DEPTH 100000 -+static int max_queue_depth = -1; -+module_param(max_queue_depth, int, 0); -+MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); -+ -+static int max_sgl_entries = -1; -+module_param(max_sgl_entries, int, 0); -+MODULE_PARM_DESC(max_sgl_entries, " max sg entries "); -+ -+static int msix_disable = -1; -+module_param(msix_disable, int, 0); -+MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); -+ -+static int smp_affinity_enable = 1; -+module_param(smp_affinity_enable, int, S_IRUGO); -+MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)"); -+ -+static int max_msix_vectors = -1; -+module_param(max_msix_vectors, int, 0); -+MODULE_PARM_DESC(max_msix_vectors, -+ " max msix vectors"); -+ -+static int mpt2sas_fwfault_debug; -+MODULE_PARM_DESC(mpt2sas_fwfault_debug, -+ " enable detection of firmware fault and halt firmware - (default=0)"); -+ -+static int -+_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag); -+ -+/** -+ * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. -+ * -+ */ -+static int -+_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) -+{ -+ int ret = param_set_int(val, kp); -+ struct MPT3SAS_ADAPTER *ioc; -+ -+ if (ret) -+ return ret; -+ -+ /* global ioc spinlock to protect controller list on list operations */ -+ pr_info("setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); -+ spin_lock(&gioc_lock_mpt2sas); -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) -+ ioc->fwfault_debug = mpt2sas_fwfault_debug; -+ spin_unlock(&gioc_lock_mpt2sas); -+ return 0; -+} -+module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, -+ param_get_int, &mpt2sas_fwfault_debug, 0644); -+ -+/** -+ * mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc -+ * @arg: input argument, used to derive ioc -+ * -+ * Return 0 if controller is removed from pci subsystem. -+ * Return -1 for other case. -+ */ -+static int mpt2sas_remove_dead_ioc_func(void *arg) -+{ -+ struct MPT3SAS_ADAPTER *ioc = (struct MPT3SAS_ADAPTER *)arg; -+ struct pci_dev *pdev; -+ -+ if ((ioc == NULL)) -+ return -1; -+ -+ pdev = ioc->pdev; -+ if ((pdev == NULL)) -+ return -1; -+ pci_stop_and_remove_bus_device_locked(pdev); -+ return 0; -+} -+ -+/** -+ * _base_fault_reset_work - workq handling ioc fault conditions -+ * @work: input argument, used to derive ioc -+ * Context: sleep. -+ * -+ * Return nothing. -+ */ -+static void -+_base_fault_reset_work(struct work_struct *work) -+{ -+ struct MPT3SAS_ADAPTER *ioc = -+ container_of(work, struct MPT3SAS_ADAPTER, fault_reset_work.work); -+ unsigned long flags; -+ u32 doorbell; -+ int rc; -+ struct task_struct *p; -+ -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ if (ioc->shost_recovery || ioc->pci_error_recovery) -+ goto rearm_timer; -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+ -+ doorbell = mpt2sas_base_get_iocstate(ioc, 0); -+ if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) { -+ pr_err(MPT3SAS_FMT "SAS host is non-operational !!!!\n", -+ ioc->name); -+ -+ /* It may be possible that EEH recovery can resolve some of -+ * pci bus failure issues rather removing the dead ioc function -+ * by considering controller is in a non-operational state. So -+ * here priority is given to the EEH recovery. If it doesn't -+ * not resolve this issue, mpt3sas driver will consider this -+ * controller to non-operational state and remove the dead ioc -+ * function. -+ */ -+ if (ioc->non_operational_loop++ < 5) { -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, -+ flags); -+ goto rearm_timer; -+ } -+ -+ /* -+ * Call _scsih_flush_pending_cmds callback so that we flush all -+ * pending commands back to OS. This call is required to aovid -+ * deadlock at block layer. Dead IOC will fail to do diag reset, -+ * and this call is safe since dead ioc will never return any -+ * command back from HW. -+ */ -+ ioc->schedule_dead_ioc_flush_running_cmds(ioc); -+ /* -+ * Set remove_host flag early since kernel thread will -+ * take some time to execute. -+ */ -+ ioc->remove_host = 1; -+ /*Remove the Dead Host */ -+ p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc, -+ "%s_dead_ioc_%d", ioc->driver_name, ioc->id); -+ if (IS_ERR(p)) -+ pr_err(MPT3SAS_FMT -+ "%s: Running mpt2sas_dead_ioc thread failed !!!!\n", -+ ioc->name, __func__); -+ else -+ pr_err(MPT3SAS_FMT -+ "%s: Running mpt2sas_dead_ioc thread success !!!!\n", -+ ioc->name, __func__); -+ return; /* don't rearm timer */ -+ } -+ -+ ioc->non_operational_loop = 0; -+ -+ if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) { -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ pr_warn(MPT3SAS_FMT "%s: hard reset: %s\n", ioc->name, -+ __func__, (rc == 0) ? "success" : "failed"); -+ doorbell = mpt2sas_base_get_iocstate(ioc, 0); -+ if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) -+ mpt2sas_base_fault_info(ioc, doorbell & -+ MPI2_DOORBELL_DATA_MASK); -+ if (rc && (doorbell & MPI2_IOC_STATE_MASK) != -+ MPI2_IOC_STATE_OPERATIONAL) -+ return; /* don't rearm timer */ -+ } -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ rearm_timer: -+ if (ioc->fault_reset_work_q) -+ queue_delayed_work(ioc->fault_reset_work_q, -+ &ioc->fault_reset_work, -+ msecs_to_jiffies(FAULT_POLLING_INTERVAL)); -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+} -+ -+/** -+ * mpt2sas_base_start_watchdog - start the fault_reset_work_q -+ * @ioc: per adapter object -+ * Context: sleep. -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) -+{ -+ unsigned long flags; -+ -+ if (ioc->fault_reset_work_q) -+ return; -+ -+ /* initialize fault polling */ -+ -+ INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); -+ snprintf(ioc->fault_reset_work_q_name, -+ sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", -+ ioc->driver_name, ioc->id); -+ ioc->fault_reset_work_q = -+ create_singlethread_workqueue(ioc->fault_reset_work_q_name); -+ if (!ioc->fault_reset_work_q) { -+ pr_err(MPT3SAS_FMT "%s: failed (line=%d)\n", -+ ioc->name, __func__, __LINE__); -+ return; -+ } -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ if (ioc->fault_reset_work_q) -+ queue_delayed_work(ioc->fault_reset_work_q, -+ &ioc->fault_reset_work, -+ msecs_to_jiffies(FAULT_POLLING_INTERVAL)); -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+} -+ -+/** -+ * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q -+ * @ioc: per adapter object -+ * Context: sleep. -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc) -+{ -+ unsigned long flags; -+ struct workqueue_struct *wq; -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ wq = ioc->fault_reset_work_q; -+ ioc->fault_reset_work_q = NULL; -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+ if (wq) { -+ if (!cancel_delayed_work_sync(&ioc->fault_reset_work)) -+ flush_workqueue(wq); -+ destroy_workqueue(wq); -+ } -+} -+ -+/** -+ * mpt2sas_base_fault_info - verbose translation of firmware FAULT code -+ * @ioc: per adapter object -+ * @fault_code: fault code -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code) -+{ -+ pr_err(MPT3SAS_FMT "fault_state(0x%04x)!\n", -+ ioc->name, fault_code); -+} -+ -+/** -+ * mpt2sas_halt_firmware - halt's mpt controller firmware -+ * @ioc: per adapter object -+ * -+ * For debugging timeout related issues. Writing 0xCOFFEE00 -+ * to the doorbell register will halt controller firmware. With -+ * the purpose to stop both driver and firmware, the enduser can -+ * obtain a ring buffer from controller UART. -+ */ -+void -+mpt2sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u32 doorbell; -+ -+ if (!ioc->fwfault_debug) -+ return; -+ -+ dump_stack(); -+ -+ doorbell = readl(&ioc->chip->Doorbell); -+ if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) -+ mpt2sas_base_fault_info(ioc , doorbell); -+ else { -+ writel(0xC0FFEE00, &ioc->chip->Doorbell); -+ pr_err(MPT3SAS_FMT "Firmware is halted due to command timeout\n", -+ ioc->name); -+ } -+ -+ if (ioc->fwfault_debug == 2) -+ for (;;) -+ ; -+ else -+ panic("panic in %s\n", __func__); -+} -+ -+/** -+ * _base_sas_ioc_info - verbose translation of the ioc status -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @request_hdr: request mf -+ * -+ * Return nothing. -+ */ -+static void -+_base_sas_ioc_info(struct MPT3SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, -+ MPI2RequestHeader_t *request_hdr) -+{ -+ u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ char *desc = NULL; -+ u16 frame_sz; -+ char *func_str = NULL; -+ -+ /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */ -+ if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || -+ request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) -+ return; -+ -+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) -+ return; -+ -+ switch (ioc_status) { -+ -+/**************************************************************************** -+* Common IOCStatus values for all replies -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_INVALID_FUNCTION: -+ desc = "invalid function"; -+ break; -+ case MPI2_IOCSTATUS_BUSY: -+ desc = "busy"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_SGL: -+ desc = "invalid sgl"; -+ break; -+ case MPI2_IOCSTATUS_INTERNAL_ERROR: -+ desc = "internal error"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_VPID: -+ desc = "invalid vpid"; -+ break; -+ case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: -+ desc = "insufficient resources"; -+ break; -+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER: -+ desc = "insufficient power"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_FIELD: -+ desc = "invalid field"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_STATE: -+ desc = "invalid state"; -+ break; -+ case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: -+ desc = "op state not supported"; -+ break; -+ -+/**************************************************************************** -+* Config IOCStatus values -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION: -+ desc = "config invalid action"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE: -+ desc = "config invalid type"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE: -+ desc = "config invalid page"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_INVALID_DATA: -+ desc = "config invalid data"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS: -+ desc = "config no defaults"; -+ break; -+ case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT: -+ desc = "config cant commit"; -+ break; -+ -+/**************************************************************************** -+* SCSI IO Reply -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: -+ case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: -+ case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: -+ case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: -+ case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: -+ case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: -+ case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: -+ case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: -+ case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: -+ case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: -+ case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: -+ case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: -+ break; -+ -+/**************************************************************************** -+* For use by SCSI Initiator and SCSI Target end-to-end data protection -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: -+ desc = "eedp guard error"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: -+ desc = "eedp ref tag error"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: -+ desc = "eedp app tag error"; -+ break; -+ -+/**************************************************************************** -+* SCSI Target values -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX: -+ desc = "target invalid io index"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_ABORTED: -+ desc = "target aborted"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: -+ desc = "target no conn retryable"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_NO_CONNECTION: -+ desc = "target no connection"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: -+ desc = "target xfer count mismatch"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: -+ desc = "target data offset error"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: -+ desc = "target too much write data"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT: -+ desc = "target iu too short"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: -+ desc = "target ack nak timeout"; -+ break; -+ case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED: -+ desc = "target nak received"; -+ break; -+ -+/**************************************************************************** -+* Serial Attached SCSI values -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED: -+ desc = "smp request failed"; -+ break; -+ case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN: -+ desc = "smp data overrun"; -+ break; -+ -+/**************************************************************************** -+* Diagnostic Buffer Post / Diagnostic Release values -+****************************************************************************/ -+ -+ case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED: -+ desc = "diagnostic released"; -+ break; -+ default: -+ break; -+ } -+ -+ if (!desc) -+ return; -+ -+ switch (request_hdr->Function) { -+ case MPI2_FUNCTION_CONFIG: -+ frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size; -+ func_str = "config_page"; -+ break; -+ case MPI2_FUNCTION_SCSI_TASK_MGMT: -+ frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t); -+ func_str = "task_mgmt"; -+ break; -+ case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: -+ frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t); -+ func_str = "sas_iounit_ctl"; -+ break; -+ case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: -+ frame_sz = sizeof(Mpi2SepRequest_t); -+ func_str = "enclosure"; -+ break; -+ case MPI2_FUNCTION_IOC_INIT: -+ frame_sz = sizeof(Mpi2IOCInitRequest_t); -+ func_str = "ioc_init"; -+ break; -+ case MPI2_FUNCTION_PORT_ENABLE: -+ frame_sz = sizeof(Mpi2PortEnableRequest_t); -+ func_str = "port_enable"; -+ break; -+ case MPI2_FUNCTION_SMP_PASSTHROUGH: -+ frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size; -+ func_str = "smp_passthru"; -+ break; -+ default: -+ frame_sz = 32; -+ func_str = "unknown"; -+ break; -+ } -+ -+ pr_warn(MPT3SAS_FMT "ioc_status: %s(0x%04x), request(0x%p),(%s)\n", -+ ioc->name, desc, ioc_status, request_hdr, func_str); -+ -+ _debug_dump_mf(request_hdr, frame_sz/4); -+} -+ -+/** -+ * _base_display_event_data - verbose translation of firmware asyn events -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * -+ * Return nothing. -+ */ -+static void -+_base_display_event_data(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventNotificationReply_t *mpi_reply) -+{ -+ char *desc = NULL; -+ u16 event; -+ -+ if (!(ioc->logging_level & MPT_DEBUG_EVENTS)) -+ return; -+ -+ event = le16_to_cpu(mpi_reply->Event); -+ -+ switch (event) { -+ case MPI2_EVENT_LOG_DATA: -+ desc = "Log Data"; -+ break; -+ case MPI2_EVENT_STATE_CHANGE: -+ desc = "Status Change"; -+ break; -+ case MPI2_EVENT_HARD_RESET_RECEIVED: -+ desc = "Hard Reset Received"; -+ break; -+ case MPI2_EVENT_EVENT_CHANGE: -+ desc = "Event Change"; -+ break; -+ case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: -+ desc = "Device Status Change"; -+ break; -+ case MPI2_EVENT_IR_OPERATION_STATUS: -+ if (!ioc->hide_ir_msg) -+ desc = "IR Operation Status"; -+ break; -+ case MPI2_EVENT_SAS_DISCOVERY: -+ { -+ Mpi2EventDataSasDiscovery_t *event_data = -+ (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; -+ pr_info(MPT3SAS_FMT "Discovery: (%s)", ioc->name, -+ (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? -+ "start" : "stop"); -+ if (event_data->DiscoveryStatus) -+ pr_info("discovery_status(0x%08x)", -+ le32_to_cpu(event_data->DiscoveryStatus)); -+ pr_info("\n"); -+ return; -+ } -+ case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: -+ desc = "SAS Broadcast Primitive"; -+ break; -+ case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: -+ desc = "SAS Init Device Status Change"; -+ break; -+ case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW: -+ desc = "SAS Init Table Overflow"; -+ break; -+ case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: -+ desc = "SAS Topology Change List"; -+ break; -+ case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: -+ desc = "SAS Enclosure Device Status Change"; -+ break; -+ case MPI2_EVENT_IR_VOLUME: -+ if (!ioc->hide_ir_msg) -+ desc = "IR Volume"; -+ break; -+ case MPI2_EVENT_IR_PHYSICAL_DISK: -+ if (!ioc->hide_ir_msg) -+ desc = "IR Physical Disk"; -+ break; -+ case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: -+ if (!ioc->hide_ir_msg) -+ desc = "IR Configuration Change List"; -+ break; -+ case MPI2_EVENT_LOG_ENTRY_ADDED: -+ if (!ioc->hide_ir_msg) -+ desc = "Log Entry Added"; -+ break; -+ case MPI2_EVENT_TEMP_THRESHOLD: -+ desc = "Temperature Threshold"; -+ break; -+ case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION: -+ desc = "Active cable exception"; -+ break; -+ } -+ -+ if (!desc) -+ return; -+ -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc); -+} -+ -+/** -+ * _base_sas_log_info - verbose translation of firmware log info -+ * @ioc: per adapter object -+ * @log_info: log info -+ * -+ * Return nothing. -+ */ -+static void -+_base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info) -+{ -+ union loginfo_type { -+ u32 loginfo; -+ struct { -+ u32 subcode:16; -+ u32 code:8; -+ u32 originator:4; -+ u32 bus_type:4; -+ } dw; -+ }; -+ union loginfo_type sas_loginfo; -+ char *originator_str = NULL; -+ -+ sas_loginfo.loginfo = log_info; -+ if (sas_loginfo.dw.bus_type != 3 /*SAS*/) -+ return; -+ -+ /* each nexus loss loginfo */ -+ if (log_info == 0x31170000) -+ return; -+ -+ /* eat the loginfos associated with task aborts */ -+ if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info == -+ 0x31140000 || log_info == 0x31130000)) -+ return; -+ -+ switch (sas_loginfo.dw.originator) { -+ case 0: -+ originator_str = "IOP"; -+ break; -+ case 1: -+ originator_str = "PL"; -+ break; -+ case 2: -+ if (!ioc->hide_ir_msg) -+ originator_str = "IR"; -+ else -+ originator_str = "WarpDrive"; -+ break; -+ } -+ -+ pr_warn(MPT3SAS_FMT -+ "log_info(0x%08x): originator(%s), code(0x%02x), sub_code(0x%04x)\n", -+ ioc->name, log_info, -+ originator_str, sas_loginfo.dw.code, -+ sas_loginfo.dw.subcode); -+} -+ -+/** -+ * _base_display_reply_info - -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Return nothing. -+ */ -+static void -+_base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ u16 ioc_status; -+ u32 loginfo = 0; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (unlikely(!mpi_reply)) { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -+ -+ if ((ioc_status & MPI2_IOCSTATUS_MASK) && -+ (ioc->logging_level & MPT_DEBUG_REPLY)) { -+ _base_sas_ioc_info(ioc , mpi_reply, -+ mpt2sas_base_get_msg_frame(ioc, smid)); -+ } -+ -+ if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { -+ loginfo = le32_to_cpu(mpi_reply->IOCLogInfo); -+ _base_sas_log_info(ioc, loginfo); -+ } -+ -+ if (ioc_status || loginfo) { -+ ioc_status &= MPI2_IOCSTATUS_MASK; -+ mpt2sas_trigger_mpi(ioc, ioc_status, loginfo); -+ } -+} -+ -+/** -+ * mpt2sas_base_done - base internal command completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) -+ return mpt2sas_check_for_pending_internal_cmds(ioc, smid); -+ -+ if (ioc->base_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ -+ ioc->base_cmds.status |= MPT3_CMD_COMPLETE; -+ if (mpi_reply) { -+ ioc->base_cmds.status |= MPT3_CMD_REPLY_VALID; -+ memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); -+ } -+ ioc->base_cmds.status &= ~MPT3_CMD_PENDING; -+ -+ complete(&ioc->base_cmds.done); -+ return 1; -+} -+ -+/** -+ * _base_async_event - main callback handler for firmware asyn events -+ * @ioc: per adapter object -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) -+{ -+ Mpi2EventNotificationReply_t *mpi_reply; -+ Mpi2EventAckRequest_t *ack_request; -+ u16 smid; -+ struct _event_ack_list *delayed_event_ack; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (!mpi_reply) -+ return 1; -+ if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) -+ return 1; -+ -+ _base_display_event_data(ioc, mpi_reply); -+ -+ if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) -+ goto out; -+ smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); -+ if (!smid) { -+ delayed_event_ack = kzalloc(sizeof(*delayed_event_ack), -+ GFP_ATOMIC); -+ if (!delayed_event_ack) -+ goto out; -+ INIT_LIST_HEAD(&delayed_event_ack->list); -+ delayed_event_ack->Event = mpi_reply->Event; -+ delayed_event_ack->EventContext = mpi_reply->EventContext; -+ list_add_tail(&delayed_event_ack->list, -+ &ioc->delayed_event_ack_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED: EVENT ACK: event (0x%04x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->Event))); -+ goto out; -+ } -+ -+ ack_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); -+ ack_request->Function = MPI2_FUNCTION_EVENT_ACK; -+ ack_request->Event = mpi_reply->Event; -+ ack_request->EventContext = mpi_reply->EventContext; -+ ack_request->VF_ID = 0; /* TODO */ -+ ack_request->VP_ID = 0; -+ mpt2sas_base_put_smid_default(ioc, smid); -+ -+ out: -+ -+ /* scsih callback handler */ -+ mpt2sas_scsih_event_callback(ioc, msix_index, reply); -+ -+ /* ctl callback handler */ -+ mpt2sas_ctl_event_callback(ioc, msix_index, reply); -+ -+ return 1; -+} -+ -+/** -+ * _base_get_cb_idx - obtain the callback index -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Return callback index. -+ */ -+static u8 -+_base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ int i; -+ u8 cb_idx; -+ -+ if (smid < ioc->hi_priority_smid) { -+ i = smid - 1; -+ cb_idx = ioc->scsi_lookup[i].cb_idx; -+ } else if (smid < ioc->internal_smid) { -+ i = smid - ioc->hi_priority_smid; -+ cb_idx = ioc->hpr_lookup[i].cb_idx; -+ } else if (smid <= ioc->hba_queue_depth) { -+ i = smid - ioc->internal_smid; -+ cb_idx = ioc->internal_lookup[i].cb_idx; -+ } else -+ cb_idx = 0xFF; -+ return cb_idx; -+} -+ -+/** -+ * _base_mask_interrupts - disable interrupts -+ * @ioc: per adapter object -+ * -+ * Disabling ResetIRQ, Reply and Doorbell Interrupts -+ * -+ * Return nothing. -+ */ -+static void -+_base_mask_interrupts(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u32 him_register; -+ -+ ioc->mask_interrupts = 1; -+ him_register = readl(&ioc->chip->HostInterruptMask); -+ him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK; -+ writel(him_register, &ioc->chip->HostInterruptMask); -+ readl(&ioc->chip->HostInterruptMask); -+} -+ -+/** -+ * _base_unmask_interrupts - enable interrupts -+ * @ioc: per adapter object -+ * -+ * Enabling only Reply Interrupts -+ * -+ * Return nothing. -+ */ -+static void -+_base_unmask_interrupts(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u32 him_register; -+ -+ him_register = readl(&ioc->chip->HostInterruptMask); -+ him_register &= ~MPI2_HIM_RIM; -+ writel(him_register, &ioc->chip->HostInterruptMask); -+ ioc->mask_interrupts = 0; -+} -+ -+union reply_descriptor { -+ u64 word; -+ struct { -+ u32 low; -+ u32 high; -+ } u; -+}; -+ -+/** -+ * _base_interrupt - MPT adapter (IOC) specific interrupt handler. -+ * @irq: irq number (not used) -+ * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure -+ * @r: pt_regs pointer (not used) -+ * -+ * Return IRQ_HANDLE if processed, else IRQ_NONE. -+ */ -+static irqreturn_t -+_base_interrupt(int irq, void *bus_id) -+{ -+ struct adapter_reply_queue *reply_q = bus_id; -+ union reply_descriptor rd; -+ u32 completed_cmds; -+ u8 request_desript_type; -+ u16 smid; -+ u8 cb_idx; -+ u32 reply; -+ u8 msix_index = reply_q->msix_index; -+ struct MPT3SAS_ADAPTER *ioc = reply_q->ioc; -+ Mpi2ReplyDescriptorsUnion_t *rpf; -+ u8 rc; -+ -+ if (ioc->mask_interrupts) -+ return IRQ_NONE; -+ -+ if (!atomic_add_unless(&reply_q->busy, 1, 1)) -+ return IRQ_NONE; -+ -+ rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index]; -+ request_desript_type = rpf->Default.ReplyFlags -+ & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; -+ if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { -+ atomic_dec(&reply_q->busy); -+ return IRQ_NONE; -+ } -+ -+ completed_cmds = 0; -+ cb_idx = 0xFF; -+ do { -+ rd.word = le64_to_cpu(rpf->Words); -+ if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) -+ goto out; -+ reply = 0; -+ smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); -+ if (request_desript_type == -+ MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS || -+ request_desript_type == -+ MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { -+ cb_idx = _base_get_cb_idx(ioc, smid); -+ if ((likely(cb_idx < MPT_MAX_CALLBACKS)) && -+ (likely(mpt_callbacks[cb_idx] != NULL))) { -+ rc = mpt_callbacks[cb_idx](ioc, smid, -+ msix_index, 0); -+ if (rc) -+ mpt2sas_base_free_smid(ioc, smid); -+ } -+ } else if (request_desript_type == -+ MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { -+ reply = le32_to_cpu( -+ rpf->AddressReply.ReplyFrameAddress); -+ if (reply > ioc->reply_dma_max_address || -+ reply < ioc->reply_dma_min_address) -+ reply = 0; -+ if (smid) { -+ cb_idx = _base_get_cb_idx(ioc, smid); -+ if ((likely(cb_idx < MPT_MAX_CALLBACKS)) && -+ (likely(mpt_callbacks[cb_idx] != NULL))) { -+ rc = mpt_callbacks[cb_idx](ioc, smid, -+ msix_index, reply); -+ if (reply) -+ _base_display_reply_info(ioc, -+ smid, msix_index, reply); -+ if (rc) -+ mpt2sas_base_free_smid(ioc, -+ smid); -+ } -+ } else { -+ _base_async_event(ioc, msix_index, reply); -+ } -+ -+ /* reply free queue handling */ -+ if (reply) { -+ ioc->reply_free_host_index = -+ (ioc->reply_free_host_index == -+ (ioc->reply_free_queue_depth - 1)) ? -+ 0 : ioc->reply_free_host_index + 1; -+ ioc->reply_free[ioc->reply_free_host_index] = -+ cpu_to_le32(reply); -+ wmb(); -+ writel(ioc->reply_free_host_index, -+ &ioc->chip->ReplyFreeHostIndex); -+ } -+ } -+ -+ rpf->Words = cpu_to_le64(ULLONG_MAX); -+ reply_q->reply_post_host_index = -+ (reply_q->reply_post_host_index == -+ (ioc->reply_post_queue_depth - 1)) ? 0 : -+ reply_q->reply_post_host_index + 1; -+ request_desript_type = -+ reply_q->reply_post_free[reply_q->reply_post_host_index]. -+ Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; -+ completed_cmds++; -+ if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) -+ goto out; -+ if (!reply_q->reply_post_host_index) -+ rpf = reply_q->reply_post_free; -+ else -+ rpf++; -+ } while (1); -+ -+ out: -+ -+ if (!completed_cmds) { -+ atomic_dec(&reply_q->busy); -+ return IRQ_NONE; -+ } -+ -+ wmb(); -+ if (ioc->is_warpdrive) { -+ writel(reply_q->reply_post_host_index, -+ ioc->reply_post_host_index[msix_index]); -+ atomic_dec(&reply_q->busy); -+ return IRQ_HANDLED; -+ } -+ -+ /* Update Reply Post Host Index. -+ * For those HBA's which support combined reply queue feature -+ * 1. Get the correct Supplemental Reply Post Host Index Register. -+ * i.e. (msix_index / 8)th entry from Supplemental Reply Post Host -+ * Index Register address bank i.e replyPostRegisterIndex[], -+ * 2. Then update this register with new reply host index value -+ * in ReplyPostIndex field and the MSIxIndex field with -+ * msix_index value reduced to a value between 0 and 7, -+ * using a modulo 8 operation. Since each Supplemental Reply Post -+ * Host Index Register supports 8 MSI-X vectors. -+ * -+ * For other HBA's just update the Reply Post Host Index register with -+ * new reply host index value in ReplyPostIndex Field and msix_index -+ * value in MSIxIndex field. -+ */ -+ if (ioc->msix96_vector) -+ writel(reply_q->reply_post_host_index | ((msix_index & 7) << -+ MPI2_RPHI_MSIX_INDEX_SHIFT), -+ ioc->replyPostRegisterIndex[msix_index/8]); -+ else -+ writel(reply_q->reply_post_host_index | (msix_index << -+ MPI2_RPHI_MSIX_INDEX_SHIFT), -+ &ioc->chip->ReplyPostHostIndex); -+ atomic_dec(&reply_q->busy); -+ return IRQ_HANDLED; -+} -+ -+/** -+ * _base_is_controller_msix_enabled - is controller support muli-reply queues -+ * @ioc: per adapter object -+ * -+ */ -+static inline int -+_base_is_controller_msix_enabled(struct MPT3SAS_ADAPTER *ioc) -+{ -+ return (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable; -+} -+ -+/** -+ * mpt2sas_base_sync_reply_irqs - flush pending MSIX interrupts -+ * @ioc: per adapter object -+ * Context: non ISR conext -+ * -+ * Called when a Task Management request has completed. -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct adapter_reply_queue *reply_q; -+ -+ /* If MSIX capability is turned off -+ * then multi-queues are not enabled -+ */ -+ if (!_base_is_controller_msix_enabled(ioc)) -+ return; -+ -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery) -+ return; -+ /* TMs are on msix_index == 0 */ -+ if (reply_q->msix_index == 0) -+ continue; -+ synchronize_irq(reply_q->vector); -+ } -+} -+ -+/** -+ * mpt2sas_base_release_callback_handler - clear interrupt callback handler -+ * @cb_idx: callback index -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_release_callback_handler(u8 cb_idx) -+{ -+ mpt_callbacks[cb_idx] = NULL; -+} -+ -+/** -+ * mpt2sas_base_register_callback_handler - obtain index for the interrupt callback handler -+ * @cb_func: callback function -+ * -+ * Returns cb_func. -+ */ -+u8 -+mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func) -+{ -+ u8 cb_idx; -+ -+ for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--) -+ if (mpt_callbacks[cb_idx] == NULL) -+ break; -+ -+ mpt_callbacks[cb_idx] = cb_func; -+ return cb_idx; -+} -+ -+/** -+ * mpt2sas_base_initialize_callback_handler - initialize the interrupt callback handler -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_initialize_callback_handler(void) -+{ -+ u8 cb_idx; -+ -+ for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++) -+ mpt2sas_base_release_callback_handler(cb_idx); -+} -+ -+ -+/** -+ * _base_build_zero_len_sge - build zero length sg entry -+ * @ioc: per adapter object -+ * @paddr: virtual address for SGE -+ * -+ * Create a zero length scatter gather entry to insure the IOCs hardware has -+ * something to use if the target device goes brain dead and tries -+ * to send data even when none is asked for. -+ * -+ * Return nothing. -+ */ -+static void -+_base_build_zero_len_sge(struct MPT3SAS_ADAPTER *ioc, void *paddr) -+{ -+ u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT | -+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST | -+ MPI2_SGE_FLAGS_SIMPLE_ELEMENT) << -+ MPI2_SGE_FLAGS_SHIFT); -+ ioc->base_add_sg_single(paddr, flags_length, -1); -+} -+ -+/** -+ * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr. -+ * @paddr: virtual address for SGE -+ * @flags_length: SGE flags and data transfer length -+ * @dma_addr: Physical address -+ * -+ * Return nothing. -+ */ -+static void -+_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr) -+{ -+ Mpi2SGESimple32_t *sgel = paddr; -+ -+ flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING | -+ MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; -+ sgel->FlagsLength = cpu_to_le32(flags_length); -+ sgel->Address = cpu_to_le32(dma_addr); -+} -+ -+ -+/** -+ * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr. -+ * @paddr: virtual address for SGE -+ * @flags_length: SGE flags and data transfer length -+ * @dma_addr: Physical address -+ * -+ * Return nothing. -+ */ -+static void -+_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr) -+{ -+ Mpi2SGESimple64_t *sgel = paddr; -+ -+ flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING | -+ MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; -+ sgel->FlagsLength = cpu_to_le32(flags_length); -+ sgel->Address = cpu_to_le64(dma_addr); -+} -+ -+/** -+ * _base_get_chain_buffer_tracker - obtain chain tracker -+ * @ioc: per adapter object -+ * @smid: smid associated to an IO request -+ * -+ * Returns chain tracker(from ioc->free_chain_list) -+ */ -+static struct chain_tracker * -+_base_get_chain_buffer_tracker(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ struct chain_tracker *chain_req; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (list_empty(&ioc->free_chain_list)) { -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "chain buffers not available\n", ioc->name)); -+ return NULL; -+ } -+ chain_req = list_entry(ioc->free_chain_list.next, -+ struct chain_tracker, tracker_list); -+ list_del_init(&chain_req->tracker_list); -+ list_add_tail(&chain_req->tracker_list, -+ &ioc->scsi_lookup[smid - 1].chain_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return chain_req; -+} -+ -+ -+/** -+ * _base_build_sg - build generic sg -+ * @ioc: per adapter object -+ * @psge: virtual address for SGE -+ * @data_out_dma: physical address for WRITES -+ * @data_out_sz: data xfer size for WRITES -+ * @data_in_dma: physical address for READS -+ * @data_in_sz: data xfer size for READS -+ * -+ * Return nothing. -+ */ -+static void -+_base_build_sg(struct MPT3SAS_ADAPTER *ioc, void *psge, -+ dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, -+ size_t data_in_sz) -+{ -+ u32 sgl_flags; -+ -+ if (!data_out_sz && !data_in_sz) { -+ _base_build_zero_len_sge(ioc, psge); -+ return; -+ } -+ -+ if (data_out_sz && data_in_sz) { -+ /* WRITE sgel first */ -+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ ioc->base_add_sg_single(psge, sgl_flags | -+ data_out_sz, data_out_dma); -+ -+ /* incr sgel */ -+ psge += ioc->sge_size; -+ -+ /* READ sgel last */ -+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | -+ MPI2_SGE_FLAGS_END_OF_LIST); -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ ioc->base_add_sg_single(psge, sgl_flags | -+ data_in_sz, data_in_dma); -+ } else if (data_out_sz) /* WRITE */ { -+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | -+ MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC); -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ ioc->base_add_sg_single(psge, sgl_flags | -+ data_out_sz, data_out_dma); -+ } else if (data_in_sz) /* READ */ { -+ sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | -+ MPI2_SGE_FLAGS_END_OF_LIST); -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ ioc->base_add_sg_single(psge, sgl_flags | -+ data_in_sz, data_in_dma); -+ } -+} -+ -+/* IEEE format sgls */ -+ -+/** -+ * _base_add_sg_single_ieee - add sg element for IEEE format -+ * @paddr: virtual address for SGE -+ * @flags: SGE flags -+ * @chain_offset: number of 128 byte elements from start of segment -+ * @length: data transfer length -+ * @dma_addr: Physical address -+ * -+ * Return nothing. -+ */ -+static void -+_base_add_sg_single_ieee(void *paddr, u8 flags, u8 chain_offset, u32 length, -+ dma_addr_t dma_addr) -+{ -+ Mpi25IeeeSgeChain64_t *sgel = paddr; -+ -+ sgel->Flags = flags; -+ sgel->NextChainOffset = chain_offset; -+ sgel->Length = cpu_to_le32(length); -+ sgel->Address = cpu_to_le64(dma_addr); -+} -+ -+/** -+ * _base_build_zero_len_sge_ieee - build zero length sg entry for IEEE format -+ * @ioc: per adapter object -+ * @paddr: virtual address for SGE -+ * -+ * Create a zero length scatter gather entry to insure the IOCs hardware has -+ * something to use if the target device goes brain dead and tries -+ * to send data even when none is asked for. -+ * -+ * Return nothing. -+ */ -+static void -+_base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr) -+{ -+ u8 sgl_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR | -+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST); -+ -+ _base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1); -+} -+ -+/** -+ * _base_build_sg_scmd - main sg creation routine -+ * @ioc: per adapter object -+ * @scmd: scsi command -+ * @smid: system request message index -+ * Context: none. -+ * -+ * The main routine that builds scatter gather table from a given -+ * scsi request sent via the .queuecommand main handler. -+ * -+ * Returns 0 success, anything else error -+ */ -+static int -+_base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc, -+ struct scsi_cmnd *scmd, u16 smid) -+{ -+ Mpi2SCSIIORequest_t *mpi_request; -+ dma_addr_t chain_dma; -+ struct scatterlist *sg_scmd; -+ void *sg_local, *chain; -+ u32 chain_offset; -+ u32 chain_length; -+ u32 chain_flags; -+ int sges_left; -+ u32 sges_in_segment; -+ u32 sgl_flags; -+ u32 sgl_flags_last_element; -+ u32 sgl_flags_end_buffer; -+ struct chain_tracker *chain_req; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ -+ /* init scatter gather flags */ -+ sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT; -+ if (scmd->sc_data_direction == DMA_TO_DEVICE) -+ sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC; -+ sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT) -+ << MPI2_SGE_FLAGS_SHIFT; -+ sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT | -+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST) -+ << MPI2_SGE_FLAGS_SHIFT; -+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -+ -+ sg_scmd = scsi_sglist(scmd); -+ sges_left = scsi_dma_map(scmd); -+ if (sges_left < 0) { -+ sdev_printk(KERN_ERR, scmd->device, -+ "pci_map_sg failed: request for %d bytes!\n", -+ scsi_bufflen(scmd)); -+ return -ENOMEM; -+ } -+ -+ sg_local = &mpi_request->SGL; -+ sges_in_segment = ioc->max_sges_in_main_message; -+ if (sges_left <= sges_in_segment) -+ goto fill_in_last_segment; -+ -+ mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) + -+ (sges_in_segment * ioc->sge_size))/4; -+ -+ /* fill in main message segment when there is a chain following */ -+ while (sges_in_segment) { -+ if (sges_in_segment == 1) -+ ioc->base_add_sg_single(sg_local, -+ sgl_flags_last_element | sg_dma_len(sg_scmd), -+ sg_dma_address(sg_scmd)); -+ else -+ ioc->base_add_sg_single(sg_local, sgl_flags | -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size; -+ sges_left--; -+ sges_in_segment--; -+ } -+ -+ /* initializing the chain flags and pointers */ -+ chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; -+ chain_req = _base_get_chain_buffer_tracker(ioc, smid); -+ if (!chain_req) -+ return -1; -+ chain = chain_req->chain_buffer; -+ chain_dma = chain_req->chain_buffer_dma; -+ do { -+ sges_in_segment = (sges_left <= -+ ioc->max_sges_in_chain_message) ? sges_left : -+ ioc->max_sges_in_chain_message; -+ chain_offset = (sges_left == sges_in_segment) ? -+ 0 : (sges_in_segment * ioc->sge_size)/4; -+ chain_length = sges_in_segment * ioc->sge_size; -+ if (chain_offset) { -+ chain_offset = chain_offset << -+ MPI2_SGE_CHAIN_OFFSET_SHIFT; -+ chain_length += ioc->sge_size; -+ } -+ ioc->base_add_sg_single(sg_local, chain_flags | chain_offset | -+ chain_length, chain_dma); -+ sg_local = chain; -+ if (!chain_offset) -+ goto fill_in_last_segment; -+ -+ /* fill in chain segments */ -+ while (sges_in_segment) { -+ if (sges_in_segment == 1) -+ ioc->base_add_sg_single(sg_local, -+ sgl_flags_last_element | -+ sg_dma_len(sg_scmd), -+ sg_dma_address(sg_scmd)); -+ else -+ ioc->base_add_sg_single(sg_local, sgl_flags | -+ sg_dma_len(sg_scmd), -+ sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size; -+ sges_left--; -+ sges_in_segment--; -+ } -+ -+ chain_req = _base_get_chain_buffer_tracker(ioc, smid); -+ if (!chain_req) -+ return -1; -+ chain = chain_req->chain_buffer; -+ chain_dma = chain_req->chain_buffer_dma; -+ } while (1); -+ -+ -+ fill_in_last_segment: -+ -+ /* fill the last segment */ -+ while (sges_left) { -+ if (sges_left == 1) -+ ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer | -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ else -+ ioc->base_add_sg_single(sg_local, sgl_flags | -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size; -+ sges_left--; -+ } -+ -+ return 0; -+} -+ -+/** -+ * _base_build_sg_scmd_ieee - main sg creation routine for IEEE format -+ * @ioc: per adapter object -+ * @scmd: scsi command -+ * @smid: system request message index -+ * Context: none. -+ * -+ * The main routine that builds scatter gather table from a given -+ * scsi request sent via the .queuecommand main handler. -+ * -+ * Returns 0 success, anything else error -+ */ -+static int -+_base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, -+ struct scsi_cmnd *scmd, u16 smid) -+{ -+ Mpi2SCSIIORequest_t *mpi_request; -+ dma_addr_t chain_dma; -+ struct scatterlist *sg_scmd; -+ void *sg_local, *chain; -+ u32 chain_offset; -+ u32 chain_length; -+ int sges_left; -+ u32 sges_in_segment; -+ u8 simple_sgl_flags; -+ u8 simple_sgl_flags_last; -+ u8 chain_sgl_flags; -+ struct chain_tracker *chain_req; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ -+ /* init scatter gather flags */ -+ simple_sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ simple_sgl_flags_last = simple_sgl_flags | -+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST; -+ chain_sgl_flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ -+ sg_scmd = scsi_sglist(scmd); -+ sges_left = scsi_dma_map(scmd); -+ if (sges_left < 0) { -+ sdev_printk(KERN_ERR, scmd->device, -+ "pci_map_sg failed: request for %d bytes!\n", -+ scsi_bufflen(scmd)); -+ return -ENOMEM; -+ } -+ -+ sg_local = &mpi_request->SGL; -+ sges_in_segment = (ioc->request_sz - -+ offsetof(Mpi2SCSIIORequest_t, SGL))/ioc->sge_size_ieee; -+ if (sges_left <= sges_in_segment) -+ goto fill_in_last_segment; -+ -+ mpi_request->ChainOffset = (sges_in_segment - 1 /* chain element */) + -+ (offsetof(Mpi2SCSIIORequest_t, SGL)/ioc->sge_size_ieee); -+ -+ /* fill in main message segment when there is a chain following */ -+ while (sges_in_segment > 1) { -+ _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size_ieee; -+ sges_left--; -+ sges_in_segment--; -+ } -+ -+ /* initializing the pointers */ -+ chain_req = _base_get_chain_buffer_tracker(ioc, smid); -+ if (!chain_req) -+ return -1; -+ chain = chain_req->chain_buffer; -+ chain_dma = chain_req->chain_buffer_dma; -+ do { -+ sges_in_segment = (sges_left <= -+ ioc->max_sges_in_chain_message) ? sges_left : -+ ioc->max_sges_in_chain_message; -+ chain_offset = (sges_left == sges_in_segment) ? -+ 0 : sges_in_segment; -+ chain_length = sges_in_segment * ioc->sge_size_ieee; -+ if (chain_offset) -+ chain_length += ioc->sge_size_ieee; -+ _base_add_sg_single_ieee(sg_local, chain_sgl_flags, -+ chain_offset, chain_length, chain_dma); -+ -+ sg_local = chain; -+ if (!chain_offset) -+ goto fill_in_last_segment; -+ -+ /* fill in chain segments */ -+ while (sges_in_segment) { -+ _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size_ieee; -+ sges_left--; -+ sges_in_segment--; -+ } -+ -+ chain_req = _base_get_chain_buffer_tracker(ioc, smid); -+ if (!chain_req) -+ return -1; -+ chain = chain_req->chain_buffer; -+ chain_dma = chain_req->chain_buffer_dma; -+ } while (1); -+ -+ -+ fill_in_last_segment: -+ -+ /* fill the last segment */ -+ while (sges_left > 0) { -+ if (sges_left == 1) -+ _base_add_sg_single_ieee(sg_local, -+ simple_sgl_flags_last, 0, sg_dma_len(sg_scmd), -+ sg_dma_address(sg_scmd)); -+ else -+ _base_add_sg_single_ieee(sg_local, simple_sgl_flags, 0, -+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); -+ sg_scmd = sg_next(sg_scmd); -+ sg_local += ioc->sge_size_ieee; -+ sges_left--; -+ } -+ -+ return 0; -+} -+ -+/** -+ * _base_build_sg_ieee - build generic sg for IEEE format -+ * @ioc: per adapter object -+ * @psge: virtual address for SGE -+ * @data_out_dma: physical address for WRITES -+ * @data_out_sz: data xfer size for WRITES -+ * @data_in_dma: physical address for READS -+ * @data_in_sz: data xfer size for READS -+ * -+ * Return nothing. -+ */ -+static void -+_base_build_sg_ieee(struct MPT3SAS_ADAPTER *ioc, void *psge, -+ dma_addr_t data_out_dma, size_t data_out_sz, dma_addr_t data_in_dma, -+ size_t data_in_sz) -+{ -+ u8 sgl_flags; -+ -+ if (!data_out_sz && !data_in_sz) { -+ _base_build_zero_len_sge_ieee(ioc, psge); -+ return; -+ } -+ -+ if (data_out_sz && data_in_sz) { -+ /* WRITE sgel first */ -+ sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ _base_add_sg_single_ieee(psge, sgl_flags, 0, data_out_sz, -+ data_out_dma); -+ -+ /* incr sgel */ -+ psge += ioc->sge_size_ieee; -+ -+ /* READ sgel last */ -+ sgl_flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST; -+ _base_add_sg_single_ieee(psge, sgl_flags, 0, data_in_sz, -+ data_in_dma); -+ } else if (data_out_sz) /* WRITE */ { -+ sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ _base_add_sg_single_ieee(psge, sgl_flags, 0, data_out_sz, -+ data_out_dma); -+ } else if (data_in_sz) /* READ */ { -+ sgl_flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | -+ MPI25_IEEE_SGE_FLAGS_END_OF_LIST | -+ MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; -+ _base_add_sg_single_ieee(psge, sgl_flags, 0, data_in_sz, -+ data_in_dma); -+ } -+} -+ -+#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10)) -+ -+/** -+ * _base_config_dma_addressing - set dma addressing -+ * @ioc: per adapter object -+ * @pdev: PCI device struct -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) -+{ -+ struct sysinfo s; -+ u64 consistent_dma_mask; -+ -+ if (ioc->dma_mask) -+ consistent_dma_mask = DMA_BIT_MASK(64); -+ else -+ consistent_dma_mask = DMA_BIT_MASK(32); -+ -+ if (sizeof(dma_addr_t) > 4) { -+ const uint64_t required_mask = -+ dma_get_required_mask(&pdev->dev); -+ if ((required_mask > DMA_BIT_MASK(32)) && -+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && -+ !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) { -+ ioc->base_add_sg_single = &_base_add_sg_single_64; -+ ioc->sge_size = sizeof(Mpi2SGESimple64_t); -+ ioc->dma_mask = 64; -+ goto out; -+ } -+ } -+ -+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) -+ && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { -+ ioc->base_add_sg_single = &_base_add_sg_single_32; -+ ioc->sge_size = sizeof(Mpi2SGESimple32_t); -+ ioc->dma_mask = 32; -+ } else -+ return -ENODEV; -+ -+ out: -+ si_meminfo(&s); -+ pr_info(MPT3SAS_FMT -+ "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", -+ ioc->name, ioc->dma_mask, convert_to_kb(s.totalram)); -+ -+ return 0; -+} -+ -+static int -+_base_change_consistent_dma_mask(struct MPT3SAS_ADAPTER *ioc, -+ struct pci_dev *pdev) -+{ -+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { -+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+/** -+ * _base_check_enable_msix - checks MSIX capabable. -+ * @ioc: per adapter object -+ * -+ * Check to see if card is capable of MSIX, and set number -+ * of available msix vectors -+ */ -+static int -+_base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int base; -+ u16 message_control; -+ -+ /* Check whether controller SAS2008 B0 controller, -+ * if it is SAS2008 B0 controller use IO-APIC instead of MSIX -+ */ -+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && -+ ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) { -+ return -EINVAL; -+ } -+ -+ base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); -+ if (!base) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n", -+ ioc->name)); -+ return -EINVAL; -+ } -+ -+ /* get msix vector count */ -+ /* NUMA_IO not supported for older controllers */ -+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || -+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) -+ ioc->msix_vector_count = 1; -+ else { -+ pci_read_config_word(ioc->pdev, base + 2, &message_control); -+ ioc->msix_vector_count = (message_control & 0x3FF) + 1; -+ } -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "msix is supported, vector_count(%d)\n", -+ ioc->name, ioc->msix_vector_count)); -+ return 0; -+} -+ -+/** -+ * _base_free_irq - free irq -+ * @ioc: per adapter object -+ * -+ * Freeing respective reply_queue from the list. -+ */ -+static void -+_base_free_irq(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct adapter_reply_queue *reply_q, *next; -+ -+ if (list_empty(&ioc->reply_queue_list)) -+ return; -+ -+ list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { -+ list_del(&reply_q->list); -+ if (smp_affinity_enable) { -+ irq_set_affinity_hint(reply_q->vector, NULL); -+ free_cpumask_var(reply_q->affinity_hint); -+ } -+ free_irq(reply_q->vector, reply_q); -+ kfree(reply_q); -+ } -+} -+ -+/** -+ * _base_request_irq - request irq -+ * @ioc: per adapter object -+ * @index: msix index into vector table -+ * @vector: irq vector -+ * -+ * Inserting respective reply_queue into the list. -+ */ -+static int -+_base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector) -+{ -+ struct adapter_reply_queue *reply_q; -+ int r; -+ -+ reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); -+ if (!reply_q) { -+ pr_err(MPT3SAS_FMT "unable to allocate memory %d!\n", -+ ioc->name, (int)sizeof(struct adapter_reply_queue)); -+ return -ENOMEM; -+ } -+ reply_q->ioc = ioc; -+ reply_q->msix_index = index; -+ reply_q->vector = vector; -+ -+ if (smp_affinity_enable) { -+ if (!zalloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) { -+ kfree(reply_q); -+ return -ENOMEM; -+ } -+ } -+ -+ atomic_set(&reply_q->busy, 0); -+ if (ioc->msix_enable) -+ snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", -+ ioc->driver_name, ioc->id, index); -+ else -+ snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", -+ ioc->driver_name, ioc->id); -+ r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, -+ reply_q); -+ if (r) { -+ pr_err(MPT3SAS_FMT "unable to allocate interrupt %d!\n", -+ reply_q->name, vector); -+ free_cpumask_var(reply_q->affinity_hint); -+ kfree(reply_q); -+ return -EBUSY; -+ } -+ -+ INIT_LIST_HEAD(&reply_q->list); -+ list_add_tail(&reply_q->list, &ioc->reply_queue_list); -+ return 0; -+} -+ -+/** -+ * _base_assign_reply_queues - assigning msix index for each cpu -+ * @ioc: per adapter object -+ * -+ * The enduser would need to set the affinity via /proc/irq/#/smp_affinity -+ * -+ * It would nice if we could call irq_set_affinity, however it is not -+ * an exported symbol -+ */ -+static void -+_base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) -+{ -+ unsigned int cpu, nr_cpus, nr_msix, index = 0; -+ struct adapter_reply_queue *reply_q; -+ -+ if (!_base_is_controller_msix_enabled(ioc)) -+ return; -+ -+ memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); -+ -+ nr_cpus = num_online_cpus(); -+ nr_msix = ioc->reply_queue_count = min(ioc->reply_queue_count, -+ ioc->facts.MaxMSIxVectors); -+ if (!nr_msix) -+ return; -+ -+ cpu = cpumask_first(cpu_online_mask); -+ -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { -+ -+ unsigned int i, group = nr_cpus / nr_msix; -+ -+ if (cpu >= nr_cpus) -+ break; -+ -+ if (index < nr_cpus % nr_msix) -+ group++; -+ -+ for (i = 0 ; i < group ; i++) { -+ ioc->cpu_msix_table[cpu] = index; -+ if (smp_affinity_enable) -+ cpumask_or(reply_q->affinity_hint, -+ reply_q->affinity_hint, get_cpu_mask(cpu)); -+ cpu = cpumask_next(cpu, cpu_online_mask); -+ } -+ if (smp_affinity_enable) -+ if (irq_set_affinity_hint(reply_q->vector, -+ reply_q->affinity_hint)) -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "Err setting affinity hint to irq vector %d\n", -+ ioc->name, reply_q->vector)); -+ index++; -+ } -+} -+ -+/** -+ * _base_disable_msix - disables msix -+ * @ioc: per adapter object -+ * -+ */ -+static void -+_base_disable_msix(struct MPT3SAS_ADAPTER *ioc) -+{ -+ if (!ioc->msix_enable) -+ return; -+ pci_disable_msix(ioc->pdev); -+ ioc->msix_enable = 0; -+} -+ -+/** -+ * _base_enable_msix - enables msix, failback to io_apic -+ * @ioc: per adapter object -+ * -+ */ -+static int -+_base_enable_msix(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct msix_entry *entries, *a; -+ int r; -+ int i; -+ u8 try_msix = 0; -+ -+ if (msix_disable == -1 || msix_disable == 0) -+ try_msix = 1; -+ -+ if (!try_msix) -+ goto try_ioapic; -+ -+ if (_base_check_enable_msix(ioc) != 0) -+ goto try_ioapic; -+ -+ ioc->reply_queue_count = min_t(int, ioc->cpu_count, -+ ioc->msix_vector_count); -+ -+ printk(MPT3SAS_FMT "MSI-X vectors supported: %d, no of cores" -+ ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count, -+ ioc->cpu_count, max_msix_vectors); -+ -+ if (!ioc->rdpq_array_enable && max_msix_vectors == -1) -+ max_msix_vectors = 8; -+ -+ if (max_msix_vectors > 0) { -+ ioc->reply_queue_count = min_t(int, max_msix_vectors, -+ ioc->reply_queue_count); -+ ioc->msix_vector_count = ioc->reply_queue_count; -+ } else if (max_msix_vectors == 0) -+ goto try_ioapic; -+ -+ if (ioc->msix_vector_count < ioc->cpu_count) -+ smp_affinity_enable = 0; -+ -+ entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry), -+ GFP_KERNEL); -+ if (!entries) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT -+ "kcalloc failed @ at %s:%d/%s() !!!\n", -+ ioc->name, __FILE__, __LINE__, __func__)); -+ goto try_ioapic; -+ } -+ -+ for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) -+ a->entry = i; -+ -+ r = pci_enable_msix_exact(ioc->pdev, entries, ioc->reply_queue_count); -+ if (r) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT -+ "pci_enable_msix_exact failed (r=%d) !!!\n", -+ ioc->name, r)); -+ kfree(entries); -+ goto try_ioapic; -+ } -+ -+ ioc->msix_enable = 1; -+ for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) { -+ r = _base_request_irq(ioc, i, a->vector); -+ if (r) { -+ _base_free_irq(ioc); -+ _base_disable_msix(ioc); -+ kfree(entries); -+ goto try_ioapic; -+ } -+ } -+ -+ kfree(entries); -+ return 0; -+ -+/* failback to io_apic interrupt routing */ -+ try_ioapic: -+ -+ ioc->reply_queue_count = 1; -+ r = _base_request_irq(ioc, 0, ioc->pdev->irq); -+ -+ return r; -+} -+ -+/** -+ * mpt2sas_base_unmap_resources - free controller resources -+ * @ioc: per adapter object -+ */ -+void -+mpt2sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct pci_dev *pdev = ioc->pdev; -+ -+ dexitprintk(ioc, printk(MPT3SAS_FMT "%s\n", -+ ioc->name, __func__)); -+ -+ _base_free_irq(ioc); -+ _base_disable_msix(ioc); -+ -+ if (ioc->msix96_vector) { -+ kfree(ioc->replyPostRegisterIndex); -+ ioc->replyPostRegisterIndex = NULL; -+ } -+ -+ if (ioc->chip_phys) { -+ iounmap(ioc->chip); -+ ioc->chip_phys = 0; -+ } -+ -+ if (pci_is_enabled(pdev)) { -+ pci_release_selected_regions(ioc->pdev, ioc->bars); -+ pci_disable_pcie_error_reporting(pdev); -+ pci_disable_device(pdev); -+ } -+} -+ -+/** -+ * mpt2sas_base_map_resources - map in controller resources (io/irq/memap) -+ * @ioc: per adapter object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct pci_dev *pdev = ioc->pdev; -+ u32 memap_sz; -+ u32 pio_sz; -+ int i, r = 0; -+ u64 pio_chip = 0; -+ u64 chip_phys = 0; -+ struct adapter_reply_queue *reply_q; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", -+ ioc->name, __func__)); -+ -+ ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); -+ if (pci_enable_device_mem(pdev)) { -+ pr_warn(MPT3SAS_FMT "pci_enable_device_mem: failed\n", -+ ioc->name); -+ ioc->bars = 0; -+ return -ENODEV; -+ } -+ -+ -+ if (pci_request_selected_regions(pdev, ioc->bars, -+ ioc->driver_name)) { -+ pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n", -+ ioc->name); -+ ioc->bars = 0; -+ r = -ENODEV; -+ goto out_fail; -+ } -+ -+/* AER (Advanced Error Reporting) hooks */ -+ pci_enable_pcie_error_reporting(pdev); -+ -+ pci_set_master(pdev); -+ -+ -+ if (_base_config_dma_addressing(ioc, pdev) != 0) { -+ pr_warn(MPT3SAS_FMT "no suitable DMA mask for %s\n", -+ ioc->name, pci_name(pdev)); -+ r = -ENODEV; -+ goto out_fail; -+ } -+ -+ for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) && -+ (!memap_sz || !pio_sz); i++) { -+ if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { -+ if (pio_sz) -+ continue; -+ pio_chip = (u64)pci_resource_start(pdev, i); -+ pio_sz = pci_resource_len(pdev, i); -+ } else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { -+ if (memap_sz) -+ continue; -+ ioc->chip_phys = pci_resource_start(pdev, i); -+ chip_phys = (u64)ioc->chip_phys; -+ memap_sz = pci_resource_len(pdev, i); -+ ioc->chip = ioremap(ioc->chip_phys, memap_sz); -+ } -+ } -+ -+ if (ioc->chip == NULL) { -+ pr_err(MPT3SAS_FMT "unable to map adapter memory! " -+ " or resource not found\n", ioc->name); -+ r = -EINVAL; -+ goto out_fail; -+ } -+ -+ _base_mask_interrupts(ioc); -+ -+ r = _base_get_ioc_facts(ioc, CAN_SLEEP); -+ if (r) -+ goto out_fail; -+ -+ if (!ioc->rdpq_array_enable_assigned) { -+ ioc->rdpq_array_enable = ioc->rdpq_array_capable; -+ ioc->rdpq_array_enable_assigned = 1; -+ } -+ -+ r = _base_enable_msix(ioc); -+ if (r) -+ goto out_fail; -+ -+ /* Use the Combined reply queue feature only for SAS3 C0 & higher -+ * revision HBAs and also only when reply queue count is greater than 8 -+ */ -+ if (ioc->msix96_vector && ioc->reply_queue_count > 8) { -+ /* Determine the Supplemental Reply Post Host Index Registers -+ * Addresse. Supplemental Reply Post Host Index Registers -+ * starts at offset MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET and -+ * each register is at offset bytes of -+ * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET from previous one. -+ */ -+ ioc->replyPostRegisterIndex = kcalloc( -+ MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT, -+ sizeof(resource_size_t *), GFP_KERNEL); -+ if (!ioc->replyPostRegisterIndex) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "allocation for reply Post Register Index failed!!!\n", -+ ioc->name)); -+ r = -ENOMEM; -+ goto out_fail; -+ } -+ -+ for (i = 0; i < MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT; i++) { -+ ioc->replyPostRegisterIndex[i] = (resource_size_t *) -+ ((u8 *)&ioc->chip->Doorbell + -+ MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET + -+ (i * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET)); -+ } -+ } else -+ ioc->msix96_vector = 0; -+ -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) -+ pr_info(MPT3SAS_FMT "%s: IRQ %d\n", -+ reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : -+ "IO-APIC enabled"), reply_q->vector); -+ -+ pr_info(MPT3SAS_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", -+ ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); -+ pr_info(MPT3SAS_FMT "ioport(0x%016llx), size(%d)\n", -+ ioc->name, (unsigned long long)pio_chip, pio_sz); -+ -+ /* Save PCI configuration state for recovery from PCI AER/EEH errors */ -+ pci_save_state(pdev); -+ return 0; -+ -+ out_fail: -+ mpt2sas_base_unmap_resources(ioc); -+ return r; -+} -+ -+/** -+ * mpt2sas_base_get_msg_frame - obtain request mf pointer -+ * @ioc: per adapter object -+ * @smid: system request message index(smid zero is invalid) -+ * -+ * Returns virt pointer to message frame. -+ */ -+void * -+mpt2sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return (void *)(ioc->request + (smid * ioc->request_sz)); -+} -+ -+/** -+ * mpt2sas_base_get_sense_buffer - obtain a sense buffer virt addr -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns virt pointer to sense buffer. -+ */ -+void * -+mpt2sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); -+} -+ -+/** -+ * mpt2sas_base_get_sense_buffer_dma - obtain a sense buffer dma addr -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns phys pointer to the low 32bit address of the sense buffer. -+ */ -+__le32 -+mpt2sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return cpu_to_le32(ioc->sense_dma + ((smid - 1) * -+ SCSI_SENSE_BUFFERSIZE)); -+} -+ -+/** -+ * mpt2sas_base_get_reply_virt_addr - obtain reply frames virt address -+ * @ioc: per adapter object -+ * @phys_addr: lower 32 physical addr of the reply -+ * -+ * Converts 32bit lower physical addr into a virt address. -+ */ -+void * -+mpt2sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr) -+{ -+ if (!phys_addr) -+ return NULL; -+ return ioc->reply + (phys_addr - (u32)ioc->reply_dma); -+} -+ -+static inline u8 -+_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc) -+{ -+ return ioc->cpu_msix_table[raw_smp_processor_id()]; -+} -+ -+/** -+ * mpt2sas_base_get_smid - obtain a free smid from internal queue -+ * @ioc: per adapter object -+ * @cb_idx: callback index -+ * -+ * Returns smid (zero is invalid) -+ */ -+u16 -+mpt2sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx) -+{ -+ unsigned long flags; -+ struct request_tracker *request; -+ u16 smid; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (list_empty(&ioc->internal_free_list)) { -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ pr_err(MPT3SAS_FMT "%s: smid not available\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ request = list_entry(ioc->internal_free_list.next, -+ struct request_tracker, tracker_list); -+ request->cb_idx = cb_idx; -+ smid = request->smid; -+ list_del(&request->tracker_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return smid; -+} -+ -+/** -+ * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue -+ * @ioc: per adapter object -+ * @cb_idx: callback index -+ * @scmd: pointer to scsi command object -+ * -+ * Returns smid (zero is invalid) -+ */ -+u16 -+mpt2sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, -+ struct scsi_cmnd *scmd) -+{ -+ unsigned long flags; -+ struct scsiio_tracker *request; -+ u16 smid; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (list_empty(&ioc->free_list)) { -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ pr_err(MPT3SAS_FMT "%s: smid not available\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ request = list_entry(ioc->free_list.next, -+ struct scsiio_tracker, tracker_list); -+ request->scmd = scmd; -+ request->cb_idx = cb_idx; -+ smid = request->smid; -+ request->msix_io = _base_get_msix_index(ioc); -+ list_del(&request->tracker_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return smid; -+} -+ -+/** -+ * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue -+ * @ioc: per adapter object -+ * @cb_idx: callback index -+ * -+ * Returns smid (zero is invalid) -+ */ -+u16 -+mpt2sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx) -+{ -+ unsigned long flags; -+ struct request_tracker *request; -+ u16 smid; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (list_empty(&ioc->hpr_free_list)) { -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return 0; -+ } -+ -+ request = list_entry(ioc->hpr_free_list.next, -+ struct request_tracker, tracker_list); -+ request->cb_idx = cb_idx; -+ smid = request->smid; -+ list_del(&request->tracker_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return smid; -+} -+ -+/** -+ * mpt2sas_base_free_smid - put smid back on free_list -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ unsigned long flags; -+ int i; -+ struct chain_tracker *chain_req, *next; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ if (smid < ioc->hi_priority_smid) { -+ /* scsiio queue */ -+ i = smid - 1; -+ if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { -+ list_for_each_entry_safe(chain_req, next, -+ &ioc->scsi_lookup[i].chain_list, tracker_list) { -+ list_del_init(&chain_req->tracker_list); -+ list_add(&chain_req->tracker_list, -+ &ioc->free_chain_list); -+ } -+ } -+ ioc->scsi_lookup[i].cb_idx = 0xFF; -+ ioc->scsi_lookup[i].scmd = NULL; -+ ioc->scsi_lookup[i].direct_io = 0; -+ list_add(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ /* -+ * See _wait_for_commands_to_complete() call with regards -+ * to this code. -+ */ -+ if (ioc->shost_recovery && ioc->pending_io_count) { -+ if (ioc->pending_io_count == 1) -+ wake_up(&ioc->reset_wq); -+ ioc->pending_io_count--; -+ } -+ return; -+ } else if (smid < ioc->internal_smid) { -+ /* hi-priority */ -+ i = smid - ioc->hi_priority_smid; -+ ioc->hpr_lookup[i].cb_idx = 0xFF; -+ list_add(&ioc->hpr_lookup[i].tracker_list, &ioc->hpr_free_list); -+ } else if (smid <= ioc->hba_queue_depth) { -+ /* internal queue */ -+ i = smid - ioc->internal_smid; -+ ioc->internal_lookup[i].cb_idx = 0xFF; -+ list_add(&ioc->internal_lookup[i].tracker_list, -+ &ioc->internal_free_list); -+ } -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+} -+ -+/** -+ * _base_writeq - 64 bit write to MMIO -+ * @ioc: per adapter object -+ * @b: data payload -+ * @addr: address in MMIO space -+ * @writeq_lock: spin lock -+ * -+ * Glue for handling an atomic 64 bit word to MMIO. This special handling takes -+ * care of 32 bit environment where its not quarenteed to send the entire word -+ * in one transfer. -+ */ -+#if defined(writeq) && defined(CONFIG_64BIT) -+static inline void -+_base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) -+{ -+ writeq(cpu_to_le64(b), addr); -+} -+#else -+static inline void -+_base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) -+{ -+ unsigned long flags; -+ __u64 data_out = cpu_to_le64(b); -+ -+ spin_lock_irqsave(writeq_lock, flags); -+ writel((u32)(data_out), addr); -+ writel((u32)(data_out >> 32), (addr + 4)); -+ spin_unlock_irqrestore(writeq_lock, flags); -+} -+#endif -+ -+/** -+ * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @handle: device handle -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) -+{ -+ Mpi2RequestDescriptorUnion_t descriptor; -+ u64 *request = (u64 *)&descriptor; -+ -+ -+ descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; -+ descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); -+ descriptor.SCSIIO.SMID = cpu_to_le16(smid); -+ descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); -+ descriptor.SCSIIO.LMID = 0; -+ _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, -+ &ioc->scsi_lookup_lock); -+} -+ -+/** -+ * mpt2sas_base_put_smid_fast_path - send fast path request to firmware -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @handle: device handle -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u16 handle) -+{ -+ Mpi2RequestDescriptorUnion_t descriptor; -+ u64 *request = (u64 *)&descriptor; -+ -+ descriptor.SCSIIO.RequestFlags = -+ MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; -+ descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); -+ descriptor.SCSIIO.SMID = cpu_to_le16(smid); -+ descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); -+ descriptor.SCSIIO.LMID = 0; -+ _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, -+ &ioc->scsi_lookup_lock); -+} -+ -+/** -+ * mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_task: msix_task will be same as msix of IO incase of task abort else 0. -+ * Return nothing. -+ */ -+void -+mpt2sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u16 msix_task) -+{ -+ Mpi2RequestDescriptorUnion_t descriptor; -+ u64 *request = (u64 *)&descriptor; -+ -+ descriptor.HighPriority.RequestFlags = -+ MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; -+ descriptor.HighPriority.MSIxIndex = msix_task; -+ descriptor.HighPriority.SMID = cpu_to_le16(smid); -+ descriptor.HighPriority.LMID = 0; -+ descriptor.HighPriority.Reserved1 = 0; -+ _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, -+ &ioc->scsi_lookup_lock); -+} -+ -+/** -+ * mpt2sas_base_put_smid_default - Default, primarily used for config pages -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ Mpi2RequestDescriptorUnion_t descriptor; -+ u64 *request = (u64 *)&descriptor; -+ -+ descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; -+ descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); -+ descriptor.Default.SMID = cpu_to_le16(smid); -+ descriptor.Default.LMID = 0; -+ descriptor.Default.DescriptorTypeDependent = 0; -+ _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, -+ &ioc->scsi_lookup_lock); -+} -+ -+/** -+ * _base_display_OEMs_branding - Display branding string -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) -+{ -+ if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) -+ return; -+ -+ switch (ioc->pdev->subsystem_vendor) { -+ case PCI_VENDOR_ID_INTEL: -+ switch (ioc->pdev->device) { -+ case MPI2_MFGPAGE_DEVID_SAS2008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_INTEL_RMS2LL080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS2LL080_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS2LL040_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS2LL040_BRANDING); -+ break; -+ case MPT2SAS_INTEL_SSD910_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_SSD910_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Intel(R) Controller: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ case MPI2_MFGPAGE_DEVID_SAS2308_2: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_INTEL_RS25GB008_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RS25GB008_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25JB080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25JB080_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25JB040_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25JB040_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25KB080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25KB080_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25KB040_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25KB040_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25LB040_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25LB040_BRANDING); -+ break; -+ case MPT2SAS_INTEL_RMS25LB080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_INTEL_RMS25LB080_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Intel(R) Controller: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ case MPI25_MFGPAGE_DEVID_SAS3008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT3SAS_INTEL_RMS3JC080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_INTEL_RMS3JC080_BRANDING); -+ break; -+ -+ case MPT3SAS_INTEL_RS3GC008_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_INTEL_RS3GC008_BRANDING); -+ break; -+ case MPT3SAS_INTEL_RS3FC044_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_INTEL_RS3FC044_BRANDING); -+ break; -+ case MPT3SAS_INTEL_RS3UC080_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_INTEL_RS3UC080_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Intel(R) Controller: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Intel(R) Controller: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case PCI_VENDOR_ID_DELL: -+ switch (ioc->pdev->device) { -+ case MPI2_MFGPAGE_DEVID_SAS2008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING); -+ break; -+ case MPT2SAS_DELL_PERC_H200_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_PERC_H200_BRANDING); -+ break; -+ case MPT2SAS_DELL_6GBPS_SAS_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_DELL_6GBPS_SAS_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Dell 6Gbps HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case MPI25_MFGPAGE_DEVID_SAS3008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT3SAS_DELL_12G_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_DELL_12G_HBA_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Dell HBA: Subsystem ID: 0x%X\n", ioc->name, -+ ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case PCI_VENDOR_ID_CISCO: -+ switch (ioc->pdev->device) { -+ case MPI25_MFGPAGE_DEVID_SAS3008: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT3SAS_CISCO_12G_8E_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_8E_HBA_BRANDING); -+ break; -+ case MPT3SAS_CISCO_12G_8I_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_8I_HBA_BRANDING); -+ break; -+ case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case MPI25_MFGPAGE_DEVID_SAS3108_1: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); -+ break; -+ case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING -+ ); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "Cisco SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ break; -+ case MPT2SAS_HP_3PAR_SSVID: -+ switch (ioc->pdev->device) { -+ case MPI2_MFGPAGE_DEVID_SAS2004: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ case MPI2_MFGPAGE_DEVID_SAS2308_2: -+ switch (ioc->pdev->subsystem_device) { -+ case MPT2SAS_HP_2_4_INTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_2_4_INTERNAL_BRANDING); -+ break; -+ case MPT2SAS_HP_2_4_EXTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_2_4_EXTERNAL_BRANDING); -+ break; -+ case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); -+ break; -+ case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: -+ pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); -+ break; -+ default: -+ pr_info(MPT3SAS_FMT -+ "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ default: -+ pr_info(MPT3SAS_FMT -+ "HP SAS HBA: Subsystem ID: 0x%X\n", -+ ioc->name, ioc->pdev->subsystem_device); -+ break; -+ } -+ default: -+ break; -+ } -+} -+ -+/** -+ * _base_display_ioc_capabilities - Disply IOC's capabilities. -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int i = 0; -+ char desc[16]; -+ u32 iounit_pg1_flags; -+ u32 bios_version; -+ -+ bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); -+ strncpy(desc, ioc->manu_pg0.ChipName, 16); -+ pr_info(MPT3SAS_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "\ -+ "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n", -+ ioc->name, desc, -+ (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, -+ (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, -+ (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, -+ ioc->facts.FWVersion.Word & 0x000000FF, -+ ioc->pdev->revision, -+ (bios_version & 0xFF000000) >> 24, -+ (bios_version & 0x00FF0000) >> 16, -+ (bios_version & 0x0000FF00) >> 8, -+ bios_version & 0x000000FF); -+ -+ _base_display_OEMs_branding(ioc); -+ -+ pr_info(MPT3SAS_FMT "Protocol=(", ioc->name); -+ -+ if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { -+ pr_info("Initiator"); -+ i++; -+ } -+ -+ if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) { -+ pr_info("%sTarget", i ? "," : ""); -+ i++; -+ } -+ -+ i = 0; -+ pr_info("), "); -+ pr_info("Capabilities=("); -+ -+ if (!ioc->hide_ir_msg) { -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { -+ pr_info("Raid"); -+ i++; -+ } -+ } -+ -+ if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { -+ pr_info("%sTLR", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) { -+ pr_info("%sMulticast", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) { -+ pr_info("%sBIDI Target", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) { -+ pr_info("%sEEDP", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) { -+ pr_info("%sSnapshot Buffer", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) { -+ pr_info("%sDiag Trace Buffer", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { -+ pr_info("%sDiag Extended Buffer", i ? "," : ""); -+ i++; -+ } -+ -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { -+ pr_info("%sTask Set Full", i ? "," : ""); -+ i++; -+ } -+ -+ iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); -+ if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { -+ pr_info("%sNCQ", i ? "," : ""); -+ i++; -+ } -+ -+ pr_info(")\n"); -+} -+ -+/** -+ * mpt2sas_base_update_missing_delay - change the missing delay timers -+ * @ioc: per adapter object -+ * @device_missing_delay: amount of time till device is reported missing -+ * @io_missing_delay: interval IO is returned when there is a missing device -+ * -+ * Return nothing. -+ * -+ * Passed on the command line, this function will modify the device missing -+ * delay, as well as the io missing delay. This should be called at driver -+ * load time. -+ */ -+void -+mpt2sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, -+ u16 device_missing_delay, u8 io_missing_delay) -+{ -+ u16 dmd, dmd_new, dmd_orignal; -+ u8 io_missing_delay_original; -+ u16 sz; -+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; -+ Mpi2ConfigReply_t mpi_reply; -+ u8 num_phys = 0; -+ u16 ioc_status; -+ -+ mpt2sas_config_get_number_hba_phys(ioc, &num_phys); -+ if (!num_phys) -+ return; -+ -+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys * -+ sizeof(Mpi2SasIOUnit1PhyData_t)); -+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg1) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, -+ sas_iounit_pg1, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ /* device missing delay */ -+ dmd = sas_iounit_pg1->ReportDeviceMissingDelay; -+ if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) -+ dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; -+ else -+ dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; -+ dmd_orignal = dmd; -+ if (device_missing_delay > 0x7F) { -+ dmd = (device_missing_delay > 0x7F0) ? 0x7F0 : -+ device_missing_delay; -+ dmd = dmd / 16; -+ dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16; -+ } else -+ dmd = device_missing_delay; -+ sas_iounit_pg1->ReportDeviceMissingDelay = dmd; -+ -+ /* io missing delay */ -+ io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay; -+ sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay; -+ -+ if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, -+ sz)) { -+ if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) -+ dmd_new = (dmd & -+ MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; -+ else -+ dmd_new = -+ dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; -+ pr_info(MPT3SAS_FMT "device_missing_delay: old(%d), new(%d)\n", -+ ioc->name, dmd_orignal, dmd_new); -+ pr_info(MPT3SAS_FMT "ioc_missing_delay: old(%d), new(%d)\n", -+ ioc->name, io_missing_delay_original, -+ io_missing_delay); -+ ioc->device_missing_delay = dmd_new; -+ ioc->io_missing_delay = io_missing_delay; -+ } -+ -+out: -+ kfree(sas_iounit_pg1); -+} -+/** -+ * _base_static_config_pages - static start of day config pages -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ u32 iounit_pg1_flags; -+ -+ mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); -+ if (ioc->ir_firmware) -+ mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply, -+ &ioc->manu_pg10); -+ -+ /* -+ * Ensure correct T10 PI operation if vendor left EEDPTagMode -+ * flag unset in NVDATA. -+ */ -+ mpt2sas_config_get_manufacturing_pg11(ioc, &mpi_reply, &ioc->manu_pg11); -+ if (ioc->manu_pg11.EEDPTagMode == 0) { -+ pr_err("%s: overriding NVDATA EEDPTagMode setting\n", -+ ioc->name); -+ ioc->manu_pg11.EEDPTagMode &= ~0x3; -+ ioc->manu_pg11.EEDPTagMode |= 0x1; -+ mpt2sas_config_set_manufacturing_pg11(ioc, &mpi_reply, -+ &ioc->manu_pg11); -+ } -+ -+ mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); -+ mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); -+ mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); -+ mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); -+ mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); -+ mpt2sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); -+ _base_display_ioc_capabilities(ioc); -+ -+ /* -+ * Enable task_set_full handling in iounit_pg1 when the -+ * facts capabilities indicate that its supported. -+ */ -+ iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); -+ if ((ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING)) -+ iounit_pg1_flags &= -+ ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; -+ else -+ iounit_pg1_flags |= -+ MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; -+ ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); -+ mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); -+ -+ if (ioc->iounit_pg8.NumSensors) -+ ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; -+} -+ -+/** -+ * _base_release_memory_pools - release memory -+ * @ioc: per adapter object -+ * -+ * Free memory allocated from _base_allocate_memory_pools. -+ * -+ * Return nothing. -+ */ -+static void -+_base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int i = 0; -+ struct reply_post_struct *rps; -+ -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ if (ioc->request) { -+ pci_free_consistent(ioc->pdev, ioc->request_dma_sz, -+ ioc->request, ioc->request_dma); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "request_pool(0x%p): free\n", -+ ioc->name, ioc->request)); -+ ioc->request = NULL; -+ } -+ -+ if (ioc->sense) { -+ pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma); -+ if (ioc->sense_dma_pool) -+ pci_pool_destroy(ioc->sense_dma_pool); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "sense_pool(0x%p): free\n", -+ ioc->name, ioc->sense)); -+ ioc->sense = NULL; -+ } -+ -+ if (ioc->reply) { -+ pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma); -+ if (ioc->reply_dma_pool) -+ pci_pool_destroy(ioc->reply_dma_pool); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_pool(0x%p): free\n", -+ ioc->name, ioc->reply)); -+ ioc->reply = NULL; -+ } -+ -+ if (ioc->reply_free) { -+ pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free, -+ ioc->reply_free_dma); -+ if (ioc->reply_free_dma_pool) -+ pci_pool_destroy(ioc->reply_free_dma_pool); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_free_pool(0x%p): free\n", -+ ioc->name, ioc->reply_free)); -+ ioc->reply_free = NULL; -+ } -+ -+ if (ioc->reply_post) { -+ do { -+ rps = &ioc->reply_post[i]; -+ if (rps->reply_post_free) { -+ pci_pool_free( -+ ioc->reply_post_free_dma_pool, -+ rps->reply_post_free, -+ rps->reply_post_free_dma); -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_post_free_pool(0x%p): free\n", -+ ioc->name, rps->reply_post_free)); -+ rps->reply_post_free = NULL; -+ } -+ } while (ioc->rdpq_array_enable && -+ (++i < ioc->reply_queue_count)); -+ -+ if (ioc->reply_post_free_dma_pool) -+ pci_pool_destroy(ioc->reply_post_free_dma_pool); -+ kfree(ioc->reply_post); -+ } -+ -+ if (ioc->config_page) { -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT -+ "config_page(0x%p): free\n", ioc->name, -+ ioc->config_page)); -+ pci_free_consistent(ioc->pdev, ioc->config_page_sz, -+ ioc->config_page, ioc->config_page_dma); -+ } -+ -+ if (ioc->scsi_lookup) { -+ free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); -+ ioc->scsi_lookup = NULL; -+ } -+ kfree(ioc->hpr_lookup); -+ kfree(ioc->internal_lookup); -+ if (ioc->chain_lookup) { -+ for (i = 0; i < ioc->chain_depth; i++) { -+ if (ioc->chain_lookup[i].chain_buffer) -+ pci_pool_free(ioc->chain_dma_pool, -+ ioc->chain_lookup[i].chain_buffer, -+ ioc->chain_lookup[i].chain_buffer_dma); -+ } -+ if (ioc->chain_dma_pool) -+ pci_pool_destroy(ioc->chain_dma_pool); -+ free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); -+ ioc->chain_lookup = NULL; -+ } -+} -+ -+/** -+ * _base_allocate_memory_pools - allocate start of day memory pools -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 success, anything else error -+ */ -+static int -+_base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ struct mpt2sas_facts *facts; -+ u16 max_sge_elements; -+ u16 chains_needed_per_io; -+ u32 sz, total_sz, reply_post_free_sz; -+ u32 retry_sz; -+ u16 max_request_credit; -+ unsigned short sg_tablesize; -+ u16 sge_size; -+ int i; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ -+ retry_sz = 0; -+ facts = &ioc->facts; -+ -+ /* command line tunables for max sgl entries */ -+ if (max_sgl_entries != -1) -+ sg_tablesize = max_sgl_entries; -+ else { -+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION) -+ sg_tablesize = MPT2SAS_SG_DEPTH; -+ else -+ sg_tablesize = MPT3SAS_SG_DEPTH; -+ } -+ -+ if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS) -+ sg_tablesize = MPT_MIN_PHYS_SEGMENTS; -+ else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { -+ sg_tablesize = min_t(unsigned short, sg_tablesize, -+ SCSI_MAX_SG_CHAIN_SEGMENTS); -+ pr_warn(MPT3SAS_FMT -+ "sg_tablesize(%u) is bigger than kernel" -+ " defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name, -+ sg_tablesize, MPT_MAX_PHYS_SEGMENTS); -+ } -+ ioc->shost->sg_tablesize = sg_tablesize; -+ -+ ioc->internal_depth = min_t(int, (facts->HighPriorityCredit + (5)), -+ (facts->RequestCredit / 4)); -+ if (ioc->internal_depth < INTERNAL_CMDS_COUNT) { -+ if (facts->RequestCredit <= (INTERNAL_CMDS_COUNT + -+ INTERNAL_SCSIIO_CMDS_COUNT)) { -+ pr_err(MPT3SAS_FMT "IOC doesn't have enough Request \ -+ Credits, it has just %d number of credits\n", -+ ioc->name, facts->RequestCredit); -+ return -ENOMEM; -+ } -+ ioc->internal_depth = 10; -+ } -+ -+ ioc->hi_priority_depth = ioc->internal_depth - (5); -+ /* command line tunables for max controller queue depth */ -+ if (max_queue_depth != -1 && max_queue_depth != 0) { -+ max_request_credit = min_t(u16, max_queue_depth + -+ ioc->internal_depth, facts->RequestCredit); -+ if (max_request_credit > MAX_HBA_QUEUE_DEPTH) -+ max_request_credit = MAX_HBA_QUEUE_DEPTH; -+ } else -+ max_request_credit = min_t(u16, facts->RequestCredit, -+ MAX_HBA_QUEUE_DEPTH); -+ -+ /* Firmware maintains additional facts->HighPriorityCredit number of -+ * credits for HiPriprity Request messages, so hba queue depth will be -+ * sum of max_request_credit and high priority queue depth. -+ */ -+ ioc->hba_queue_depth = max_request_credit + ioc->hi_priority_depth; -+ -+ /* request frame size */ -+ ioc->request_sz = facts->IOCRequestFrameSize * 4; -+ -+ /* reply frame size */ -+ ioc->reply_sz = facts->ReplyFrameSize * 4; -+ -+ /* chain segment size */ -+ if (ioc->hba_mpi_version_belonged != MPI2_VERSION) { -+ if (facts->IOCMaxChainSegmentSize) -+ ioc->chain_segment_sz = -+ facts->IOCMaxChainSegmentSize * -+ MAX_CHAIN_ELEMT_SZ; -+ else -+ /* set to 128 bytes size if IOCMaxChainSegmentSize is zero */ -+ ioc->chain_segment_sz = DEFAULT_NUM_FWCHAIN_ELEMTS * -+ MAX_CHAIN_ELEMT_SZ; -+ } else -+ ioc->chain_segment_sz = ioc->request_sz; -+ -+ /* calculate the max scatter element size */ -+ sge_size = max_t(u16, ioc->sge_size, ioc->sge_size_ieee); -+ -+ retry_allocation: -+ total_sz = 0; -+ /* calculate number of sg elements left over in the 1st frame */ -+ max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) - -+ sizeof(Mpi2SGEIOUnion_t)) + sge_size); -+ ioc->max_sges_in_main_message = max_sge_elements/sge_size; -+ -+ /* now do the same for a chain buffer */ -+ max_sge_elements = ioc->chain_segment_sz - sge_size; -+ ioc->max_sges_in_chain_message = max_sge_elements/sge_size; -+ -+ /* -+ * MPT3SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE -+ */ -+ chains_needed_per_io = ((ioc->shost->sg_tablesize - -+ ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message) -+ + 1; -+ if (chains_needed_per_io > facts->MaxChainDepth) { -+ chains_needed_per_io = facts->MaxChainDepth; -+ ioc->shost->sg_tablesize = min_t(u16, -+ ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message -+ * chains_needed_per_io), ioc->shost->sg_tablesize); -+ } -+ ioc->chains_needed_per_io = chains_needed_per_io; -+ -+ /* reply free queue sizing - taking into account for 64 FW events */ -+ ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; -+ -+ /* calculate reply descriptor post queue depth */ -+ ioc->reply_post_queue_depth = ioc->hba_queue_depth + -+ ioc->reply_free_queue_depth + 1 ; -+ /* align the reply post queue on the next 16 count boundary */ -+ if (ioc->reply_post_queue_depth % 16) -+ ioc->reply_post_queue_depth += 16 - -+ (ioc->reply_post_queue_depth % 16); -+ -+ if (ioc->reply_post_queue_depth > -+ facts->MaxReplyDescriptorPostQueueDepth) { -+ ioc->reply_post_queue_depth = -+ facts->MaxReplyDescriptorPostQueueDepth - -+ (facts->MaxReplyDescriptorPostQueueDepth % 16); -+ ioc->hba_queue_depth = -+ ((ioc->reply_post_queue_depth - 64) / 2) - 1; -+ ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; -+ } -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "scatter gather: " \ -+ "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " -+ "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message, -+ ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize, -+ ioc->chains_needed_per_io)); -+ -+ /* reply post queue, 16 byte align */ -+ reply_post_free_sz = ioc->reply_post_queue_depth * -+ sizeof(Mpi2DefaultReplyDescriptor_t); -+ -+ sz = reply_post_free_sz; -+ if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable) -+ sz *= ioc->reply_queue_count; -+ -+ ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ? -+ (ioc->reply_queue_count):1, -+ sizeof(struct reply_post_struct), GFP_KERNEL); -+ -+ if (!ioc->reply_post) { -+ pr_err(MPT3SAS_FMT "reply_post_free pool: kcalloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool", -+ ioc->pdev, sz, 16, 0); -+ if (!ioc->reply_post_free_dma_pool) { -+ pr_err(MPT3SAS_FMT -+ "reply_post_free pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ i = 0; -+ do { -+ ioc->reply_post[i].reply_post_free = -+ pci_pool_alloc(ioc->reply_post_free_dma_pool, -+ GFP_KERNEL, -+ &ioc->reply_post[i].reply_post_free_dma); -+ if (!ioc->reply_post[i].reply_post_free) { -+ pr_err(MPT3SAS_FMT -+ "reply_post_free pool: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ memset(ioc->reply_post[i].reply_post_free, 0, sz); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply post free pool (0x%p): depth(%d)," -+ "element_size(%d), pool_size(%d kB)\n", ioc->name, -+ ioc->reply_post[i].reply_post_free, -+ ioc->reply_post_queue_depth, 8, sz/1024)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_post_free_dma = (0x%llx)\n", ioc->name, -+ (unsigned long long) -+ ioc->reply_post[i].reply_post_free_dma)); -+ total_sz += sz; -+ } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count)); -+ -+ if (ioc->dma_mask == 64) { -+ if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) { -+ pr_warn(MPT3SAS_FMT -+ "no suitable consistent DMA mask for %s\n", -+ ioc->name, pci_name(ioc->pdev)); -+ goto out; -+ } -+ } -+ -+ ioc->scsiio_depth = ioc->hba_queue_depth - -+ ioc->hi_priority_depth - ioc->internal_depth; -+ -+ /* set the scsi host can_queue depth -+ * with some internal commands that could be outstanding -+ */ -+ ioc->shost->can_queue = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT; -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "scsi host: can_queue depth (%d)\n", -+ ioc->name, ioc->shost->can_queue)); -+ -+ -+ /* contiguous pool for request and chains, 16 byte align, one extra " -+ * "frame for smid=0 -+ */ -+ ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; -+ sz = ((ioc->scsiio_depth + 1) * ioc->request_sz); -+ -+ /* hi-priority queue */ -+ sz += (ioc->hi_priority_depth * ioc->request_sz); -+ -+ /* internal queue */ -+ sz += (ioc->internal_depth * ioc->request_sz); -+ -+ ioc->request_dma_sz = sz; -+ ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma); -+ if (!ioc->request) { -+ pr_err(MPT3SAS_FMT "request pool: pci_alloc_consistent " \ -+ "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " -+ "total(%d kB)\n", ioc->name, ioc->hba_queue_depth, -+ ioc->chains_needed_per_io, ioc->request_sz, sz/1024); -+ if (ioc->scsiio_depth < MPT3SAS_SAS_QUEUE_DEPTH) -+ goto out; -+ retry_sz = 64; -+ ioc->hba_queue_depth -= retry_sz; -+ _base_release_memory_pools(ioc); -+ goto retry_allocation; -+ } -+ -+ if (retry_sz) -+ pr_err(MPT3SAS_FMT "request pool: pci_alloc_consistent " \ -+ "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " -+ "total(%d kb)\n", ioc->name, ioc->hba_queue_depth, -+ ioc->chains_needed_per_io, ioc->request_sz, sz/1024); -+ -+ /* hi-priority queue */ -+ ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * -+ ioc->request_sz); -+ ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) * -+ ioc->request_sz); -+ -+ /* internal queue */ -+ ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth * -+ ioc->request_sz); -+ ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * -+ ioc->request_sz); -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "request pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n", -+ ioc->name, ioc->request, ioc->hba_queue_depth, ioc->request_sz, -+ (ioc->hba_queue_depth * ioc->request_sz)/1024)); -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "request pool: dma(0x%llx)\n", -+ ioc->name, (unsigned long long) ioc->request_dma)); -+ total_sz += sz; -+ -+ sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker); -+ ioc->scsi_lookup_pages = get_order(sz); -+ ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages( -+ GFP_KERNEL, ioc->scsi_lookup_pages); -+ if (!ioc->scsi_lookup) { -+ pr_err(MPT3SAS_FMT "scsi_lookup: get_free_pages failed, sz(%d)\n", -+ ioc->name, (int)sz); -+ goto out; -+ } -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "scsiio(0x%p): depth(%d)\n", -+ ioc->name, ioc->request, ioc->scsiio_depth)); -+ -+ ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); -+ sz = ioc->chain_depth * sizeof(struct chain_tracker); -+ ioc->chain_pages = get_order(sz); -+ ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( -+ GFP_KERNEL, ioc->chain_pages); -+ if (!ioc->chain_lookup) { -+ pr_err(MPT3SAS_FMT "chain_lookup: __get_free_pages failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, -+ ioc->chain_segment_sz, 16, 0); -+ if (!ioc->chain_dma_pool) { -+ pr_err(MPT3SAS_FMT "chain_dma_pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ for (i = 0; i < ioc->chain_depth; i++) { -+ ioc->chain_lookup[i].chain_buffer = pci_pool_alloc( -+ ioc->chain_dma_pool , GFP_KERNEL, -+ &ioc->chain_lookup[i].chain_buffer_dma); -+ if (!ioc->chain_lookup[i].chain_buffer) { -+ ioc->chain_depth = i; -+ goto chain_done; -+ } -+ total_sz += ioc->chain_segment_sz; -+ } -+ chain_done: -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "chain pool depth(%d), frame_size(%d), pool_size(%d kB)\n", -+ ioc->name, ioc->chain_depth, ioc->chain_segment_sz, -+ ((ioc->chain_depth * ioc->chain_segment_sz))/1024)); -+ -+ /* initialize hi-priority queue smid's */ -+ ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, -+ sizeof(struct request_tracker), GFP_KERNEL); -+ if (!ioc->hpr_lookup) { -+ pr_err(MPT3SAS_FMT "hpr_lookup: kcalloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->hi_priority_smid = ioc->scsiio_depth + 1; -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "hi_priority(0x%p): depth(%d), start smid(%d)\n", -+ ioc->name, ioc->hi_priority, -+ ioc->hi_priority_depth, ioc->hi_priority_smid)); -+ -+ /* initialize internal queue smid's */ -+ ioc->internal_lookup = kcalloc(ioc->internal_depth, -+ sizeof(struct request_tracker), GFP_KERNEL); -+ if (!ioc->internal_lookup) { -+ pr_err(MPT3SAS_FMT "internal_lookup: kcalloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "internal(0x%p): depth(%d), start smid(%d)\n", -+ ioc->name, ioc->internal, -+ ioc->internal_depth, ioc->internal_smid)); -+ -+ /* sense buffers, 4 byte align */ -+ sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE; -+ ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4, -+ 0); -+ if (!ioc->sense_dma_pool) { -+ pr_err(MPT3SAS_FMT "sense pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL, -+ &ioc->sense_dma); -+ if (!ioc->sense) { -+ pr_err(MPT3SAS_FMT "sense pool: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "sense pool(0x%p): depth(%d), element_size(%d), pool_size" -+ "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth, -+ SCSI_SENSE_BUFFERSIZE, sz/1024)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "sense_dma(0x%llx)\n", -+ ioc->name, (unsigned long long)ioc->sense_dma)); -+ total_sz += sz; -+ -+ /* reply pool, 4 byte align */ -+ sz = ioc->reply_free_queue_depth * ioc->reply_sz; -+ ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4, -+ 0); -+ if (!ioc->reply_dma_pool) { -+ pr_err(MPT3SAS_FMT "reply pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL, -+ &ioc->reply_dma); -+ if (!ioc->reply) { -+ pr_err(MPT3SAS_FMT "reply pool: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->reply_dma_min_address = (u32)(ioc->reply_dma); -+ ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz; -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n", -+ ioc->name, ioc->reply, -+ ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply_dma(0x%llx)\n", -+ ioc->name, (unsigned long long)ioc->reply_dma)); -+ total_sz += sz; -+ -+ /* reply free queue, 16 byte align */ -+ sz = ioc->reply_free_queue_depth * 4; -+ ioc->reply_free_dma_pool = pci_pool_create("reply_free pool", -+ ioc->pdev, sz, 16, 0); -+ if (!ioc->reply_free_dma_pool) { -+ pr_err(MPT3SAS_FMT "reply_free pool: pci_pool_create failed\n", -+ ioc->name); -+ goto out; -+ } -+ ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL, -+ &ioc->reply_free_dma); -+ if (!ioc->reply_free) { -+ pr_err(MPT3SAS_FMT "reply_free pool: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ memset(ioc->reply_free, 0, sz); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "reply_free pool(0x%p): " \ -+ "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name, -+ ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "reply_free_dma (0x%llx)\n", -+ ioc->name, (unsigned long long)ioc->reply_free_dma)); -+ total_sz += sz; -+ -+ ioc->config_page_sz = 512; -+ ioc->config_page = pci_alloc_consistent(ioc->pdev, -+ ioc->config_page_sz, &ioc->config_page_dma); -+ if (!ioc->config_page) { -+ pr_err(MPT3SAS_FMT -+ "config page: pci_pool_alloc failed\n", -+ ioc->name); -+ goto out; -+ } -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "config page(0x%p): size(%d)\n", -+ ioc->name, ioc->config_page, ioc->config_page_sz)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "config_page_dma(0x%llx)\n", -+ ioc->name, (unsigned long long)ioc->config_page_dma)); -+ total_sz += ioc->config_page_sz; -+ -+ pr_info(MPT3SAS_FMT "Allocated physical memory: size(%d kB)\n", -+ ioc->name, total_sz/1024); -+ pr_info(MPT3SAS_FMT -+ "Current Controller Queue Depth(%d),Max Controller Queue Depth(%d)\n", -+ ioc->name, ioc->shost->can_queue, facts->RequestCredit); -+ pr_info(MPT3SAS_FMT "Scatter Gather Elements per IO(%d)\n", -+ ioc->name, ioc->shost->sg_tablesize); -+ return 0; -+ -+ out: -+ return -ENOMEM; -+} -+ -+/** -+ * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter. -+ * @ioc: Pointer to MPT_ADAPTER structure -+ * @cooked: Request raw or cooked IOC state -+ * -+ * Returns all IOC Doorbell register bits if cooked==0, else just the -+ * Doorbell bits in MPI_IOC_STATE_MASK. -+ */ -+u32 -+mpt2sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked) -+{ -+ u32 s, sc; -+ -+ s = readl(&ioc->chip->Doorbell); -+ sc = s & MPI2_IOC_STATE_MASK; -+ return cooked ? sc : s; -+} -+ -+/** -+ * _base_wait_on_iocstate - waiting on a particular ioc state -+ * @ioc_state: controller state { READY, OPERATIONAL, or RESET } -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout, -+ int sleep_flag) -+{ -+ u32 count, cntdn; -+ u32 current_state; -+ -+ count = 0; -+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; -+ do { -+ current_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (current_state == ioc_state) -+ return 0; -+ if (count && current_state == MPI2_IOC_STATE_FAULT) -+ break; -+ if (sleep_flag == CAN_SLEEP) -+ usleep_range(1000, 1500); -+ else -+ udelay(500); -+ count++; -+ } while (--cntdn); -+ -+ return current_state; -+} -+ -+/** -+ * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by -+ * a write to the doorbell) -+ * @ioc: per adapter object -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. -+ */ -+static int -+_base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag); -+ -+static int -+_base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout, -+ int sleep_flag) -+{ -+ u32 cntdn, count; -+ u32 int_status; -+ -+ count = 0; -+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; -+ do { -+ int_status = readl(&ioc->chip->HostInterruptStatus); -+ if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: successful count(%d), timeout(%d)\n", -+ ioc->name, __func__, count, timeout)); -+ return 0; -+ } -+ if (sleep_flag == CAN_SLEEP) -+ usleep_range(1000, 1500); -+ else -+ udelay(500); -+ count++; -+ } while (--cntdn); -+ -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to timeout count(%d), int_status(%x)!\n", -+ ioc->name, __func__, count, int_status); -+ return -EFAULT; -+} -+ -+/** -+ * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell. -+ * @ioc: per adapter object -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to -+ * doorbell. -+ */ -+static int -+_base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout, -+ int sleep_flag) -+{ -+ u32 cntdn, count; -+ u32 int_status; -+ u32 doorbell; -+ -+ count = 0; -+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; -+ do { -+ int_status = readl(&ioc->chip->HostInterruptStatus); -+ if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: successful count(%d), timeout(%d)\n", -+ ioc->name, __func__, count, timeout)); -+ return 0; -+ } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { -+ doorbell = readl(&ioc->chip->Doorbell); -+ if ((doorbell & MPI2_IOC_STATE_MASK) == -+ MPI2_IOC_STATE_FAULT) { -+ mpt2sas_base_fault_info(ioc , doorbell); -+ return -EFAULT; -+ } -+ } else if (int_status == 0xFFFFFFFF) -+ goto out; -+ -+ if (sleep_flag == CAN_SLEEP) -+ usleep_range(1000, 1500); -+ else -+ udelay(500); -+ count++; -+ } while (--cntdn); -+ -+ out: -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to timeout count(%d), int_status(%x)!\n", -+ ioc->name, __func__, count, int_status); -+ return -EFAULT; -+} -+ -+/** -+ * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use -+ * @ioc: per adapter object -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ */ -+static int -+_base_wait_for_doorbell_not_used(struct MPT3SAS_ADAPTER *ioc, int timeout, -+ int sleep_flag) -+{ -+ u32 cntdn, count; -+ u32 doorbell_reg; -+ -+ count = 0; -+ cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; -+ do { -+ doorbell_reg = readl(&ioc->chip->Doorbell); -+ if (!(doorbell_reg & MPI2_DOORBELL_USED)) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: successful count(%d), timeout(%d)\n", -+ ioc->name, __func__, count, timeout)); -+ return 0; -+ } -+ if (sleep_flag == CAN_SLEEP) -+ usleep_range(1000, 1500); -+ else -+ udelay(500); -+ count++; -+ } while (--cntdn); -+ -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n", -+ ioc->name, __func__, count, doorbell_reg); -+ return -EFAULT; -+} -+ -+/** -+ * _base_send_ioc_reset - send doorbell reset -+ * @ioc: per adapter object -+ * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout, -+ int sleep_flag) -+{ -+ u32 ioc_state; -+ int r = 0; -+ -+ if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) { -+ pr_err(MPT3SAS_FMT "%s: unknown reset_type\n", -+ ioc->name, __func__); -+ return -EFAULT; -+ } -+ -+ if (!(ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY)) -+ return -EFAULT; -+ -+ pr_info(MPT3SAS_FMT "sending message unit reset !!\n", ioc->name); -+ -+ writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT, -+ &ioc->chip->Doorbell); -+ if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) { -+ r = -EFAULT; -+ goto out; -+ } -+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, -+ timeout, sleep_flag); -+ if (ioc_state) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed going to ready state (ioc_state=0x%x)\n", -+ ioc->name, __func__, ioc_state); -+ r = -EFAULT; -+ goto out; -+ } -+ out: -+ pr_info(MPT3SAS_FMT "message unit reset: %s\n", -+ ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); -+ return r; -+} -+ -+/** -+ * _base_handshake_req_reply_wait - send request thru doorbell interface -+ * @ioc: per adapter object -+ * @request_bytes: request length -+ * @request: pointer having request payload -+ * @reply_bytes: reply length -+ * @reply: pointer to reply payload -+ * @timeout: timeout in second -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, -+ u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag) -+{ -+ MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply; -+ int i; -+ u8 failed; -+ u16 dummy; -+ __le32 *mfp; -+ -+ /* make sure doorbell is not in use */ -+ if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { -+ pr_err(MPT3SAS_FMT -+ "doorbell is in use (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ -+ /* clear pending doorbell interrupts from previous state changes */ -+ if (readl(&ioc->chip->HostInterruptStatus) & -+ MPI2_HIS_IOC2SYS_DB_STATUS) -+ writel(0, &ioc->chip->HostInterruptStatus); -+ -+ /* send message to ioc */ -+ writel(((MPI2_FUNCTION_HANDSHAKE<chip->Doorbell); -+ -+ if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake int failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ writel(0, &ioc->chip->HostInterruptStatus); -+ -+ if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake ack failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ -+ /* send message 32-bits at a time */ -+ for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) { -+ writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell); -+ if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) -+ failed = 1; -+ } -+ -+ if (failed) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake sending request failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ -+ /* now wait for the reply */ -+ if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake int failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ -+ /* read the first two 16-bits, it gives the total length of the reply */ -+ reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell) -+ & MPI2_DOORBELL_DATA_MASK); -+ writel(0, &ioc->chip->HostInterruptStatus); -+ if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake int failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell) -+ & MPI2_DOORBELL_DATA_MASK); -+ writel(0, &ioc->chip->HostInterruptStatus); -+ -+ for (i = 2; i < default_reply->MsgLength * 2; i++) { -+ if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { -+ pr_err(MPT3SAS_FMT -+ "doorbell handshake int failed (line=%d)\n", -+ ioc->name, __LINE__); -+ return -EFAULT; -+ } -+ if (i >= reply_bytes/2) /* overflow case */ -+ dummy = readl(&ioc->chip->Doorbell); -+ else -+ reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell) -+ & MPI2_DOORBELL_DATA_MASK); -+ writel(0, &ioc->chip->HostInterruptStatus); -+ } -+ -+ _base_wait_for_doorbell_int(ioc, 5, sleep_flag); -+ if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "doorbell is in use (line=%d)\n", ioc->name, __LINE__)); -+ } -+ writel(0, &ioc->chip->HostInterruptStatus); -+ -+ if (ioc->logging_level & MPT_DEBUG_INIT) { -+ mfp = (__le32 *)reply; -+ pr_info("\toffset:data\n"); -+ for (i = 0; i < reply_bytes/4; i++) -+ pr_info("\t[0x%02x]:%08x\n", i*4, -+ le32_to_cpu(mfp[i])); -+ } -+ return 0; -+} -+ -+/** -+ * mpt2sas_base_sas_iounit_control - send sas iounit control to FW -+ * @ioc: per adapter object -+ * @mpi_reply: the reply payload from FW -+ * @mpi_request: the request payload sent to FW -+ * -+ * The SAS IO Unit Control Request message allows the host to perform low-level -+ * operations, such as resets on the PHYs of the IO Unit, also allows the host -+ * to obtain the IOC assigned device handles for a device if it has other -+ * identifying information about the device, in addition allows the host to -+ * remove IOC resources associated with the device. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2SasIoUnitControlReply_t *mpi_reply, -+ Mpi2SasIoUnitControlRequest_t *mpi_request) -+{ -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ bool issue_reset = false; -+ int rc; -+ void *request; -+ u16 wait_state_count; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ mutex_lock(&ioc->base_cmds.mutex); -+ -+ if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: base_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ ioc->base_cmds.status = MPT3_CMD_PENDING; -+ request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->base_cmds.smid = smid; -+ memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)); -+ if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || -+ mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) -+ ioc->ioc_link_reset_in_progress = 1; -+ init_completion(&ioc->base_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, -+ msecs_to_jiffies(10000)); -+ if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || -+ mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) && -+ ioc->ioc_link_reset_in_progress) -+ ioc->ioc_link_reset_in_progress = 0; -+ if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SasIoUnitControlRequest_t)/4); -+ if (!(ioc->base_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = true; -+ goto issue_host_reset; -+ } -+ if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) -+ memcpy(mpi_reply, ioc->base_cmds.reply, -+ sizeof(Mpi2SasIoUnitControlReply_t)); -+ else -+ memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t)); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ goto out; -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ rc = -EFAULT; -+ out: -+ mutex_unlock(&ioc->base_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * mpt2sas_base_scsi_enclosure_processor - sending request to sep device -+ * @ioc: per adapter object -+ * @mpi_reply: the reply payload from FW -+ * @mpi_request: the request payload sent to FW -+ * -+ * The SCSI Enclosure Processor request message causes the IOC to -+ * communicate with SES devices to control LED status signals. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request) -+{ -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ bool issue_reset = false; -+ int rc; -+ void *request; -+ u16 wait_state_count; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ mutex_lock(&ioc->base_cmds.mutex); -+ -+ if (ioc->base_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: base_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, -+ __func__, wait_state_count); -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ ioc->base_cmds.status = MPT3_CMD_PENDING; -+ request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->base_cmds.smid = smid; -+ memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); -+ init_completion(&ioc->base_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, -+ msecs_to_jiffies(10000)); -+ if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SepRequest_t)/4); -+ if (!(ioc->base_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = false; -+ goto issue_host_reset; -+ } -+ if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID) -+ memcpy(mpi_reply, ioc->base_cmds.reply, -+ sizeof(Mpi2SepReply_t)); -+ else -+ memset(mpi_reply, 0, sizeof(Mpi2SepReply_t)); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ goto out; -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ rc = -EFAULT; -+ out: -+ mutex_unlock(&ioc->base_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * _base_get_port_facts - obtain port facts reply and save in ioc -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port, int sleep_flag) -+{ -+ Mpi2PortFactsRequest_t mpi_request; -+ Mpi2PortFactsReply_t mpi_reply; -+ struct mpt2sas_port_facts *pfacts; -+ int mpi_reply_sz, mpi_request_sz, r; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); -+ mpi_request_sz = sizeof(Mpi2PortFactsRequest_t); -+ memset(&mpi_request, 0, mpi_request_sz); -+ mpi_request.Function = MPI2_FUNCTION_PORT_FACTS; -+ mpi_request.PortNumber = port; -+ r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, -+ (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); -+ -+ if (r != 0) { -+ pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", -+ ioc->name, __func__, r); -+ return r; -+ } -+ -+ pfacts = &ioc->pfacts[port]; -+ memset(pfacts, 0, sizeof(struct mpt2sas_port_facts)); -+ pfacts->PortNumber = mpi_reply.PortNumber; -+ pfacts->VP_ID = mpi_reply.VP_ID; -+ pfacts->VF_ID = mpi_reply.VF_ID; -+ pfacts->MaxPostedCmdBuffers = -+ le16_to_cpu(mpi_reply.MaxPostedCmdBuffers); -+ -+ return 0; -+} -+ -+/** -+ * _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL -+ * @ioc: per adapter object -+ * @timeout: -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout, -+ int sleep_flag) -+{ -+ u32 ioc_state; -+ int rc; -+ -+ dinitprintk(ioc, printk(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ if (ioc->pci_error_recovery) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "%s: host in pci error recovery\n", ioc->name, __func__)); -+ return -EFAULT; -+ } -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ dhsprintk(ioc, printk(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n", -+ ioc->name, __func__, ioc_state)); -+ -+ if (((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) || -+ (ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) -+ return 0; -+ -+ if (ioc_state & MPI2_DOORBELL_USED) { -+ dhsprintk(ioc, printk(MPT3SAS_FMT -+ "unexpected doorbell active!\n", ioc->name)); -+ goto issue_diag_reset; -+ } -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { -+ mpt2sas_base_fault_info(ioc, ioc_state & -+ MPI2_DOORBELL_DATA_MASK); -+ goto issue_diag_reset; -+ } -+ -+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, -+ timeout, sleep_flag); -+ if (ioc_state) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "%s: failed going to ready state (ioc_state=0x%x)\n", -+ ioc->name, __func__, ioc_state)); -+ return -EFAULT; -+ } -+ -+ issue_diag_reset: -+ rc = _base_diag_reset(ioc, sleep_flag); -+ return rc; -+} -+ -+/** -+ * _base_get_ioc_facts - obtain ioc facts reply and save in ioc -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ Mpi2IOCFactsRequest_t mpi_request; -+ Mpi2IOCFactsReply_t mpi_reply; -+ struct mpt2sas_facts *facts; -+ int mpi_reply_sz, mpi_request_sz, r; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ r = _base_wait_for_iocstate(ioc, 10, sleep_flag); -+ if (r) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "%s: failed getting to correct state\n", -+ ioc->name, __func__)); -+ return r; -+ } -+ mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); -+ mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t); -+ memset(&mpi_request, 0, mpi_request_sz); -+ mpi_request.Function = MPI2_FUNCTION_IOC_FACTS; -+ r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, -+ (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); -+ -+ if (r != 0) { -+ pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", -+ ioc->name, __func__, r); -+ return r; -+ } -+ -+ facts = &ioc->facts; -+ memset(facts, 0, sizeof(struct mpt2sas_facts)); -+ facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion); -+ facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion); -+ facts->VP_ID = mpi_reply.VP_ID; -+ facts->VF_ID = mpi_reply.VF_ID; -+ facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions); -+ facts->MaxChainDepth = mpi_reply.MaxChainDepth; -+ facts->WhoInit = mpi_reply.WhoInit; -+ facts->NumberOfPorts = mpi_reply.NumberOfPorts; -+ facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors; -+ facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit); -+ facts->MaxReplyDescriptorPostQueueDepth = -+ le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); -+ facts->ProductID = le16_to_cpu(mpi_reply.ProductID); -+ facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities); -+ if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)) -+ ioc->ir_firmware = 1; -+ if ((facts->IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE)) -+ ioc->rdpq_array_capable = 1; -+ facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); -+ facts->IOCRequestFrameSize = -+ le16_to_cpu(mpi_reply.IOCRequestFrameSize); -+ if (ioc->hba_mpi_version_belonged != MPI2_VERSION) { -+ facts->IOCMaxChainSegmentSize = -+ le16_to_cpu(mpi_reply.IOCMaxChainSegmentSize); -+ } -+ facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators); -+ facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets); -+ ioc->shost->max_id = -1; -+ facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders); -+ facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures); -+ facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags); -+ facts->HighPriorityCredit = -+ le16_to_cpu(mpi_reply.HighPriorityCredit); -+ facts->ReplyFrameSize = mpi_reply.ReplyFrameSize; -+ facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle); -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "hba queue depth(%d), max chains per io(%d)\n", -+ ioc->name, facts->RequestCredit, -+ facts->MaxChainDepth)); -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "request frame size(%d), reply frame size(%d)\n", ioc->name, -+ facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4)); -+ return 0; -+} -+ -+/** -+ * _base_send_ioc_init - send ioc_init to firmware -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ Mpi2IOCInitRequest_t mpi_request; -+ Mpi2IOCInitReply_t mpi_reply; -+ int i, r = 0; -+ ktime_t current_time; -+ u16 ioc_status; -+ u32 reply_post_free_array_sz = 0; -+ Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL; -+ dma_addr_t reply_post_free_array_dma; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_IOC_INIT; -+ mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; -+ mpi_request.VF_ID = 0; /* TODO */ -+ mpi_request.VP_ID = 0; -+ mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged); -+ mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); -+ -+ if (_base_is_controller_msix_enabled(ioc)) -+ mpi_request.HostMSIxVectors = ioc->reply_queue_count; -+ mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); -+ mpi_request.ReplyDescriptorPostQueueDepth = -+ cpu_to_le16(ioc->reply_post_queue_depth); -+ mpi_request.ReplyFreeQueueDepth = -+ cpu_to_le16(ioc->reply_free_queue_depth); -+ -+ mpi_request.SenseBufferAddressHigh = -+ cpu_to_le32((u64)ioc->sense_dma >> 32); -+ mpi_request.SystemReplyAddressHigh = -+ cpu_to_le32((u64)ioc->reply_dma >> 32); -+ mpi_request.SystemRequestFrameBaseAddress = -+ cpu_to_le64((u64)ioc->request_dma); -+ mpi_request.ReplyFreeQueueAddress = -+ cpu_to_le64((u64)ioc->reply_free_dma); -+ -+ if (ioc->rdpq_array_enable) { -+ reply_post_free_array_sz = ioc->reply_queue_count * -+ sizeof(Mpi2IOCInitRDPQArrayEntry); -+ reply_post_free_array = pci_alloc_consistent(ioc->pdev, -+ reply_post_free_array_sz, &reply_post_free_array_dma); -+ if (!reply_post_free_array) { -+ pr_err(MPT3SAS_FMT -+ "reply_post_free_array: pci_alloc_consistent failed\n", -+ ioc->name); -+ r = -ENOMEM; -+ goto out; -+ } -+ memset(reply_post_free_array, 0, reply_post_free_array_sz); -+ for (i = 0; i < ioc->reply_queue_count; i++) -+ reply_post_free_array[i].RDPQBaseAddress = -+ cpu_to_le64( -+ (u64)ioc->reply_post[i].reply_post_free_dma); -+ mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE; -+ mpi_request.ReplyDescriptorPostQueueAddress = -+ cpu_to_le64((u64)reply_post_free_array_dma); -+ } else { -+ mpi_request.ReplyDescriptorPostQueueAddress = -+ cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma); -+ } -+ -+ /* This time stamp specifies number of milliseconds -+ * since epoch ~ midnight January 1, 1970. -+ */ -+ current_time = ktime_get_real(); -+ mpi_request.TimeStamp = cpu_to_le64(ktime_to_ms(current_time)); -+ -+ if (ioc->logging_level & MPT_DEBUG_INIT) { -+ __le32 *mfp; -+ int i; -+ -+ mfp = (__le32 *)&mpi_request; -+ pr_info("\toffset:data\n"); -+ for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) -+ pr_info("\t[0x%02x]:%08x\n", i*4, -+ le32_to_cpu(mfp[i])); -+ } -+ -+ r = _base_handshake_req_reply_wait(ioc, -+ sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request, -+ sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10, -+ sleep_flag); -+ -+ if (r != 0) { -+ pr_err(MPT3SAS_FMT "%s: handshake failed (r=%d)\n", -+ ioc->name, __func__, r); -+ goto out; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS || -+ mpi_reply.IOCLogInfo) { -+ pr_err(MPT3SAS_FMT "%s: failed\n", ioc->name, __func__); -+ r = -EIO; -+ } -+ -+out: -+ if (reply_post_free_array) -+ pci_free_consistent(ioc->pdev, reply_post_free_array_sz, -+ reply_post_free_array, -+ reply_post_free_array_dma); -+ return r; -+} -+ -+/** -+ * mpt2sas_port_enable_done - command completion routine for port enable -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ u16 ioc_status; -+ -+ if (ioc->port_enable_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (!mpi_reply) -+ return 1; -+ -+ if (mpi_reply->Function != MPI2_FUNCTION_PORT_ENABLE) -+ return 1; -+ -+ ioc->port_enable_cmds.status &= ~MPT3_CMD_PENDING; -+ ioc->port_enable_cmds.status |= MPT3_CMD_COMPLETE; -+ ioc->port_enable_cmds.status |= MPT3_CMD_REPLY_VALID; -+ memcpy(ioc->port_enable_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ ioc->port_enable_failed = 1; -+ -+ if (ioc->is_driver_loading) { -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ mpt2sas_port_enable_complete(ioc); -+ return 1; -+ } else { -+ ioc->start_scan_failed = ioc_status; -+ ioc->start_scan = 0; -+ return 1; -+ } -+ } -+ complete(&ioc->port_enable_cmds.done); -+ return 1; -+} -+ -+/** -+ * _base_send_port_enable - send port_enable(discovery stuff) to firmware -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_send_port_enable(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ Mpi2PortEnableRequest_t *mpi_request; -+ Mpi2PortEnableReply_t *mpi_reply; -+ unsigned long timeleft; -+ int r = 0; -+ u16 smid; -+ u16 ioc_status; -+ -+ pr_info(MPT3SAS_FMT "sending port enable !!\n", ioc->name); -+ -+ if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { -+ pr_err(MPT3SAS_FMT "%s: internal command already in use\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ ioc->port_enable_cmds.status = MPT3_CMD_PENDING; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->port_enable_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; -+ -+ init_completion(&ioc->port_enable_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done, -+ 300*HZ); -+ if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2PortEnableRequest_t)/4); -+ if (ioc->port_enable_cmds.status & MPT3_CMD_RESET) -+ r = -EFAULT; -+ else -+ r = -ETIME; -+ goto out; -+ } -+ -+ mpi_reply = ioc->port_enable_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "%s: failed with (ioc_status=0x%08x)\n", -+ ioc->name, __func__, ioc_status); -+ r = -EFAULT; -+ goto out; -+ } -+ -+ out: -+ ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; -+ pr_info(MPT3SAS_FMT "port enable: %s\n", ioc->name, ((r == 0) ? -+ "SUCCESS" : "FAILED")); -+ return r; -+} -+ -+/** -+ * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply) -+ * @ioc: per adapter object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_port_enable(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2PortEnableRequest_t *mpi_request; -+ u16 smid; -+ -+ pr_info(MPT3SAS_FMT "sending port enable !!\n", ioc->name); -+ -+ if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { -+ pr_err(MPT3SAS_FMT "%s: internal command already in use\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ ioc->port_enable_cmds.status = MPT3_CMD_PENDING; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->port_enable_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; -+ -+ mpt2sas_base_put_smid_default(ioc, smid); -+ return 0; -+} -+ -+/** -+ * _base_determine_wait_on_discovery - desposition -+ * @ioc: per adapter object -+ * -+ * Decide whether to wait on discovery to complete. Used to either -+ * locate boot device, or report volumes ahead of physical devices. -+ * -+ * Returns 1 for wait, 0 for don't wait -+ */ -+static int -+_base_determine_wait_on_discovery(struct MPT3SAS_ADAPTER *ioc) -+{ -+ /* We wait for discovery to complete if IR firmware is loaded. -+ * The sas topology events arrive before PD events, so we need time to -+ * turn on the bit in ioc->pd_handles to indicate PD -+ * Also, it maybe required to report Volumes ahead of physical -+ * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. -+ */ -+ if (ioc->ir_firmware) -+ return 1; -+ -+ /* if no Bios, then we don't need to wait */ -+ if (!ioc->bios_pg3.BiosVersion) -+ return 0; -+ -+ /* Bios is present, then we drop down here. -+ * -+ * If there any entries in the Bios Page 2, then we wait -+ * for discovery to complete. -+ */ -+ -+ /* Current Boot Device */ -+ if ((ioc->bios_pg2.CurrentBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK) == -+ MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && -+ /* Request Boot Device */ -+ (ioc->bios_pg2.ReqBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK) == -+ MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && -+ /* Alternate Request Boot Device */ -+ (ioc->bios_pg2.ReqAltBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK) == -+ MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) -+ return 0; -+ -+ return 1; -+} -+ -+/** -+ * _base_unmask_events - turn on notification for this event -+ * @ioc: per adapter object -+ * @event: firmware event -+ * -+ * The mask is stored in ioc->event_masks. -+ */ -+static void -+_base_unmask_events(struct MPT3SAS_ADAPTER *ioc, u16 event) -+{ -+ u32 desired_event; -+ -+ if (event >= 128) -+ return; -+ -+ desired_event = (1 << (event % 32)); -+ -+ if (event < 32) -+ ioc->event_masks[0] &= ~desired_event; -+ else if (event < 64) -+ ioc->event_masks[1] &= ~desired_event; -+ else if (event < 96) -+ ioc->event_masks[2] &= ~desired_event; -+ else if (event < 128) -+ ioc->event_masks[3] &= ~desired_event; -+} -+ -+/** -+ * _base_event_notification - send event notification -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_event_notification(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ Mpi2EventNotificationRequest_t *mpi_request; -+ unsigned long timeleft; -+ u16 smid; -+ int r = 0; -+ int i; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ if (ioc->base_cmds.status & MPT3_CMD_PENDING) { -+ pr_err(MPT3SAS_FMT "%s: internal command already in use\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ return -EAGAIN; -+ } -+ ioc->base_cmds.status = MPT3_CMD_PENDING; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->base_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) -+ mpi_request->EventMasks[i] = -+ cpu_to_le32(ioc->event_masks[i]); -+ init_completion(&ioc->base_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); -+ if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2EventNotificationRequest_t)/4); -+ if (ioc->base_cmds.status & MPT3_CMD_RESET) -+ r = -EFAULT; -+ else -+ r = -ETIME; -+ } else -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s: complete\n", -+ ioc->name, __func__)); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ return r; -+} -+ -+/** -+ * mpt2sas_base_validate_event_type - validating event types -+ * @ioc: per adapter object -+ * @event: firmware event -+ * -+ * This will turn on firmware event notification when application -+ * ask for that event. We don't mask events that are already enabled. -+ */ -+void -+mpt2sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, u32 *event_type) -+{ -+ int i, j; -+ u32 event_mask, desired_event; -+ u8 send_update_to_fw; -+ -+ for (i = 0, send_update_to_fw = 0; i < -+ MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) { -+ event_mask = ~event_type[i]; -+ desired_event = 1; -+ for (j = 0; j < 32; j++) { -+ if (!(event_mask & desired_event) && -+ (ioc->event_masks[i] & desired_event)) { -+ ioc->event_masks[i] &= ~desired_event; -+ send_update_to_fw = 1; -+ } -+ desired_event = (desired_event << 1); -+ } -+ } -+ -+ if (!send_update_to_fw) -+ return; -+ -+ mutex_lock(&ioc->base_cmds.mutex); -+ _base_event_notification(ioc, CAN_SLEEP); -+ mutex_unlock(&ioc->base_cmds.mutex); -+} -+ -+/** -+ * _base_diag_reset - the "big hammer" start of day reset -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ u32 host_diagnostic; -+ u32 ioc_state; -+ u32 count; -+ u32 hcb_size; -+ -+ pr_info(MPT3SAS_FMT "sending diag reset !!\n", ioc->name); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT "clear interrupts\n", -+ ioc->name)); -+ -+ count = 0; -+ do { -+ /* Write magic sequence to WriteSequence register -+ * Loop until in diagnostic mode -+ */ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "write magic sequence\n", ioc->name)); -+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence); -+ writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence); -+ -+ /* wait 100 msec */ -+ if (sleep_flag == CAN_SLEEP) -+ msleep(100); -+ else -+ mdelay(100); -+ -+ if (count++ > 20) -+ goto out; -+ -+ host_diagnostic = readl(&ioc->chip->HostDiagnostic); -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n", -+ ioc->name, count, host_diagnostic)); -+ -+ } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); -+ -+ hcb_size = readl(&ioc->chip->HCBSize); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT "diag reset: issued\n", -+ ioc->name)); -+ writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, -+ &ioc->chip->HostDiagnostic); -+ -+ /*This delay allows the chip PCIe hardware time to finish reset tasks*/ -+ if (sleep_flag == CAN_SLEEP) -+ msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); -+ else -+ mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); -+ -+ /* Approximately 300 second max wait */ -+ for (count = 0; count < (300000000 / -+ MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) { -+ -+ host_diagnostic = readl(&ioc->chip->HostDiagnostic); -+ -+ if (host_diagnostic == 0xFFFFFFFF) -+ goto out; -+ if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) -+ break; -+ -+ /* Wait to pass the second read delay window */ -+ if (sleep_flag == CAN_SLEEP) -+ msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC -+ / 1000); -+ else -+ mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC -+ / 1000); -+ } -+ -+ if (host_diagnostic & MPI2_DIAG_HCB_MODE) { -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "restart the adapter assuming the HCB Address points to good F/W\n", -+ ioc->name)); -+ host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; -+ host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; -+ writel(host_diagnostic, &ioc->chip->HostDiagnostic); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "re-enable the HCDW\n", ioc->name)); -+ writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, -+ &ioc->chip->HCBSize); -+ } -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT "restart the adapter\n", -+ ioc->name)); -+ writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, -+ &ioc->chip->HostDiagnostic); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "disable writes to the diagnostic register\n", ioc->name)); -+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); -+ -+ drsprintk(ioc, pr_info(MPT3SAS_FMT -+ "Wait for FW to go to the READY state\n", ioc->name)); -+ ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20, -+ sleep_flag); -+ if (ioc_state) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed going to ready state (ioc_state=0x%x)\n", -+ ioc->name, __func__, ioc_state); -+ goto out; -+ } -+ -+ pr_info(MPT3SAS_FMT "diag reset: SUCCESS\n", ioc->name); -+ return 0; -+ -+ out: -+ pr_err(MPT3SAS_FMT "diag reset: FAILED\n", ioc->name); -+ return -EFAULT; -+} -+ -+/** -+ * _base_make_ioc_ready - put controller in READY state -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * @type: FORCE_BIG_HAMMER or SOFT_RESET -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, int sleep_flag, -+ enum reset_type type) -+{ -+ u32 ioc_state; -+ int rc; -+ int count; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ if (ioc->pci_error_recovery) -+ return 0; -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n", -+ ioc->name, __func__, ioc_state)); -+ -+ /* if in RESET state, it should move to READY state shortly */ -+ count = 0; -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_RESET) { -+ while ((ioc_state & MPI2_IOC_STATE_MASK) != -+ MPI2_IOC_STATE_READY) { -+ if (count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed going to ready state (ioc_state=0x%x)\n", -+ ioc->name, __func__, ioc_state); -+ return -EFAULT; -+ } -+ if (sleep_flag == CAN_SLEEP) -+ ssleep(1); -+ else -+ mdelay(1000); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ } -+ } -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) -+ return 0; -+ -+ if (ioc_state & MPI2_DOORBELL_USED) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "unexpected doorbell active!\n", -+ ioc->name)); -+ goto issue_diag_reset; -+ } -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { -+ mpt2sas_base_fault_info(ioc, ioc_state & -+ MPI2_DOORBELL_DATA_MASK); -+ goto issue_diag_reset; -+ } -+ -+ if (type == FORCE_BIG_HAMMER) -+ goto issue_diag_reset; -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) -+ if (!(_base_send_ioc_reset(ioc, -+ MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) { -+ return 0; -+ } -+ -+ issue_diag_reset: -+ rc = _base_diag_reset(ioc, CAN_SLEEP); -+ return rc; -+} -+ -+/** -+ * _base_make_ioc_operational - put controller in OPERATIONAL state -+ * @ioc: per adapter object -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ int r, i, index; -+ unsigned long flags; -+ u32 reply_address; -+ u16 smid; -+ struct _tr_list *delayed_tr, *delayed_tr_next; -+ struct _sc_list *delayed_sc, *delayed_sc_next; -+ struct _event_ack_list *delayed_event_ack, *delayed_event_ack_next; -+ u8 hide_flag; -+ struct adapter_reply_queue *reply_q; -+ Mpi2ReplyDescriptorsUnion_t *reply_post_free_contig; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ /* clean the delayed target reset list */ -+ list_for_each_entry_safe(delayed_tr, delayed_tr_next, -+ &ioc->delayed_tr_list, list) { -+ list_del(&delayed_tr->list); -+ kfree(delayed_tr); -+ } -+ -+ -+ list_for_each_entry_safe(delayed_tr, delayed_tr_next, -+ &ioc->delayed_tr_volume_list, list) { -+ list_del(&delayed_tr->list); -+ kfree(delayed_tr); -+ } -+ -+ list_for_each_entry_safe(delayed_sc, delayed_sc_next, -+ &ioc->delayed_sc_list, list) { -+ list_del(&delayed_sc->list); -+ kfree(delayed_sc); -+ } -+ -+ list_for_each_entry_safe(delayed_event_ack, delayed_event_ack_next, -+ &ioc->delayed_event_ack_list, list) { -+ list_del(&delayed_event_ack->list); -+ kfree(delayed_event_ack); -+ } -+ -+ /* initialize the scsi lookup free list */ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ INIT_LIST_HEAD(&ioc->free_list); -+ smid = 1; -+ for (i = 0; i < ioc->scsiio_depth; i++, smid++) { -+ INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); -+ ioc->scsi_lookup[i].cb_idx = 0xFF; -+ ioc->scsi_lookup[i].smid = smid; -+ ioc->scsi_lookup[i].scmd = NULL; -+ ioc->scsi_lookup[i].direct_io = 0; -+ list_add_tail(&ioc->scsi_lookup[i].tracker_list, -+ &ioc->free_list); -+ } -+ -+ /* hi-priority queue */ -+ INIT_LIST_HEAD(&ioc->hpr_free_list); -+ smid = ioc->hi_priority_smid; -+ for (i = 0; i < ioc->hi_priority_depth; i++, smid++) { -+ ioc->hpr_lookup[i].cb_idx = 0xFF; -+ ioc->hpr_lookup[i].smid = smid; -+ list_add_tail(&ioc->hpr_lookup[i].tracker_list, -+ &ioc->hpr_free_list); -+ } -+ -+ /* internal queue */ -+ INIT_LIST_HEAD(&ioc->internal_free_list); -+ smid = ioc->internal_smid; -+ for (i = 0; i < ioc->internal_depth; i++, smid++) { -+ ioc->internal_lookup[i].cb_idx = 0xFF; -+ ioc->internal_lookup[i].smid = smid; -+ list_add_tail(&ioc->internal_lookup[i].tracker_list, -+ &ioc->internal_free_list); -+ } -+ -+ /* chain pool */ -+ INIT_LIST_HEAD(&ioc->free_chain_list); -+ for (i = 0; i < ioc->chain_depth; i++) -+ list_add_tail(&ioc->chain_lookup[i].tracker_list, -+ &ioc->free_chain_list); -+ -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ /* initialize Reply Free Queue */ -+ for (i = 0, reply_address = (u32)ioc->reply_dma ; -+ i < ioc->reply_free_queue_depth ; i++, reply_address += -+ ioc->reply_sz) -+ ioc->reply_free[i] = cpu_to_le32(reply_address); -+ -+ /* initialize reply queues */ -+ if (ioc->is_driver_loading) -+ _base_assign_reply_queues(ioc); -+ -+ /* initialize Reply Post Free Queue */ -+ index = 0; -+ reply_post_free_contig = ioc->reply_post[0].reply_post_free; -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { -+ /* -+ * If RDPQ is enabled, switch to the next allocation. -+ * Otherwise advance within the contiguous region. -+ */ -+ if (ioc->rdpq_array_enable) { -+ reply_q->reply_post_free = -+ ioc->reply_post[index++].reply_post_free; -+ } else { -+ reply_q->reply_post_free = reply_post_free_contig; -+ reply_post_free_contig += ioc->reply_post_queue_depth; -+ } -+ -+ reply_q->reply_post_host_index = 0; -+ for (i = 0; i < ioc->reply_post_queue_depth; i++) -+ reply_q->reply_post_free[i].Words = -+ cpu_to_le64(ULLONG_MAX); -+ if (!_base_is_controller_msix_enabled(ioc)) -+ goto skip_init_reply_post_free_queue; -+ } -+ skip_init_reply_post_free_queue: -+ -+ r = _base_send_ioc_init(ioc, sleep_flag); -+ if (r) -+ return r; -+ -+ /* initialize reply free host index */ -+ ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; -+ writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); -+ -+ /* initialize reply post host index */ -+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { -+ if (ioc->msix96_vector) -+ writel((reply_q->msix_index & 7)<< -+ MPI2_RPHI_MSIX_INDEX_SHIFT, -+ ioc->replyPostRegisterIndex[reply_q->msix_index/8]); -+ else -+ writel(reply_q->msix_index << -+ MPI2_RPHI_MSIX_INDEX_SHIFT, -+ &ioc->chip->ReplyPostHostIndex); -+ -+ if (!_base_is_controller_msix_enabled(ioc)) -+ goto skip_init_reply_post_host_index; -+ } -+ -+ skip_init_reply_post_host_index: -+ -+ _base_unmask_interrupts(ioc); -+ r = _base_event_notification(ioc, sleep_flag); -+ if (r) -+ return r; -+ -+ if (sleep_flag == CAN_SLEEP) -+ _base_static_config_pages(ioc); -+ -+ -+ if (ioc->is_driver_loading) { -+ -+ if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier -+ == 0x80) { -+ hide_flag = (u8) ( -+ le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & -+ MFG_PAGE10_HIDE_SSDS_MASK); -+ if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) -+ ioc->mfg_pg10_hide_flag = hide_flag; -+ } -+ -+ ioc->wait_for_discovery_to_complete = -+ _base_determine_wait_on_discovery(ioc); -+ -+ return r; /* scan_start and scan_finished support */ -+ } -+ -+ r = _base_send_port_enable(ioc, sleep_flag); -+ if (r) -+ return r; -+ -+ return r; -+} -+ -+/** -+ * mpt2sas_base_free_resources - free resources controller resources -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) -+{ -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ /* synchronizing freeing resource with pci_access_mutex lock */ -+ mutex_lock(&ioc->pci_access_mutex); -+ if (ioc->chip_phys && ioc->chip) { -+ _base_mask_interrupts(ioc); -+ ioc->shost_recovery = 1; -+ _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); -+ ioc->shost_recovery = 0; -+ } -+ -+ mpt2sas_base_unmap_resources(ioc); -+ mutex_unlock(&ioc->pci_access_mutex); -+ return; -+} -+ -+/** -+ * mpt2sas_base_attach - attach controller instance -+ * @ioc: per adapter object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_attach(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int r, i; -+ int cpu_id, last_cpu_id = 0; -+ -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ /* setup cpu_msix_table */ -+ ioc->cpu_count = num_online_cpus(); -+ for_each_online_cpu(cpu_id) -+ last_cpu_id = cpu_id; -+ ioc->cpu_msix_table_sz = last_cpu_id + 1; -+ ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); -+ ioc->reply_queue_count = 1; -+ if (!ioc->cpu_msix_table) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT -+ "allocation for cpu_msix_table failed!!!\n", -+ ioc->name)); -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ -+ if (ioc->is_warpdrive) { -+ ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, -+ sizeof(resource_size_t *), GFP_KERNEL); -+ if (!ioc->reply_post_host_index) { -+ dfailprintk(ioc, pr_info(MPT3SAS_FMT "allocation " -+ "for cpu_msix_table failed!!!\n", ioc->name)); -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ } -+ -+ ioc->rdpq_array_enable_assigned = 0; -+ ioc->dma_mask = 0; -+ r = mpt2sas_base_map_resources(ioc); -+ if (r) -+ goto out_free_resources; -+ -+ if (ioc->is_warpdrive) { -+ ioc->reply_post_host_index[0] = (resource_size_t __iomem *) -+ &ioc->chip->ReplyPostHostIndex; -+ -+ for (i = 1; i < ioc->cpu_msix_table_sz; i++) -+ ioc->reply_post_host_index[i] = -+ (resource_size_t __iomem *) -+ ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) -+ * 4))); -+ } -+ -+ pci_set_drvdata(ioc->pdev, ioc->shost); -+ r = _base_get_ioc_facts(ioc, CAN_SLEEP); -+ if (r) -+ goto out_free_resources; -+ -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ ioc->build_sg_scmd = &_base_build_sg_scmd; -+ ioc->build_sg = &_base_build_sg; -+ ioc->build_zero_len_sge = &_base_build_zero_len_sge; -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ /* -+ * In SAS3.0, -+ * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and -+ * Target Status - all require the IEEE formated scatter gather -+ * elements. -+ */ -+ ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; -+ ioc->build_sg = &_base_build_sg_ieee; -+ ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; -+ ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); -+ break; -+ } -+ -+ /* -+ * These function pointers for other requests that don't -+ * the require IEEE scatter gather elements. -+ * -+ * For example Configuration Pages and SAS IOUNIT Control don't. -+ */ -+ ioc->build_sg_mpi = &_base_build_sg; -+ ioc->build_zero_len_sge_mpi = &_base_build_zero_len_sge; -+ -+ r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); -+ if (r) -+ goto out_free_resources; -+ -+ ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, -+ sizeof(struct mpt2sas_port_facts), GFP_KERNEL); -+ if (!ioc->pfacts) { -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ -+ for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { -+ r = _base_get_port_facts(ioc, i, CAN_SLEEP); -+ if (r) -+ goto out_free_resources; -+ } -+ -+ r = _base_allocate_memory_pools(ioc, CAN_SLEEP); -+ if (r) -+ goto out_free_resources; -+ -+ init_waitqueue_head(&ioc->reset_wq); -+ -+ /* allocate memory pd handle bitmask list */ -+ ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); -+ if (ioc->facts.MaxDevHandle % 8) -+ ioc->pd_handles_sz++; -+ ioc->pd_handles = kzalloc(ioc->pd_handles_sz, -+ GFP_KERNEL); -+ if (!ioc->pd_handles) { -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ ioc->blocking_handles = kzalloc(ioc->pd_handles_sz, -+ GFP_KERNEL); -+ if (!ioc->blocking_handles) { -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ -+ ioc->fwfault_debug = mpt2sas_fwfault_debug; -+ -+ /* base internal command bits */ -+ mutex_init(&ioc->base_cmds.mutex); -+ ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ -+ /* port_enable command bits */ -+ ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->port_enable_cmds.status = MPT3_CMD_NOT_USED; -+ -+ /* transport internal command bits */ -+ ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->transport_cmds.mutex); -+ -+ /* scsih internal command bits */ -+ ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->scsih_cmds.mutex); -+ -+ /* task management internal command bits */ -+ ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->tm_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->tm_cmds.mutex); -+ -+ /* config page internal command bits */ -+ ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->config_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->config_cmds.mutex); -+ -+ /* ctl module internal command bits */ -+ ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); -+ ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_init(&ioc->ctl_cmds.mutex); -+ -+ if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || -+ !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || -+ !ioc->config_cmds.reply || !ioc->ctl_cmds.reply || -+ !ioc->ctl_cmds.sense) { -+ r = -ENOMEM; -+ goto out_free_resources; -+ } -+ -+ for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) -+ ioc->event_masks[i] = -1; -+ -+ /* here we enable the events we care about */ -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY); -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); -+ _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); -+ _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); -+ _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME); -+ _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); -+ _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); -+ _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); -+ _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD); -+ if (ioc->hba_mpi_version_belonged == MPI26_VERSION) -+ _base_unmask_events(ioc, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION); -+ -+ r = _base_make_ioc_operational(ioc, CAN_SLEEP); -+ if (r) -+ goto out_free_resources; -+ -+ ioc->non_operational_loop = 0; -+ return 0; -+ -+ out_free_resources: -+ -+ ioc->remove_host = 1; -+ -+ mpt2sas_base_free_resources(ioc); -+ _base_release_memory_pools(ioc); -+ pci_set_drvdata(ioc->pdev, NULL); -+ kfree(ioc->cpu_msix_table); -+ if (ioc->is_warpdrive) -+ kfree(ioc->reply_post_host_index); -+ kfree(ioc->pd_handles); -+ kfree(ioc->blocking_handles); -+ kfree(ioc->tm_cmds.reply); -+ kfree(ioc->transport_cmds.reply); -+ kfree(ioc->scsih_cmds.reply); -+ kfree(ioc->config_cmds.reply); -+ kfree(ioc->base_cmds.reply); -+ kfree(ioc->port_enable_cmds.reply); -+ kfree(ioc->ctl_cmds.reply); -+ kfree(ioc->ctl_cmds.sense); -+ kfree(ioc->pfacts); -+ ioc->ctl_cmds.reply = NULL; -+ ioc->base_cmds.reply = NULL; -+ ioc->tm_cmds.reply = NULL; -+ ioc->scsih_cmds.reply = NULL; -+ ioc->transport_cmds.reply = NULL; -+ ioc->config_cmds.reply = NULL; -+ ioc->pfacts = NULL; -+ return r; -+} -+ -+ -+/** -+ * mpt2sas_base_detach - remove controller instance -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_base_detach(struct MPT3SAS_ADAPTER *ioc) -+{ -+ dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ mpt2sas_base_stop_watchdog(ioc); -+ mpt2sas_base_free_resources(ioc); -+ _base_release_memory_pools(ioc); -+ pci_set_drvdata(ioc->pdev, NULL); -+ kfree(ioc->cpu_msix_table); -+ if (ioc->is_warpdrive) -+ kfree(ioc->reply_post_host_index); -+ kfree(ioc->pd_handles); -+ kfree(ioc->blocking_handles); -+ kfree(ioc->pfacts); -+ kfree(ioc->ctl_cmds.reply); -+ kfree(ioc->ctl_cmds.sense); -+ kfree(ioc->base_cmds.reply); -+ kfree(ioc->port_enable_cmds.reply); -+ kfree(ioc->tm_cmds.reply); -+ kfree(ioc->transport_cmds.reply); -+ kfree(ioc->scsih_cmds.reply); -+ kfree(ioc->config_cmds.reply); -+} -+ -+/** -+ * _base_reset_handler - reset callback handler (for base) -+ * @ioc: per adapter object -+ * @reset_phase: phase -+ * -+ * The handler for doing any required cleanup or initialization. -+ * -+ * The reset phase can be MPT3_IOC_PRE_RESET, MPT3_IOC_AFTER_RESET, -+ * MPT3_IOC_DONE_RESET -+ * -+ * Return nothing. -+ */ -+static void -+_base_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) -+{ -+ mpt2sas_scsih_reset_handler(ioc, reset_phase); -+ mpt2sas_ctl_reset_handler(ioc, reset_phase); -+ switch (reset_phase) { -+ case MPT3_IOC_PRE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); -+ break; -+ case MPT3_IOC_AFTER_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); -+ if (ioc->transport_cmds.status & MPT3_CMD_PENDING) { -+ ioc->transport_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->transport_cmds.smid); -+ complete(&ioc->transport_cmds.done); -+ } -+ if (ioc->base_cmds.status & MPT3_CMD_PENDING) { -+ ioc->base_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid); -+ complete(&ioc->base_cmds.done); -+ } -+ if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) { -+ ioc->port_enable_failed = 1; -+ ioc->port_enable_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); -+ if (ioc->is_driver_loading) { -+ ioc->start_scan_failed = -+ MPI2_IOCSTATUS_INTERNAL_ERROR; -+ ioc->start_scan = 0; -+ ioc->port_enable_cmds.status = -+ MPT3_CMD_NOT_USED; -+ } else -+ complete(&ioc->port_enable_cmds.done); -+ } -+ if (ioc->config_cmds.status & MPT3_CMD_PENDING) { -+ ioc->config_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); -+ ioc->config_cmds.smid = USHRT_MAX; -+ complete(&ioc->config_cmds.done); -+ } -+ break; -+ case MPT3_IOC_DONE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); -+ break; -+ } -+} -+ -+/** -+ * _wait_for_commands_to_complete - reset controller -+ * @ioc: Pointer to MPT_ADAPTER structure -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * -+ * This function waiting(3s) for all pending commands to complete -+ * prior to putting controller in reset. -+ */ -+static void -+_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) -+{ -+ u32 ioc_state; -+ unsigned long flags; -+ u16 i; -+ -+ ioc->pending_io_count = 0; -+ if (sleep_flag != CAN_SLEEP) -+ return; -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) -+ return; -+ -+ /* pending command count */ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ for (i = 0; i < ioc->scsiio_depth; i++) -+ if (ioc->scsi_lookup[i].cb_idx != 0xFF) -+ ioc->pending_io_count++; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ if (!ioc->pending_io_count) -+ return; -+ -+ /* wait for pending commands to complete */ -+ wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ); -+} -+ -+/** -+ * mpt2sas_base_hard_reset_handler - reset controller -+ * @ioc: Pointer to MPT_ADAPTER structure -+ * @sleep_flag: CAN_SLEEP or NO_SLEEP -+ * @type: FORCE_BIG_HAMMER or SOFT_RESET -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag, -+ enum reset_type type) -+{ -+ int r; -+ unsigned long flags; -+ u32 ioc_state; -+ u8 is_fault = 0, is_trigger = 0; -+ -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ if (ioc->pci_error_recovery) { -+ pr_err(MPT3SAS_FMT "%s: pci error recovery reset\n", -+ ioc->name, __func__); -+ r = 0; -+ goto out_unlocked; -+ } -+ -+ if (mpt2sas_fwfault_debug) -+ mpt2sas_halt_firmware(ioc); -+ -+ /* TODO - What we really should be doing is pulling -+ * out all the code associated with NO_SLEEP; its never used. -+ * That is legacy code from mpt fusion driver, ported over. -+ * I will leave this BUG_ON here for now till its been resolved. -+ */ -+ BUG_ON(sleep_flag == NO_SLEEP); -+ -+ /* wait for an active reset in progress to complete */ -+ if (!mutex_trylock(&ioc->reset_in_progress_mutex)) { -+ do { -+ ssleep(1); -+ } while (ioc->shost_recovery == 1); -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+ return ioc->ioc_reset_in_progress_status; -+ } -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ ioc->shost_recovery = 1; -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) && -+ (!(ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED))) { -+ is_trigger = 1; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) -+ is_fault = 1; -+ } -+ _base_reset_handler(ioc, MPT3_IOC_PRE_RESET); -+ _wait_for_commands_to_complete(ioc, sleep_flag); -+ _base_mask_interrupts(ioc); -+ r = _base_make_ioc_ready(ioc, sleep_flag, type); -+ if (r) -+ goto out; -+ _base_reset_handler(ioc, MPT3_IOC_AFTER_RESET); -+ -+ /* If this hard reset is called while port enable is active, then -+ * there is no reason to call make_ioc_operational -+ */ -+ if (ioc->is_driver_loading && ioc->port_enable_failed) { -+ ioc->remove_host = 1; -+ r = -EFAULT; -+ goto out; -+ } -+ r = _base_get_ioc_facts(ioc, CAN_SLEEP); -+ if (r) -+ goto out; -+ -+ if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable) -+ panic("%s: Issue occurred with flashing controller firmware." -+ "Please reboot the system and ensure that the correct" -+ " firmware version is running\n", ioc->name); -+ -+ r = _base_make_ioc_operational(ioc, sleep_flag); -+ if (!r) -+ _base_reset_handler(ioc, MPT3_IOC_DONE_RESET); -+ -+ out: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: %s\n", -+ ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); -+ -+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -+ ioc->ioc_reset_in_progress_status = r; -+ ioc->shost_recovery = 0; -+ spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -+ ioc->ioc_reset_count++; -+ mutex_unlock(&ioc->reset_in_progress_mutex); -+ -+ out_unlocked: -+ if ((r == 0) && is_trigger) { -+ if (is_fault) -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_FW_FAULT); -+ else -+ mpt2sas_trigger_master(ioc, -+ MASTER_TRIGGER_ADAPTER_RESET); -+ } -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+ return r; -+} -diff --git a/drivers/scsi/mpt2sas/mpt3sas_base.h b/drivers/scsi/mpt2sas/mpt3sas_base.h -new file mode 100644 -index 0000000..a580770 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_base.h -@@ -0,0 +1,1462 @@ -+/* -+ * This is the Fusion MPT base driver providing common API layer interface -+ * for access to MPT (Message Passing Technology) firmware. -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#ifndef MPT3SAS_BASE_H_INCLUDED -+#define MPT3SAS_BASE_H_INCLUDED -+ -+#include "mpi/mpi2_type.h" -+#include "mpi/mpi2.h" -+#include "mpi/mpi2_ioc.h" -+#include "mpi/mpi2_cnfg.h" -+#include "mpi/mpi2_init.h" -+#include "mpi/mpi2_raid.h" -+#include "mpi/mpi2_tool.h" -+#include "mpi/mpi2_sas.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_debug.h" -+#include "mpt3sas_trigger_diag.h" -+ -+/* driver versioning info */ -+#define MPT3SAS_DRIVER_NAME "mpt3sas" -+#define MPT3SAS_AUTHOR "Avago Technologies " -+#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -+#define MPT3SAS_DRIVER_VERSION "13.100.00.00" -+#define MPT3SAS_MAJOR_VERSION 13 -+#define MPT3SAS_MINOR_VERSION 100 -+#define MPT3SAS_BUILD_VERSION 0 -+#define MPT3SAS_RELEASE_VERSION 00 -+ -+#define MPT2SAS_DRIVER_NAME "mpt2sas" -+#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -+#define MPT2SAS_DRIVER_VERSION "20.102.00.00" -+#define MPT2SAS_MAJOR_VERSION 20 -+#define MPT2SAS_MINOR_VERSION 102 -+#define MPT2SAS_BUILD_VERSION 0 -+#define MPT2SAS_RELEASE_VERSION 00 -+ -+/* -+ * Set MPT3SAS_SG_DEPTH value based on user input. -+ */ -+#define MPT_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS -+#define MPT_MIN_PHYS_SEGMENTS 16 -+ -+#ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE -+#define MPT3SAS_SG_DEPTH CONFIG_SCSI_MPT3SAS_MAX_SGE -+#else -+#define MPT3SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS -+#endif -+ -+#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE -+#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE -+#else -+#define MPT2SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS -+#endif -+ -+/* -+ * Generic Defines -+ */ -+#define MPT3SAS_SATA_QUEUE_DEPTH 32 -+#define MPT3SAS_SAS_QUEUE_DEPTH 254 -+#define MPT3SAS_RAID_QUEUE_DEPTH 128 -+ -+#define MPT3SAS_RAID_MAX_SECTORS 8192 -+ -+#define MPT_NAME_LENGTH 32 /* generic length of strings */ -+#define MPT_STRING_LENGTH 64 -+ -+#define MPT_MAX_CALLBACKS 32 -+ -+ -+#define CAN_SLEEP 1 -+#define NO_SLEEP 0 -+ -+#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */ -+/* reserved for issuing internally framed scsi io cmds */ -+#define INTERNAL_SCSIIO_CMDS_COUNT 3 -+ -+#define MPI3_HIM_MASK 0xFFFFFFFF /* mask every bit*/ -+ -+#define MPT3SAS_INVALID_DEVICE_HANDLE 0xFFFF -+ -+#define MAX_CHAIN_ELEMT_SZ 16 -+#define DEFAULT_NUM_FWCHAIN_ELEMTS 8 -+ -+/* -+ * reset phases -+ */ -+#define MPT3_IOC_PRE_RESET 1 /* prior to host reset */ -+#define MPT3_IOC_AFTER_RESET 2 /* just after host reset */ -+#define MPT3_IOC_DONE_RESET 3 /* links re-initialized */ -+ -+/* -+ * logging format -+ */ -+#define MPT3SAS_FMT "%s: " -+ -+/* -+ * WarpDrive Specific Log codes -+ */ -+ -+#define MPT2_WARPDRIVE_LOGENTRY (0x8002) -+#define MPT2_WARPDRIVE_LC_SSDT (0x41) -+#define MPT2_WARPDRIVE_LC_SSDLW (0x43) -+#define MPT2_WARPDRIVE_LC_SSDLF (0x44) -+#define MPT2_WARPDRIVE_LC_BRMF (0x4D) -+ -+/* -+ * per target private data -+ */ -+#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01 -+#define MPT_TARGET_FLAGS_VOLUME 0x02 -+#define MPT_TARGET_FLAGS_DELETED 0x04 -+#define MPT_TARGET_FASTPATH_IO 0x08 -+ -+#define SAS2_PCI_DEVICE_B0_REVISION (0x01) -+#define SAS3_PCI_DEVICE_C0_REVISION (0x02) -+ -+/* -+ * Intel HBA branding -+ */ -+#define MPT2SAS_INTEL_RMS25JB080_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25JB080" -+#define MPT2SAS_INTEL_RMS25JB040_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25JB040" -+#define MPT2SAS_INTEL_RMS25KB080_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25KB080" -+#define MPT2SAS_INTEL_RMS25KB040_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25KB040" -+#define MPT2SAS_INTEL_RMS25LB040_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25LB040" -+#define MPT2SAS_INTEL_RMS25LB080_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS25LB080" -+#define MPT2SAS_INTEL_RMS2LL080_BRANDING \ -+ "Intel Integrated RAID Module RMS2LL080" -+#define MPT2SAS_INTEL_RMS2LL040_BRANDING \ -+ "Intel Integrated RAID Module RMS2LL040" -+#define MPT2SAS_INTEL_RS25GB008_BRANDING \ -+ "Intel(R) RAID Controller RS25GB008" -+#define MPT2SAS_INTEL_SSD910_BRANDING \ -+ "Intel(R) SSD 910 Series" -+ -+#define MPT3SAS_INTEL_RMS3JC080_BRANDING \ -+ "Intel(R) Integrated RAID Module RMS3JC080" -+#define MPT3SAS_INTEL_RS3GC008_BRANDING \ -+ "Intel(R) RAID Controller RS3GC008" -+#define MPT3SAS_INTEL_RS3FC044_BRANDING \ -+ "Intel(R) RAID Controller RS3FC044" -+#define MPT3SAS_INTEL_RS3UC080_BRANDING \ -+ "Intel(R) RAID Controller RS3UC080" -+ -+/* -+ * Intel HBA SSDIDs -+ */ -+#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516 -+#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517 -+#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518 -+#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519 -+#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A -+#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B -+#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E -+#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F -+#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 -+#define MPT2SAS_INTEL_SSD910_SSDID 0x3700 -+ -+#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521 -+#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522 -+#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523 -+#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524 -+ -+/* -+ * Dell HBA branding -+ */ -+#define MPT2SAS_DELL_BRANDING_SIZE 32 -+ -+#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA" -+#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter" -+#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated" -+#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular" -+#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded" -+#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200" -+#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS" -+ -+#define MPT3SAS_DELL_12G_HBA_BRANDING \ -+ "Dell 12Gbps HBA" -+ -+/* -+ * Dell HBA SSDIDs -+ */ -+#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C -+#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D -+#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E -+#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F -+#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20 -+#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21 -+#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22 -+ -+#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46 -+ -+/* -+ * Cisco HBA branding -+ */ -+#define MPT3SAS_CISCO_12G_8E_HBA_BRANDING \ -+ "Cisco 9300-8E 12G SAS HBA" -+#define MPT3SAS_CISCO_12G_8I_HBA_BRANDING \ -+ "Cisco 9300-8i 12G SAS HBA" -+#define MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING \ -+ "Cisco 12G Modular SAS Pass through Controller" -+#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING \ -+ "UCS C3X60 12G SAS Pass through Controller" -+/* -+ * Cisco HBA SSSDIDs -+ */ -+#define MPT3SAS_CISCO_12G_8E_HBA_SSDID 0x14C -+#define MPT3SAS_CISCO_12G_8I_HBA_SSDID 0x154 -+#define MPT3SAS_CISCO_12G_AVILA_HBA_SSDID 0x155 -+#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID 0x156 -+ -+/* -+ * status bits for ioc->diag_buffer_status -+ */ -+#define MPT3_DIAG_BUFFER_IS_REGISTERED (0x01) -+#define MPT3_DIAG_BUFFER_IS_RELEASED (0x02) -+#define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04) -+ -+/* -+ * HP HBA branding -+ */ -+#define MPT2SAS_HP_3PAR_SSVID 0x1590 -+ -+#define MPT2SAS_HP_2_4_INTERNAL_BRANDING \ -+ "HP H220 Host Bus Adapter" -+#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING \ -+ "HP H221 Host Bus Adapter" -+#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING \ -+ "HP H222 Host Bus Adapter" -+#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING \ -+ "HP H220i Host Bus Adapter" -+#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING \ -+ "HP H210i Host Bus Adapter" -+ -+/* -+ * HO HBA SSDIDs -+ */ -+#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 -+#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 -+#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 -+#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 -+#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 -+ -+/* -+ * Combined Reply Queue constants, -+ * There are twelve Supplemental Reply Post Host Index Registers -+ * and each register is at offset 0x10 bytes from the previous one. -+ */ -+#define MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT 12 -+#define MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET (0x10) -+ -+/* OEM Identifiers */ -+#define MFG10_OEM_ID_INVALID (0x00000000) -+#define MFG10_OEM_ID_DELL (0x00000001) -+#define MFG10_OEM_ID_FSC (0x00000002) -+#define MFG10_OEM_ID_SUN (0x00000003) -+#define MFG10_OEM_ID_IBM (0x00000004) -+ -+/* GENERIC Flags 0*/ -+#define MFG10_GF0_OCE_DISABLED (0x00000001) -+#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002) -+#define MFG10_GF0_R10_DISPLAY (0x00000004) -+#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008) -+#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010) -+ -+#define VIRTUAL_IO_FAILED_RETRY (0x32010081) -+ -+/* OEM Specific Flags will come from OEM specific header files */ -+struct Mpi2ManufacturingPage10_t { -+ MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ -+ U8 OEMIdentifier; /* 04h */ -+ U8 Reserved1; /* 05h */ -+ U16 Reserved2; /* 08h */ -+ U32 Reserved3; /* 0Ch */ -+ U32 GenericFlags0; /* 10h */ -+ U32 GenericFlags1; /* 14h */ -+ U32 Reserved4; /* 18h */ -+ U32 OEMSpecificFlags0; /* 1Ch */ -+ U32 OEMSpecificFlags1; /* 20h */ -+ U32 Reserved5[18]; /* 24h - 60h*/ -+}; -+ -+ -+/* Miscellaneous options */ -+struct Mpi2ManufacturingPage11_t { -+ MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ -+ __le32 Reserved1; /* 04h */ -+ u8 Reserved2; /* 08h */ -+ u8 EEDPTagMode; /* 09h */ -+ u8 Reserved3; /* 0Ah */ -+ u8 Reserved4; /* 0Bh */ -+ __le32 Reserved5[23]; /* 0Ch-60h*/ -+}; -+ -+/** -+ * struct MPT3SAS_TARGET - starget private hostdata -+ * @starget: starget object -+ * @sas_address: target sas address -+ * @raid_device: raid_device pointer to access volume data -+ * @handle: device handle -+ * @num_luns: number luns -+ * @flags: MPT_TARGET_FLAGS_XXX flags -+ * @deleted: target flaged for deletion -+ * @tm_busy: target is busy with TM request. -+ * @sdev: The sas_device associated with this target -+ */ -+struct MPT3SAS_TARGET { -+ struct scsi_target *starget; -+ u64 sas_address; -+ struct _raid_device *raid_device; -+ u16 handle; -+ int num_luns; -+ u32 flags; -+ u8 deleted; -+ u8 tm_busy; -+ struct _sas_device *sdev; -+}; -+ -+ -+/* -+ * per device private data -+ */ -+#define MPT_DEVICE_FLAGS_INIT 0x01 -+#define MPT_DEVICE_TLR_ON 0x02 -+ -+#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) -+#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) -+#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) -+#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) -+ -+/** -+ * struct MPT3SAS_DEVICE - sdev private hostdata -+ * @sas_target: starget private hostdata -+ * @lun: lun number -+ * @flags: MPT_DEVICE_XXX flags -+ * @configured_lun: lun is configured -+ * @block: device is in SDEV_BLOCK state -+ * @tlr_snoop_check: flag used in determining whether to disable TLR -+ * @eedp_enable: eedp support enable bit -+ * @eedp_type: 0(type_1), 1(type_2), 2(type_3) -+ * @eedp_block_length: block size -+ */ -+struct MPT3SAS_DEVICE { -+ struct MPT3SAS_TARGET *sas_target; -+ unsigned int lun; -+ u32 flags; -+ u8 configured_lun; -+ u8 block; -+ u8 tlr_snoop_check; -+ u8 ignore_delay_remove; -+}; -+ -+#define MPT3_CMD_NOT_USED 0x8000 /* free */ -+#define MPT3_CMD_COMPLETE 0x0001 /* completed */ -+#define MPT3_CMD_PENDING 0x0002 /* pending */ -+#define MPT3_CMD_REPLY_VALID 0x0004 /* reply is valid */ -+#define MPT3_CMD_RESET 0x0008 /* host reset dropped the command */ -+ -+/** -+ * struct _internal_cmd - internal commands struct -+ * @mutex: mutex -+ * @done: completion -+ * @reply: reply message pointer -+ * @sense: sense data -+ * @status: MPT3_CMD_XXX status -+ * @smid: system message id -+ */ -+struct _internal_cmd { -+ struct mutex mutex; -+ struct completion done; -+ void *reply; -+ void *sense; -+ u16 status; -+ u16 smid; -+}; -+ -+ -+ -+/** -+ * struct _sas_device - attached device information -+ * @list: sas device list -+ * @starget: starget object -+ * @sas_address: device sas address -+ * @device_name: retrieved from the SAS IDENTIFY frame. -+ * @handle: device handle -+ * @sas_address_parent: sas address of parent expander or sas host -+ * @enclosure_handle: enclosure handle -+ * @enclosure_logical_id: enclosure logical identifier -+ * @volume_handle: volume handle (valid when hidden raid member) -+ * @volume_wwid: volume unique identifier -+ * @device_info: bitfield provides detailed info about the device -+ * @id: target id -+ * @channel: target channel -+ * @slot: number number -+ * @phy: phy identifier provided in sas device page 0 -+ * @responding: used in _scsih_sas_device_mark_responding -+ * @fast_path: fast path feature enable bit -+ * @pfa_led_on: flag for PFA LED status -+ * @pend_sas_rphy_add: flag to check if device is in sas_rphy_add() -+ * addition routine. -+ */ -+struct _sas_device { -+ struct list_head list; -+ struct scsi_target *starget; -+ u64 sas_address; -+ u64 device_name; -+ u16 handle; -+ u64 sas_address_parent; -+ u16 enclosure_handle; -+ u64 enclosure_logical_id; -+ u16 volume_handle; -+ u64 volume_wwid; -+ u32 device_info; -+ int id; -+ int channel; -+ u16 slot; -+ u8 phy; -+ u8 responding; -+ u8 fast_path; -+ u8 pfa_led_on; -+ u8 pend_sas_rphy_add; -+ u8 enclosure_level; -+ u8 connector_name[4]; -+ struct kref refcount; -+}; -+ -+static inline void sas_device_get(struct _sas_device *s) -+{ -+ kref_get(&s->refcount); -+} -+ -+static inline void sas_device_free(struct kref *r) -+{ -+ kfree(container_of(r, struct _sas_device, refcount)); -+} -+ -+static inline void sas_device_put(struct _sas_device *s) -+{ -+ kref_put(&s->refcount, sas_device_free); -+} -+ -+/** -+ * struct _raid_device - raid volume link list -+ * @list: sas device list -+ * @starget: starget object -+ * @sdev: scsi device struct (volumes are single lun) -+ * @wwid: unique identifier for the volume -+ * @handle: device handle -+ * @block_size: Block size of the volume -+ * @id: target id -+ * @channel: target channel -+ * @volume_type: the raid level -+ * @device_info: bitfield provides detailed info about the hidden components -+ * @num_pds: number of hidden raid components -+ * @responding: used in _scsih_raid_device_mark_responding -+ * @percent_complete: resync percent complete -+ * @direct_io_enabled: Whether direct io to PDs are allowed or not -+ * @stripe_exponent: X where 2powX is the stripe sz in blocks -+ * @block_exponent: X where 2powX is the block sz in bytes -+ * @max_lba: Maximum number of LBA in the volume -+ * @stripe_sz: Stripe Size of the volume -+ * @device_info: Device info of the volume member disk -+ * @pd_handle: Array of handles of the physical drives for direct I/O in le16 -+ */ -+#define MPT_MAX_WARPDRIVE_PDS 8 -+struct _raid_device { -+ struct list_head list; -+ struct scsi_target *starget; -+ struct scsi_device *sdev; -+ u64 wwid; -+ u16 handle; -+ u16 block_sz; -+ int id; -+ int channel; -+ u8 volume_type; -+ u8 num_pds; -+ u8 responding; -+ u8 percent_complete; -+ u8 direct_io_enabled; -+ u8 stripe_exponent; -+ u8 block_exponent; -+ u64 max_lba; -+ u32 stripe_sz; -+ u32 device_info; -+ u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; -+}; -+ -+/** -+ * struct _boot_device - boot device info -+ * @is_raid: flag to indicate whether this is volume -+ * @device: holds pointer for either struct _sas_device or -+ * struct _raid_device -+ */ -+struct _boot_device { -+ u8 is_raid; -+ void *device; -+}; -+ -+/** -+ * struct _sas_port - wide/narrow sas port information -+ * @port_list: list of ports belonging to expander -+ * @num_phys: number of phys belonging to this port -+ * @remote_identify: attached device identification -+ * @rphy: sas transport rphy object -+ * @port: sas transport wide/narrow port object -+ * @phy_list: _sas_phy list objects belonging to this port -+ */ -+struct _sas_port { -+ struct list_head port_list; -+ u8 num_phys; -+ struct sas_identify remote_identify; -+ struct sas_rphy *rphy; -+ struct sas_port *port; -+ struct list_head phy_list; -+}; -+ -+/** -+ * struct _sas_phy - phy information -+ * @port_siblings: list of phys belonging to a port -+ * @identify: phy identification -+ * @remote_identify: attached device identification -+ * @phy: sas transport phy object -+ * @phy_id: unique phy id -+ * @handle: device handle for this phy -+ * @attached_handle: device handle for attached device -+ * @phy_belongs_to_port: port has been created for this phy -+ */ -+struct _sas_phy { -+ struct list_head port_siblings; -+ struct sas_identify identify; -+ struct sas_identify remote_identify; -+ struct sas_phy *phy; -+ u8 phy_id; -+ u16 handle; -+ u16 attached_handle; -+ u8 phy_belongs_to_port; -+}; -+ -+/** -+ * struct _sas_node - sas_host/expander information -+ * @list: list of expanders -+ * @parent_dev: parent device class -+ * @num_phys: number phys belonging to this sas_host/expander -+ * @sas_address: sas address of this sas_host/expander -+ * @handle: handle for this sas_host/expander -+ * @sas_address_parent: sas address of parent expander or sas host -+ * @enclosure_handle: handle for this a member of an enclosure -+ * @device_info: bitwise defining capabilities of this sas_host/expander -+ * @responding: used in _scsih_expander_device_mark_responding -+ * @phy: a list of phys that make up this sas_host/expander -+ * @sas_port_list: list of ports attached to this sas_host/expander -+ */ -+struct _sas_node { -+ struct list_head list; -+ struct device *parent_dev; -+ u8 num_phys; -+ u64 sas_address; -+ u16 handle; -+ u64 sas_address_parent; -+ u16 enclosure_handle; -+ u64 enclosure_logical_id; -+ u8 responding; -+ struct _sas_phy *phy; -+ struct list_head sas_port_list; -+}; -+ -+/** -+ * enum reset_type - reset state -+ * @FORCE_BIG_HAMMER: issue diagnostic reset -+ * @SOFT_RESET: issue message_unit_reset, if fails to to big hammer -+ */ -+enum reset_type { -+ FORCE_BIG_HAMMER, -+ SOFT_RESET, -+}; -+ -+/** -+ * struct chain_tracker - firmware chain tracker -+ * @chain_buffer: chain buffer -+ * @chain_buffer_dma: physical address -+ * @tracker_list: list of free request (ioc->free_chain_list) -+ */ -+struct chain_tracker { -+ void *chain_buffer; -+ dma_addr_t chain_buffer_dma; -+ struct list_head tracker_list; -+}; -+ -+/** -+ * struct scsiio_tracker - scsi mf request tracker -+ * @smid: system message id -+ * @scmd: scsi request pointer -+ * @cb_idx: callback index -+ * @direct_io: To indicate whether I/O is direct (WARPDRIVE) -+ * @tracker_list: list of free request (ioc->free_list) -+ * @msix_io: IO's msix -+ */ -+struct scsiio_tracker { -+ u16 smid; -+ struct scsi_cmnd *scmd; -+ u8 cb_idx; -+ u8 direct_io; -+ struct list_head chain_list; -+ struct list_head tracker_list; -+ u16 msix_io; -+}; -+ -+/** -+ * struct request_tracker - firmware request tracker -+ * @smid: system message id -+ * @cb_idx: callback index -+ * @tracker_list: list of free request (ioc->free_list) -+ */ -+struct request_tracker { -+ u16 smid; -+ u8 cb_idx; -+ struct list_head tracker_list; -+}; -+ -+/** -+ * struct _tr_list - target reset list -+ * @handle: device handle -+ * @state: state machine -+ */ -+struct _tr_list { -+ struct list_head list; -+ u16 handle; -+ u16 state; -+}; -+ -+/** -+ * struct _sc_list - delayed SAS_IO_UNIT_CONTROL message list -+ * @handle: device handle -+ */ -+struct _sc_list { -+ struct list_head list; -+ u16 handle; -+}; -+ -+/** -+ * struct _event_ack_list - delayed event acknowledgment list -+ * @Event: Event ID -+ * @EventContext: used to track the event uniquely -+ */ -+struct _event_ack_list { -+ struct list_head list; -+ u16 Event; -+ u32 EventContext; -+}; -+ -+/** -+ * struct adapter_reply_queue - the reply queue struct -+ * @ioc: per adapter object -+ * @msix_index: msix index into vector table -+ * @vector: irq vector -+ * @reply_post_host_index: head index in the pool where FW completes IO -+ * @reply_post_free: reply post base virt address -+ * @name: the name registered to request_irq() -+ * @busy: isr is actively processing replies on another cpu -+ * @list: this list -+*/ -+struct adapter_reply_queue { -+ struct MPT3SAS_ADAPTER *ioc; -+ u8 msix_index; -+ unsigned int vector; -+ u32 reply_post_host_index; -+ Mpi2ReplyDescriptorsUnion_t *reply_post_free; -+ char name[MPT_NAME_LENGTH]; -+ atomic_t busy; -+ cpumask_var_t affinity_hint; -+ struct list_head list; -+}; -+ -+typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); -+ -+/* SAS3.0 support */ -+typedef int (*MPT_BUILD_SG_SCMD)(struct MPT3SAS_ADAPTER *ioc, -+ struct scsi_cmnd *scmd, u16 smid); -+typedef void (*MPT_BUILD_SG)(struct MPT3SAS_ADAPTER *ioc, void *psge, -+ dma_addr_t data_out_dma, size_t data_out_sz, -+ dma_addr_t data_in_dma, size_t data_in_sz); -+typedef void (*MPT_BUILD_ZERO_LEN_SGE)(struct MPT3SAS_ADAPTER *ioc, -+ void *paddr); -+ -+ -+ -+/* IOC Facts and Port Facts converted from little endian to cpu */ -+union mpi3_version_union { -+ MPI2_VERSION_STRUCT Struct; -+ u32 Word; -+}; -+ -+struct mpt2sas_facts { -+ u16 MsgVersion; -+ u16 HeaderVersion; -+ u8 IOCNumber; -+ u8 VP_ID; -+ u8 VF_ID; -+ u16 IOCExceptions; -+ u16 IOCStatus; -+ u32 IOCLogInfo; -+ u8 MaxChainDepth; -+ u8 WhoInit; -+ u8 NumberOfPorts; -+ u8 MaxMSIxVectors; -+ u16 RequestCredit; -+ u16 ProductID; -+ u32 IOCCapabilities; -+ union mpi3_version_union FWVersion; -+ u16 IOCRequestFrameSize; -+ u16 IOCMaxChainSegmentSize; -+ u16 MaxInitiators; -+ u16 MaxTargets; -+ u16 MaxSasExpanders; -+ u16 MaxEnclosures; -+ u16 ProtocolFlags; -+ u16 HighPriorityCredit; -+ u16 MaxReplyDescriptorPostQueueDepth; -+ u8 ReplyFrameSize; -+ u8 MaxVolumes; -+ u16 MaxDevHandle; -+ u16 MaxPersistentEntries; -+ u16 MinDevHandle; -+}; -+ -+struct mpt2sas_port_facts { -+ u8 PortNumber; -+ u8 VP_ID; -+ u8 VF_ID; -+ u8 PortType; -+ u16 MaxPostedCmdBuffers; -+}; -+ -+struct reply_post_struct { -+ Mpi2ReplyDescriptorsUnion_t *reply_post_free; -+ dma_addr_t reply_post_free_dma; -+}; -+ -+/** -+ * enum mutex_type - task management mutex type -+ * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it -+ * @TM_MUTEX_ON: mutex is required -+ */ -+enum mutex_type { -+ TM_MUTEX_OFF = 0, -+ TM_MUTEX_ON = 1, -+}; -+ -+typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); -+/** -+ * struct MPT3SAS_ADAPTER - per adapter struct -+ * @list: ioc_list -+ * @shost: shost object -+ * @id: unique adapter id -+ * @cpu_count: number online cpus -+ * @name: generic ioc string -+ * @tmp_string: tmp string used for logging -+ * @pdev: pci pdev object -+ * @pio_chip: physical io register space -+ * @chip: memory mapped register space -+ * @chip_phys: physical addrss prior to mapping -+ * @logging_level: see mpt3sas_debug.h -+ * @fwfault_debug: debuging FW timeouts -+ * @ir_firmware: IR firmware present -+ * @bars: bitmask of BAR's that must be configured -+ * @mask_interrupts: ignore interrupt -+ * @dma_mask: used to set the consistent dma mask -+ * @fault_reset_work_q_name: fw fault work queue -+ * @fault_reset_work_q: "" -+ * @fault_reset_work: "" -+ * @firmware_event_name: fw event work queue -+ * @firmware_event_thread: "" -+ * @fw_event_lock: -+ * @fw_event_list: list of fw events -+ * @aen_event_read_flag: event log was read -+ * @broadcast_aen_busy: broadcast aen waiting to be serviced -+ * @shost_recovery: host reset in progress -+ * @ioc_reset_in_progress_lock: -+ * @ioc_link_reset_in_progress: phy/hard reset in progress -+ * @ignore_loginfos: ignore loginfos during task management -+ * @remove_host: flag for when driver unloads, to avoid sending dev resets -+ * @pci_error_recovery: flag to prevent ioc access until slot reset completes -+ * @wait_for_discovery_to_complete: flag set at driver load time when -+ * waiting on reporting devices -+ * @is_driver_loading: flag set at driver load time -+ * @port_enable_failed: flag set when port enable has failed -+ * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work -+ * @start_scan_failed: means port enable failed, return's the ioc_status -+ * @msix_enable: flag indicating msix is enabled -+ * @msix_vector_count: number msix vectors -+ * @cpu_msix_table: table for mapping cpus to msix index -+ * @cpu_msix_table_sz: table size -+ * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands -+ * @scsi_io_cb_idx: shost generated commands -+ * @tm_cb_idx: task management commands -+ * @scsih_cb_idx: scsih internal commands -+ * @transport_cb_idx: transport internal commands -+ * @ctl_cb_idx: clt internal commands -+ * @base_cb_idx: base internal commands -+ * @config_cb_idx: base internal commands -+ * @tm_tr_cb_idx : device removal target reset handshake -+ * @tm_tr_volume_cb_idx : volume removal target reset -+ * @base_cmds: -+ * @transport_cmds: -+ * @scsih_cmds: -+ * @tm_cmds: -+ * @ctl_cmds: -+ * @config_cmds: -+ * @base_add_sg_single: handler for either 32/64 bit sgl's -+ * @event_type: bits indicating which events to log -+ * @event_context: unique id for each logged event -+ * @event_log: event log pointer -+ * @event_masks: events that are masked -+ * @facts: static facts data -+ * @pfacts: static port facts data -+ * @manu_pg0: static manufacturing page 0 -+ * @manu_pg10: static manufacturing page 10 -+ * @manu_pg11: static manufacturing page 11 -+ * @bios_pg2: static bios page 2 -+ * @bios_pg3: static bios page 3 -+ * @ioc_pg8: static ioc page 8 -+ * @iounit_pg0: static iounit page 0 -+ * @iounit_pg1: static iounit page 1 -+ * @iounit_pg8: static iounit page 8 -+ * @sas_hba: sas host object -+ * @sas_expander_list: expander object list -+ * @sas_node_lock: -+ * @sas_device_list: sas device object list -+ * @sas_device_init_list: sas device object list (used only at init time) -+ * @sas_device_lock: -+ * @io_missing_delay: time for IO completed by fw when PDR enabled -+ * @device_missing_delay: time for device missing by fw when PDR enabled -+ * @sas_id : used for setting volume target IDs -+ * @blocking_handles: bitmask used to identify which devices need blocking -+ * @pd_handles : bitmask for PD handles -+ * @pd_handles_sz : size of pd_handle bitmask -+ * @config_page_sz: config page size -+ * @config_page: reserve memory for config page payload -+ * @config_page_dma: -+ * @hba_queue_depth: hba request queue depth -+ * @sge_size: sg element size for either 32/64 bit -+ * @scsiio_depth: SCSI_IO queue depth -+ * @request_sz: per request frame size -+ * @request: pool of request frames -+ * @request_dma: -+ * @request_dma_sz: -+ * @scsi_lookup: firmware request tracker list -+ * @scsi_lookup_lock: -+ * @free_list: free list of request -+ * @pending_io_count: -+ * @reset_wq: -+ * @chain: pool of chains -+ * @chain_dma: -+ * @max_sges_in_main_message: number sg elements in main message -+ * @max_sges_in_chain_message: number sg elements per chain -+ * @chains_needed_per_io: max chains per io -+ * @chain_depth: total chains allocated -+ * @chain_segment_sz: gives the max number of -+ * SGEs accommodate on single chain buffer -+ * @hi_priority_smid: -+ * @hi_priority: -+ * @hi_priority_dma: -+ * @hi_priority_depth: -+ * @hpr_lookup: -+ * @hpr_free_list: -+ * @internal_smid: -+ * @internal: -+ * @internal_dma: -+ * @internal_depth: -+ * @internal_lookup: -+ * @internal_free_list: -+ * @sense: pool of sense -+ * @sense_dma: -+ * @sense_dma_pool: -+ * @reply_depth: hba reply queue depth: -+ * @reply_sz: per reply frame size: -+ * @reply: pool of replys: -+ * @reply_dma: -+ * @reply_dma_pool: -+ * @reply_free_queue_depth: reply free depth -+ * @reply_free: pool for reply free queue (32 bit addr) -+ * @reply_free_dma: -+ * @reply_free_dma_pool: -+ * @reply_free_host_index: tail index in pool to insert free replys -+ * @reply_post_queue_depth: reply post queue depth -+ * @reply_post_struct: struct for reply_post_free physical & virt address -+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init -+ * @rdpq_array_enable: rdpq_array support is enabled in the driver -+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag -+ * is assigned only ones -+ * @reply_queue_count: number of reply queue's -+ * @reply_queue_list: link list contaning the reply queue info -+ * @msix96_vector: 96 MSI-X vector support -+ * @replyPostRegisterIndex: index of next position in Reply Desc Post Queue -+ * @delayed_tr_list: target reset link list -+ * @delayed_tr_volume_list: volume target reset link list -+ * @delayed_sc_list: -+ * @delayed_event_ack_list: -+ * @temp_sensors_count: flag to carry the number of temperature sensors -+ * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and -+ * pci resource handling. PCI resource freeing will lead to free -+ * vital hardware/memory resource, which might be in use by cli/sysfs -+ * path functions resulting in Null pointer reference followed by kernel -+ * crash. To avoid the above race condition we use mutex syncrhonization -+ * which ensures the syncrhonization between cli/sysfs_show path. -+ */ -+struct MPT3SAS_ADAPTER { -+ struct list_head list; -+ struct Scsi_Host *shost; -+ u8 id; -+ int cpu_count; -+ char name[MPT_NAME_LENGTH]; -+ char driver_name[MPT_NAME_LENGTH]; -+ char tmp_string[MPT_STRING_LENGTH]; -+ struct pci_dev *pdev; -+ Mpi2SystemInterfaceRegs_t __iomem *chip; -+ resource_size_t chip_phys; -+ int logging_level; -+ int fwfault_debug; -+ u8 ir_firmware; -+ int bars; -+ u8 mask_interrupts; -+ int dma_mask; -+ -+ /* fw fault handler */ -+ char fault_reset_work_q_name[20]; -+ struct workqueue_struct *fault_reset_work_q; -+ struct delayed_work fault_reset_work; -+ -+ /* fw event handler */ -+ char firmware_event_name[20]; -+ struct workqueue_struct *firmware_event_thread; -+ spinlock_t fw_event_lock; -+ struct list_head fw_event_list; -+ -+ /* misc flags */ -+ int aen_event_read_flag; -+ u8 broadcast_aen_busy; -+ u16 broadcast_aen_pending; -+ u8 shost_recovery; -+ -+ struct mutex reset_in_progress_mutex; -+ spinlock_t ioc_reset_in_progress_lock; -+ u8 ioc_link_reset_in_progress; -+ u8 ioc_reset_in_progress_status; -+ -+ u8 ignore_loginfos; -+ u8 remove_host; -+ u8 pci_error_recovery; -+ u8 wait_for_discovery_to_complete; -+ u8 is_driver_loading; -+ u8 port_enable_failed; -+ u8 start_scan; -+ u16 start_scan_failed; -+ -+ u8 msix_enable; -+ u16 msix_vector_count; -+ u8 *cpu_msix_table; -+ u16 cpu_msix_table_sz; -+ resource_size_t __iomem **reply_post_host_index; -+ u32 ioc_reset_count; -+ MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; -+ u32 non_operational_loop; -+ -+ /* internal commands, callback index */ -+ u8 scsi_io_cb_idx; -+ u8 tm_cb_idx; -+ u8 transport_cb_idx; -+ u8 scsih_cb_idx; -+ u8 ctl_cb_idx; -+ u8 base_cb_idx; -+ u8 port_enable_cb_idx; -+ u8 config_cb_idx; -+ u8 tm_tr_cb_idx; -+ u8 tm_tr_volume_cb_idx; -+ u8 tm_sas_control_cb_idx; -+ struct _internal_cmd base_cmds; -+ struct _internal_cmd port_enable_cmds; -+ struct _internal_cmd transport_cmds; -+ struct _internal_cmd scsih_cmds; -+ struct _internal_cmd tm_cmds; -+ struct _internal_cmd ctl_cmds; -+ struct _internal_cmd config_cmds; -+ -+ MPT_ADD_SGE base_add_sg_single; -+ -+ /* function ptr for either IEEE or MPI sg elements */ -+ MPT_BUILD_SG_SCMD build_sg_scmd; -+ MPT_BUILD_SG build_sg; -+ MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge; -+ u16 sge_size_ieee; -+ u16 hba_mpi_version_belonged; -+ -+ /* function ptr for MPI sg elements only */ -+ MPT_BUILD_SG build_sg_mpi; -+ MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge_mpi; -+ -+ /* event log */ -+ u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; -+ u32 event_context; -+ void *event_log; -+ u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; -+ -+ /* static config pages */ -+ struct mpt2sas_facts facts; -+ struct mpt2sas_port_facts *pfacts; -+ Mpi2ManufacturingPage0_t manu_pg0; -+ struct Mpi2ManufacturingPage10_t manu_pg10; -+ struct Mpi2ManufacturingPage11_t manu_pg11; -+ Mpi2BiosPage2_t bios_pg2; -+ Mpi2BiosPage3_t bios_pg3; -+ Mpi2IOCPage8_t ioc_pg8; -+ Mpi2IOUnitPage0_t iounit_pg0; -+ Mpi2IOUnitPage1_t iounit_pg1; -+ Mpi2IOUnitPage8_t iounit_pg8; -+ -+ struct _boot_device req_boot_device; -+ struct _boot_device req_alt_boot_device; -+ struct _boot_device current_boot_device; -+ -+ /* sas hba, expander, and device list */ -+ struct _sas_node sas_hba; -+ struct list_head sas_expander_list; -+ spinlock_t sas_node_lock; -+ struct list_head sas_device_list; -+ struct list_head sas_device_init_list; -+ spinlock_t sas_device_lock; -+ struct list_head raid_device_list; -+ spinlock_t raid_device_lock; -+ u8 io_missing_delay; -+ u16 device_missing_delay; -+ int sas_id; -+ -+ void *blocking_handles; -+ void *pd_handles; -+ u16 pd_handles_sz; -+ -+ /* config page */ -+ u16 config_page_sz; -+ void *config_page; -+ dma_addr_t config_page_dma; -+ -+ /* scsiio request */ -+ u16 hba_queue_depth; -+ u16 sge_size; -+ u16 scsiio_depth; -+ u16 request_sz; -+ u8 *request; -+ dma_addr_t request_dma; -+ u32 request_dma_sz; -+ struct scsiio_tracker *scsi_lookup; -+ ulong scsi_lookup_pages; -+ spinlock_t scsi_lookup_lock; -+ struct list_head free_list; -+ int pending_io_count; -+ wait_queue_head_t reset_wq; -+ -+ /* chain */ -+ struct chain_tracker *chain_lookup; -+ struct list_head free_chain_list; -+ struct dma_pool *chain_dma_pool; -+ ulong chain_pages; -+ u16 max_sges_in_main_message; -+ u16 max_sges_in_chain_message; -+ u16 chains_needed_per_io; -+ u32 chain_depth; -+ u16 chain_segment_sz; -+ -+ /* hi-priority queue */ -+ u16 hi_priority_smid; -+ u8 *hi_priority; -+ dma_addr_t hi_priority_dma; -+ u16 hi_priority_depth; -+ struct request_tracker *hpr_lookup; -+ struct list_head hpr_free_list; -+ -+ /* internal queue */ -+ u16 internal_smid; -+ u8 *internal; -+ dma_addr_t internal_dma; -+ u16 internal_depth; -+ struct request_tracker *internal_lookup; -+ struct list_head internal_free_list; -+ -+ /* sense */ -+ u8 *sense; -+ dma_addr_t sense_dma; -+ struct dma_pool *sense_dma_pool; -+ -+ /* reply */ -+ u16 reply_sz; -+ u8 *reply; -+ dma_addr_t reply_dma; -+ u32 reply_dma_max_address; -+ u32 reply_dma_min_address; -+ struct dma_pool *reply_dma_pool; -+ -+ /* reply free queue */ -+ u16 reply_free_queue_depth; -+ __le32 *reply_free; -+ dma_addr_t reply_free_dma; -+ struct dma_pool *reply_free_dma_pool; -+ u32 reply_free_host_index; -+ -+ /* reply post queue */ -+ u16 reply_post_queue_depth; -+ struct reply_post_struct *reply_post; -+ u8 rdpq_array_capable; -+ u8 rdpq_array_enable; -+ u8 rdpq_array_enable_assigned; -+ struct dma_pool *reply_post_free_dma_pool; -+ u8 reply_queue_count; -+ struct list_head reply_queue_list; -+ -+ u8 msix96_vector; -+ /* reply post register index */ -+ resource_size_t **replyPostRegisterIndex; -+ -+ struct list_head delayed_tr_list; -+ struct list_head delayed_tr_volume_list; -+ struct list_head delayed_sc_list; -+ struct list_head delayed_event_ack_list; -+ u8 temp_sensors_count; -+ struct mutex pci_access_mutex; -+ -+ /* diag buffer support */ -+ u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT]; -+ dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; -+ u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; -+ u32 ring_buffer_offset; -+ u32 ring_buffer_sz; -+ u8 is_warpdrive; -+ u8 hide_ir_msg; -+ u8 mfg_pg10_hide_flag; -+ u8 hide_drives; -+ spinlock_t diag_trigger_lock; -+ u8 diag_trigger_active; -+ struct SL_WH_MASTER_TRIGGER_T diag_trigger_master; -+ struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event; -+ struct SL_WH_SCSI_TRIGGERS_T diag_trigger_scsi; -+ struct SL_WH_MPI_TRIGGERS_T diag_trigger_mpi; -+}; -+ -+typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+ -+ -+/* base shared API */ -+extern struct list_head mpt2sas_ioc_list; -+extern char driver_name[MPT_NAME_LENGTH]; -+/* spinlock on list operations over IOCs -+ * Case: when multiple warpdrive cards(IOCs) are in use -+ * Each IOC will added to the ioc list structure on initialization. -+ * Watchdog threads run at regular intervals to check IOC for any -+ * fault conditions which will trigger the dead_ioc thread to -+ * deallocate pci resource, resulting deleting the IOC netry from list, -+ * this deletion need to protected by spinlock to enusre that -+ * ioc removal is syncrhonized, if not synchronized it might lead to -+ * list_del corruption as the ioc list is traversed in cli path. -+ */ -+extern spinlock_t gioc_lock_mpt2sas; -+ -+void mpt2sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc); -+void mpt2sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc); -+ -+int mpt2sas_base_attach(struct MPT3SAS_ADAPTER *ioc); -+void mpt2sas_base_detach(struct MPT3SAS_ADAPTER *ioc); -+int mpt2sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc); -+void mpt2sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc); -+int mpt2sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag, -+ enum reset_type type); -+ -+void *mpt2sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+void *mpt2sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, -+ u16 smid); -+ -+void mpt2sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc); -+ -+/* hi-priority queue */ -+u16 mpt2sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx); -+u16 mpt2sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, -+ struct scsi_cmnd *scmd); -+ -+u16 mpt2sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx); -+void mpt2sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+void mpt2sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u16 handle); -+void mpt2sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u16 handle); -+void mpt2sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, -+ u16 smid, u16 msix_task); -+void mpt2sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+void mpt2sas_base_initialize_callback_handler(void); -+u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func); -+void mpt2sas_base_release_callback_handler(u8 cb_idx); -+ -+u8 mpt2sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+u8 mpt2sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u8 msix_index, u32 reply); -+void *mpt2sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, -+ u32 phys_addr); -+ -+u32 mpt2sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked); -+ -+void mpt2sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code); -+int mpt2sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2SasIoUnitControlReply_t *mpi_reply, -+ Mpi2SasIoUnitControlRequest_t *mpi_request); -+int mpt2sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); -+ -+void mpt2sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, -+ u32 *event_type); -+ -+void mpt2sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc); -+ -+void mpt2sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, -+ u16 device_missing_delay, u8 io_missing_delay); -+ -+int mpt2sas_port_enable(struct MPT3SAS_ADAPTER *ioc); -+ -+ -+/* scsih shared API */ -+u8 mpt2sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, -+ u32 reply); -+void mpt2sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase); -+ -+int mpt2sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ uint channel, uint id, uint lun, u8 type, u16 smid_task, -+ ulong timeout, enum mutex_type m_type); -+void mpt2sas_scsih_set_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle); -+void mpt2sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle); -+void mpt2sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -+void mpt2sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address); -+u8 mpt2sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, -+ u16 smid); -+ -+struct _sas_node *mpt2sas_scsih_expander_find_by_handle( -+ struct MPT3SAS_ADAPTER *ioc, u16 handle); -+struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address( -+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -+struct _sas_device *mpt2sas_get_sdev_by_addr( -+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -+struct _sas_device *__mpt2sas_get_sdev_by_addr( -+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -+ -+void mpt2sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); -+struct _raid_device * -+mpt2sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle); -+ -+/* config shared API */ -+u8 mpt2sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+int mpt2sas_config_get_number_hba_phys(struct MPT3SAS_ADAPTER *ioc, -+ u8 *num_phys); -+int mpt2sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page); -+int mpt2sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, -+ u16 sz); -+int mpt2sas_config_get_manufacturing_pg10(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage10_t *config_page); -+ -+int mpt2sas_config_get_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage11_t *config_page); -+int mpt2sas_config_set_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage11_t *config_page); -+ -+int mpt2sas_config_get_bios_pg2(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2BiosPage2_t *config_page); -+int mpt2sas_config_get_bios_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2BiosPage3_t *config_page); -+int mpt2sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOUnitPage0_t *config_page); -+int mpt2sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage0_t *config_page, -+ u32 form, u32 handle); -+int mpt2sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, -+ u32 form, u32 handle); -+int mpt2sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, -+ u16 sz); -+int mpt2sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOUnitPage1_t *config_page); -+int mpt2sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz); -+int mpt2sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOUnitPage1_t *config_page); -+int mpt2sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOUnitPage8_t *config_page); -+int mpt2sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, -+ u16 sz); -+int mpt2sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, -+ u16 sz); -+int mpt2sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2IOCPage8_t *config_page); -+int mpt2sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ExpanderPage0_t *config_page, -+ u32 form, u32 handle); -+int mpt2sas_config_get_expander_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ExpanderPage1_t *config_page, -+ u32 phy_number, u16 handle); -+int mpt2sas_config_get_enclosure_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, -+ u32 form, u32 handle); -+int mpt2sas_config_get_phy_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number); -+int mpt2sas_config_get_phy_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number); -+int mpt2sas_config_get_raid_volume_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, -+ u32 handle); -+int mpt2sas_config_get_number_pds(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u8 *num_pds); -+int mpt2sas_config_get_raid_volume_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, -+ u32 handle, u16 sz); -+int mpt2sas_config_get_phys_disk_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, -+ u32 form, u32 form_specific); -+int mpt2sas_config_get_volume_handle(struct MPT3SAS_ADAPTER *ioc, u16 pd_handle, -+ u16 *volume_handle); -+int mpt2sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, -+ u16 volume_handle, u64 *wwid); -+ -+/* ctl shared API */ -+extern struct device_attribute *mpt2sas_host_attrs[]; -+extern struct device_attribute *mpt2sas_dev_attrs[]; -+void mpt2sas_ctl_init(ushort hbas_to_enumerate); -+void mpt2sas_ctl_exit(ushort hbas_to_enumerate); -+u8 mpt2sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+void mpt2sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase); -+u8 mpt2sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, -+ u8 msix_index, u32 reply); -+void mpt2sas_ctl_add_to_event_log(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventNotificationReply_t *mpi_reply); -+ -+void mpt2sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, -+ u8 bits_to_regsiter); -+int mpt2sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, -+ u8 *issue_reset); -+ -+/* transport shared API */ -+extern struct scsi_transport_template *mpt2sas_transport_template; -+u8 mpt2sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply); -+struct _sas_port *mpt2sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, -+ u16 handle, u64 sas_address); -+void mpt2sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, -+ u64 sas_address_parent); -+int mpt2sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy -+ *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); -+int mpt2sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_phy *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, -+ struct device *parent_dev); -+void mpt2sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); -+extern struct sas_function_template mpt2sas_transport_functions; -+extern struct scsi_transport_template *mpt2sas_transport_template; -+extern int scsi_internal_device_block(struct scsi_device *sdev); -+extern int scsi_internal_device_unblock(struct scsi_device *sdev, -+ enum scsi_device_state new_state); -+/* trigger data externs */ -+void mpt2sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data); -+void mpt2sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data); -+void mpt2sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, -+ u32 tigger_bitmask); -+void mpt2sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event, -+ u16 log_entry_qualifier); -+void mpt2sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, -+ u8 asc, u8 ascq); -+void mpt2sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, -+ u32 loginfo); -+ -+/* warpdrive APIs */ -+u8 mpt2sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc); -+void mpt2sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device); -+u8 -+mpt2sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+void -+mpt2sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io); -+void -+mpt2sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, -+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, -+ u16 smid); -+ -+#endif /* MPT3SAS_BASE_H_INCLUDED */ -diff --git a/drivers/scsi/mpt2sas/mpt3sas_config.c b/drivers/scsi/mpt2sas/mpt3sas_config.c -new file mode 100644 -index 0000000..0f67b2c ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_config.c -@@ -0,0 +1,1716 @@ -+/* -+ * This module provides common API for accessing firmware configuration pages -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+/* local definitions */ -+ -+/* Timeout for config page request (in seconds) */ -+#define MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT 15 -+ -+/* Common sgl flags for READING a config page. */ -+#define MPT3_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ -+ | MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT) -+ -+/* Common sgl flags for WRITING a config page. */ -+#define MPT3_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ -+ MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ -+ | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \ -+ << MPI2_SGE_FLAGS_SHIFT) -+ -+/** -+ * struct config_request - obtain dma memory via routine -+ * @sz: size -+ * @page: virt pointer -+ * @page_dma: phys pointer -+ * -+ */ -+struct config_request { -+ u16 sz; -+ void *page; -+ dma_addr_t page_dma; -+}; -+ -+/** -+ * _config_display_some_debug - debug routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @calling_function_name: string pass from calling function -+ * @mpi_reply: reply message frame -+ * Context: none. -+ * -+ * Function for displaying debug info helpful when debugging issues -+ * in this module. -+ */ -+static void -+_config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ char *calling_function_name, MPI2DefaultReply_t *mpi_reply) -+{ -+ Mpi2ConfigRequest_t *mpi_request; -+ char *desc = NULL; -+ -+ if (!(ioc->logging_level & MPT_DEBUG_CONFIG)) -+ return; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) { -+ case MPI2_CONFIG_PAGETYPE_IO_UNIT: -+ desc = "io_unit"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_IOC: -+ desc = "ioc"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_BIOS: -+ desc = "bios"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_RAID_VOLUME: -+ desc = "raid_volume"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_MANUFACTURING: -+ desc = "manufaucturing"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK: -+ desc = "physdisk"; -+ break; -+ case MPI2_CONFIG_PAGETYPE_EXTENDED: -+ switch (mpi_request->ExtPageType) { -+ case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT: -+ desc = "sas_io_unit"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER: -+ desc = "sas_expander"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE: -+ desc = "sas_device"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY: -+ desc = "sas_phy"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_LOG: -+ desc = "log"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE: -+ desc = "enclosure"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG: -+ desc = "raid_config"; -+ break; -+ case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING: -+ desc = "driver_mapping"; -+ break; -+ } -+ break; -+ } -+ -+ if (!desc) -+ return; -+ -+ pr_info(MPT3SAS_FMT -+ "%s: %s(%d), action(%d), form(0x%08x), smid(%d)\n", -+ ioc->name, calling_function_name, desc, -+ mpi_request->Header.PageNumber, mpi_request->Action, -+ le32_to_cpu(mpi_request->PageAddress), smid); -+ -+ if (!mpi_reply) -+ return; -+ -+ if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) -+ pr_info(MPT3SAS_FMT -+ "\tiocstatus(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo)); -+} -+ -+/** -+ * _config_alloc_config_dma_memory - obtain physical memory -+ * @ioc: per adapter object -+ * @mem: struct config_request -+ * -+ * A wrapper for obtaining dma-able memory for config page request. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_config_alloc_config_dma_memory(struct MPT3SAS_ADAPTER *ioc, -+ struct config_request *mem) -+{ -+ int r = 0; -+ -+ if (mem->sz > ioc->config_page_sz) { -+ mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz, -+ &mem->page_dma, GFP_KERNEL); -+ if (!mem->page) { -+ pr_err(MPT3SAS_FMT -+ "%s: dma_alloc_coherent failed asking for (%d) bytes!!\n", -+ ioc->name, __func__, mem->sz); -+ r = -ENOMEM; -+ } -+ } else { /* use tmp buffer if less than 512 bytes */ -+ mem->page = ioc->config_page; -+ mem->page_dma = ioc->config_page_dma; -+ } -+ return r; -+} -+ -+/** -+ * _config_free_config_dma_memory - wrapper to free the memory -+ * @ioc: per adapter object -+ * @mem: struct config_request -+ * -+ * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static void -+_config_free_config_dma_memory(struct MPT3SAS_ADAPTER *ioc, -+ struct config_request *mem) -+{ -+ if (mem->sz > ioc->config_page_sz) -+ dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page, -+ mem->page_dma); -+} -+ -+/** -+ * mpt2sas_config_done - config page completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: none. -+ * -+ * The callback handler when using _config_request. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ if (ioc->config_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->config_cmds.smid != smid) -+ return 1; -+ ioc->config_cmds.status |= MPT3_CMD_COMPLETE; -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply) { -+ ioc->config_cmds.status |= MPT3_CMD_REPLY_VALID; -+ memcpy(ioc->config_cmds.reply, mpi_reply, -+ mpi_reply->MsgLength*4); -+ } -+ ioc->config_cmds.status &= ~MPT3_CMD_PENDING; -+ _config_display_some_debug(ioc, smid, "config_done", mpi_reply); -+ ioc->config_cmds.smid = USHRT_MAX; -+ complete(&ioc->config_cmds.done); -+ return 1; -+} -+ -+/** -+ * _config_request - main routine for sending config page requests -+ * @ioc: per adapter object -+ * @mpi_request: request message frame -+ * @mpi_reply: reply mf payload returned from firmware -+ * @timeout: timeout in seconds -+ * @config_page: contents of the config page -+ * @config_page_sz: size of config page -+ * Context: sleep -+ * -+ * A generic API for config page requests to firmware. -+ * -+ * The ioc->config_cmds.status flag should be MPT3_CMD_NOT_USED before calling -+ * this API. -+ * -+ * The callback index is set inside `ioc->config_cb_idx. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t -+ *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout, -+ void *config_page, u16 config_page_sz) -+{ -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ Mpi2ConfigRequest_t *config_request; -+ int r; -+ u8 retry_count, issue_host_reset = 0; -+ u16 wait_state_count; -+ struct config_request mem; -+ u32 ioc_status = UINT_MAX; -+ -+ mutex_lock(&ioc->config_cmds.mutex); -+ if (ioc->config_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: config_cmd in use\n", -+ ioc->name, __func__); -+ mutex_unlock(&ioc->config_cmds.mutex); -+ return -EAGAIN; -+ } -+ -+ retry_count = 0; -+ memset(&mem, 0, sizeof(struct config_request)); -+ -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ -+ if (config_page) { -+ mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion; -+ mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber; -+ mpi_request->Header.PageType = mpi_reply->Header.PageType; -+ mpi_request->Header.PageLength = mpi_reply->Header.PageLength; -+ mpi_request->ExtPageLength = mpi_reply->ExtPageLength; -+ mpi_request->ExtPageType = mpi_reply->ExtPageType; -+ if (mpi_request->Header.PageLength) -+ mem.sz = mpi_request->Header.PageLength * 4; -+ else -+ mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; -+ r = _config_alloc_config_dma_memory(ioc, &mem); -+ if (r != 0) -+ goto out; -+ if (mpi_request->Action == -+ MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT || -+ mpi_request->Action == -+ MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) { -+ ioc->base_add_sg_single(&mpi_request->PageBufferSGE, -+ MPT3_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, -+ mem.page_dma); -+ memcpy(mem.page, config_page, min_t(u16, mem.sz, -+ config_page_sz)); -+ } else { -+ memset(config_page, 0, config_page_sz); -+ ioc->base_add_sg_single(&mpi_request->PageBufferSGE, -+ MPT3_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma); -+ memset(mem.page, 0, min_t(u16, mem.sz, config_page_sz)); -+ } -+ } -+ -+ retry_config: -+ if (retry_count) { -+ if (retry_count > 2) { /* attempt only 2 retries */ -+ r = -EFAULT; -+ goto free_mem; -+ } -+ pr_info(MPT3SAS_FMT "%s: attempting retry (%d)\n", -+ ioc->name, __func__, retry_count); -+ } -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ ioc->config_cmds.status = MPT3_CMD_NOT_USED; -+ r = -EFAULT; -+ goto free_mem; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ioc->config_cmds.status = MPT3_CMD_NOT_USED; -+ r = -EAGAIN; -+ goto free_mem; -+ } -+ -+ r = 0; -+ memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t)); -+ ioc->config_cmds.status = MPT3_CMD_PENDING; -+ config_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->config_cmds.smid = smid; -+ memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); -+ _config_display_some_debug(ioc, smid, "config_request", NULL); -+ init_completion(&ioc->config_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, -+ timeout*HZ); -+ if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2ConfigRequest_t)/4); -+ retry_count++; -+ if (ioc->config_cmds.smid == smid) -+ mpt2sas_base_free_smid(ioc, smid); -+ if ((ioc->shost_recovery) || (ioc->config_cmds.status & -+ MPT3_CMD_RESET) || ioc->pci_error_recovery) -+ goto retry_config; -+ issue_host_reset = 1; -+ r = -EFAULT; -+ goto free_mem; -+ } -+ -+ if (ioc->config_cmds.status & MPT3_CMD_REPLY_VALID) { -+ memcpy(mpi_reply, ioc->config_cmds.reply, -+ sizeof(Mpi2ConfigReply_t)); -+ -+ /* Reply Frame Sanity Checks to workaround FW issues */ -+ if ((mpi_request->Header.PageType & 0xF) != -+ (mpi_reply->Header.PageType & 0xF)) { -+ _debug_dump_mf(mpi_request, ioc->request_sz/4); -+ _debug_dump_reply(mpi_reply, ioc->request_sz/4); -+ panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \ -+ " mpi_reply mismatch: Requested PageType(0x%02x)" \ -+ " Reply PageType(0x%02x)\n", \ -+ ioc->name, __func__, -+ (mpi_request->Header.PageType & 0xF), -+ (mpi_reply->Header.PageType & 0xF)); -+ } -+ -+ if (((mpi_request->Header.PageType & 0xF) == -+ MPI2_CONFIG_PAGETYPE_EXTENDED) && -+ mpi_request->ExtPageType != mpi_reply->ExtPageType) { -+ _debug_dump_mf(mpi_request, ioc->request_sz/4); -+ _debug_dump_reply(mpi_reply, ioc->request_sz/4); -+ panic(KERN_WARNING MPT3SAS_FMT "%s: Firmware BUG:" \ -+ " mpi_reply mismatch: Requested ExtPageType(0x%02x)" -+ " Reply ExtPageType(0x%02x)\n", -+ ioc->name, __func__, mpi_request->ExtPageType, -+ mpi_reply->ExtPageType); -+ } -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) -+ & MPI2_IOCSTATUS_MASK; -+ } -+ -+ if (retry_count) -+ pr_info(MPT3SAS_FMT "%s: retry (%d) completed!!\n", \ -+ ioc->name, __func__, retry_count); -+ -+ if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) && -+ config_page && mpi_request->Action == -+ MPI2_CONFIG_ACTION_PAGE_READ_CURRENT) { -+ u8 *p = (u8 *)mem.page; -+ -+ /* Config Page Sanity Checks to workaround FW issues */ -+ if (p) { -+ if ((mpi_request->Header.PageType & 0xF) != -+ (p[3] & 0xF)) { -+ _debug_dump_mf(mpi_request, ioc->request_sz/4); -+ _debug_dump_reply(mpi_reply, ioc->request_sz/4); -+ _debug_dump_config(p, min_t(u16, mem.sz, -+ config_page_sz)/4); -+ panic(KERN_WARNING MPT3SAS_FMT -+ "%s: Firmware BUG:" \ -+ " config page mismatch:" -+ " Requested PageType(0x%02x)" -+ " Reply PageType(0x%02x)\n", -+ ioc->name, __func__, -+ (mpi_request->Header.PageType & 0xF), -+ (p[3] & 0xF)); -+ } -+ -+ if (((mpi_request->Header.PageType & 0xF) == -+ MPI2_CONFIG_PAGETYPE_EXTENDED) && -+ (mpi_request->ExtPageType != p[6])) { -+ _debug_dump_mf(mpi_request, ioc->request_sz/4); -+ _debug_dump_reply(mpi_reply, ioc->request_sz/4); -+ _debug_dump_config(p, min_t(u16, mem.sz, -+ config_page_sz)/4); -+ panic(KERN_WARNING MPT3SAS_FMT -+ "%s: Firmware BUG:" \ -+ " config page mismatch:" -+ " Requested ExtPageType(0x%02x)" -+ " Reply ExtPageType(0x%02x)\n", -+ ioc->name, __func__, -+ mpi_request->ExtPageType, p[6]); -+ } -+ } -+ memcpy(config_page, mem.page, min_t(u16, mem.sz, -+ config_page_sz)); -+ } -+ -+ free_mem: -+ if (config_page) -+ _config_free_config_dma_memory(ioc, &mem); -+ out: -+ ioc->config_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_unlock(&ioc->config_cmds.mutex); -+ -+ if (issue_host_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_manufacturing_pg7 - obtain manufacturing page 7 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, -+ u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 7; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING7_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_manufacturing_pg10(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage10_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 10; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_manufacturing_pg11 - obtain manufacturing page 11 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage11_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 11; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_set_manufacturing_pg11 - set manufacturing page 11 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_set_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, -+ struct Mpi2ManufacturingPage11_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; -+ mpi_request.Header.PageNumber = 11; -+ mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_bios_pg2 - obtain bios page 2 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_bios_pg2(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; -+ mpi_request.Header.PageNumber = 2; -+ mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_bios_pg3 - obtain bios page 3 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_bios_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2BiosPage3_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; -+ mpi_request.Header.PageNumber = 3; -+ mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_iounit_pg0 - obtain iounit page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_iounit_pg1 - obtain iounit page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_set_iounit_pg1 - set iounit page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_iounit_pg3 - obtain iounit page 3 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 3; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_iounit_pg8 - obtain iounit page 8 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; -+ mpi_request.Header.PageNumber = 8; -+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; -+ mpi_request.Header.PageNumber = 8; -+ mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: device handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage0_t *config_page, -+ u32 form, u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; -+ mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; -+ mpi_request.Header.PageNumber = 0; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: device handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, -+ u32 form, u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; -+ mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION; -+ mpi_request.Header.PageNumber = 1; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_number_hba_phys - obtain number of phys on the host -+ * @ioc: per adapter object -+ * @num_phys: pointer returned with the number of phys -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_number_hba_phys(struct MPT3SAS_ADAPTER *ioc, u8 *num_phys) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ u16 ioc_status; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasIOUnitPage0_t config_page; -+ -+ *num_phys = 0; -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, -+ sizeof(Mpi2SasIOUnitPage0_t)); -+ if (!r) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) -+ *num_phys = config_page.NumPhys; -+ } -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Calling function should call config_get_number_hba_phys prior to -+ * this function, so enough memory is allocated for config_page. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, -+ u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Calling function should call config_get_number_hba_phys prior to -+ * this function, so enough memory is allocated for config_page. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, -+ u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Calling function should call config_get_number_hba_phys prior to -+ * this function, so enough memory is allocated for config_page. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, -+ u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; -+ _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_expander_pg0 - obtain expander page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: expander handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_expander_pg1 - obtain expander page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @phy_number: phy number -+ * @handle: expander handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_expander_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, -+ u16 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = -+ cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | -+ (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: expander handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_enclosure_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_phy_pg0 - obtain phy page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @phy_number: phy number -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_phy_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = -+ cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_phy_pg1 - obtain phy page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @phy_number: phy number -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_phy_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = -+ cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: volume handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_raid_volume_pg1(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, -+ u32 handle) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; -+ mpi_request.Header.PageNumber = 1; -+ mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume -+ * @ioc: per adapter object -+ * @handle: volume handle -+ * @num_pds: returns pds count -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_number_pds(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u8 *num_pds) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ Mpi2RaidVolPage0_t config_page; -+ Mpi2ConfigReply_t mpi_reply; -+ int r; -+ u16 ioc_status; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ *num_pds = 0; -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = -+ cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, -+ sizeof(Mpi2RaidVolPage0_t)); -+ if (!r) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) -+ *num_pds = config_page.NumPhysDisks; -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_HANDLE or HANDLE -+ * @handle: volume handle -+ * @sz: size of buffer passed in config_page -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_raid_volume_pg0(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, -+ u32 handle, u16 sz) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | handle); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0 -+ * @ioc: per adapter object -+ * @mpi_reply: reply mf payload returned from firmware -+ * @config_page: contents of the config page -+ * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE -+ * @form_specific: specific to the form -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_phys_disk_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t -+ *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form, -+ u32 form_specific) -+{ -+ Mpi2ConfigRequest_t mpi_request; -+ int r; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; -+ mpi_request.Header.PageNumber = 0; -+ mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.PageAddress = cpu_to_le32(form | form_specific); -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ r = _config_request(ioc, &mpi_request, mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ sizeof(*config_page)); -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_volume_handle - returns volume handle for give hidden -+ * raid components -+ * @ioc: per adapter object -+ * @pd_handle: phys disk handle -+ * @volume_handle: volume handle -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_volume_handle(struct MPT3SAS_ADAPTER *ioc, u16 pd_handle, -+ u16 *volume_handle) -+{ -+ Mpi2RaidConfigurationPage0_t *config_page = NULL; -+ Mpi2ConfigRequest_t mpi_request; -+ Mpi2ConfigReply_t mpi_reply; -+ int r, i, config_page_sz; -+ u16 ioc_status; -+ int config_num; -+ u16 element_type; -+ u16 phys_disk_dev_handle; -+ -+ *volume_handle = 0; -+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_CONFIG; -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; -+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; -+ mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG; -+ mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION; -+ mpi_request.Header.PageNumber = 0; -+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); -+ if (r) -+ goto out; -+ -+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; -+ config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); -+ config_page = kmalloc(config_page_sz, GFP_KERNEL); -+ if (!config_page) { -+ r = -1; -+ goto out; -+ } -+ -+ config_num = 0xff; -+ while (1) { -+ mpi_request.PageAddress = cpu_to_le32(config_num + -+ MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM); -+ r = _config_request(ioc, &mpi_request, &mpi_reply, -+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, -+ config_page_sz); -+ if (r) -+ goto out; -+ r = -1; -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ goto out; -+ for (i = 0; i < config_page->NumElements; i++) { -+ element_type = le16_to_cpu(config_page-> -+ ConfigElement[i].ElementFlags) & -+ MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE; -+ if (element_type == -+ MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT || -+ element_type == -+ MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) { -+ phys_disk_dev_handle = -+ le16_to_cpu(config_page->ConfigElement[i]. -+ PhysDiskDevHandle); -+ if (phys_disk_dev_handle == pd_handle) { -+ *volume_handle = -+ le16_to_cpu(config_page-> -+ ConfigElement[i].VolDevHandle); -+ r = 0; -+ goto out; -+ } -+ } else if (element_type == -+ MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) { -+ *volume_handle = 0; -+ r = 0; -+ goto out; -+ } -+ } -+ config_num = config_page->ConfigNum; -+ } -+ out: -+ kfree(config_page); -+ return r; -+} -+ -+/** -+ * mpt2sas_config_get_volume_wwid - returns wwid given the volume handle -+ * @ioc: per adapter object -+ * @volume_handle: volume handle -+ * @wwid: volume wwid -+ * Context: sleep. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, u16 volume_handle, -+ u64 *wwid) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2RaidVolPage1_t raid_vol_pg1; -+ -+ *wwid = 0; -+ if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, -+ volume_handle))) { -+ *wwid = le64_to_cpu(raid_vol_pg1.WWID); -+ return 0; -+ } else -+ return -1; -+} -diff --git a/drivers/scsi/mpt2sas/mpt3sas_ctl.c b/drivers/scsi/mpt2sas/mpt3sas_ctl.c -new file mode 100644 -index 0000000..5c0cc30 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_ctl.c -@@ -0,0 +1,3483 @@ -+/* -+ * Management Module Support for MPT (Message Passing Technology) based -+ * controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "mpt3sas_base.h" -+#include "mpt3sas_ctl.h" -+ -+ -+static struct fasync_struct *async_queue; -+static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); -+ -+ -+/** -+ * enum block_state - blocking state -+ * @NON_BLOCKING: non blocking -+ * @BLOCKING: blocking -+ * -+ * These states are for ioctls that need to wait for a response -+ * from firmware, so they probably require sleep. -+ */ -+enum block_state { -+ NON_BLOCKING, -+ BLOCKING, -+}; -+ -+/** -+ * _ctl_sas_device_find_by_handle - sas device search -+ * @ioc: per adapter object -+ * @handle: sas device handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->sas_device_lock -+ * -+ * This searches for sas_device based on sas_address, then return sas_device -+ * object. -+ */ -+static struct _sas_device * -+_ctl_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_device *sas_device, *r; -+ -+ r = NULL; -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -+ if (sas_device->handle != handle) -+ continue; -+ r = sas_device; -+ goto out; -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * _ctl_display_some_debug - debug routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @calling_function_name: string pass from calling function -+ * @mpi_reply: reply message frame -+ * Context: none. -+ * -+ * Function for displaying debug info helpful when debugging issues -+ * in this module. -+ */ -+static void -+_ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ char *calling_function_name, MPI2DefaultReply_t *mpi_reply) -+{ -+ Mpi2ConfigRequest_t *mpi_request; -+ char *desc = NULL; -+ -+ if (!(ioc->logging_level & MPT_DEBUG_IOCTL)) -+ return; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ switch (mpi_request->Function) { -+ case MPI2_FUNCTION_SCSI_IO_REQUEST: -+ { -+ Mpi2SCSIIORequest_t *scsi_request = -+ (Mpi2SCSIIORequest_t *)mpi_request; -+ -+ snprintf(ioc->tmp_string, MPT_STRING_LENGTH, -+ "scsi_io, cmd(0x%02x), cdb_len(%d)", -+ scsi_request->CDB.CDB32[0], -+ le16_to_cpu(scsi_request->IoFlags) & 0xF); -+ desc = ioc->tmp_string; -+ break; -+ } -+ case MPI2_FUNCTION_SCSI_TASK_MGMT: -+ desc = "task_mgmt"; -+ break; -+ case MPI2_FUNCTION_IOC_INIT: -+ desc = "ioc_init"; -+ break; -+ case MPI2_FUNCTION_IOC_FACTS: -+ desc = "ioc_facts"; -+ break; -+ case MPI2_FUNCTION_CONFIG: -+ { -+ Mpi2ConfigRequest_t *config_request = -+ (Mpi2ConfigRequest_t *)mpi_request; -+ -+ snprintf(ioc->tmp_string, MPT_STRING_LENGTH, -+ "config, type(0x%02x), ext_type(0x%02x), number(%d)", -+ (config_request->Header.PageType & -+ MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType, -+ config_request->Header.PageNumber); -+ desc = ioc->tmp_string; -+ break; -+ } -+ case MPI2_FUNCTION_PORT_FACTS: -+ desc = "port_facts"; -+ break; -+ case MPI2_FUNCTION_PORT_ENABLE: -+ desc = "port_enable"; -+ break; -+ case MPI2_FUNCTION_EVENT_NOTIFICATION: -+ desc = "event_notification"; -+ break; -+ case MPI2_FUNCTION_FW_DOWNLOAD: -+ desc = "fw_download"; -+ break; -+ case MPI2_FUNCTION_FW_UPLOAD: -+ desc = "fw_upload"; -+ break; -+ case MPI2_FUNCTION_RAID_ACTION: -+ desc = "raid_action"; -+ break; -+ case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: -+ { -+ Mpi2SCSIIORequest_t *scsi_request = -+ (Mpi2SCSIIORequest_t *)mpi_request; -+ -+ snprintf(ioc->tmp_string, MPT_STRING_LENGTH, -+ "raid_pass, cmd(0x%02x), cdb_len(%d)", -+ scsi_request->CDB.CDB32[0], -+ le16_to_cpu(scsi_request->IoFlags) & 0xF); -+ desc = ioc->tmp_string; -+ break; -+ } -+ case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: -+ desc = "sas_iounit_cntl"; -+ break; -+ case MPI2_FUNCTION_SATA_PASSTHROUGH: -+ desc = "sata_pass"; -+ break; -+ case MPI2_FUNCTION_DIAG_BUFFER_POST: -+ desc = "diag_buffer_post"; -+ break; -+ case MPI2_FUNCTION_DIAG_RELEASE: -+ desc = "diag_release"; -+ break; -+ case MPI2_FUNCTION_SMP_PASSTHROUGH: -+ desc = "smp_passthrough"; -+ break; -+ } -+ -+ if (!desc) -+ return; -+ -+ pr_info(MPT3SAS_FMT "%s: %s, smid(%d)\n", -+ ioc->name, calling_function_name, desc, smid); -+ -+ if (!mpi_reply) -+ return; -+ -+ if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) -+ pr_info(MPT3SAS_FMT -+ "\tiocstatus(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo)); -+ -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ mpi_request->Function == -+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { -+ Mpi2SCSIIOReply_t *scsi_reply = -+ (Mpi2SCSIIOReply_t *)mpi_reply; -+ struct _sas_device *sas_device = NULL; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = _ctl_sas_device_find_by_handle(ioc, -+ le16_to_cpu(scsi_reply->DevHandle)); -+ if (sas_device) { -+ pr_warn(MPT3SAS_FMT "\tsas_address(0x%016llx), phy(%d)\n", -+ ioc->name, (unsigned long long) -+ sas_device->sas_address, sas_device->phy); -+ pr_warn(MPT3SAS_FMT -+ "\tenclosure_logical_id(0x%016llx), slot(%d)\n", -+ ioc->name, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) -+ pr_info(MPT3SAS_FMT -+ "\tscsi_state(0x%02x), scsi_status" -+ "(0x%02x)\n", ioc->name, -+ scsi_reply->SCSIState, -+ scsi_reply->SCSIStatus); -+ } -+} -+ -+/** -+ * mpt2sas_ctl_done - ctl module completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: none. -+ * -+ * The callback handler when using ioc->ctl_cb_idx. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ Mpi2SCSIIOReply_t *scsiio_reply; -+ const void *sense_data; -+ u32 sz; -+ -+ if (ioc->ctl_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->ctl_cmds.smid != smid) -+ return 1; -+ ioc->ctl_cmds.status |= MPT3_CMD_COMPLETE; -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply) { -+ memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); -+ ioc->ctl_cmds.status |= MPT3_CMD_REPLY_VALID; -+ /* get sense data */ -+ if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ mpi_reply->Function == -+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { -+ scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; -+ if (scsiio_reply->SCSIState & -+ MPI2_SCSI_STATE_AUTOSENSE_VALID) { -+ sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, -+ le32_to_cpu(scsiio_reply->SenseCount)); -+ sense_data = mpt2sas_base_get_sense_buffer(ioc, -+ smid); -+ memcpy(ioc->ctl_cmds.sense, sense_data, sz); -+ } -+ } -+ } -+ _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); -+ ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING; -+ complete(&ioc->ctl_cmds.done); -+ return 1; -+} -+ -+/** -+ * _ctl_check_event_type - determines when an event needs logging -+ * @ioc: per adapter object -+ * @event: firmware event -+ * -+ * The bitmask in ioc->event_type[] indicates which events should be -+ * be saved in the driver event_log. This bitmask is set by application. -+ * -+ * Returns 1 when event should be captured, or zero means no match. -+ */ -+static int -+_ctl_check_event_type(struct MPT3SAS_ADAPTER *ioc, u16 event) -+{ -+ u16 i; -+ u32 desired_event; -+ -+ if (event >= 128 || !event || !ioc->event_log) -+ return 0; -+ -+ desired_event = (1 << (event % 32)); -+ if (!desired_event) -+ desired_event = 1; -+ i = event / 32; -+ return desired_event & ioc->event_type[i]; -+} -+ -+/** -+ * mpt2sas_ctl_add_to_event_log - add event -+ * @ioc: per adapter object -+ * @mpi_reply: reply message frame -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_ctl_add_to_event_log(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventNotificationReply_t *mpi_reply) -+{ -+ struct MPT3_IOCTL_EVENTS *event_log; -+ u16 event; -+ int i; -+ u32 sz, event_data_sz; -+ u8 send_aen = 0; -+ -+ if (!ioc->event_log) -+ return; -+ -+ event = le16_to_cpu(mpi_reply->Event); -+ -+ if (_ctl_check_event_type(ioc, event)) { -+ -+ /* insert entry into circular event_log */ -+ i = ioc->event_context % MPT3SAS_CTL_EVENT_LOG_SIZE; -+ event_log = ioc->event_log; -+ event_log[i].event = event; -+ event_log[i].context = ioc->event_context++; -+ -+ event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4; -+ sz = min_t(u32, event_data_sz, MPT3_EVENT_DATA_SIZE); -+ memset(event_log[i].data, 0, MPT3_EVENT_DATA_SIZE); -+ memcpy(event_log[i].data, mpi_reply->EventData, sz); -+ send_aen = 1; -+ } -+ -+ /* This aen_event_read_flag flag is set until the -+ * application has read the event log. -+ * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify. -+ */ -+ if (event == MPI2_EVENT_LOG_ENTRY_ADDED || -+ (send_aen && !ioc->aen_event_read_flag)) { -+ ioc->aen_event_read_flag = 1; -+ wake_up_interruptible(&ctl_poll_wait); -+ if (async_queue) -+ kill_fasync(&async_queue, SIGIO, POLL_IN); -+ } -+} -+ -+/** -+ * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time) -+ * @ioc: per adapter object -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt. -+ * -+ * This function merely adds a new work task into ioc->firmware_event_thread. -+ * The tasks are worked from _firmware_event_work in user context. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, -+ u32 reply) -+{ -+ Mpi2EventNotificationReply_t *mpi_reply; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply) -+ mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); -+ return 1; -+} -+ -+/** -+ * _ctl_verify_adapter - validates ioc_number passed from application -+ * @ioc: per adapter object -+ * @iocpp: The ioc pointer is returned in this. -+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & -+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device. -+ * -+ * Return (-1) means error, else ioc_number. -+ */ -+static int -+_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp, -+ int mpi_version) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ int version = 0; -+ /* global ioc lock to protect controller on list operations */ -+ spin_lock(&gioc_lock_mpt2sas); -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { -+ if (ioc->id != ioc_number) -+ continue; -+ /* Check whether this ioctl command is from right -+ * ioctl device or not, if not continue the search. -+ */ -+ version = ioc->hba_mpi_version_belonged; -+ /* MPI25_VERSION and MPI26_VERSION uses same ioctl -+ * device. -+ */ -+ if (mpi_version == (MPI25_VERSION | MPI26_VERSION)) { -+ if ((version == MPI25_VERSION) || -+ (version == MPI26_VERSION)) -+ goto out; -+ else -+ continue; -+ } else { -+ if (version != mpi_version) -+ continue; -+ } -+out: -+ spin_unlock(&gioc_lock_mpt2sas); -+ *iocpp = ioc; -+ return ioc_number; -+ } -+ spin_unlock(&gioc_lock_mpt2sas); -+ *iocpp = NULL; -+ return -1; -+} -+ -+/** -+ * mpt2sas_ctl_reset_handler - reset callback handler (for ctl) -+ * @ioc: per adapter object -+ * @reset_phase: phase -+ * -+ * The handler for doing any required cleanup or initialization. -+ * -+ * The reset phase can be MPT3_IOC_PRE_RESET, MPT3_IOC_AFTER_RESET, -+ * MPT3_IOC_DONE_RESET -+ */ -+void -+mpt2sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) -+{ -+ int i; -+ u8 issue_reset; -+ -+ switch (reset_phase) { -+ case MPT3_IOC_PRE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); -+ for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { -+ if (!(ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED)) -+ continue; -+ if ((ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ continue; -+ mpt2sas_send_diag_release(ioc, i, &issue_reset); -+ } -+ break; -+ case MPT3_IOC_AFTER_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); -+ if (ioc->ctl_cmds.status & MPT3_CMD_PENDING) { -+ ioc->ctl_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid); -+ complete(&ioc->ctl_cmds.done); -+ } -+ break; -+ case MPT3_IOC_DONE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); -+ -+ for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { -+ if (!(ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED)) -+ continue; -+ if ((ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ continue; -+ ioc->diag_buffer_status[i] |= -+ MPT3_DIAG_BUFFER_IS_DIAG_RESET; -+ } -+ break; -+ } -+} -+ -+/** -+ * _ctl_fasync_mpt2sas - -+ * @fd - -+ * @filep - -+ * @mode - -+ * -+ * Called when application request fasyn callback handler. -+ */ -+int -+_ctl_fasync_mpt2sas(int fd, struct file *filep, int mode) -+{ -+ return fasync_helper(fd, filep, mode, &async_queue); -+} -+ -+/** -+ * _ctl_poll_mpt2sas - -+ * @file - -+ * @wait - -+ * -+ */ -+unsigned int -+_ctl_poll_mpt2sas(struct file *filep, poll_table *wait) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ -+ poll_wait(filep, &ctl_poll_wait, wait); -+ -+ /* global ioc lock to protect controller on list operations */ -+ spin_lock(&gioc_lock_mpt2sas); -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { -+ if (ioc->aen_event_read_flag) { -+ spin_unlock(&gioc_lock_mpt2sas); -+ return POLLIN | POLLRDNORM; -+ } -+ } -+ spin_unlock(&gioc_lock_mpt2sas); -+ return 0; -+} -+ -+/** -+ * _ctl_set_task_mid - assign an active smid to tm request -+ * @ioc: per adapter object -+ * @karg - (struct mpt3_ioctl_command) -+ * @tm_request - pointer to mf from user space -+ * -+ * Returns 0 when an smid if found, else fail. -+ * during failure, the reply frame is filled. -+ */ -+static int -+_ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg, -+ Mpi2SCSITaskManagementRequest_t *tm_request) -+{ -+ u8 found = 0; -+ u16 i; -+ u16 handle; -+ struct scsi_cmnd *scmd; -+ struct MPT3SAS_DEVICE *priv_data; -+ unsigned long flags; -+ Mpi2SCSITaskManagementReply_t *tm_reply; -+ u32 sz; -+ u32 lun; -+ char *desc = NULL; -+ -+ if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) -+ desc = "abort_task"; -+ else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) -+ desc = "query_task"; -+ else -+ return 0; -+ -+ lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN); -+ -+ handle = le16_to_cpu(tm_request->DevHandle); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ for (i = ioc->scsiio_depth; i && !found; i--) { -+ scmd = ioc->scsi_lookup[i - 1].scmd; -+ if (scmd == NULL || scmd->device == NULL || -+ scmd->device->hostdata == NULL) -+ continue; -+ if (lun != scmd->device->lun) -+ continue; -+ priv_data = scmd->device->hostdata; -+ if (priv_data->sas_target == NULL) -+ continue; -+ if (priv_data->sas_target->handle != handle) -+ continue; -+ tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid); -+ found = 1; -+ } -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ if (!found) { -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), lun(%d), no active mid!!\n", -+ ioc->name, -+ desc, le16_to_cpu(tm_request->DevHandle), lun)); -+ tm_reply = ioc->ctl_cmds.reply; -+ tm_reply->DevHandle = tm_request->DevHandle; -+ tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; -+ tm_reply->TaskType = tm_request->TaskType; -+ tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4; -+ tm_reply->VP_ID = tm_request->VP_ID; -+ tm_reply->VF_ID = tm_request->VF_ID; -+ sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz); -+ if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply, -+ sz)) -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ return 1; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, -+ desc, le16_to_cpu(tm_request->DevHandle), lun, -+ le16_to_cpu(tm_request->TaskMID))); -+ return 0; -+} -+ -+/** -+ * _ctl_do_mpt_command - main handler for MPT3COMMAND opcode -+ * @ioc: per adapter object -+ * @karg - (struct mpt3_ioctl_command) -+ * @mf - pointer to mf in user space -+ */ -+static long -+_ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, -+ void __user *mf) -+{ -+ MPI2RequestHeader_t *mpi_request = NULL, *request; -+ MPI2DefaultReply_t *mpi_reply; -+ u32 ioc_state; -+ u16 ioc_status; -+ u16 smid; -+ unsigned long timeout, timeleft; -+ u8 issue_reset; -+ u32 sz; -+ void *psge; -+ void *data_out = NULL; -+ dma_addr_t data_out_dma = 0; -+ size_t data_out_sz = 0; -+ void *data_in = NULL; -+ dma_addr_t data_in_dma = 0; -+ size_t data_in_sz = 0; -+ long ret; -+ u16 wait_state_count; -+ -+ issue_reset = 0; -+ -+ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", -+ ioc->name, __func__); -+ ret = -EAGAIN; -+ goto out; -+ } -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ ret = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, -+ __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); -+ if (!mpi_request) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed obtaining a memory for mpi_request\n", -+ ioc->name, __func__); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ /* Check for overflow and wraparound */ -+ if (karg.data_sge_offset * 4 > ioc->request_sz || -+ karg.data_sge_offset > (UINT_MAX / 4)) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ /* copy in request message frame from user */ -+ if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, -+ __func__); -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { -+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ret = -EAGAIN; -+ goto out; -+ } -+ } else { -+ -+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ret = -EAGAIN; -+ goto out; -+ } -+ } -+ -+ ret = 0; -+ ioc->ctl_cmds.status = MPT3_CMD_PENDING; -+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -+ request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memcpy(request, mpi_request, karg.data_sge_offset*4); -+ ioc->ctl_cmds.smid = smid; -+ data_out_sz = karg.data_out_size; -+ data_in_sz = karg.data_in_size; -+ -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { -+ if (!le16_to_cpu(mpi_request->FunctionDependent1) || -+ le16_to_cpu(mpi_request->FunctionDependent1) > -+ ioc->facts.MaxDevHandle) { -+ ret = -EINVAL; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } -+ -+ /* obtain dma-able memory for data transfer */ -+ if (data_out_sz) /* WRITE */ { -+ data_out = pci_alloc_consistent(ioc->pdev, data_out_sz, -+ &data_out_dma); -+ if (!data_out) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ if (copy_from_user(data_out, karg.data_out_buf_ptr, -+ data_out_sz)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -EFAULT; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } -+ -+ if (data_in_sz) /* READ */ { -+ data_in = pci_alloc_consistent(ioc->pdev, data_in_sz, -+ &data_in_dma); -+ if (!data_in) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } -+ -+ psge = (void *)request + (karg.data_sge_offset*4); -+ -+ /* send command to firmware */ -+ _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); -+ -+ init_completion(&ioc->ctl_cmds.done); -+ switch (mpi_request->Function) { -+ case MPI2_FUNCTION_SCSI_IO_REQUEST: -+ case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: -+ { -+ Mpi2SCSIIORequest_t *scsiio_request = -+ (Mpi2SCSIIORequest_t *)request; -+ scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; -+ scsiio_request->SenseBufferLowAddress = -+ mpt2sas_base_get_sense_buffer_dma(ioc, smid); -+ memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) -+ mpt2sas_base_put_smid_scsi_io(ioc, smid, -+ le16_to_cpu(mpi_request->FunctionDependent1)); -+ else -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ case MPI2_FUNCTION_SCSI_TASK_MGMT: -+ { -+ Mpi2SCSITaskManagementRequest_t *tm_request = -+ (Mpi2SCSITaskManagementRequest_t *)request; -+ -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n", -+ ioc->name, -+ le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); -+ -+ if (tm_request->TaskType == -+ MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || -+ tm_request->TaskType == -+ MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) { -+ if (_ctl_set_task_mid(ioc, &karg, tm_request)) { -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } -+ -+ mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( -+ tm_request->DevHandle)); -+ ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ mpt2sas_base_put_smid_hi_priority(ioc, smid, 0); -+ break; -+ } -+ case MPI2_FUNCTION_SMP_PASSTHROUGH: -+ { -+ Mpi2SmpPassthroughRequest_t *smp_request = -+ (Mpi2SmpPassthroughRequest_t *)mpi_request; -+ u8 *data; -+ -+ /* ioc determines which port to use */ -+ smp_request->PhysicalPort = 0xFF; -+ if (smp_request->PassthroughFlags & -+ MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) -+ data = (u8 *)&smp_request->SGL; -+ else { -+ if (unlikely(data_out == NULL)) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ mpt2sas_base_free_smid(ioc, smid); -+ ret = -EINVAL; -+ goto out; -+ } -+ data = data_out; -+ } -+ -+ if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) { -+ ioc->ioc_link_reset_in_progress = 1; -+ ioc->ignore_loginfos = 1; -+ } -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, -+ data_in_sz); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ case MPI2_FUNCTION_SATA_PASSTHROUGH: -+ case MPI2_FUNCTION_FW_DOWNLOAD: -+ case MPI2_FUNCTION_FW_UPLOAD: -+ { -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, -+ data_in_sz); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ case MPI2_FUNCTION_TOOLBOX: -+ { -+ Mpi2ToolboxCleanRequest_t *toolbox_request = -+ (Mpi2ToolboxCleanRequest_t *)mpi_request; -+ -+ if (toolbox_request->Tool == MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL) { -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ } else { -+ ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ } -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: -+ { -+ Mpi2SasIoUnitControlRequest_t *sasiounit_request = -+ (Mpi2SasIoUnitControlRequest_t *)mpi_request; -+ -+ if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET -+ || sasiounit_request->Operation == -+ MPI2_SAS_OP_PHY_LINK_RESET) { -+ ioc->ioc_link_reset_in_progress = 1; -+ ioc->ignore_loginfos = 1; -+ } -+ /* drop to default case for posting the request */ -+ } -+ default: -+ ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, -+ data_in_dma, data_in_sz); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ break; -+ } -+ -+ if (karg.timeout < MPT3_IOCTL_DEFAULT_TIMEOUT) -+ timeout = MPT3_IOCTL_DEFAULT_TIMEOUT; -+ else -+ timeout = karg.timeout; -+ timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, -+ timeout*HZ); -+ if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { -+ Mpi2SCSITaskManagementRequest_t *tm_request = -+ (Mpi2SCSITaskManagementRequest_t *)mpi_request; -+ mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu( -+ tm_request->DevHandle)); -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); -+ } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || -+ mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) && -+ ioc->ioc_link_reset_in_progress) { -+ ioc->ioc_link_reset_in_progress = 0; -+ ioc->ignore_loginfos = 0; -+ } -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", ioc->name, -+ __func__); -+ _debug_dump_mf(mpi_request, karg.data_sge_offset); -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ mpi_reply = ioc->ctl_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ -+ if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && -+ (ioc->logging_level & MPT_DEBUG_TM)) { -+ Mpi2SCSITaskManagementReply_t *tm_reply = -+ (Mpi2SCSITaskManagementReply_t *)mpi_reply; -+ -+ pr_info(MPT3SAS_FMT "TASK_MGMT: " \ -+ "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " -+ "TerminationCount(0x%08x)\n", ioc->name, -+ le16_to_cpu(tm_reply->IOCStatus), -+ le32_to_cpu(tm_reply->IOCLogInfo), -+ le32_to_cpu(tm_reply->TerminationCount)); -+ } -+ -+ /* copy out xdata to user */ -+ if (data_in_sz) { -+ if (copy_to_user(karg.data_in_buf_ptr, data_in, -+ data_in_sz)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENODATA; -+ goto out; -+ } -+ } -+ -+ /* copy out reply message frame to user */ -+ if (karg.max_reply_bytes) { -+ sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz); -+ if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply, -+ sz)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENODATA; -+ goto out; -+ } -+ } -+ -+ /* copy out sense to user */ -+ if (karg.max_sense_bytes && (mpi_request->Function == -+ MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == -+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { -+ sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); -+ if (copy_to_user(karg.sense_data_ptr, ioc->ctl_cmds.sense, -+ sz)) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ ret = -ENODATA; -+ goto out; -+ } -+ } -+ -+ issue_host_reset: -+ if (issue_reset) { -+ ret = -ENODATA; -+ if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || -+ mpi_request->Function == -+ MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || -+ mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) { -+ pr_info(MPT3SAS_FMT "issue target reset: handle = (0x%04x)\n", -+ ioc->name, -+ le16_to_cpu(mpi_request->FunctionDependent1)); -+ mpt2sas_halt_firmware(ioc); -+ mpt2sas_scsih_issue_tm(ioc, -+ le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, -+ 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, -+ TM_MUTEX_ON); -+ } else -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ } -+ -+ out: -+ -+ /* free memory associated with sg buffers */ -+ if (data_in) -+ pci_free_consistent(ioc->pdev, data_in_sz, data_in, -+ data_in_dma); -+ -+ if (data_out) -+ pci_free_consistent(ioc->pdev, data_out_sz, data_out, -+ data_out_dma); -+ -+ kfree(mpi_request); -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ return ret; -+} -+ -+/** -+ * _ctl_getiocinfo - main handler for MPT3IOCINFO opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_iocinfo karg; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ memset(&karg, 0 , sizeof(karg)); -+ if (ioc->pfacts) -+ karg.port_number = ioc->pfacts[0].PortNumber; -+ karg.hw_rev = ioc->pdev->revision; -+ karg.pci_id = ioc->pdev->device; -+ karg.subsystem_device = ioc->pdev->subsystem_device; -+ karg.subsystem_vendor = ioc->pdev->subsystem_vendor; -+ karg.pci_information.u.bits.bus = ioc->pdev->bus->number; -+ karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn); -+ karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn); -+ karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus); -+ karg.firmware_version = ioc->facts.FWVersion.Word; -+ strcpy(karg.driver_version, ioc->driver_name); -+ strcat(karg.driver_version, "-"); -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ if (ioc->is_warpdrive) -+ karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; -+ else -+ karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; -+ strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION); -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3; -+ strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION); -+ break; -+ } -+ karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); -+ -+ if (copy_to_user(arg, &karg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * _ctl_eventquery - main handler for MPT3EVENTQUERY opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_eventquery(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_eventquery karg; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ karg.event_entries = MPT3SAS_CTL_EVENT_LOG_SIZE; -+ memcpy(karg.event_types, ioc->event_type, -+ MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); -+ -+ if (copy_to_user(arg, &karg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * _ctl_eventenable - main handler for MPT3EVENTENABLE opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_eventenable(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_eventenable karg; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ memcpy(ioc->event_type, karg.event_types, -+ MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); -+ mpt2sas_base_validate_event_type(ioc, ioc->event_type); -+ -+ if (ioc->event_log) -+ return 0; -+ /* initialize event_log */ -+ ioc->event_context = 0; -+ ioc->aen_event_read_flag = 0; -+ ioc->event_log = kcalloc(MPT3SAS_CTL_EVENT_LOG_SIZE, -+ sizeof(struct MPT3_IOCTL_EVENTS), GFP_KERNEL); -+ if (!ioc->event_log) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -ENOMEM; -+ } -+ return 0; -+} -+ -+/** -+ * _ctl_eventreport - main handler for MPT3EVENTREPORT opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_eventreport(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_eventreport karg; -+ u32 number_bytes, max_events, max; -+ struct mpt3_ioctl_eventreport __user *uarg = arg; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ number_bytes = karg.hdr.max_data_size - -+ sizeof(struct mpt3_ioctl_header); -+ max_events = number_bytes/sizeof(struct MPT3_IOCTL_EVENTS); -+ max = min_t(u32, MPT3SAS_CTL_EVENT_LOG_SIZE, max_events); -+ -+ /* If fewer than 1 event is requested, there must have -+ * been some type of error. -+ */ -+ if (!max || !ioc->event_log) -+ return -ENODATA; -+ -+ number_bytes = max * sizeof(struct MPT3_IOCTL_EVENTS); -+ if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ /* reset flag so SIGIO can restart */ -+ ioc->aen_event_read_flag = 0; -+ return 0; -+} -+ -+/** -+ * _ctl_do_reset - main handler for MPT3HARDRESET opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_diag_reset karg; -+ int retval; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery || -+ ioc->is_driver_loading) -+ return -EAGAIN; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", ioc->name, -+ __func__)); -+ -+ retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ pr_info(MPT3SAS_FMT "host reset: %s\n", -+ ioc->name, ((!retval) ? "SUCCESS" : "FAILED")); -+ return 0; -+} -+ -+/** -+ * _ctl_btdh_search_sas_device - searching for sas device -+ * @ioc: per adapter object -+ * @btdh: btdh ioctl payload -+ */ -+static int -+_ctl_btdh_search_sas_device(struct MPT3SAS_ADAPTER *ioc, -+ struct mpt3_ioctl_btdh_mapping *btdh) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ int rc = 0; -+ -+ if (list_empty(&ioc->sas_device_list)) -+ return rc; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -+ if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && -+ btdh->handle == sas_device->handle) { -+ btdh->bus = sas_device->channel; -+ btdh->id = sas_device->id; -+ rc = 1; -+ goto out; -+ } else if (btdh->bus == sas_device->channel && btdh->id == -+ sas_device->id && btdh->handle == 0xFFFF) { -+ btdh->handle = sas_device->handle; -+ rc = 1; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_btdh_search_raid_device - searching for raid device -+ * @ioc: per adapter object -+ * @btdh: btdh ioctl payload -+ */ -+static int -+_ctl_btdh_search_raid_device(struct MPT3SAS_ADAPTER *ioc, -+ struct mpt3_ioctl_btdh_mapping *btdh) -+{ -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ int rc = 0; -+ -+ if (list_empty(&ioc->raid_device_list)) -+ return rc; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && -+ btdh->handle == raid_device->handle) { -+ btdh->bus = raid_device->channel; -+ btdh->id = raid_device->id; -+ rc = 1; -+ goto out; -+ } else if (btdh->bus == raid_device->channel && btdh->id == -+ raid_device->id && btdh->handle == 0xFFFF) { -+ btdh->handle = raid_device->handle; -+ rc = 1; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_btdh_mapping - main handler for MPT3BTDHMAPPING opcode -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_btdh_mapping(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_ioctl_btdh_mapping karg; -+ int rc; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ rc = _ctl_btdh_search_sas_device(ioc, &karg); -+ if (!rc) -+ _ctl_btdh_search_raid_device(ioc, &karg); -+ -+ if (copy_to_user(arg, &karg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * _ctl_diag_capability - return diag buffer capability -+ * @ioc: per adapter object -+ * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED -+ * -+ * returns 1 when diag buffer support is enabled in firmware -+ */ -+static u8 -+_ctl_diag_capability(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type) -+{ -+ u8 rc = 0; -+ -+ switch (buffer_type) { -+ case MPI2_DIAG_BUF_TYPE_TRACE: -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) -+ rc = 1; -+ break; -+ case MPI2_DIAG_BUF_TYPE_SNAPSHOT: -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) -+ rc = 1; -+ break; -+ case MPI2_DIAG_BUF_TYPE_EXTENDED: -+ if (ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) -+ rc = 1; -+ } -+ -+ return rc; -+} -+ -+ -+/** -+ * _ctl_diag_register_2 - wrapper for registering diag buffer support -+ * @ioc: per adapter object -+ * @diag_register: the diag_register struct passed in from user space -+ * -+ */ -+static long -+_ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, -+ struct mpt3_diag_register *diag_register) -+{ -+ int rc, i; -+ void *request_data = NULL; -+ dma_addr_t request_data_dma; -+ u32 request_data_sz = 0; -+ Mpi2DiagBufferPostRequest_t *mpi_request; -+ Mpi2DiagBufferPostReply_t *mpi_reply; -+ u8 buffer_type; -+ unsigned long timeleft; -+ u16 smid; -+ u16 ioc_status; -+ u32 ioc_state; -+ u8 issue_reset = 0; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ buffer_type = diag_register->buffer_type; -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if (ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) { -+ pr_err(MPT3SAS_FMT -+ "%s: already has a registered buffer for buffer_type(0x%02x)\n", -+ ioc->name, __func__, -+ buffer_type); -+ return -EINVAL; -+ } -+ -+ if (diag_register->requested_buffer_size % 4) { -+ pr_err(MPT3SAS_FMT -+ "%s: the requested_buffer_size is not 4 byte aligned\n", -+ ioc->name, __func__); -+ return -EINVAL; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ ioc->ctl_cmds.status = MPT3_CMD_PENDING; -+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->ctl_cmds.smid = smid; -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ request_data_sz = diag_register->requested_buffer_size; -+ ioc->unique_id[buffer_type] = diag_register->unique_id; -+ ioc->diag_buffer_status[buffer_type] = 0; -+ memcpy(ioc->product_specific[buffer_type], -+ diag_register->product_specific, MPT3_PRODUCT_SPECIFIC_DWORDS); -+ ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags; -+ -+ if (request_data) { -+ request_data_dma = ioc->diag_buffer_dma[buffer_type]; -+ if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) { -+ pci_free_consistent(ioc->pdev, -+ ioc->diag_buffer_sz[buffer_type], -+ request_data, request_data_dma); -+ request_data = NULL; -+ } -+ } -+ -+ if (request_data == NULL) { -+ ioc->diag_buffer_sz[buffer_type] = 0; -+ ioc->diag_buffer_dma[buffer_type] = 0; -+ request_data = pci_alloc_consistent( -+ ioc->pdev, request_data_sz, &request_data_dma); -+ if (request_data == NULL) { -+ pr_err(MPT3SAS_FMT "%s: failed allocating memory" \ -+ " for diag buffers, requested size(%d)\n", -+ ioc->name, __func__, request_data_sz); -+ mpt2sas_base_free_smid(ioc, smid); -+ return -ENOMEM; -+ } -+ ioc->diag_buffer[buffer_type] = request_data; -+ ioc->diag_buffer_sz[buffer_type] = request_data_sz; -+ ioc->diag_buffer_dma[buffer_type] = request_data_dma; -+ } -+ -+ mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; -+ mpi_request->BufferType = diag_register->buffer_type; -+ mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags); -+ mpi_request->BufferAddress = cpu_to_le64(request_data_dma); -+ mpi_request->BufferLength = cpu_to_le32(request_data_sz); -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: diag_buffer(0x%p), dma(0x%llx), sz(%d)\n", -+ ioc->name, __func__, request_data, -+ (unsigned long long)request_data_dma, -+ le32_to_cpu(mpi_request->BufferLength))); -+ -+ for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) -+ mpi_request->ProductSpecific[i] = -+ cpu_to_le32(ioc->product_specific[buffer_type][i]); -+ -+ init_completion(&ioc->ctl_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, -+ MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); -+ -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", ioc->name, -+ __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2DiagBufferPostRequest_t)/4); -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ /* process the completed Reply Message Frame */ -+ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { -+ pr_err(MPT3SAS_FMT "%s: no reply message\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ mpi_reply = ioc->ctl_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_REGISTERED; -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", -+ ioc->name, __func__)); -+ } else { -+ pr_info(MPT3SAS_FMT -+ "%s: ioc_status(0x%04x) log_info(0x%08x)\n", -+ ioc->name, __func__, -+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); -+ rc = -EFAULT; -+ } -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ -+ out: -+ -+ if (rc && request_data) -+ pci_free_consistent(ioc->pdev, request_data_sz, -+ request_data, request_data_dma); -+ -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ return rc; -+} -+ -+/** -+ * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time -+ * @ioc: per adapter object -+ * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1 -+ * -+ * This is called when command line option diag_buffer_enable is enabled -+ * at driver load time. -+ */ -+void -+mpt2sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) -+{ -+ struct mpt3_diag_register diag_register; -+ -+ memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); -+ -+ if (bits_to_register & 1) { -+ pr_info(MPT3SAS_FMT "registering trace buffer support\n", -+ ioc->name); -+ ioc->diag_trigger_master.MasterData = -+ (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); -+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; -+ /* register for 2MB buffers */ -+ diag_register.requested_buffer_size = 2 * (1024 * 1024); -+ diag_register.unique_id = 0x7075900; -+ _ctl_diag_register_2(ioc, &diag_register); -+ } -+ -+ if (bits_to_register & 2) { -+ pr_info(MPT3SAS_FMT "registering snapshot buffer support\n", -+ ioc->name); -+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; -+ /* register for 2MB buffers */ -+ diag_register.requested_buffer_size = 2 * (1024 * 1024); -+ diag_register.unique_id = 0x7075901; -+ _ctl_diag_register_2(ioc, &diag_register); -+ } -+ -+ if (bits_to_register & 4) { -+ pr_info(MPT3SAS_FMT "registering extended buffer support\n", -+ ioc->name); -+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; -+ /* register for 2MB buffers */ -+ diag_register.requested_buffer_size = 2 * (1024 * 1024); -+ diag_register.unique_id = 0x7075901; -+ _ctl_diag_register_2(ioc, &diag_register); -+ } -+} -+ -+/** -+ * _ctl_diag_register - application register with driver -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ * -+ * This will allow the driver to setup any required buffers that will be -+ * needed by firmware to communicate with the driver. -+ */ -+static long -+_ctl_diag_register(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_register karg; -+ long rc; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ rc = _ctl_diag_register_2(ioc, &karg); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_unregister - application unregister with driver -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ * -+ * This will allow the driver to cleanup any memory allocated for diag -+ * messages and to free up any resources. -+ */ -+static long -+_ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_unregister karg; -+ void *request_data; -+ dma_addr_t request_data_dma; -+ u32 request_data_sz; -+ u8 buffer_type; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ buffer_type = karg.unique_id & 0x000000ff; -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is not registered\n", -+ ioc->name, __func__, buffer_type); -+ return -EINVAL; -+ } -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) has not been released\n", -+ ioc->name, __func__, buffer_type); -+ return -EINVAL; -+ } -+ -+ if (karg.unique_id != ioc->unique_id[buffer_type]) { -+ pr_err(MPT3SAS_FMT -+ "%s: unique_id(0x%08x) is not registered\n", -+ ioc->name, __func__, karg.unique_id); -+ return -EINVAL; -+ } -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ if (!request_data) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -ENOMEM; -+ } -+ -+ request_data_sz = ioc->diag_buffer_sz[buffer_type]; -+ request_data_dma = ioc->diag_buffer_dma[buffer_type]; -+ pci_free_consistent(ioc->pdev, request_data_sz, -+ request_data, request_data_dma); -+ ioc->diag_buffer[buffer_type] = NULL; -+ ioc->diag_buffer_status[buffer_type] = 0; -+ return 0; -+} -+ -+/** -+ * _ctl_diag_query - query relevant info associated with diag buffers -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ * -+ * The application will send only buffer_type and unique_id. Driver will -+ * inspect unique_id first, if valid, fill in all the info. If unique_id is -+ * 0x00, the driver will return info specified by Buffer Type. -+ */ -+static long -+_ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_query karg; -+ void *request_data; -+ int i; -+ u8 buffer_type; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ karg.application_flags = 0; -+ buffer_type = karg.buffer_type; -+ -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is not registered\n", -+ ioc->name, __func__, buffer_type); -+ return -EINVAL; -+ } -+ -+ if (karg.unique_id & 0xffffff00) { -+ if (karg.unique_id != ioc->unique_id[buffer_type]) { -+ pr_err(MPT3SAS_FMT -+ "%s: unique_id(0x%08x) is not registered\n", -+ ioc->name, __func__, karg.unique_id); -+ return -EINVAL; -+ } -+ } -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ if (!request_data) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have buffer for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -ENOMEM; -+ } -+ -+ if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_RELEASED) -+ karg.application_flags = (MPT3_APP_FLAGS_APP_OWNED | -+ MPT3_APP_FLAGS_BUFFER_VALID); -+ else -+ karg.application_flags = (MPT3_APP_FLAGS_APP_OWNED | -+ MPT3_APP_FLAGS_BUFFER_VALID | -+ MPT3_APP_FLAGS_FW_BUFFER_ACCESS); -+ -+ for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) -+ karg.product_specific[i] = -+ ioc->product_specific[buffer_type][i]; -+ -+ karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type]; -+ karg.driver_added_buffer_size = 0; -+ karg.unique_id = ioc->unique_id[buffer_type]; -+ karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type]; -+ -+ if (copy_to_user(arg, &karg, sizeof(struct mpt3_diag_query))) { -+ pr_err(MPT3SAS_FMT -+ "%s: unable to write mpt3_diag_query data @ %p\n", -+ ioc->name, __func__, arg); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+/** -+ * mpt2sas_send_diag_release - Diag Release Message -+ * @ioc: per adapter object -+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED -+ * @issue_reset - specifies whether host reset is required. -+ * -+ */ -+int -+mpt2sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, -+ u8 *issue_reset) -+{ -+ Mpi2DiagReleaseRequest_t *mpi_request; -+ Mpi2DiagReleaseReply_t *mpi_reply; -+ u16 smid; -+ u16 ioc_status; -+ u32 ioc_state; -+ int rc; -+ unsigned long timeleft; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ rc = 0; -+ *issue_reset = 0; -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_RELEASED; -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: skipping due to FAULT state\n", ioc->name, -+ __func__)); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ ioc->ctl_cmds.status = MPT3_CMD_PENDING; -+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->ctl_cmds.smid = smid; -+ -+ mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE; -+ mpi_request->BufferType = buffer_type; -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ -+ init_completion(&ioc->ctl_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, -+ MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); -+ -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", ioc->name, -+ __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2DiagReleaseRequest_t)/4); -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_RESET)) -+ *issue_reset = 1; -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ /* process the completed Reply Message Frame */ -+ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { -+ pr_err(MPT3SAS_FMT "%s: no reply message\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ mpi_reply = ioc->ctl_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_RELEASED; -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", -+ ioc->name, __func__)); -+ } else { -+ pr_info(MPT3SAS_FMT -+ "%s: ioc_status(0x%04x) log_info(0x%08x)\n", -+ ioc->name, __func__, -+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); -+ rc = -EFAULT; -+ } -+ -+ out: -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ return rc; -+} -+ -+/** -+ * _ctl_diag_release - request to send Diag Release Message to firmware -+ * @arg - user space buffer containing ioctl content -+ * -+ * This allows ownership of the specified buffer to returned to the driver, -+ * allowing an application to read the buffer without fear that firmware is -+ * overwritting information in the buffer. -+ */ -+static long -+_ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_release karg; -+ void *request_data; -+ int rc; -+ u8 buffer_type; -+ u8 issue_reset = 0; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ buffer_type = karg.unique_id & 0x000000ff; -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is not registered\n", -+ ioc->name, __func__, buffer_type); -+ return -EINVAL; -+ } -+ -+ if (karg.unique_id != ioc->unique_id[buffer_type]) { -+ pr_err(MPT3SAS_FMT -+ "%s: unique_id(0x%08x) is not registered\n", -+ ioc->name, __func__, karg.unique_id); -+ return -EINVAL; -+ } -+ -+ if (ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is already released\n", -+ ioc->name, __func__, -+ buffer_type); -+ return 0; -+ } -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ -+ if (!request_data) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have memory allocated for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -ENOMEM; -+ } -+ -+ /* buffers were released by due to host reset */ -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_DIAG_RESET)) { -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_RELEASED; -+ ioc->diag_buffer_status[buffer_type] &= -+ ~MPT3_DIAG_BUFFER_IS_DIAG_RESET; -+ pr_err(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) was released due to host reset\n", -+ ioc->name, __func__, buffer_type); -+ return 0; -+ } -+ -+ rc = mpt2sas_send_diag_release(ioc, buffer_type, &issue_reset); -+ -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ -+ return rc; -+} -+ -+/** -+ * _ctl_diag_read_buffer - request for copy of the diag buffer -+ * @ioc: per adapter object -+ * @arg - user space buffer containing ioctl content -+ */ -+static long -+_ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) -+{ -+ struct mpt3_diag_read_buffer karg; -+ struct mpt3_diag_read_buffer __user *uarg = arg; -+ void *request_data, *diag_data; -+ Mpi2DiagBufferPostRequest_t *mpi_request; -+ Mpi2DiagBufferPostReply_t *mpi_reply; -+ int rc, i; -+ u8 buffer_type; -+ unsigned long timeleft, request_size, copy_size; -+ u16 smid; -+ u16 ioc_status; -+ u8 issue_reset = 0; -+ -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, -+ __func__)); -+ -+ buffer_type = karg.unique_id & 0x000000ff; -+ if (!_ctl_diag_capability(ioc, buffer_type)) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have capability for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -EPERM; -+ } -+ -+ if (karg.unique_id != ioc->unique_id[buffer_type]) { -+ pr_err(MPT3SAS_FMT -+ "%s: unique_id(0x%08x) is not registered\n", -+ ioc->name, __func__, karg.unique_id); -+ return -EINVAL; -+ } -+ -+ request_data = ioc->diag_buffer[buffer_type]; -+ if (!request_data) { -+ pr_err(MPT3SAS_FMT -+ "%s: doesn't have buffer for buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type); -+ return -ENOMEM; -+ } -+ -+ request_size = ioc->diag_buffer_sz[buffer_type]; -+ -+ if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { -+ pr_err(MPT3SAS_FMT "%s: either the starting_offset " \ -+ "or bytes_to_read are not 4 byte aligned\n", ioc->name, -+ __func__); -+ return -EINVAL; -+ } -+ -+ if (karg.starting_offset > request_size) -+ return -EINVAL; -+ -+ diag_data = (void *)(request_data + karg.starting_offset); -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: diag_buffer(%p), offset(%d), sz(%d)\n", -+ ioc->name, __func__, -+ diag_data, karg.starting_offset, karg.bytes_to_read)); -+ -+ /* Truncate data on requests that are too large */ -+ if ((diag_data + karg.bytes_to_read < diag_data) || -+ (diag_data + karg.bytes_to_read > request_data + request_size)) -+ copy_size = request_size - karg.starting_offset; -+ else -+ copy_size = karg.bytes_to_read; -+ -+ if (copy_to_user((void __user *)uarg->diagnostic_data, -+ diag_data, copy_size)) { -+ pr_err(MPT3SAS_FMT -+ "%s: Unable to write mpt_diag_read_buffer_t data @ %p\n", -+ ioc->name, __func__, diag_data); -+ return -EFAULT; -+ } -+ -+ if ((karg.flags & MPT3_FLAGS_REREGISTER) == 0) -+ return 0; -+ -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: Reregister buffer_type(0x%02x)\n", -+ ioc->name, __func__, buffer_type)); -+ if ((ioc->diag_buffer_status[buffer_type] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: buffer_type(0x%02x) is still registered\n", -+ ioc->name, __func__, buffer_type)); -+ return 0; -+ } -+ /* Get a free request frame and save the message context. -+ */ -+ -+ if (ioc->ctl_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: ctl_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ ioc->ctl_cmds.status = MPT3_CMD_PENDING; -+ memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->ctl_cmds.smid = smid; -+ -+ mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; -+ mpi_request->BufferType = buffer_type; -+ mpi_request->BufferLength = -+ cpu_to_le32(ioc->diag_buffer_sz[buffer_type]); -+ mpi_request->BufferAddress = -+ cpu_to_le64(ioc->diag_buffer_dma[buffer_type]); -+ for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) -+ mpi_request->ProductSpecific[i] = -+ cpu_to_le32(ioc->product_specific[buffer_type][i]); -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ -+ init_completion(&ioc->ctl_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, -+ MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); -+ -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", ioc->name, -+ __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2DiagBufferPostRequest_t)/4); -+ if (!(ioc->ctl_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ /* process the completed Reply Message Frame */ -+ if ((ioc->ctl_cmds.status & MPT3_CMD_REPLY_VALID) == 0) { -+ pr_err(MPT3SAS_FMT "%s: no reply message\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ mpi_reply = ioc->ctl_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -+ -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ ioc->diag_buffer_status[buffer_type] |= -+ MPT3_DIAG_BUFFER_IS_REGISTERED; -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT "%s: success\n", -+ ioc->name, __func__)); -+ } else { -+ pr_info(MPT3SAS_FMT -+ "%s: ioc_status(0x%04x) log_info(0x%08x)\n", -+ ioc->name, __func__, -+ ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); -+ rc = -EFAULT; -+ } -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ -+ out: -+ -+ ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; -+ return rc; -+} -+ -+ -+ -+#ifdef CONFIG_COMPAT -+/** -+ * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. -+ * @ioc: per adapter object -+ * @cmd - ioctl opcode -+ * @arg - (struct mpt3_ioctl_command32) -+ * -+ * MPT3COMMAND32 - Handle 32bit applications running on 64bit os. -+ */ -+static long -+_ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd, -+ void __user *arg) -+{ -+ struct mpt3_ioctl_command32 karg32; -+ struct mpt3_ioctl_command32 __user *uarg; -+ struct mpt3_ioctl_command karg; -+ -+ if (_IOC_SIZE(cmd) != sizeof(struct mpt3_ioctl_command32)) -+ return -EINVAL; -+ -+ uarg = (struct mpt3_ioctl_command32 __user *) arg; -+ -+ if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ memset(&karg, 0, sizeof(struct mpt3_ioctl_command)); -+ karg.hdr.ioc_number = karg32.hdr.ioc_number; -+ karg.hdr.port_number = karg32.hdr.port_number; -+ karg.hdr.max_data_size = karg32.hdr.max_data_size; -+ karg.timeout = karg32.timeout; -+ karg.max_reply_bytes = karg32.max_reply_bytes; -+ karg.data_in_size = karg32.data_in_size; -+ karg.data_out_size = karg32.data_out_size; -+ karg.max_sense_bytes = karg32.max_sense_bytes; -+ karg.data_sge_offset = karg32.data_sge_offset; -+ karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); -+ karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); -+ karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); -+ karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); -+ return _ctl_do_mpt_command(ioc, karg, &uarg->mf); -+} -+#endif -+ -+/** -+ * _ctl_ioctl_main - main ioctl entry point -+ * @file - (struct file) -+ * @cmd - ioctl opcode -+ * @arg - user space data buffer -+ * @compat - handles 32 bit applications in 64bit os -+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & -+ * MPI25_VERSION | MPI26_VERSION for mpt3ctl ioctl device. -+ */ -+static long -+_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, -+ u8 compat, u16 mpi_version) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ struct mpt3_ioctl_header ioctl_header; -+ enum block_state state; -+ long ret = -EINVAL; -+ -+ /* get IOCTL header */ -+ if (copy_from_user(&ioctl_header, (char __user *)arg, -+ sizeof(struct mpt3_ioctl_header))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ return -EFAULT; -+ } -+ -+ if (_ctl_verify_adapter(ioctl_header.ioc_number, -+ &ioc, mpi_version) == -1 || !ioc) -+ return -ENODEV; -+ -+ /* pci_access_mutex lock acquired by ioctl path */ -+ mutex_lock(&ioc->pci_access_mutex); -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery || -+ ioc->is_driver_loading || ioc->remove_host) { -+ ret = -EAGAIN; -+ goto out_unlock_pciaccess; -+ } -+ -+ state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; -+ if (state == NON_BLOCKING) { -+ if (!mutex_trylock(&ioc->ctl_cmds.mutex)) { -+ ret = -EAGAIN; -+ goto out_unlock_pciaccess; -+ } -+ } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { -+ ret = -ERESTARTSYS; -+ goto out_unlock_pciaccess; -+ } -+ -+ -+ switch (cmd) { -+ case MPT3IOCINFO: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_iocinfo)) -+ ret = _ctl_getiocinfo(ioc, arg); -+ break; -+#ifdef CONFIG_COMPAT -+ case MPT3COMMAND32: -+#endif -+ case MPT3COMMAND: -+ { -+ struct mpt3_ioctl_command __user *uarg; -+ struct mpt3_ioctl_command karg; -+ -+#ifdef CONFIG_COMPAT -+ if (compat) { -+ ret = _ctl_compat_mpt_command(ioc, cmd, arg); -+ break; -+ } -+#endif -+ if (copy_from_user(&karg, arg, sizeof(karg))) { -+ pr_err("failure at %s:%d/%s()!\n", -+ __FILE__, __LINE__, __func__); -+ ret = -EFAULT; -+ break; -+ } -+ -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) { -+ uarg = arg; -+ ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); -+ } -+ break; -+ } -+ case MPT3EVENTQUERY: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_eventquery)) -+ ret = _ctl_eventquery(ioc, arg); -+ break; -+ case MPT3EVENTENABLE: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_eventenable)) -+ ret = _ctl_eventenable(ioc, arg); -+ break; -+ case MPT3EVENTREPORT: -+ ret = _ctl_eventreport(ioc, arg); -+ break; -+ case MPT3HARDRESET: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_diag_reset)) -+ ret = _ctl_do_reset(ioc, arg); -+ break; -+ case MPT3BTDHMAPPING: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_btdh_mapping)) -+ ret = _ctl_btdh_mapping(ioc, arg); -+ break; -+ case MPT3DIAGREGISTER: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_register)) -+ ret = _ctl_diag_register(ioc, arg); -+ break; -+ case MPT3DIAGUNREGISTER: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_unregister)) -+ ret = _ctl_diag_unregister(ioc, arg); -+ break; -+ case MPT3DIAGQUERY: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_query)) -+ ret = _ctl_diag_query(ioc, arg); -+ break; -+ case MPT3DIAGRELEASE: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_release)) -+ ret = _ctl_diag_release(ioc, arg); -+ break; -+ case MPT3DIAGREADBUFFER: -+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_diag_read_buffer)) -+ ret = _ctl_diag_read_buffer(ioc, arg); -+ break; -+ default: -+ dctlprintk(ioc, pr_info(MPT3SAS_FMT -+ "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); -+ break; -+ } -+ -+ mutex_unlock(&ioc->ctl_cmds.mutex); -+out_unlock_pciaccess: -+ mutex_unlock(&ioc->pci_access_mutex); -+ return ret; -+} -+ -+/** -+ * _ctl_ioctl_mpt2sas - mpt3ctl main ioctl entry point (unlocked) -+ * @file - (struct file) -+ * @cmd - ioctl opcode -+ * @arg - -+ */ -+long -+_ctl_ioctl_mpt2sas(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ long ret; -+ -+ /* pass MPI25_VERSION | MPI26_VERSION value, -+ * to indicate that this ioctl cmd -+ * came from mpt3ctl ioctl device. -+ */ -+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, -+ MPI25_VERSION | MPI26_VERSION); -+ return ret; -+} -+ -+/** -+ * _ctl_mpt2_ioctl_mpt2sas - mpt2ctl main ioctl entry point (unlocked) -+ * @file - (struct file) -+ * @cmd - ioctl opcode -+ * @arg - -+ */ -+long -+_ctl_mpt2_ioctl_mpt2sas(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ long ret; -+ -+ /* pass MPI2_VERSION value, to indicate that this ioctl cmd -+ * came from mpt2ctl ioctl device. -+ */ -+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION); -+ return ret; -+} -+#ifdef CONFIG_COMPAT -+/** -+ *_ ctl_ioctl_compat - main ioctl entry point (compat) -+ * @file - -+ * @cmd - -+ * @arg - -+ * -+ * This routine handles 32 bit applications in 64bit os. -+ */ -+long -+_ctl_ioctl_compat_mpt2sas(struct file *file, unsigned cmd, unsigned long arg) -+{ -+ long ret; -+ -+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, -+ MPI25_VERSION | MPI26_VERSION); -+ return ret; -+} -+ -+/** -+ *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat) -+ * @file - -+ * @cmd - -+ * @arg - -+ * -+ * This routine handles 32 bit applications in 64bit os. -+ */ -+long -+_ctl_mpt2_ioctl_compat_mpt2sas(struct file *file, unsigned cmd, unsigned long arg) -+{ -+ long ret; -+ -+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION); -+ return ret; -+} -+#endif -+ -+/* scsi host attributes */ -+/** -+ * _ctl_version_fw_show - firmware version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", -+ (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, -+ (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, -+ (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, -+ ioc->facts.FWVersion.Word & 0x000000FF); -+} -+static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); -+ -+/** -+ * _ctl_version_bios_show - bios version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", -+ (version & 0xFF000000) >> 24, -+ (version & 0x00FF0000) >> 16, -+ (version & 0x0000FF00) >> 8, -+ version & 0x000000FF); -+} -+static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); -+ -+/** -+ * _ctl_version_mpi_show - MPI (message passing interface) version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", -+ ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); -+} -+static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); -+ -+/** -+ * _ctl_version_product_show - product name -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_product_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); -+} -+static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL); -+ -+/** -+ * _ctl_version_nvdata_persistent_show - ndvata persistent version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_nvdata_persistent_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%08xh\n", -+ le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); -+} -+static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, -+ _ctl_version_nvdata_persistent_show, NULL); -+ -+/** -+ * _ctl_version_nvdata_default_show - nvdata default version -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute -+ *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%08xh\n", -+ le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); -+} -+static DEVICE_ATTR(version_nvdata_default, S_IRUGO, -+ _ctl_version_nvdata_default_show, NULL); -+ -+/** -+ * _ctl_board_name_show - board name -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_board_name_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); -+} -+static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); -+ -+/** -+ * _ctl_board_assembly_show - board assembly name -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); -+} -+static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL); -+ -+/** -+ * _ctl_board_tracer_show - board tracer number -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); -+} -+static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL); -+ -+/** -+ * _ctl_io_delay_show - io missing delay -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is for firmware implemention for deboucing device -+ * removal events. -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); -+} -+static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL); -+ -+/** -+ * _ctl_device_delay_show - device missing delay -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is for firmware implemention for deboucing device -+ * removal events. -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); -+} -+static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL); -+ -+/** -+ * _ctl_fw_queue_depth_show - global credits -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is firmware queue depth limit -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); -+} -+static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL); -+ -+/** -+ * _ctl_sas_address_show - sas address -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is the controller sas address -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+ -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "0x%016llx\n", -+ (unsigned long long)ioc->sas_hba.sas_address); -+} -+static DEVICE_ATTR(host_sas_address, S_IRUGO, -+ _ctl_host_sas_address_show, NULL); -+ -+/** -+ * _ctl_logging_level_show - logging level -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); -+} -+static ssize_t -+_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int val = 0; -+ -+ if (sscanf(buf, "%x", &val) != 1) -+ return -EINVAL; -+ -+ ioc->logging_level = val; -+ pr_info(MPT3SAS_FMT "logging_level=%08xh\n", ioc->name, -+ ioc->logging_level); -+ return strlen(buf); -+} -+static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, -+ _ctl_logging_level_store); -+ -+/** -+ * _ctl_fwfault_debug_show - show/store fwfault_debug -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * mpt2sas_fwfault_debug is command line option -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); -+} -+static ssize_t -+_ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int val = 0; -+ -+ if (sscanf(buf, "%d", &val) != 1) -+ return -EINVAL; -+ -+ ioc->fwfault_debug = val; -+ pr_info(MPT3SAS_FMT "fwfault_debug=%d\n", ioc->name, -+ ioc->fwfault_debug); -+ return strlen(buf); -+} -+static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, -+ _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); -+ -+/** -+ * _ctl_ioc_reset_count_show - ioc reset count -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is firmware queue depth limit -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count); -+} -+static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); -+ -+/** -+ * _ctl_ioc_reply_queue_count_show - number of reply queues -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is number of reply queues -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_ioc_reply_queue_count_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ u8 reply_queue_count; -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ if ((ioc->facts.IOCCapabilities & -+ MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable) -+ reply_queue_count = ioc->reply_queue_count; -+ else -+ reply_queue_count = 1; -+ -+ return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); -+} -+static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show, -+ NULL); -+ -+/** -+ * _ctl_BRM_status_show - Backup Rail Monitor Status -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is number of reply queues -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ Mpi2IOUnitPage3_t *io_unit_pg3 = NULL; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 backup_rail_monitor_status = 0; -+ u16 ioc_status; -+ int sz; -+ ssize_t rc = 0; -+ -+ if (!ioc->is_warpdrive) { -+ pr_err(MPT3SAS_FMT "%s: BRM attribute is only for" -+ " warpdrive\n", ioc->name, __func__); -+ goto out; -+ } -+ /* pci_access_mutex lock acquired by sysfs show path */ -+ mutex_lock(&ioc->pci_access_mutex); -+ if (ioc->pci_error_recovery || ioc->remove_host) { -+ mutex_unlock(&ioc->pci_access_mutex); -+ return 0; -+ } -+ -+ /* allocate upto GPIOVal 36 entries */ -+ sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); -+ io_unit_pg3 = kzalloc(sz, GFP_KERNEL); -+ if (!io_unit_pg3) { -+ pr_err(MPT3SAS_FMT "%s: failed allocating memory " -+ "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz); -+ goto out; -+ } -+ -+ if (mpt2sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != -+ 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed reading iounit_pg3\n", ioc->name, -+ __func__); -+ goto out; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "%s: iounit_pg3 failed with " -+ "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status); -+ goto out; -+ } -+ -+ if (io_unit_pg3->GPIOCount < 25) { -+ pr_err(MPT3SAS_FMT "%s: iounit_pg3->GPIOCount less than " -+ "25 entries, detected (%d) entries\n", ioc->name, __func__, -+ io_unit_pg3->GPIOCount); -+ goto out; -+ } -+ -+ /* BRM status is in bit zero of GPIOVal[24] */ -+ backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]); -+ rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1)); -+ -+ out: -+ kfree(io_unit_pg3); -+ mutex_unlock(&ioc->pci_access_mutex); -+ return rc; -+} -+static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); -+ -+struct DIAG_BUFFER_START { -+ __le32 Size; -+ __le32 DiagVersion; -+ u8 BufferType; -+ u8 Reserved[3]; -+ __le32 Reserved1; -+ __le32 Reserved2; -+ __le32 Reserved3; -+}; -+ -+/** -+ * _ctl_host_trace_buffer_size_show - host buffer size (trace only) -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_host_trace_buffer_size_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ u32 size = 0; -+ struct DIAG_BUFFER_START *request_data; -+ -+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { -+ pr_err(MPT3SAS_FMT -+ "%s: host_trace_buffer is not registered\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: host_trace_buffer is not registered\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ request_data = (struct DIAG_BUFFER_START *) -+ ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; -+ if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || -+ le32_to_cpu(request_data->DiagVersion) == 0x01000000 || -+ le32_to_cpu(request_data->DiagVersion) == 0x01010000) && -+ le32_to_cpu(request_data->Reserved3) == 0x4742444c) -+ size = le32_to_cpu(request_data->Size); -+ -+ ioc->ring_buffer_sz = size; -+ return snprintf(buf, PAGE_SIZE, "%d\n", size); -+} -+static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, -+ _ctl_host_trace_buffer_size_show, NULL); -+ -+/** -+ * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ * -+ * You will only be able to read 4k bytes of ring buffer at a time. -+ * In order to read beyond 4k bytes, you will have to write out the -+ * offset to the same attribute, it will move the pointer. -+ */ -+static ssize_t -+_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ void *request_data; -+ u32 size; -+ -+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { -+ pr_err(MPT3SAS_FMT -+ "%s: host_trace_buffer is not registered\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ pr_err(MPT3SAS_FMT -+ "%s: host_trace_buffer is not registered\n", -+ ioc->name, __func__); -+ return 0; -+ } -+ -+ if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) -+ return 0; -+ -+ size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; -+ size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size; -+ request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; -+ memcpy(buf, request_data, size); -+ return size; -+} -+ -+static ssize_t -+_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int val = 0; -+ -+ if (sscanf(buf, "%d", &val) != 1) -+ return -EINVAL; -+ -+ ioc->ring_buffer_offset = val; -+ return strlen(buf); -+} -+static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, -+ _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); -+ -+ -+/*****************************************/ -+ -+/** -+ * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ * -+ * This is a mechnism to post/release host_trace_buffers -+ */ -+static ssize_t -+_ctl_host_trace_buffer_enable_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || -+ ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0)) -+ return snprintf(buf, PAGE_SIZE, "off\n"); -+ else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ return snprintf(buf, PAGE_SIZE, "release\n"); -+ else -+ return snprintf(buf, PAGE_SIZE, "post\n"); -+} -+ -+static ssize_t -+_ctl_host_trace_buffer_enable_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ char str[10] = ""; -+ struct mpt3_diag_register diag_register; -+ u8 issue_reset = 0; -+ -+ /* don't allow post/release occurr while recovery is active */ -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery || ioc->is_driver_loading) -+ return -EBUSY; -+ -+ if (sscanf(buf, "%9s", str) != 1) -+ return -EINVAL; -+ -+ if (!strcmp(str, "post")) { -+ /* exit out if host buffers are already posted */ -+ if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && -+ (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) && -+ ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) == 0)) -+ goto out; -+ memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); -+ pr_info(MPT3SAS_FMT "posting host trace buffers\n", -+ ioc->name); -+ diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; -+ diag_register.requested_buffer_size = (1024 * 1024); -+ diag_register.unique_id = 0x7075900; -+ ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; -+ _ctl_diag_register_2(ioc, &diag_register); -+ } else if (!strcmp(str, "release")) { -+ /* exit out if host buffers are already released */ -+ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) -+ goto out; -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) -+ goto out; -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ goto out; -+ pr_info(MPT3SAS_FMT "releasing host trace buffer\n", -+ ioc->name); -+ mpt2sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, -+ &issue_reset); -+ } -+ -+ out: -+ return strlen(buf); -+} -+static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, -+ _ctl_host_trace_buffer_enable_show, -+ _ctl_host_trace_buffer_enable_store); -+ -+/*********** diagnostic trigger suppport *********************************/ -+ -+/** -+ * _ctl_diag_trigger_master_show - show the diag_trigger_master attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_master_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+ -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = sizeof(struct SL_WH_MASTER_TRIGGER_T); -+ memcpy(buf, &ioc->diag_trigger_master, rc); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_trigger_master_store - store the diag_trigger_master attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_master_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+ -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = min(sizeof(struct SL_WH_MASTER_TRIGGER_T), count); -+ memset(&ioc->diag_trigger_master, 0, -+ sizeof(struct SL_WH_MASTER_TRIGGER_T)); -+ memcpy(&ioc->diag_trigger_master, buf, rc); -+ ioc->diag_trigger_master.MasterData |= -+ (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR, -+ _ctl_diag_trigger_master_show, _ctl_diag_trigger_master_store); -+ -+ -+/** -+ * _ctl_diag_trigger_event_show - show the diag_trigger_event attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_event_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = sizeof(struct SL_WH_EVENT_TRIGGERS_T); -+ memcpy(buf, &ioc->diag_trigger_event, rc); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_trigger_event_store - store the diag_trigger_event attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_event_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+ -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t sz; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ sz = min(sizeof(struct SL_WH_EVENT_TRIGGERS_T), count); -+ memset(&ioc->diag_trigger_event, 0, -+ sizeof(struct SL_WH_EVENT_TRIGGERS_T)); -+ memcpy(&ioc->diag_trigger_event, buf, sz); -+ if (ioc->diag_trigger_event.ValidEntries > NUM_VALID_ENTRIES) -+ ioc->diag_trigger_event.ValidEntries = NUM_VALID_ENTRIES; -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return sz; -+} -+static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR, -+ _ctl_diag_trigger_event_show, _ctl_diag_trigger_event_store); -+ -+ -+/** -+ * _ctl_diag_trigger_scsi_show - show the diag_trigger_scsi attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_scsi_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = sizeof(struct SL_WH_SCSI_TRIGGERS_T); -+ memcpy(buf, &ioc->diag_trigger_scsi, rc); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_trigger_scsi_store - store the diag_trigger_scsi attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_scsi_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t sz; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ sz = min(sizeof(struct SL_WH_SCSI_TRIGGERS_T), count); -+ memset(&ioc->diag_trigger_scsi, 0, -+ sizeof(struct SL_WH_EVENT_TRIGGERS_T)); -+ memcpy(&ioc->diag_trigger_scsi, buf, sz); -+ if (ioc->diag_trigger_scsi.ValidEntries > NUM_VALID_ENTRIES) -+ ioc->diag_trigger_scsi.ValidEntries = NUM_VALID_ENTRIES; -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return sz; -+} -+static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR, -+ _ctl_diag_trigger_scsi_show, _ctl_diag_trigger_scsi_store); -+ -+ -+/** -+ * _ctl_diag_trigger_scsi_show - show the diag_trigger_mpi attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_mpi_show(struct device *cdev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t rc; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ rc = sizeof(struct SL_WH_MPI_TRIGGERS_T); -+ memcpy(buf, &ioc->diag_trigger_mpi, rc); -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return rc; -+} -+ -+/** -+ * _ctl_diag_trigger_mpi_store - store the diag_trigger_mpi attribute -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * A sysfs 'read/write' shost attribute. -+ */ -+static ssize_t -+_ctl_diag_trigger_mpi_store(struct device *cdev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct Scsi_Host *shost = class_to_shost(cdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ unsigned long flags; -+ ssize_t sz; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ sz = min(sizeof(struct SL_WH_MPI_TRIGGERS_T), count); -+ memset(&ioc->diag_trigger_mpi, 0, -+ sizeof(ioc->diag_trigger_mpi)); -+ memcpy(&ioc->diag_trigger_mpi, buf, sz); -+ if (ioc->diag_trigger_mpi.ValidEntries > NUM_VALID_ENTRIES) -+ ioc->diag_trigger_mpi.ValidEntries = NUM_VALID_ENTRIES; -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return sz; -+} -+ -+static DEVICE_ATTR(diag_trigger_mpi, S_IRUGO | S_IWUSR, -+ _ctl_diag_trigger_mpi_show, _ctl_diag_trigger_mpi_store); -+ -+/*********** diagnostic trigger suppport *** END ****************************/ -+ -+ -+ -+/*****************************************/ -+ -+struct device_attribute *mpt2sas_host_attrs[] = { -+ &dev_attr_version_fw, -+ &dev_attr_version_bios, -+ &dev_attr_version_mpi, -+ &dev_attr_version_product, -+ &dev_attr_version_nvdata_persistent, -+ &dev_attr_version_nvdata_default, -+ &dev_attr_board_name, -+ &dev_attr_board_assembly, -+ &dev_attr_board_tracer, -+ &dev_attr_io_delay, -+ &dev_attr_device_delay, -+ &dev_attr_logging_level, -+ &dev_attr_fwfault_debug, -+ &dev_attr_fw_queue_depth, -+ &dev_attr_host_sas_address, -+ &dev_attr_ioc_reset_count, -+ &dev_attr_host_trace_buffer_size, -+ &dev_attr_host_trace_buffer, -+ &dev_attr_host_trace_buffer_enable, -+ &dev_attr_reply_queue_count, -+ &dev_attr_diag_trigger_master, -+ &dev_attr_diag_trigger_event, -+ &dev_attr_diag_trigger_scsi, -+ &dev_attr_diag_trigger_mpi, -+ &dev_attr_BRM_status, -+ NULL, -+}; -+ -+/* device attributes */ -+ -+/** -+ * _ctl_device_sas_address_show - sas address -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is the sas address for the target -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; -+ -+ return snprintf(buf, PAGE_SIZE, "0x%016llx\n", -+ (unsigned long long)sas_device_priv_data->sas_target->sas_address); -+} -+static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); -+ -+/** -+ * _ctl_device_handle_show - device handle -+ * @cdev - pointer to embedded class device -+ * @buf - the buffer returned -+ * -+ * This is the firmware assigned device handle -+ * -+ * A sysfs 'read-only' shost attribute. -+ */ -+static ssize_t -+_ctl_device_handle_show(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; -+ -+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", -+ sas_device_priv_data->sas_target->handle); -+} -+static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); -+ -+struct device_attribute *mpt2sas_dev_attrs[] = { -+ &dev_attr_sas_address, -+ &dev_attr_sas_device_handle, -+ NULL, -+}; -+ -+/* file operations table for mpt3ctl device */ -+static const struct file_operations ctl_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = _ctl_ioctl_mpt2sas, -+ .poll = _ctl_poll_mpt2sas, -+ .fasync = _ctl_fasync_mpt2sas, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = _ctl_ioctl_compat_mpt2sas, -+#endif -+}; -+ -+/* file operations table for mpt2ctl device */ -+static const struct file_operations ctl_gen2_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = _ctl_mpt2_ioctl_mpt2sas, -+ .poll = _ctl_poll_mpt2sas, -+ .fasync = _ctl_fasync_mpt2sas, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = _ctl_mpt2_ioctl_compat_mpt2sas, -+#endif -+}; -+ -+static struct miscdevice ctl_dev = { -+ .minor = MPT3SAS_MINOR, -+ .name = MPT3SAS_DEV_NAME, -+ .fops = &ctl_fops, -+}; -+ -+static struct miscdevice gen2_ctl_dev = { -+ .minor = MPT2SAS_MINOR, -+ .name = MPT2SAS_DEV_NAME, -+ .fops = &ctl_gen2_fops, -+}; -+ -+/** -+ * mpt2sas_ctl_init - main entry point for ctl. -+ * -+ */ -+void -+mpt2sas_ctl_init(ushort hbas_to_enumerate) -+{ -+ async_queue = NULL; -+ -+ /* Don't register mpt3ctl ioctl device if -+ * hbas_to_enumarate is one. -+ */ -+ if (hbas_to_enumerate != 1) -+ if (misc_register(&ctl_dev) < 0) -+ pr_err("%s can't register misc device [minor=%d]\n", -+ MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR); -+ -+ /* Don't register mpt3ctl ioctl device if -+ * hbas_to_enumarate is two. -+ */ -+ if (hbas_to_enumerate != 2) -+ if (misc_register(&gen2_ctl_dev) < 0) -+ pr_err("%s can't register misc device [minor=%d]\n", -+ MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); -+ -+ init_waitqueue_head(&ctl_poll_wait); -+} -+ -+/** -+ * mpt2sas_ctl_exit - exit point for ctl -+ * -+ */ -+void -+mpt2sas_ctl_exit(ushort hbas_to_enumerate) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ int i; -+ -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { -+ -+ /* free memory associated to diag buffers */ -+ for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { -+ if (!ioc->diag_buffer[i]) -+ continue; -+ if (!(ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED)) -+ continue; -+ if ((ioc->diag_buffer_status[i] & -+ MPT3_DIAG_BUFFER_IS_RELEASED)) -+ continue; -+ pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i], -+ ioc->diag_buffer[i], ioc->diag_buffer_dma[i]); -+ ioc->diag_buffer[i] = NULL; -+ ioc->diag_buffer_status[i] = 0; -+ } -+ -+ kfree(ioc->event_log); -+ } -+ if (hbas_to_enumerate != 1) -+ misc_deregister(&ctl_dev); -+ if (hbas_to_enumerate != 2) -+ misc_deregister(&gen2_ctl_dev); -+} -diff --git a/drivers/scsi/mpt2sas/mpt3sas_ctl.h b/drivers/scsi/mpt2sas/mpt3sas_ctl.h -new file mode 100644 -index 0000000..8940835 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_ctl.h -@@ -0,0 +1,423 @@ -+/* -+ * Management Module Support for MPT (Message Passing Technology) based -+ * controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.h -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#ifndef MPT3SAS_CTL_H_INCLUDED -+#define MPT3SAS_CTL_H_INCLUDED -+ -+#ifdef __KERNEL__ -+#include -+#endif -+ -+#ifndef MPT2SAS_MINOR -+#define MPT2SAS_MINOR (MPT_MINOR + 1) -+#endif -+#ifndef MPT3SAS_MINOR -+#define MPT3SAS_MINOR (MPT_MINOR + 2) -+#endif -+#define MPT2SAS_DEV_NAME "mpt2ctl" -+#define MPT3SAS_DEV_NAME "mpt3ctl" -+#define MPT3_MAGIC_NUMBER 'L' -+#define MPT3_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */ -+ -+/** -+ * IOCTL opcodes -+ */ -+#define MPT3IOCINFO _IOWR(MPT3_MAGIC_NUMBER, 17, \ -+ struct mpt3_ioctl_iocinfo) -+#define MPT3COMMAND _IOWR(MPT3_MAGIC_NUMBER, 20, \ -+ struct mpt3_ioctl_command) -+#ifdef CONFIG_COMPAT -+#define MPT3COMMAND32 _IOWR(MPT3_MAGIC_NUMBER, 20, \ -+ struct mpt3_ioctl_command32) -+#endif -+#define MPT3EVENTQUERY _IOWR(MPT3_MAGIC_NUMBER, 21, \ -+ struct mpt3_ioctl_eventquery) -+#define MPT3EVENTENABLE _IOWR(MPT3_MAGIC_NUMBER, 22, \ -+ struct mpt3_ioctl_eventenable) -+#define MPT3EVENTREPORT _IOWR(MPT3_MAGIC_NUMBER, 23, \ -+ struct mpt3_ioctl_eventreport) -+#define MPT3HARDRESET _IOWR(MPT3_MAGIC_NUMBER, 24, \ -+ struct mpt3_ioctl_diag_reset) -+#define MPT3BTDHMAPPING _IOWR(MPT3_MAGIC_NUMBER, 31, \ -+ struct mpt3_ioctl_btdh_mapping) -+ -+/* diag buffer support */ -+#define MPT3DIAGREGISTER _IOWR(MPT3_MAGIC_NUMBER, 26, \ -+ struct mpt3_diag_register) -+#define MPT3DIAGRELEASE _IOWR(MPT3_MAGIC_NUMBER, 27, \ -+ struct mpt3_diag_release) -+#define MPT3DIAGUNREGISTER _IOWR(MPT3_MAGIC_NUMBER, 28, \ -+ struct mpt3_diag_unregister) -+#define MPT3DIAGQUERY _IOWR(MPT3_MAGIC_NUMBER, 29, \ -+ struct mpt3_diag_query) -+#define MPT3DIAGREADBUFFER _IOWR(MPT3_MAGIC_NUMBER, 30, \ -+ struct mpt3_diag_read_buffer) -+ -+/** -+ * struct mpt3_ioctl_header - main header structure -+ * @ioc_number - IOC unit number -+ * @port_number - IOC port number -+ * @max_data_size - maximum number bytes to transfer on read -+ */ -+struct mpt3_ioctl_header { -+ uint32_t ioc_number; -+ uint32_t port_number; -+ uint32_t max_data_size; -+}; -+ -+/** -+ * struct mpt3_ioctl_diag_reset - diagnostic reset -+ * @hdr - generic header -+ */ -+struct mpt3_ioctl_diag_reset { -+ struct mpt3_ioctl_header hdr; -+}; -+ -+ -+/** -+ * struct mpt3_ioctl_pci_info - pci device info -+ * @device - pci device id -+ * @function - pci function id -+ * @bus - pci bus id -+ * @segment_id - pci segment id -+ */ -+struct mpt3_ioctl_pci_info { -+ union { -+ struct { -+ uint32_t device:5; -+ uint32_t function:3; -+ uint32_t bus:24; -+ } bits; -+ uint32_t word; -+ } u; -+ uint32_t segment_id; -+}; -+ -+ -+#define MPT2_IOCTL_INTERFACE_SCSI (0x00) -+#define MPT2_IOCTL_INTERFACE_FC (0x01) -+#define MPT2_IOCTL_INTERFACE_FC_IP (0x02) -+#define MPT2_IOCTL_INTERFACE_SAS (0x03) -+#define MPT2_IOCTL_INTERFACE_SAS2 (0x04) -+#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05) -+#define MPT3_IOCTL_INTERFACE_SAS3 (0x06) -+#define MPT2_IOCTL_VERSION_LENGTH (32) -+ -+/** -+ * struct mpt3_ioctl_iocinfo - generic controller info -+ * @hdr - generic header -+ * @adapter_type - type of adapter (spi, fc, sas) -+ * @port_number - port number -+ * @pci_id - PCI Id -+ * @hw_rev - hardware revision -+ * @sub_system_device - PCI subsystem Device ID -+ * @sub_system_vendor - PCI subsystem Vendor ID -+ * @rsvd0 - reserved -+ * @firmware_version - firmware version -+ * @bios_version - BIOS version -+ * @driver_version - driver version - 32 ASCII characters -+ * @rsvd1 - reserved -+ * @scsi_id - scsi id of adapter 0 -+ * @rsvd2 - reserved -+ * @pci_information - pci info (2nd revision) -+ */ -+struct mpt3_ioctl_iocinfo { -+ struct mpt3_ioctl_header hdr; -+ uint32_t adapter_type; -+ uint32_t port_number; -+ uint32_t pci_id; -+ uint32_t hw_rev; -+ uint32_t subsystem_device; -+ uint32_t subsystem_vendor; -+ uint32_t rsvd0; -+ uint32_t firmware_version; -+ uint32_t bios_version; -+ uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH]; -+ uint8_t rsvd1; -+ uint8_t scsi_id; -+ uint16_t rsvd2; -+ struct mpt3_ioctl_pci_info pci_information; -+}; -+ -+ -+/* number of event log entries */ -+#define MPT3SAS_CTL_EVENT_LOG_SIZE (50) -+ -+/** -+ * struct mpt3_ioctl_eventquery - query event count and type -+ * @hdr - generic header -+ * @event_entries - number of events returned by get_event_report -+ * @rsvd - reserved -+ * @event_types - type of events currently being captured -+ */ -+struct mpt3_ioctl_eventquery { -+ struct mpt3_ioctl_header hdr; -+ uint16_t event_entries; -+ uint16_t rsvd; -+ uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; -+}; -+ -+/** -+ * struct mpt3_ioctl_eventenable - enable/disable event capturing -+ * @hdr - generic header -+ * @event_types - toggle off/on type of events to be captured -+ */ -+struct mpt3_ioctl_eventenable { -+ struct mpt3_ioctl_header hdr; -+ uint32_t event_types[4]; -+}; -+ -+#define MPT3_EVENT_DATA_SIZE (192) -+/** -+ * struct MPT3_IOCTL_EVENTS - -+ * @event - the event that was reported -+ * @context - unique value for each event assigned by driver -+ * @data - event data returned in fw reply message -+ */ -+struct MPT3_IOCTL_EVENTS { -+ uint32_t event; -+ uint32_t context; -+ uint8_t data[MPT3_EVENT_DATA_SIZE]; -+}; -+ -+/** -+ * struct mpt3_ioctl_eventreport - returing event log -+ * @hdr - generic header -+ * @event_data - (see struct MPT3_IOCTL_EVENTS) -+ */ -+struct mpt3_ioctl_eventreport { -+ struct mpt3_ioctl_header hdr; -+ struct MPT3_IOCTL_EVENTS event_data[1]; -+}; -+ -+/** -+ * struct mpt3_ioctl_command - generic mpt firmware passthru ioctl -+ * @hdr - generic header -+ * @timeout - command timeout in seconds. (if zero then use driver default -+ * value). -+ * @reply_frame_buf_ptr - reply location -+ * @data_in_buf_ptr - destination for read -+ * @data_out_buf_ptr - data source for write -+ * @sense_data_ptr - sense data location -+ * @max_reply_bytes - maximum number of reply bytes to be sent to app. -+ * @data_in_size - number bytes for data transfer in (read) -+ * @data_out_size - number bytes for data transfer out (write) -+ * @max_sense_bytes - maximum number of bytes for auto sense buffers -+ * @data_sge_offset - offset in words from the start of the request message to -+ * the first SGL -+ * @mf[1]; -+ */ -+struct mpt3_ioctl_command { -+ struct mpt3_ioctl_header hdr; -+ uint32_t timeout; -+ void __user *reply_frame_buf_ptr; -+ void __user *data_in_buf_ptr; -+ void __user *data_out_buf_ptr; -+ void __user *sense_data_ptr; -+ uint32_t max_reply_bytes; -+ uint32_t data_in_size; -+ uint32_t data_out_size; -+ uint32_t max_sense_bytes; -+ uint32_t data_sge_offset; -+ uint8_t mf[1]; -+}; -+ -+#ifdef CONFIG_COMPAT -+struct mpt3_ioctl_command32 { -+ struct mpt3_ioctl_header hdr; -+ uint32_t timeout; -+ uint32_t reply_frame_buf_ptr; -+ uint32_t data_in_buf_ptr; -+ uint32_t data_out_buf_ptr; -+ uint32_t sense_data_ptr; -+ uint32_t max_reply_bytes; -+ uint32_t data_in_size; -+ uint32_t data_out_size; -+ uint32_t max_sense_bytes; -+ uint32_t data_sge_offset; -+ uint8_t mf[1]; -+}; -+#endif -+ -+/** -+ * struct mpt3_ioctl_btdh_mapping - mapping info -+ * @hdr - generic header -+ * @id - target device identification number -+ * @bus - SCSI bus number that the target device exists on -+ * @handle - device handle for the target device -+ * @rsvd - reserved -+ * -+ * To obtain a bus/id the application sets -+ * handle to valid handle, and bus/id to 0xFFFF. -+ * -+ * To obtain the device handle the application sets -+ * bus/id valid value, and the handle to 0xFFFF. -+ */ -+struct mpt3_ioctl_btdh_mapping { -+ struct mpt3_ioctl_header hdr; -+ uint32_t id; -+ uint32_t bus; -+ uint16_t handle; -+ uint16_t rsvd; -+}; -+ -+ -+ -+/* application flags for mpt3_diag_register, mpt3_diag_query */ -+#define MPT3_APP_FLAGS_APP_OWNED (0x0001) -+#define MPT3_APP_FLAGS_BUFFER_VALID (0x0002) -+#define MPT3_APP_FLAGS_FW_BUFFER_ACCESS (0x0004) -+ -+/* flags for mpt3_diag_read_buffer */ -+#define MPT3_FLAGS_REREGISTER (0x0001) -+ -+#define MPT3_PRODUCT_SPECIFIC_DWORDS 23 -+ -+/** -+ * struct mpt3_diag_register - application register with driver -+ * @hdr - generic header -+ * @reserved - -+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED -+ * @application_flags - misc flags -+ * @diagnostic_flags - specifies flags affecting command processing -+ * @product_specific - product specific information -+ * @requested_buffer_size - buffers size in bytes -+ * @unique_id - tag specified by application that is used to signal ownership -+ * of the buffer. -+ * -+ * This will allow the driver to setup any required buffers that will be -+ * needed by firmware to communicate with the driver. -+ */ -+struct mpt3_diag_register { -+ struct mpt3_ioctl_header hdr; -+ uint8_t reserved; -+ uint8_t buffer_type; -+ uint16_t application_flags; -+ uint32_t diagnostic_flags; -+ uint32_t product_specific[MPT3_PRODUCT_SPECIFIC_DWORDS]; -+ uint32_t requested_buffer_size; -+ uint32_t unique_id; -+}; -+ -+/** -+ * struct mpt3_diag_unregister - application unregister with driver -+ * @hdr - generic header -+ * @unique_id - tag uniquely identifies the buffer to be unregistered -+ * -+ * This will allow the driver to cleanup any memory allocated for diag -+ * messages and to free up any resources. -+ */ -+struct mpt3_diag_unregister { -+ struct mpt3_ioctl_header hdr; -+ uint32_t unique_id; -+}; -+ -+/** -+ * struct mpt3_diag_query - query relevant info associated with diag buffers -+ * @hdr - generic header -+ * @reserved - -+ * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED -+ * @application_flags - misc flags -+ * @diagnostic_flags - specifies flags affecting command processing -+ * @product_specific - product specific information -+ * @total_buffer_size - diag buffer size in bytes -+ * @driver_added_buffer_size - size of extra space appended to end of buffer -+ * @unique_id - unique id associated with this buffer. -+ * -+ * The application will send only buffer_type and unique_id. Driver will -+ * inspect unique_id first, if valid, fill in all the info. If unique_id is -+ * 0x00, the driver will return info specified by Buffer Type. -+ */ -+struct mpt3_diag_query { -+ struct mpt3_ioctl_header hdr; -+ uint8_t reserved; -+ uint8_t buffer_type; -+ uint16_t application_flags; -+ uint32_t diagnostic_flags; -+ uint32_t product_specific[MPT3_PRODUCT_SPECIFIC_DWORDS]; -+ uint32_t total_buffer_size; -+ uint32_t driver_added_buffer_size; -+ uint32_t unique_id; -+}; -+ -+/** -+ * struct mpt3_diag_release - request to send Diag Release Message to firmware -+ * @hdr - generic header -+ * @unique_id - tag uniquely identifies the buffer to be released -+ * -+ * This allows ownership of the specified buffer to returned to the driver, -+ * allowing an application to read the buffer without fear that firmware is -+ * overwritting information in the buffer. -+ */ -+struct mpt3_diag_release { -+ struct mpt3_ioctl_header hdr; -+ uint32_t unique_id; -+}; -+ -+/** -+ * struct mpt3_diag_read_buffer - request for copy of the diag buffer -+ * @hdr - generic header -+ * @status - -+ * @reserved - -+ * @flags - misc flags -+ * @starting_offset - starting offset within drivers buffer where to start -+ * reading data at into the specified application buffer -+ * @bytes_to_read - number of bytes to copy from the drivers buffer into the -+ * application buffer starting at starting_offset. -+ * @unique_id - unique id associated with this buffer. -+ * @diagnostic_data - data payload -+ */ -+struct mpt3_diag_read_buffer { -+ struct mpt3_ioctl_header hdr; -+ uint8_t status; -+ uint8_t reserved; -+ uint16_t flags; -+ uint32_t starting_offset; -+ uint32_t bytes_to_read; -+ uint32_t unique_id; -+ uint32_t diagnostic_data[1]; -+}; -+ -+#endif /* MPT3SAS_CTL_H_INCLUDED */ -diff --git a/drivers/scsi/mpt2sas/mpt3sas_debug.h b/drivers/scsi/mpt2sas/mpt3sas_debug.h -new file mode 100644 -index 0000000..cceeb2c ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_debug.h -@@ -0,0 +1,206 @@ -+/* -+ * Logging Support for MPT (Message Passing Technology) based controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_debug.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#ifndef MPT3SAS_DEBUG_H_INCLUDED -+#define MPT3SAS_DEBUG_H_INCLUDED -+ -+#define MPT_DEBUG 0x00000001 -+#define MPT_DEBUG_MSG_FRAME 0x00000002 -+#define MPT_DEBUG_SG 0x00000004 -+#define MPT_DEBUG_EVENTS 0x00000008 -+#define MPT_DEBUG_EVENT_WORK_TASK 0x00000010 -+#define MPT_DEBUG_INIT 0x00000020 -+#define MPT_DEBUG_EXIT 0x00000040 -+#define MPT_DEBUG_FAIL 0x00000080 -+#define MPT_DEBUG_TM 0x00000100 -+#define MPT_DEBUG_REPLY 0x00000200 -+#define MPT_DEBUG_HANDSHAKE 0x00000400 -+#define MPT_DEBUG_CONFIG 0x00000800 -+#define MPT_DEBUG_DL 0x00001000 -+#define MPT_DEBUG_RESET 0x00002000 -+#define MPT_DEBUG_SCSI 0x00004000 -+#define MPT_DEBUG_IOCTL 0x00008000 -+#define MPT_DEBUG_SAS 0x00020000 -+#define MPT_DEBUG_TRANSPORT 0x00040000 -+#define MPT_DEBUG_TASK_SET_FULL 0x00080000 -+ -+#define MPT_DEBUG_TRIGGER_DIAG 0x00200000 -+ -+ -+#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \ -+{ \ -+ if (IOC->logging_level & BITS) \ -+ CMD; \ -+} -+ -+/* -+ * debug macros -+ */ -+ -+#define dprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG) -+ -+#define dsgprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG) -+ -+#define devtprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS) -+ -+#define dewtprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK) -+ -+#define dinitprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT) -+ -+#define dexitprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT) -+ -+#define dfailprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL) -+ -+#define dtmprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM) -+ -+#define dreplyprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY) -+ -+#define dhsprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE) -+ -+#define dcprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG) -+ -+#define ddlprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL) -+ -+#define drsprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET) -+ -+#define dsprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI) -+ -+#define dctlprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL) -+ -+#define dsasprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS) -+ -+#define dsastransport(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) -+ -+#define dmfprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME) -+ -+#define dtsfprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL) -+ -+#define dtransportprintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT) -+ -+#define dTriggerDiagPrintk(IOC, CMD) \ -+ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRIGGER_DIAG) -+ -+ -+ -+/* inline functions for dumping debug data*/ -+ -+/** -+ * _debug_dump_mf - print message frame contents -+ * @mpi_request: pointer to message frame -+ * @sz: number of dwords -+ */ -+static inline void -+_debug_dump_mf(void *mpi_request, int sz) -+{ -+ int i; -+ __le32 *mfp = (__le32 *)mpi_request; -+ -+ pr_info("mf:\n\t"); -+ for (i = 0; i < sz; i++) { -+ if (i && ((i % 8) == 0)) -+ pr_info("\n\t"); -+ pr_info("%08x ", le32_to_cpu(mfp[i])); -+ } -+ pr_info("\n"); -+} -+/** -+ * _debug_dump_reply - print message frame contents -+ * @mpi_request: pointer to message frame -+ * @sz: number of dwords -+ */ -+static inline void -+_debug_dump_reply(void *mpi_request, int sz) -+{ -+ int i; -+ __le32 *mfp = (__le32 *)mpi_request; -+ -+ pr_info("reply:\n\t"); -+ for (i = 0; i < sz; i++) { -+ if (i && ((i % 8) == 0)) -+ pr_info("\n\t"); -+ pr_info("%08x ", le32_to_cpu(mfp[i])); -+ } -+ pr_info("\n"); -+} -+/** -+ * _debug_dump_config - print config page contents -+ * @mpi_request: pointer to message frame -+ * @sz: number of dwords -+ */ -+static inline void -+_debug_dump_config(void *mpi_request, int sz) -+{ -+ int i; -+ __le32 *mfp = (__le32 *)mpi_request; -+ -+ pr_info("config:\n\t"); -+ for (i = 0; i < sz; i++) { -+ if (i && ((i % 8) == 0)) -+ pr_info("\n\t"); -+ pr_info("%08x ", le32_to_cpu(mfp[i])); -+ } -+ pr_info("\n"); -+} -+ -+#endif /* MPT3SAS_DEBUG_H_INCLUDED */ -diff --git a/drivers/scsi/mpt2sas/mpt3sas_scsih.c b/drivers/scsi/mpt2sas/mpt3sas_scsih.c -new file mode 100644 -index 0000000..0a3ad2b ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_scsih.c -@@ -0,0 +1,9356 @@ -+/* -+ * Scsi Host Layer for MPT (Message Passing Technology) based controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_scsih.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+#define RAID_CHANNEL 1 -+/* forward proto's */ -+static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander); -+static void _firmware_event_work(struct work_struct *work); -+ -+static void _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device); -+static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u8 retry_count, u8 is_pd); -+ -+static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid); -+ -+/* global parameters */ -+LIST_HEAD(mpt2sas_ioc_list); -+/* global ioc lock for list operations */ -+DEFINE_SPINLOCK(gioc_lock_mpt2sas); -+ -+MODULE_AUTHOR(MPT3SAS_AUTHOR); -+#ifdef MPT2SAS_SCSI -+MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION); -+MODULE_VERSION(MPT2SAS_DRIVER_VERSION); -+#else -+MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION); -+MODULE_VERSION(MPT3SAS_DRIVER_VERSION); -+#endif /* MPT2SAS_SCSI */ -+MODULE_LICENSE("GPL"); -+ -+/* local parameters */ -+static u8 scsi_io_cb_idx = -1; -+static u8 tm_cb_idx = -1; -+static u8 ctl_cb_idx = -1; -+static u8 base_cb_idx = -1; -+static u8 port_enable_cb_idx = -1; -+static u8 transport_cb_idx = -1; -+static u8 scsih_cb_idx = -1; -+static u8 config_cb_idx = -1; -+static int mpt2_ids; -+static int mpt3_ids; -+ -+static u8 tm_tr_cb_idx = -1 ; -+static u8 tm_tr_volume_cb_idx = -1 ; -+static u8 tm_sas_control_cb_idx = -1; -+ -+/* command line options */ -+static u32 logging_level; -+MODULE_PARM_DESC(logging_level, -+ " bits for enabling additional logging info (default=0)"); -+ -+ -+static ushort max_sectors = 0xFFFF; -+module_param(max_sectors, ushort, 0); -+MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767"); -+ -+ -+static int missing_delay[2] = {-1, -1}; -+module_param_array(missing_delay, int, NULL, 0); -+MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); -+ -+/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ -+#define MPT3SAS_MAX_LUN (16895) -+static int max_lun = MPT3SAS_MAX_LUN; -+module_param(max_lun, int, 0); -+MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); -+ -+/* diag_buffer_enable is bitwise -+ * bit 0 set = TRACE -+ * bit 1 set = SNAPSHOT -+ * bit 2 set = EXTENDED -+ * -+ * Either bit can be set, or both -+ */ -+static int diag_buffer_enable = -1; -+module_param(diag_buffer_enable, int, 0); -+MODULE_PARM_DESC(diag_buffer_enable, -+ " post diag buffers (TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); -+static int disable_discovery = -1; -+module_param(disable_discovery, int, 0); -+MODULE_PARM_DESC(disable_discovery, " disable discovery "); -+ -+ -+/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ -+static int prot_mask = -1; -+module_param(prot_mask, int, 0); -+MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); -+ -+ -+/* raid transport support */ -+struct raid_template *mpt3sas_raid_template_mpt2sas; -+struct raid_template *mpt2sas_raid_template_mpt2sas; -+ -+ -+/** -+ * struct sense_info - common structure for obtaining sense keys -+ * @skey: sense key -+ * @asc: additional sense code -+ * @ascq: additional sense code qualifier -+ */ -+struct sense_info { -+ u8 skey; -+ u8 asc; -+ u8 ascq; -+}; -+ -+#define MPT3SAS_PROCESS_TRIGGER_DIAG (0xFFFB) -+#define MPT3SAS_TURN_ON_PFA_LED (0xFFFC) -+#define MPT3SAS_PORT_ENABLE_COMPLETE (0xFFFD) -+#define MPT3SAS_ABRT_TASK_SET (0xFFFE) -+#define MPT3SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF) -+/** -+ * struct fw_event_work - firmware event struct -+ * @list: link list framework -+ * @work: work object (ioc->fault_reset_work_q) -+ * @ioc: per adapter object -+ * @device_handle: device handle -+ * @VF_ID: virtual function id -+ * @VP_ID: virtual port id -+ * @ignore: flag meaning this event has been marked to ignore -+ * @event: firmware event MPI2_EVENT_XXX defined in mpi2_ioc.h -+ * @refcount: kref for this event -+ * @event_data: reply event data payload follows -+ * -+ * This object stored on ioc->fw_event_list. -+ */ -+struct fw_event_work { -+ struct list_head list; -+ struct work_struct work; -+ -+ struct MPT3SAS_ADAPTER *ioc; -+ u16 device_handle; -+ u8 VF_ID; -+ u8 VP_ID; -+ u8 ignore; -+ u16 event; -+ struct kref refcount; -+ char event_data[0] __aligned(4); -+}; -+ -+static void fw_event_work_free(struct kref *r) -+{ -+ kfree(container_of(r, struct fw_event_work, refcount)); -+} -+ -+static void fw_event_work_get(struct fw_event_work *fw_work) -+{ -+ kref_get(&fw_work->refcount); -+} -+ -+static void fw_event_work_put(struct fw_event_work *fw_work) -+{ -+ kref_put(&fw_work->refcount, fw_event_work_free); -+} -+ -+static struct fw_event_work *alloc_fw_event_work(int len) -+{ -+ struct fw_event_work *fw_event; -+ -+ fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC); -+ if (!fw_event) -+ return NULL; -+ -+ kref_init(&fw_event->refcount); -+ return fw_event; -+} -+ -+/** -+ * struct _scsi_io_transfer - scsi io transfer -+ * @handle: sas device handle (assigned by firmware) -+ * @is_raid: flag set for hidden raid components -+ * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE, -+ * @data_length: data transfer length -+ * @data_dma: dma pointer to data -+ * @sense: sense data -+ * @lun: lun number -+ * @cdb_length: cdb length -+ * @cdb: cdb contents -+ * @timeout: timeout for this command -+ * @VF_ID: virtual function id -+ * @VP_ID: virtual port id -+ * @valid_reply: flag set for reply message -+ * @sense_length: sense length -+ * @ioc_status: ioc status -+ * @scsi_state: scsi state -+ * @scsi_status: scsi staus -+ * @log_info: log information -+ * @transfer_length: data length transfer when there is a reply message -+ * -+ * Used for sending internal scsi commands to devices within this module. -+ * Refer to _scsi_send_scsi_io(). -+ */ -+struct _scsi_io_transfer { -+ u16 handle; -+ u8 is_raid; -+ enum dma_data_direction dir; -+ u32 data_length; -+ dma_addr_t data_dma; -+ u8 sense[SCSI_SENSE_BUFFERSIZE]; -+ u32 lun; -+ u8 cdb_length; -+ u8 cdb[32]; -+ u8 timeout; -+ u8 VF_ID; -+ u8 VP_ID; -+ u8 valid_reply; -+ /* the following bits are only valid when 'valid_reply = 1' */ -+ u32 sense_length; -+ u16 ioc_status; -+ u8 scsi_state; -+ u8 scsi_status; -+ u32 log_info; -+ u32 transfer_length; -+}; -+ -+/** -+ * _scsih_set_debug_level - global setting of ioc->logging_level. -+ * -+ * Note: The logging levels are defined in mpt3sas_debug.h. -+ */ -+static int -+_scsih_set_debug_level(const char *val, struct kernel_param *kp) -+{ -+ int ret = param_set_int(val, kp); -+ struct MPT3SAS_ADAPTER *ioc; -+ -+ if (ret) -+ return ret; -+ -+ pr_info("setting logging_level(0x%08x)\n", logging_level); -+ spin_lock(&gioc_lock_mpt2sas); -+ list_for_each_entry(ioc, &mpt2sas_ioc_list, list) -+ ioc->logging_level = logging_level; -+ spin_unlock(&gioc_lock_mpt2sas); -+ return 0; -+} -+module_param_call(logging_level, _scsih_set_debug_level, param_get_int, -+ &logging_level, 0644); -+ -+/** -+ * _scsih_srch_boot_sas_address - search based on sas_address -+ * @sas_address: sas address -+ * @boot_device: boot device object from bios page 2 -+ * -+ * Returns 1 when there's a match, 0 means no match. -+ */ -+static inline int -+_scsih_srch_boot_sas_address(u64 sas_address, -+ Mpi2BootDeviceSasWwid_t *boot_device) -+{ -+ return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0; -+} -+ -+/** -+ * _scsih_srch_boot_device_name - search based on device name -+ * @device_name: device name specified in INDENTIFY fram -+ * @boot_device: boot device object from bios page 2 -+ * -+ * Returns 1 when there's a match, 0 means no match. -+ */ -+static inline int -+_scsih_srch_boot_device_name(u64 device_name, -+ Mpi2BootDeviceDeviceName_t *boot_device) -+{ -+ return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0; -+} -+ -+/** -+ * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot -+ * @enclosure_logical_id: enclosure logical id -+ * @slot_number: slot number -+ * @boot_device: boot device object from bios page 2 -+ * -+ * Returns 1 when there's a match, 0 means no match. -+ */ -+static inline int -+_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number, -+ Mpi2BootDeviceEnclosureSlot_t *boot_device) -+{ -+ return (enclosure_logical_id == le64_to_cpu(boot_device-> -+ EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device-> -+ SlotNumber)) ? 1 : 0; -+} -+ -+/** -+ * _scsih_is_boot_device - search for matching boot device. -+ * @sas_address: sas address -+ * @device_name: device name specified in INDENTIFY fram -+ * @enclosure_logical_id: enclosure logical id -+ * @slot_number: slot number -+ * @form: specifies boot device form -+ * @boot_device: boot device object from bios page 2 -+ * -+ * Returns 1 when there's a match, 0 means no match. -+ */ -+static int -+_scsih_is_boot_device(u64 sas_address, u64 device_name, -+ u64 enclosure_logical_id, u16 slot, u8 form, -+ Mpi2BiosPage2BootDevice_t *boot_device) -+{ -+ int rc = 0; -+ -+ switch (form) { -+ case MPI2_BIOSPAGE2_FORM_SAS_WWID: -+ if (!sas_address) -+ break; -+ rc = _scsih_srch_boot_sas_address( -+ sas_address, &boot_device->SasWwid); -+ break; -+ case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT: -+ if (!enclosure_logical_id) -+ break; -+ rc = _scsih_srch_boot_encl_slot( -+ enclosure_logical_id, -+ slot, &boot_device->EnclosureSlot); -+ break; -+ case MPI2_BIOSPAGE2_FORM_DEVICE_NAME: -+ if (!device_name) -+ break; -+ rc = _scsih_srch_boot_device_name( -+ device_name, &boot_device->DeviceName); -+ break; -+ case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED: -+ break; -+ } -+ -+ return rc; -+} -+ -+/** -+ * _scsih_get_sas_address - set the sas_address for given device handle -+ * @handle: device handle -+ * @sas_address: sas address -+ * -+ * Returns 0 success, non-zero when failure -+ */ -+static int -+_scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u64 *sas_address) -+{ -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u32 ioc_status; -+ -+ *sas_address = 0; -+ -+ if (handle <= ioc->sas_hba.num_phys) { -+ *sas_address = ioc->sas_hba.sas_address; -+ return 0; -+ } -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ return -ENXIO; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { -+ *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ return 0; -+ } -+ -+ /* we hit this becuase the given parent handle doesn't exist */ -+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) -+ return -ENXIO; -+ -+ /* else error case */ -+ pr_err(MPT3SAS_FMT -+ "handle(0x%04x), ioc_status(0x%04x), failure at %s:%d/%s()!\n", -+ ioc->name, handle, ioc_status, -+ __FILE__, __LINE__, __func__); -+ return -EIO; -+} -+ -+/** -+ * _scsih_determine_boot_device - determine boot device. -+ * @ioc: per adapter object -+ * @device: either sas_device or raid_device object -+ * @is_raid: [flag] 1 = raid object, 0 = sas object -+ * -+ * Determines whether this device should be first reported device to -+ * to scsi-ml or sas transport, this purpose is for persistent boot device. -+ * There are primary, alternate, and current entries in bios page 2. The order -+ * priority is primary, alternate, then current. This routine saves -+ * the corresponding device object and is_raid flag in the ioc object. -+ * The saved data to be used later in _scsih_probe_boot_devices(). -+ */ -+static void -+_scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, -+ void *device, u8 is_raid) -+{ -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ u64 sas_address; -+ u64 device_name; -+ u64 enclosure_logical_id; -+ u16 slot; -+ -+ /* only process this function when driver loads */ -+ if (!ioc->is_driver_loading) -+ return; -+ -+ /* no Bios, return immediately */ -+ if (!ioc->bios_pg3.BiosVersion) -+ return; -+ -+ if (!is_raid) { -+ sas_device = device; -+ sas_address = sas_device->sas_address; -+ device_name = sas_device->device_name; -+ enclosure_logical_id = sas_device->enclosure_logical_id; -+ slot = sas_device->slot; -+ } else { -+ raid_device = device; -+ sas_address = raid_device->wwid; -+ device_name = 0; -+ enclosure_logical_id = 0; -+ slot = 0; -+ } -+ -+ if (!ioc->req_boot_device.device) { -+ if (_scsih_is_boot_device(sas_address, device_name, -+ enclosure_logical_id, slot, -+ (ioc->bios_pg2.ReqBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK), -+ &ioc->bios_pg2.RequestedBootDevice)) { -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: req_boot_device(0x%016llx)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_address)); -+ ioc->req_boot_device.device = device; -+ ioc->req_boot_device.is_raid = is_raid; -+ } -+ } -+ -+ if (!ioc->req_alt_boot_device.device) { -+ if (_scsih_is_boot_device(sas_address, device_name, -+ enclosure_logical_id, slot, -+ (ioc->bios_pg2.ReqAltBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK), -+ &ioc->bios_pg2.RequestedAltBootDevice)) { -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: req_alt_boot_device(0x%016llx)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_address)); -+ ioc->req_alt_boot_device.device = device; -+ ioc->req_alt_boot_device.is_raid = is_raid; -+ } -+ } -+ -+ if (!ioc->current_boot_device.device) { -+ if (_scsih_is_boot_device(sas_address, device_name, -+ enclosure_logical_id, slot, -+ (ioc->bios_pg2.CurrentBootDeviceForm & -+ MPI2_BIOSPAGE2_FORM_MASK), -+ &ioc->bios_pg2.CurrentBootDevice)) { -+ dinitprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: current_boot_device(0x%016llx)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_address)); -+ ioc->current_boot_device.device = device; -+ ioc->current_boot_device.is_raid = is_raid; -+ } -+ } -+} -+ -+static struct _sas_device * -+__mpt2sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, -+ struct MPT3SAS_TARGET *tgt_priv) -+{ -+ struct _sas_device *ret; -+ -+ assert_spin_locked(&ioc->sas_device_lock); -+ -+ ret = tgt_priv->sdev; -+ if (ret) -+ sas_device_get(ret); -+ -+ return ret; -+} -+ -+static struct _sas_device * -+mpt2sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, -+ struct MPT3SAS_TARGET *tgt_priv) -+{ -+ struct _sas_device *ret; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ ret = __mpt2sas_get_sdev_from_target(ioc, tgt_priv); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return ret; -+} -+ -+ -+struct _sas_device * -+__mpt2sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ struct _sas_device *sas_device; -+ -+ assert_spin_locked(&ioc->sas_device_lock); -+ -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) -+ if (sas_device->sas_address == sas_address) -+ goto found_device; -+ -+ list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) -+ if (sas_device->sas_address == sas_address) -+ goto found_device; -+ -+ return NULL; -+ -+found_device: -+ sas_device_get(sas_device); -+ return sas_device; -+} -+ -+/** -+ * mpt2sas_get_sdev_by_addr - sas device search -+ * @ioc: per adapter object -+ * @sas_address: sas address -+ * Context: Calling function should acquire ioc->sas_device_lock -+ * -+ * This searches for sas_device based on sas_address, then return sas_device -+ * object. -+ */ -+struct _sas_device * -+mpt2sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_address); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return sas_device; -+} -+ -+static struct _sas_device * -+__mpt2sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_device *sas_device; -+ -+ assert_spin_locked(&ioc->sas_device_lock); -+ -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) -+ if (sas_device->handle == handle) -+ goto found_device; -+ -+ list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) -+ if (sas_device->handle == handle) -+ goto found_device; -+ -+ return NULL; -+ -+found_device: -+ sas_device_get(sas_device); -+ return sas_device; -+} -+ -+/** -+ * mpt2sas_get_sdev_by_handle - sas device search -+ * @ioc: per adapter object -+ * @handle: sas device handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->sas_device_lock -+ * -+ * This searches for sas_device based on sas_address, then return sas_device -+ * object. -+ */ -+static struct _sas_device * -+mpt2sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return sas_device; -+} -+ -+/** -+ * _scsih_sas_device_remove - remove sas_device from list. -+ * @ioc: per adapter object -+ * @sas_device: the sas_device object -+ * Context: This function will acquire ioc->sas_device_lock. -+ * -+ * If sas_device is on the list, remove it and decrement its reference count. -+ */ -+static void -+_scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ unsigned long flags; -+ -+ if (!sas_device) -+ return; -+ pr_info(MPT3SAS_FMT -+ "removing handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, sas_device->handle, -+ (unsigned long long) sas_device->sas_address); -+ -+ if (sas_device->enclosure_handle != 0) -+ pr_info(MPT3SAS_FMT -+ "removing enclosure logical id(0x%016llx), slot(%d)\n", -+ ioc->name, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot); -+ -+ if (sas_device->connector_name[0] != '\0') -+ pr_info(MPT3SAS_FMT -+ "removing enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ /* -+ * The lock serializes access to the list, but we still need to verify -+ * that nobody removed the entry while we were waiting on the lock. -+ */ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ if (!list_empty(&sas_device->list)) { -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+} -+ -+/** -+ * _scsih_device_remove_by_handle - removing device object by handle -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (sas_device) { -+ _scsih_remove_device(ioc, sas_device); -+ sas_device_put(sas_device); -+ } -+} -+ -+/** -+ * mpt2sas_device_remove_by_sas_address - removing device object by sas address -+ * @ioc: per adapter object -+ * @sas_address: device sas_address -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address); -+ if (sas_device) { -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (sas_device) { -+ _scsih_remove_device(ioc, sas_device); -+ sas_device_put(sas_device); -+ } -+} -+ -+/** -+ * _scsih_sas_device_add - insert sas_device to the list. -+ * @ioc: per adapter object -+ * @sas_device: the sas_device object -+ * Context: This function will acquire ioc->sas_device_lock. -+ * -+ * Adding new object to the ioc->sas_device_list. -+ */ -+static void -+_scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ unsigned long flags; -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, __func__, sas_device->handle, -+ (unsigned long long)sas_device->sas_address)); -+ -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enclosure logical id(0x%016llx), slot( %d)\n", -+ ioc->name, __func__, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot)); -+ -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, __func__, -+ sas_device->enclosure_level, sas_device->connector_name)); -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device_get(sas_device); -+ list_add_tail(&sas_device->list, &ioc->sas_device_list); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle, -+ sas_device->sas_address_parent)) { -+ _scsih_sas_device_remove(ioc, sas_device); -+ } else if (!sas_device->starget) { -+ /* -+ * When asyn scanning is enabled, its not possible to remove -+ * devices while scanning is turned on due to an oops in -+ * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start() -+ */ -+ if (!ioc->is_driver_loading) { -+ mpt2sas_transport_port_remove(ioc, -+ sas_device->sas_address, -+ sas_device->sas_address_parent); -+ _scsih_sas_device_remove(ioc, sas_device); -+ } -+ } -+} -+ -+/** -+ * _scsih_sas_device_init_add - insert sas_device to the list. -+ * @ioc: per adapter object -+ * @sas_device: the sas_device object -+ * Context: This function will acquire ioc->sas_device_lock. -+ * -+ * Adding new object at driver load time to the ioc->sas_device_init_list. -+ */ -+static void -+_scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ unsigned long flags; -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ __func__, sas_device->handle, -+ (unsigned long long)sas_device->sas_address)); -+ -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enclosure logical id(0x%016llx), slot( %d)\n", -+ ioc->name, __func__, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot)); -+ -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, __func__, sas_device->enclosure_level, -+ sas_device->connector_name)); -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device_get(sas_device); -+ list_add_tail(&sas_device->list, &ioc->sas_device_init_list); -+ _scsih_determine_boot_device(ioc, sas_device, 0); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+} -+ -+/** -+ * _scsih_raid_device_find_by_id - raid device search -+ * @ioc: per adapter object -+ * @id: sas device target id -+ * @channel: sas device channel -+ * Context: Calling function should acquire ioc->raid_device_lock -+ * -+ * This searches for raid_device based on target id, then return raid_device -+ * object. -+ */ -+static struct _raid_device * -+_scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel) -+{ -+ struct _raid_device *raid_device, *r; -+ -+ r = NULL; -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (raid_device->id == id && raid_device->channel == channel) { -+ r = raid_device; -+ goto out; -+ } -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_raid_device_find_by_handle - raid device search -+ * @ioc: per adapter object -+ * @handle: sas device handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->raid_device_lock -+ * -+ * This searches for raid_device based on handle, then return raid_device -+ * object. -+ */ -+struct _raid_device * -+mpt2sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _raid_device *raid_device, *r; -+ -+ r = NULL; -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (raid_device->handle != handle) -+ continue; -+ r = raid_device; -+ goto out; -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * _scsih_raid_device_find_by_wwid - raid device search -+ * @ioc: per adapter object -+ * @handle: sas device handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->raid_device_lock -+ * -+ * This searches for raid_device based on wwid, then return raid_device -+ * object. -+ */ -+static struct _raid_device * -+_scsih_raid_device_find_by_wwid(struct MPT3SAS_ADAPTER *ioc, u64 wwid) -+{ -+ struct _raid_device *raid_device, *r; -+ -+ r = NULL; -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (raid_device->wwid != wwid) -+ continue; -+ r = raid_device; -+ goto out; -+ } -+ -+ out: -+ return r; -+} -+ -+/** -+ * _scsih_raid_device_add - add raid_device object -+ * @ioc: per adapter object -+ * @raid_device: raid_device object -+ * -+ * This is added to the raid_device_list link list. -+ */ -+static void -+_scsih_raid_device_add(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device) -+{ -+ unsigned long flags; -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, -+ raid_device->handle, (unsigned long long)raid_device->wwid)); -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ list_add_tail(&raid_device->list, &ioc->raid_device_list); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+} -+ -+/** -+ * _scsih_raid_device_remove - delete raid_device object -+ * @ioc: per adapter object -+ * @raid_device: raid_device object -+ * -+ */ -+static void -+_scsih_raid_device_remove(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ list_del(&raid_device->list); -+ kfree(raid_device); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+} -+ -+/** -+ * mpt2sas_scsih_expander_find_by_handle - expander device search -+ * @ioc: per adapter object -+ * @handle: expander handle (assigned by firmware) -+ * Context: Calling function should acquire ioc->sas_device_lock -+ * -+ * This searches for expander device based on handle, then returns the -+ * sas_node object. -+ */ -+struct _sas_node * -+mpt2sas_scsih_expander_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_node *sas_expander, *r; -+ -+ r = NULL; -+ list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { -+ if (sas_expander->handle != handle) -+ continue; -+ r = sas_expander; -+ goto out; -+ } -+ out: -+ return r; -+} -+ -+/** -+ * mpt2sas_scsih_expander_find_by_sas_address - expander device search -+ * @ioc: per adapter object -+ * @sas_address: sas address -+ * Context: Calling function should acquire ioc->sas_node_lock. -+ * -+ * This searches for expander device based on sas_address, then returns the -+ * sas_node object. -+ */ -+struct _sas_node * -+mpt2sas_scsih_expander_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ struct _sas_node *sas_expander, *r; -+ -+ r = NULL; -+ list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { -+ if (sas_expander->sas_address != sas_address) -+ continue; -+ r = sas_expander; -+ goto out; -+ } -+ out: -+ return r; -+} -+ -+/** -+ * _scsih_expander_node_add - insert expander device to the list. -+ * @ioc: per adapter object -+ * @sas_expander: the sas_device object -+ * Context: This function will acquire ioc->sas_node_lock. -+ * -+ * Adding new object to the ioc->sas_expander_list. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_expander_node_add(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ list_add_tail(&sas_expander->list, &ioc->sas_expander_list); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+} -+ -+/** -+ * _scsih_is_end_device - determines if device is an end device -+ * @device_info: bitfield providing information about the device. -+ * Context: none -+ * -+ * Returns 1 if end device. -+ */ -+static int -+_scsih_is_end_device(u32 device_info) -+{ -+ if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE && -+ ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) | -+ (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) | -+ (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE))) -+ return 1; -+ else -+ return 0; -+} -+ -+/** -+ * _scsih_scsi_lookup_get - returns scmd entry -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns the smid stored scmd pointer. -+ */ -+static struct scsi_cmnd * -+_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return ioc->scsi_lookup[smid - 1].scmd; -+} -+ -+/** -+ * _scsih_scsi_lookup_get_clear - returns scmd entry -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns the smid stored scmd pointer. -+ * Then will derefrence the stored scmd pointer. -+ */ -+static inline struct scsi_cmnd * -+_scsih_scsi_lookup_get_clear(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ unsigned long flags; -+ struct scsi_cmnd *scmd; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ scmd = ioc->scsi_lookup[smid - 1].scmd; -+ ioc->scsi_lookup[smid - 1].scmd = NULL; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ return scmd; -+} -+ -+/** -+ * _scsih_scsi_lookup_find_by_scmd - scmd lookup -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @scmd: pointer to scsi command object -+ * Context: This function will acquire ioc->scsi_lookup_lock. -+ * -+ * This will search for a scmd pointer in the scsi_lookup array, -+ * returning the revelent smid. A returned value of zero means invalid. -+ */ -+static u16 -+_scsih_scsi_lookup_find_by_scmd(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd -+ *scmd) -+{ -+ u16 smid; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ smid = 0; -+ for (i = 0; i < ioc->scsiio_depth; i++) { -+ if (ioc->scsi_lookup[i].scmd == scmd) { -+ smid = ioc->scsi_lookup[i].smid; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return smid; -+} -+ -+/** -+ * _scsih_scsi_lookup_find_by_target - search for matching channel:id -+ * @ioc: per adapter object -+ * @id: target id -+ * @channel: channel -+ * Context: This function will acquire ioc->scsi_lookup_lock. -+ * -+ * This will search for a matching channel:id in the scsi_lookup array, -+ * returning 1 if found. -+ */ -+static u8 -+_scsih_scsi_lookup_find_by_target(struct MPT3SAS_ADAPTER *ioc, int id, -+ int channel) -+{ -+ u8 found; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ found = 0; -+ for (i = 0 ; i < ioc->scsiio_depth; i++) { -+ if (ioc->scsi_lookup[i].scmd && -+ (ioc->scsi_lookup[i].scmd->device->id == id && -+ ioc->scsi_lookup[i].scmd->device->channel == channel)) { -+ found = 1; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return found; -+} -+ -+/** -+ * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun -+ * @ioc: per adapter object -+ * @id: target id -+ * @lun: lun number -+ * @channel: channel -+ * Context: This function will acquire ioc->scsi_lookup_lock. -+ * -+ * This will search for a matching channel:id:lun in the scsi_lookup array, -+ * returning 1 if found. -+ */ -+static u8 -+_scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id, -+ unsigned int lun, int channel) -+{ -+ u8 found; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ found = 0; -+ for (i = 0 ; i < ioc->scsiio_depth; i++) { -+ if (ioc->scsi_lookup[i].scmd && -+ (ioc->scsi_lookup[i].scmd->device->id == id && -+ ioc->scsi_lookup[i].scmd->device->channel == channel && -+ ioc->scsi_lookup[i].scmd->device->lun == lun)) { -+ found = 1; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ return found; -+} -+ -+static void -+_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) -+{ -+ struct Scsi_Host *shost = sdev->host; -+ int max_depth; -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ max_depth = shost->can_queue; -+ -+ /* limit max device queue for SATA to 32 */ -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ goto not_sata; -+ sas_target_priv_data = sas_device_priv_data->sas_target; -+ if (!sas_target_priv_data) -+ goto not_sata; -+ if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) -+ goto not_sata; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); -+ if (sas_device) { -+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -+ max_depth = MPT3SAS_SATA_QUEUE_DEPTH; -+ -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ not_sata: -+ -+ if (!sdev->tagged_supported) -+ max_depth = 1; -+ if (qdepth > max_depth) -+ qdepth = max_depth; -+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); -+} -+ -+/** -+ * scsih_change_queue_depth_mpt2sas - setting device queue depth -+ * @sdev: scsi device struct -+ * @qdepth: requested queue depth -+ * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP -+ * (see include/scsi/scsi_host.h for definition) -+ * -+ * Returns queue depth. -+ */ -+int -+scsih_change_queue_depth_mpt2sas(struct scsi_device *sdev, int qdepth, int reason) -+{ -+ if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) -+ _scsih_adjust_queue_depth(sdev, qdepth); -+ else if (reason == SCSI_QDEPTH_QFULL) -+ scsi_track_queue_full(sdev, qdepth); -+ else -+ return -EOPNOTSUPP; -+ -+ if (sdev->inquiry_len > 7) -+ sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), " \ -+ "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n", -+ sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags, -+ sdev->ordered_tags, sdev->scsi_level, -+ (sdev->inquiry[7] & 2) >> 1); -+ -+ return sdev->queue_depth; -+} -+ -+/** -+ * _scsih_change_queue_type_mpt2sas - changing device queue tag type -+ * @sdev: scsi device struct -+ * @tag_type: requested tag type -+ * -+ * Returns queue tag type. -+ */ -+int -+_scsih_change_queue_type_mpt2sas(struct scsi_device *sdev, int tag_type) -+{ -+ if (sdev->tagged_supported) { -+ scsi_set_tag_type(sdev, tag_type); -+ if (tag_type) -+ scsi_activate_tcq(sdev, sdev->queue_depth); -+ else -+ scsi_deactivate_tcq(sdev, sdev->queue_depth); -+ } else -+ tag_type = 0; -+ -+ return tag_type; -+} -+ -+ -+/** -+ * scsih_target_alloc_mpt2sas - target add routine -+ * @starget: scsi target struct -+ * -+ * Returns 0 if ok. Any other return is assumed to be an error and -+ * the device is ignored. -+ */ -+int -+scsih_target_alloc_mpt2sas(struct scsi_target *starget) -+{ -+ struct Scsi_Host *shost = dev_to_shost(&starget->dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ struct sas_rphy *rphy; -+ -+ sas_target_priv_data = kzalloc(sizeof(*sas_target_priv_data), -+ GFP_KERNEL); -+ if (!sas_target_priv_data) -+ return -ENOMEM; -+ -+ starget->hostdata = sas_target_priv_data; -+ sas_target_priv_data->starget = starget; -+ sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; -+ -+ /* RAID volumes */ -+ if (starget->channel == RAID_CHANNEL) { -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, -+ starget->channel); -+ if (raid_device) { -+ sas_target_priv_data->handle = raid_device->handle; -+ sas_target_priv_data->sas_address = raid_device->wwid; -+ sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; -+ sas_target_priv_data->raid_device = raid_device; -+ if (ioc->is_warpdrive) -+ raid_device->starget = starget; -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ return 0; -+ } -+ -+ /* sas/sata devices */ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ rphy = dev_to_rphy(starget->dev.parent); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ rphy->identify.sas_address); -+ -+ if (sas_device) { -+ sas_target_priv_data->handle = sas_device->handle; -+ sas_target_priv_data->sas_address = sas_device->sas_address; -+ sas_target_priv_data->sdev = sas_device; -+ sas_device->starget = starget; -+ sas_device->id = starget->id; -+ sas_device->channel = starget->channel; -+ if (test_bit(sas_device->handle, ioc->pd_handles)) -+ sas_target_priv_data->flags |= -+ MPT_TARGET_FLAGS_RAID_COMPONENT; -+ if (sas_device->fast_path) -+ sas_target_priv_data->flags |= MPT_TARGET_FASTPATH_IO; -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return 0; -+} -+ -+/** -+ * scsih_target_destroy_mpt2sas - target destroy routine -+ * @starget: scsi target struct -+ * -+ * Returns nothing. -+ */ -+void -+scsih_target_destroy_mpt2sas(struct scsi_target *starget) -+{ -+ struct Scsi_Host *shost = dev_to_shost(&starget->dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ struct sas_rphy *rphy; -+ -+ sas_target_priv_data = starget->hostdata; -+ if (!sas_target_priv_data) -+ return; -+ -+ if (starget->channel == RAID_CHANNEL) { -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, -+ starget->channel); -+ if (raid_device) { -+ raid_device->starget = NULL; -+ raid_device->sdev = NULL; -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ goto out; -+ } -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ rphy = dev_to_rphy(starget->dev.parent); -+ sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); -+ if (sas_device && (sas_device->starget == starget) && -+ (sas_device->id == starget->id) && -+ (sas_device->channel == starget->channel)) -+ sas_device->starget = NULL; -+ -+ if (sas_device) { -+ /* -+ * Corresponding get() is in _scsih_target_alloc_mpt2sas() -+ */ -+ sas_target_priv_data->sdev = NULL; -+ sas_device_put(sas_device); -+ -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ out: -+ kfree(sas_target_priv_data); -+ starget->hostdata = NULL; -+} -+ -+/** -+ * scsih_slave_alloc_mpt2sas - device add routine -+ * @sdev: scsi device struct -+ * -+ * Returns 0 if ok. Any other return is assumed to be an error and -+ * the device is ignored. -+ */ -+int -+scsih_slave_alloc_mpt2sas(struct scsi_device *sdev) -+{ -+ struct Scsi_Host *shost; -+ struct MPT3SAS_ADAPTER *ioc; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_target *starget; -+ struct _raid_device *raid_device; -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ sas_device_priv_data = kzalloc(sizeof(*sas_device_priv_data), -+ GFP_KERNEL); -+ if (!sas_device_priv_data) -+ return -ENOMEM; -+ -+ sas_device_priv_data->lun = sdev->lun; -+ sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT; -+ -+ starget = scsi_target(sdev); -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->num_luns++; -+ sas_device_priv_data->sas_target = sas_target_priv_data; -+ sdev->hostdata = sas_device_priv_data; -+ if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT)) -+ sdev->no_uld_attach = 1; -+ -+ shost = dev_to_shost(&starget->dev); -+ ioc = shost_priv(shost); -+ if (starget->channel == RAID_CHANNEL) { -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, -+ starget->id, starget->channel); -+ if (raid_device) -+ raid_device->sdev = sdev; /* raid is single lun */ -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ } -+ -+ if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_target_priv_data->sas_address); -+ if (sas_device && (sas_device->starget == NULL)) { -+ sdev_printk(KERN_INFO, sdev, -+ "%s : sas_device->starget set to starget @ %d\n", -+ __func__, __LINE__); -+ sas_device->starget = starget; -+ } -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ } -+ -+ return 0; -+} -+ -+/** -+ * scsih_slave_destroy_mpt2sas - device destroy routine -+ * @sdev: scsi device struct -+ * -+ * Returns nothing. -+ */ -+void -+scsih_slave_destroy_mpt2sas(struct scsi_device *sdev) -+{ -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct scsi_target *starget; -+ struct Scsi_Host *shost; -+ struct MPT3SAS_ADAPTER *ioc; -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ if (!sdev->hostdata) -+ return; -+ -+ starget = scsi_target(sdev); -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->num_luns--; -+ -+ shost = dev_to_shost(&starget->dev); -+ ioc = shost_priv(shost); -+ -+ if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_from_target(ioc, -+ sas_target_priv_data); -+ if (sas_device && !sas_target_priv_data->num_luns) -+ sas_device->starget = NULL; -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ } -+ -+ kfree(sdev->hostdata); -+ sdev->hostdata = NULL; -+} -+ -+/** -+ * _scsih_display_sata_capabilities - sata capabilities -+ * @ioc: per adapter object -+ * @handle: device handle -+ * @sdev: scsi device struct -+ */ -+static void -+_scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc, -+ u16 handle, struct scsi_device *sdev) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ u32 ioc_status; -+ u16 flags; -+ u32 device_info; -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ flags = le16_to_cpu(sas_device_pg0.Flags); -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ -+ sdev_printk(KERN_INFO, sdev, -+ "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " -+ "sw_preserve(%s)\n", -+ (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" : -+ "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n", -+ (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n"); -+} -+ -+/* -+ * raid transport support - -+ * Enabled for SLES11 and newer, in older kernels the driver will panic when -+ * unloading the driver followed by a load - I beleive that the subroutine -+ * raid_class_release() is not cleaning up properly. -+ */ -+ -+/** -+ * scsih_is_raid_mpt2sas - return boolean indicating device is raid volume -+ * @dev the device struct object -+ */ -+int -+scsih_is_raid_mpt2sas(struct device *dev) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); -+ -+ if (ioc->is_warpdrive) -+ return 0; -+ return (sdev->channel == RAID_CHANNEL) ? 1 : 0; -+} -+ -+/** -+ * scsih_get_resync_mpt2sas - get raid volume resync percent complete -+ * @dev the device struct object -+ */ -+void -+scsih_get_resync_mpt2sas(struct device *dev) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); -+ static struct _raid_device *raid_device; -+ unsigned long flags; -+ Mpi2RaidVolPage0_t vol_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u32 volume_status_flags; -+ u8 percent_complete; -+ u16 handle; -+ -+ percent_complete = 0; -+ handle = 0; -+ if (ioc->is_warpdrive) -+ goto out; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, -+ sdev->channel); -+ if (raid_device) { -+ handle = raid_device->handle; -+ percent_complete = raid_device->percent_complete; -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ -+ if (!handle) -+ goto out; -+ -+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, -+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, -+ sizeof(Mpi2RaidVolPage0_t))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ percent_complete = 0; -+ goto out; -+ } -+ -+ volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); -+ if (!(volume_status_flags & -+ MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)) -+ percent_complete = 0; -+ -+ out: -+ -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ raid_set_resync(mpt2sas_raid_template_mpt2sas, dev, percent_complete); -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ raid_set_resync(mpt3sas_raid_template_mpt2sas, dev, percent_complete); -+ break; -+ } -+} -+ -+/** -+ * scsih_get_state_mpt2sas - get raid volume level -+ * @dev the device struct object -+ */ -+void -+scsih_get_state_mpt2sas(struct device *dev) -+{ -+ struct scsi_device *sdev = to_scsi_device(dev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); -+ static struct _raid_device *raid_device; -+ unsigned long flags; -+ Mpi2RaidVolPage0_t vol_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u32 volstate; -+ enum raid_state state = RAID_STATE_UNKNOWN; -+ u16 handle = 0; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, -+ sdev->channel); -+ if (raid_device) -+ handle = raid_device->handle; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ -+ if (!raid_device) -+ goto out; -+ -+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, -+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, -+ sizeof(Mpi2RaidVolPage0_t))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags); -+ if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { -+ state = RAID_STATE_RESYNCING; -+ goto out; -+ } -+ -+ switch (vol_pg0.VolumeState) { -+ case MPI2_RAID_VOL_STATE_OPTIMAL: -+ case MPI2_RAID_VOL_STATE_ONLINE: -+ state = RAID_STATE_ACTIVE; -+ break; -+ case MPI2_RAID_VOL_STATE_DEGRADED: -+ state = RAID_STATE_DEGRADED; -+ break; -+ case MPI2_RAID_VOL_STATE_FAILED: -+ case MPI2_RAID_VOL_STATE_MISSING: -+ state = RAID_STATE_OFFLINE; -+ break; -+ } -+ out: -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ raid_set_state(mpt2sas_raid_template_mpt2sas, dev, state); -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ raid_set_state(mpt3sas_raid_template_mpt2sas, dev, state); -+ break; -+ } -+} -+ -+/** -+ * _scsih_set_level - set raid level -+ * @sdev: scsi device struct -+ * @volume_type: volume type -+ */ -+static void -+_scsih_set_level(struct MPT3SAS_ADAPTER *ioc, -+ struct scsi_device *sdev, u8 volume_type) -+{ -+ enum raid_level level = RAID_LEVEL_UNKNOWN; -+ -+ switch (volume_type) { -+ case MPI2_RAID_VOL_TYPE_RAID0: -+ level = RAID_LEVEL_0; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID10: -+ level = RAID_LEVEL_10; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID1E: -+ level = RAID_LEVEL_1E; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID1: -+ level = RAID_LEVEL_1; -+ break; -+ } -+ -+ switch (ioc->hba_mpi_version_belonged) { -+ case MPI2_VERSION: -+ raid_set_level(mpt2sas_raid_template_mpt2sas, -+ &sdev->sdev_gendev, level); -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ raid_set_level(mpt3sas_raid_template_mpt2sas, -+ &sdev->sdev_gendev, level); -+ break; -+ } -+} -+ -+ -+/** -+ * _scsih_get_volume_capabilities - volume capabilities -+ * @ioc: per adapter object -+ * @sas_device: the raid_device object -+ * -+ * Returns 0 for success, else 1 -+ */ -+static int -+_scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device) -+{ -+ Mpi2RaidVolPage0_t *vol_pg0; -+ Mpi2RaidPhysDiskPage0_t pd_pg0; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 sz; -+ u8 num_pds; -+ -+ if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, -+ &num_pds)) || !num_pds) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, -+ __func__)); -+ return 1; -+ } -+ -+ raid_device->num_pds = num_pds; -+ sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * -+ sizeof(Mpi2RaidVol0PhysDisk_t)); -+ vol_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!vol_pg0) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, -+ __func__)); -+ return 1; -+ } -+ -+ if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, -+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, -+ __func__)); -+ kfree(vol_pg0); -+ return 1; -+ } -+ -+ raid_device->volume_type = vol_pg0->VolumeType; -+ -+ /* figure out what the underlying devices are by -+ * obtaining the device_info bits for the 1st device -+ */ -+ if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, -+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, -+ vol_pg0->PhysDisk[0].PhysDiskNum))) { -+ if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, -+ le16_to_cpu(pd_pg0.DevHandle)))) { -+ raid_device->device_info = -+ le32_to_cpu(sas_device_pg0.DeviceInfo); -+ } -+ } -+ -+ kfree(vol_pg0); -+ return 0; -+} -+ -+/** -+ * _scsih_enable_tlr - setting TLR flags -+ * @ioc: per adapter object -+ * @sdev: scsi device struct -+ * -+ * Enabling Transaction Layer Retries for tape devices when -+ * vpd page 0x90 is present -+ * -+ */ -+static void -+_scsih_enable_tlr(struct MPT3SAS_ADAPTER *ioc, struct scsi_device *sdev) -+{ -+ -+ /* only for TAPE */ -+ if (sdev->type != TYPE_TAPE) -+ return; -+ -+ if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)) -+ return; -+ -+ sas_enable_tlr(sdev); -+ sdev_printk(KERN_INFO, sdev, "TLR %s\n", -+ sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled"); -+ return; -+ -+} -+ -+/** -+ * scsih_slave_configure_mpt2sas - device configure routine. -+ * @sdev: scsi device struct -+ * -+ * Returns 0 if ok. Any other return is assumed to be an error and -+ * the device is ignored. -+ */ -+int -+scsih_slave_configure_mpt2sas(struct scsi_device *sdev) -+{ -+ struct Scsi_Host *shost = sdev->host; -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ int qdepth; -+ u8 ssp_target = 0; -+ char *ds = ""; -+ char *r_level = ""; -+ u16 handle, volume_handle = 0; -+ u64 volume_wwid = 0; -+ -+ qdepth = 1; -+ sas_device_priv_data = sdev->hostdata; -+ sas_device_priv_data->configured_lun = 1; -+ sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT; -+ sas_target_priv_data = sas_device_priv_data->sas_target; -+ handle = sas_target_priv_data->handle; -+ -+ /* raid volume handling */ -+ if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) { -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ if (!raid_device) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, -+ __LINE__, __func__)); -+ return 1; -+ } -+ -+ if (_scsih_get_volume_capabilities(ioc, raid_device)) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, -+ __LINE__, __func__)); -+ return 1; -+ } -+ -+ /* -+ * WARPDRIVE: Initialize the required data for Direct IO -+ */ -+ mpt2sas_init_warpdrive_properties(ioc, raid_device); -+ -+ /* RAID Queue Depth Support -+ * IS volume = underlying qdepth of drive type, either -+ * MPT3SAS_SAS_QUEUE_DEPTH or MPT3SAS_SATA_QUEUE_DEPTH -+ * IM/IME/R10 = 128 (MPT3SAS_RAID_QUEUE_DEPTH) -+ */ -+ if (raid_device->device_info & -+ MPI2_SAS_DEVICE_INFO_SSP_TARGET) { -+ qdepth = MPT3SAS_SAS_QUEUE_DEPTH; -+ ds = "SSP"; -+ } else { -+ qdepth = MPT3SAS_SATA_QUEUE_DEPTH; -+ if (raid_device->device_info & -+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -+ ds = "SATA"; -+ else -+ ds = "STP"; -+ } -+ -+ switch (raid_device->volume_type) { -+ case MPI2_RAID_VOL_TYPE_RAID0: -+ r_level = "RAID0"; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID1E: -+ qdepth = MPT3SAS_RAID_QUEUE_DEPTH; -+ if (ioc->manu_pg10.OEMIdentifier && -+ (le32_to_cpu(ioc->manu_pg10.GenericFlags0) & -+ MFG10_GF0_R10_DISPLAY) && -+ !(raid_device->num_pds % 2)) -+ r_level = "RAID10"; -+ else -+ r_level = "RAID1E"; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID1: -+ qdepth = MPT3SAS_RAID_QUEUE_DEPTH; -+ r_level = "RAID1"; -+ break; -+ case MPI2_RAID_VOL_TYPE_RAID10: -+ qdepth = MPT3SAS_RAID_QUEUE_DEPTH; -+ r_level = "RAID10"; -+ break; -+ case MPI2_RAID_VOL_TYPE_UNKNOWN: -+ default: -+ qdepth = MPT3SAS_RAID_QUEUE_DEPTH; -+ r_level = "RAIDX"; -+ break; -+ } -+ -+ if (!ioc->hide_ir_msg) -+ sdev_printk(KERN_INFO, sdev, -+ "%s: handle(0x%04x), wwid(0x%016llx)," -+ " pd_count(%d), type(%s)\n", -+ r_level, raid_device->handle, -+ (unsigned long long)raid_device->wwid, -+ raid_device->num_pds, ds); -+ -+ if (shost->max_sectors > MPT3SAS_RAID_MAX_SECTORS) { -+ blk_queue_max_hw_sectors(sdev->request_queue, -+ MPT3SAS_RAID_MAX_SECTORS); -+ sdev_printk(KERN_INFO, sdev, -+ "Set queue's max_sector to: %u\n", -+ MPT3SAS_RAID_MAX_SECTORS); -+ } -+ -+ scsih_change_queue_depth_mpt2sas(sdev, qdepth, SCSI_QDEPTH_DEFAULT); -+ -+ /* raid transport support */ -+ if (!ioc->is_warpdrive) -+ _scsih_set_level(ioc, sdev, raid_device->volume_type); -+ return 0; -+ } -+ -+ /* non-raid handling */ -+ if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { -+ if (mpt2sas_config_get_volume_handle(ioc, handle, -+ &volume_handle)) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__)); -+ return 1; -+ } -+ if (volume_handle && mpt2sas_config_get_volume_wwid(ioc, -+ volume_handle, &volume_wwid)) { -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__)); -+ return 1; -+ } -+ } -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_device_priv_data->sas_target->sas_address); -+ if (!sas_device) { -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ dfailprintk(ioc, pr_warn(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, -+ __func__)); -+ return 1; -+ } -+ -+ sas_device->volume_handle = volume_handle; -+ sas_device->volume_wwid = volume_wwid; -+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { -+ qdepth = MPT3SAS_SAS_QUEUE_DEPTH; -+ ssp_target = 1; -+ if (sas_device->device_info & -+ MPI2_SAS_DEVICE_INFO_SEP) { -+ sdev_printk(KERN_WARNING, sdev, -+ "set ignore_delay_remove for handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle); -+ sas_device_priv_data->ignore_delay_remove = 1; -+ ds = "SES"; -+ } else -+ ds = "SSP"; -+ } else { -+ qdepth = MPT3SAS_SATA_QUEUE_DEPTH; -+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) -+ ds = "STP"; -+ else if (sas_device->device_info & -+ MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -+ ds = "SATA"; -+ } -+ -+ sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " \ -+ "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", -+ ds, handle, (unsigned long long)sas_device->sas_address, -+ sas_device->phy, (unsigned long long)sas_device->device_name); -+ if (sas_device->enclosure_handle != 0) -+ sdev_printk(KERN_INFO, sdev, -+ "%s: enclosure_logical_id(0x%016llx), slot(%d)\n", -+ ds, (unsigned long long) -+ sas_device->enclosure_logical_id, sas_device->slot); -+ if (sas_device->connector_name[0] != '\0') -+ sdev_printk(KERN_INFO, sdev, -+ "%s: enclosure level(0x%04x), connector name( %s)\n", -+ ds, sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ sas_device_put(sas_device); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (!ssp_target) -+ _scsih_display_sata_capabilities(ioc, handle, sdev); -+ -+ -+ scsih_change_queue_depth_mpt2sas(sdev, qdepth, SCSI_QDEPTH_DEFAULT); -+ -+ if (ssp_target) { -+ sas_read_port_mode_page(sdev); -+ _scsih_enable_tlr(ioc, sdev); -+ } -+ -+ return 0; -+} -+ -+/** -+ * scsih_bios_param_mpt2sas - fetch head, sector, cylinder info for a disk -+ * @sdev: scsi device struct -+ * @bdev: pointer to block device context -+ * @capacity: device size (in 512 byte sectors) -+ * @params: three element array to place output: -+ * params[0] number of heads (max 255) -+ * params[1] number of sectors (max 63) -+ * params[2] number of cylinders -+ * -+ * Return nothing. -+ */ -+int -+scsih_bios_param_mpt2sas(struct scsi_device *sdev, struct block_device *bdev, -+ sector_t capacity, int params[]) -+{ -+ int heads; -+ int sectors; -+ sector_t cylinders; -+ ulong dummy; -+ -+ heads = 64; -+ sectors = 32; -+ -+ dummy = heads * sectors; -+ cylinders = capacity; -+ sector_div(cylinders, dummy); -+ -+ /* -+ * Handle extended translation size for logical drives -+ * > 1Gb -+ */ -+ if ((ulong)capacity >= 0x200000) { -+ heads = 255; -+ sectors = 63; -+ dummy = heads * sectors; -+ cylinders = capacity; -+ sector_div(cylinders, dummy); -+ } -+ -+ /* return result */ -+ params[0] = heads; -+ params[1] = sectors; -+ params[2] = cylinders; -+ -+ return 0; -+} -+ -+/** -+ * _scsih_response_code - translation of device response code -+ * @ioc: per adapter object -+ * @response_code: response code returned by the device -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_response_code(struct MPT3SAS_ADAPTER *ioc, u8 response_code) -+{ -+ char *desc; -+ -+ switch (response_code) { -+ case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: -+ desc = "task management request completed"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: -+ desc = "invalid frame"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: -+ desc = "task management request not supported"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_TM_FAILED: -+ desc = "task management request failed"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: -+ desc = "task management request succeeded"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: -+ desc = "invalid lun"; -+ break; -+ case 0xA: -+ desc = "overlapped tag attempted"; -+ break; -+ case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: -+ desc = "task queued, however not sent to target"; -+ break; -+ default: -+ desc = "unknown"; -+ break; -+ } -+ pr_warn(MPT3SAS_FMT "response_code(0x%01x): %s\n", -+ ioc->name, response_code, desc); -+} -+ -+/** -+ * _scsih_tm_done - tm completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: none. -+ * -+ * The callback handler when using scsih_issue_tm. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_tm_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ if (ioc->tm_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->tm_cmds.smid != smid) -+ return 1; -+ ioc->tm_cmds.status |= MPT3_CMD_COMPLETE; -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (mpi_reply) { -+ memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); -+ ioc->tm_cmds.status |= MPT3_CMD_REPLY_VALID; -+ } -+ ioc->tm_cmds.status &= ~MPT3_CMD_PENDING; -+ complete(&ioc->tm_cmds.done); -+ return 1; -+} -+ -+/** -+ * mpt2sas_scsih_set_tm_flag - set per target tm_busy -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * During taskmangement request, we need to freeze the device queue. -+ */ -+void -+mpt2sas_scsih_set_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ u8 skip = 0; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ if (skip) -+ continue; -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->sas_target->handle == handle) { -+ sas_device_priv_data->sas_target->tm_busy = 1; -+ skip = 1; -+ ioc->ignore_loginfos = 1; -+ } -+ } -+} -+ -+/** -+ * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * During taskmangement request, we need to freeze the device queue. -+ */ -+void -+mpt2sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ u8 skip = 0; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ if (skip) -+ continue; -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->sas_target->handle == handle) { -+ sas_device_priv_data->sas_target->tm_busy = 0; -+ skip = 1; -+ ioc->ignore_loginfos = 0; -+ } -+ } -+} -+ -+/** -+ * mpt2sas_scsih_issue_tm - main routine for sending tm requests -+ * @ioc: per adapter struct -+ * @device_handle: device handle -+ * @channel: the channel assigned by the OS -+ * @id: the id assigned by the OS -+ * @lun: lun number -+ * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) -+ * @smid_task: smid assigned to the task -+ * @timeout: timeout in seconds -+ * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF -+ * Context: user -+ * -+ * A generic API for sending task management requests to firmware. -+ * -+ * The callback index is set inside `ioc->tm_cb_idx`. -+ * -+ * Return SUCCESS or FAILED. -+ */ -+int -+mpt2sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, uint channel, -+ uint id, uint lun, u8 type, u16 smid_task, ulong timeout, -+ enum mutex_type m_type) -+{ -+ Mpi2SCSITaskManagementRequest_t *mpi_request; -+ Mpi2SCSITaskManagementReply_t *mpi_reply; -+ u16 smid = 0; -+ u32 ioc_state; -+ unsigned long timeleft; -+ struct scsiio_tracker *scsi_lookup = NULL; -+ int rc; -+ u16 msix_task = 0; -+ -+ if (m_type == TM_MUTEX_ON) -+ mutex_lock(&ioc->tm_cmds.mutex); -+ if (ioc->tm_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_info(MPT3SAS_FMT "%s: tm_cmd busy!!!\n", -+ __func__, ioc->name); -+ rc = FAILED; -+ goto err_out; -+ } -+ -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ rc = FAILED; -+ goto err_out; -+ } -+ -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 0); -+ if (ioc_state & MPI2_DOORBELL_USED) { -+ dhsprintk(ioc, pr_info(MPT3SAS_FMT -+ "unexpected doorbell active!\n", ioc->name)); -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ rc = (!rc) ? SUCCESS : FAILED; -+ goto err_out; -+ } -+ -+ if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { -+ mpt2sas_base_fault_info(ioc, ioc_state & -+ MPI2_DOORBELL_DATA_MASK); -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ rc = (!rc) ? SUCCESS : FAILED; -+ goto err_out; -+ } -+ -+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = FAILED; -+ goto err_out; -+ } -+ -+ if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) -+ scsi_lookup = &ioc->scsi_lookup[smid_task - 1]; -+ -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "sending tm: handle(0x%04x), task_type(0x%02x), smid(%d)\n", -+ ioc->name, handle, type, smid_task)); -+ ioc->tm_cmds.status = MPT3_CMD_PENDING; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->tm_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); -+ memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t)); -+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; -+ mpi_request->DevHandle = cpu_to_le16(handle); -+ mpi_request->TaskType = type; -+ mpi_request->TaskMID = cpu_to_le16(smid_task); -+ int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); -+ mpt2sas_scsih_set_tm_flag(ioc, handle); -+ init_completion(&ioc->tm_cmds.done); -+ if ((type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) && -+ (scsi_lookup->msix_io < ioc->reply_queue_count)) -+ msix_task = scsi_lookup->msix_io; -+ else -+ msix_task = 0; -+ mpt2sas_base_put_smid_hi_priority(ioc, smid, msix_task); -+ timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); -+ if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SCSITaskManagementRequest_t)/4); -+ if (!(ioc->tm_cmds.status & MPT3_CMD_RESET)) { -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ rc = (!rc) ? SUCCESS : FAILED; -+ ioc->tm_cmds.status = MPT3_CMD_NOT_USED; -+ mpt2sas_scsih_clear_tm_flag(ioc, handle); -+ goto err_out; -+ } -+ } -+ -+ /* sync IRQs in case those were busy during flush. */ -+ mpt2sas_base_sync_reply_irqs(ioc); -+ -+ if (ioc->tm_cmds.status & MPT3_CMD_REPLY_VALID) { -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); -+ mpi_reply = ioc->tm_cmds.reply; -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "complete tm: " \ -+ "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo), -+ le32_to_cpu(mpi_reply->TerminationCount))); -+ if (ioc->logging_level & MPT_DEBUG_TM) { -+ _scsih_response_code(ioc, mpi_reply->ResponseCode); -+ if (mpi_reply->IOCStatus) -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SCSITaskManagementRequest_t)/4); -+ } -+ } -+ -+ switch (type) { -+ case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: -+ rc = SUCCESS; -+ if (scsi_lookup->scmd == NULL) -+ break; -+ rc = FAILED; -+ break; -+ -+ case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: -+ if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) -+ rc = FAILED; -+ else -+ rc = SUCCESS; -+ break; -+ case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: -+ case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: -+ if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) -+ rc = FAILED; -+ else -+ rc = SUCCESS; -+ break; -+ case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: -+ rc = SUCCESS; -+ break; -+ default: -+ rc = FAILED; -+ break; -+ } -+ -+ mpt2sas_scsih_clear_tm_flag(ioc, handle); -+ ioc->tm_cmds.status = MPT3_CMD_NOT_USED; -+ if (m_type == TM_MUTEX_ON) -+ mutex_unlock(&ioc->tm_cmds.mutex); -+ -+ return rc; -+ -+ err_out: -+ if (m_type == TM_MUTEX_ON) -+ mutex_unlock(&ioc->tm_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * _scsih_tm_display_info - displays info about the device -+ * @ioc: per adapter struct -+ * @scmd: pointer to scsi command object -+ * -+ * Called by task management callback handlers. -+ */ -+static void -+_scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) -+{ -+ struct scsi_target *starget = scmd->device->sdev_target; -+ struct MPT3SAS_TARGET *priv_target = starget->hostdata; -+ struct _sas_device *sas_device = NULL; -+ unsigned long flags; -+ char *device_str = NULL; -+ -+ if (!priv_target) -+ return; -+ if (ioc->hide_ir_msg) -+ device_str = "WarpDrive"; -+ else -+ device_str = "volume"; -+ -+ scsi_print_command(scmd); -+ if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { -+ starget_printk(KERN_INFO, starget, -+ "%s handle(0x%04x), %s wwid(0x%016llx)\n", -+ device_str, priv_target->handle, -+ device_str, (unsigned long long)priv_target->sas_address); -+ } else { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_from_target(ioc, priv_target); -+ if (sas_device) { -+ if (priv_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) { -+ starget_printk(KERN_INFO, starget, -+ "volume handle(0x%04x), " -+ "volume wwid(0x%016llx)\n", -+ sas_device->volume_handle, -+ (unsigned long long)sas_device->volume_wwid); -+ } -+ starget_printk(KERN_INFO, starget, -+ "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n", -+ sas_device->handle, -+ (unsigned long long)sas_device->sas_address, -+ sas_device->phy); -+ if (sas_device->enclosure_handle != 0) -+ starget_printk(KERN_INFO, starget, -+ "enclosure_logical_id(0x%016llx), slot(%d)\n", -+ (unsigned long long) -+ sas_device->enclosure_logical_id, -+ sas_device->slot); -+ if (sas_device->connector_name[0] != '\0') -+ starget_printk(KERN_INFO, starget, -+ "enclosure level(0x%04x),connector name(%s)\n", -+ sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ } -+} -+ -+/** -+ * scsih_abort_mpt2sas - eh threads main abort routine -+ * @scmd: pointer to scsi command object -+ * -+ * Returns SUCCESS if command aborted else FAILED -+ */ -+int -+scsih_abort_mpt2sas(struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ u16 smid; -+ u16 handle; -+ int r; -+ -+ sdev_printk(KERN_INFO, scmd->device, -+ "attempting task abort! scmd(%p)\n", scmd); -+ _scsih_tm_display_info(ioc, scmd); -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { -+ sdev_printk(KERN_INFO, scmd->device, -+ "device been deleted! scmd(%p)\n", scmd); -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ r = SUCCESS; -+ goto out; -+ } -+ -+ /* search for the command */ -+ smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd); -+ if (!smid) { -+ scmd->result = DID_RESET << 16; -+ r = SUCCESS; -+ goto out; -+ } -+ -+ /* for hidden raid components and volumes this is not supported */ -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT || -+ sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) { -+ scmd->result = DID_RESET << 16; -+ r = FAILED; -+ goto out; -+ } -+ -+ mpt2sas_halt_firmware(ioc); -+ -+ handle = sas_device_priv_data->sas_target->handle; -+ r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, -+ scmd->device->id, scmd->device->lun, -+ MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, TM_MUTEX_ON); -+ -+ out: -+ sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", -+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); -+ return r; -+} -+ -+/** -+ * scsih_dev_reset_mpt2sas - eh threads main device reset routine -+ * @scmd: pointer to scsi command object -+ * -+ * Returns SUCCESS if command aborted else FAILED -+ */ -+int -+scsih_dev_reset_mpt2sas(struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct _sas_device *sas_device = NULL; -+ u16 handle; -+ int r; -+ -+ struct scsi_target *starget = scmd->device->sdev_target; -+ struct MPT3SAS_TARGET *target_priv_data = starget->hostdata; -+ -+ sdev_printk(KERN_INFO, scmd->device, -+ "attempting device reset! scmd(%p)\n", scmd); -+ _scsih_tm_display_info(ioc, scmd); -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { -+ sdev_printk(KERN_INFO, scmd->device, -+ "device been deleted! scmd(%p)\n", scmd); -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ r = SUCCESS; -+ goto out; -+ } -+ -+ /* for hidden raid components obtain the volume_handle */ -+ handle = 0; -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) { -+ sas_device = mpt2sas_get_sdev_from_target(ioc, -+ target_priv_data); -+ if (sas_device) -+ handle = sas_device->volume_handle; -+ } else -+ handle = sas_device_priv_data->sas_target->handle; -+ -+ if (!handle) { -+ scmd->result = DID_RESET << 16; -+ r = FAILED; -+ goto out; -+ } -+ -+ r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, -+ scmd->device->id, scmd->device->lun, -+ MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, TM_MUTEX_ON); -+ -+ out: -+ sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", -+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ -+ return r; -+} -+ -+/** -+ * scsih_target_reset_mpt2sas - eh threads main target reset routine -+ * @scmd: pointer to scsi command object -+ * -+ * Returns SUCCESS if command aborted else FAILED -+ */ -+int -+scsih_target_reset_mpt2sas(struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct _sas_device *sas_device = NULL; -+ u16 handle; -+ int r; -+ struct scsi_target *starget = scmd->device->sdev_target; -+ struct MPT3SAS_TARGET *target_priv_data = starget->hostdata; -+ -+ starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n", -+ scmd); -+ _scsih_tm_display_info(ioc, scmd); -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { -+ starget_printk(KERN_INFO, starget, "target been deleted! scmd(%p)\n", -+ scmd); -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ r = SUCCESS; -+ goto out; -+ } -+ -+ /* for hidden raid components obtain the volume_handle */ -+ handle = 0; -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) { -+ sas_device = mpt2sas_get_sdev_from_target(ioc, -+ target_priv_data); -+ if (sas_device) -+ handle = sas_device->volume_handle; -+ } else -+ handle = sas_device_priv_data->sas_target->handle; -+ -+ if (!handle) { -+ scmd->result = DID_RESET << 16; -+ r = FAILED; -+ goto out; -+ } -+ -+ r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, -+ scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, -+ 30, TM_MUTEX_ON); -+ -+ out: -+ starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", -+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ -+ return r; -+} -+ -+ -+/** -+ * scsih_host_reset_mpt2sas - eh threads main host reset routine -+ * @scmd: pointer to scsi command object -+ * -+ * Returns SUCCESS if command aborted else FAILED -+ */ -+int -+scsih_host_reset_mpt2sas(struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); -+ int r, retval; -+ -+ pr_info(MPT3SAS_FMT "attempting host reset! scmd(%p)\n", -+ ioc->name, scmd); -+ scsi_print_command(scmd); -+ -+ if (ioc->is_driver_loading) { -+ pr_info(MPT3SAS_FMT "Blocking the host reset\n", -+ ioc->name); -+ r = FAILED; -+ goto out; -+ } -+ -+ retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ r = (retval < 0) ? FAILED : SUCCESS; -+out: -+ pr_info(MPT3SAS_FMT "host reset: %s scmd(%p)\n", -+ ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); -+ -+ return r; -+} -+ -+/** -+ * _scsih_fw_event_add - insert and queue up fw_event -+ * @ioc: per adapter object -+ * @fw_event: object describing the event -+ * Context: This function will acquire ioc->fw_event_lock. -+ * -+ * This adds the firmware event object into link list, then queues it up to -+ * be processed from user context. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_fw_event_add(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) -+{ -+ unsigned long flags; -+ -+ if (ioc->firmware_event_thread == NULL) -+ return; -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ fw_event_work_get(fw_event); -+ INIT_LIST_HEAD(&fw_event->list); -+ list_add_tail(&fw_event->list, &ioc->fw_event_list); -+ INIT_WORK(&fw_event->work, _firmware_event_work); -+ fw_event_work_get(fw_event); -+ queue_work(ioc->firmware_event_thread, &fw_event->work); -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+} -+ -+/** -+ * _scsih_fw_event_del_from_list - delete fw_event from the list -+ * @ioc: per adapter object -+ * @fw_event: object describing the event -+ * Context: This function will acquire ioc->fw_event_lock. -+ * -+ * If the fw_event is on the fw_event_list, remove it and do a put. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_fw_event_del_from_list(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work -+ *fw_event) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ if (!list_empty(&fw_event->list)) { -+ list_del_init(&fw_event->list); -+ fw_event_work_put(fw_event); -+ } -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+} -+ -+ -+ /** -+ * mpt2sas_send_trigger_data_event - send event for processing trigger data -+ * @ioc: per adapter object -+ * @event_data: trigger event data -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) -+{ -+ struct fw_event_work *fw_event; -+ u16 sz; -+ -+ if (ioc->is_driver_loading) -+ return; -+ sz = sizeof(*event_data); -+ fw_event = alloc_fw_event_work(sz); -+ if (!fw_event) -+ return; -+ fw_event->event = MPT3SAS_PROCESS_TRIGGER_DIAG; -+ fw_event->ioc = ioc; -+ memcpy(fw_event->event_data, event_data, sizeof(*event_data)); -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+} -+ -+/** -+ * _scsih_error_recovery_delete_devices - remove devices not responding -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_error_recovery_delete_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct fw_event_work *fw_event; -+ -+ if (ioc->is_driver_loading) -+ return; -+ fw_event = alloc_fw_event_work(0); -+ if (!fw_event) -+ return; -+ fw_event->event = MPT3SAS_REMOVE_UNRESPONDING_DEVICES; -+ fw_event->ioc = ioc; -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+} -+ -+/** -+ * mpt2sas_port_enable_complete - port enable completed (fake event) -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct fw_event_work *fw_event; -+ -+ fw_event = alloc_fw_event_work(0); -+ if (!fw_event) -+ return; -+ fw_event->event = MPT3SAS_PORT_ENABLE_COMPLETE; -+ fw_event->ioc = ioc; -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+} -+ -+static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc) -+{ -+ unsigned long flags; -+ struct fw_event_work *fw_event = NULL; -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ if (!list_empty(&ioc->fw_event_list)) { -+ fw_event = list_first_entry(&ioc->fw_event_list, -+ struct fw_event_work, list); -+ list_del_init(&fw_event->list); -+ } -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+ -+ return fw_event; -+} -+ -+/** -+ * _scsih_fw_event_cleanup_queue - cleanup event queue -+ * @ioc: per adapter object -+ * -+ * Walk the firmware event queue, either killing timers, or waiting -+ * for outstanding events to complete -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct fw_event_work *fw_event; -+ -+ if (list_empty(&ioc->fw_event_list) || -+ !ioc->firmware_event_thread || in_interrupt()) -+ return; -+ -+ while ((fw_event = dequeue_next_fw_event(ioc))) { -+ /* -+ * Wait on the fw_event to complete. If this returns 1, then -+ * the event was never executed, and we need a put for the -+ * reference the work had on the fw_event. -+ * -+ * If it did execute, we wait for it to finish, and the put will -+ * happen from _firmware_event_work() -+ */ -+ if (cancel_work_sync(&fw_event->work)) -+ fw_event_work_put(fw_event); -+ -+ fw_event_work_put(fw_event); -+ } -+} -+ -+/** -+ * _scsih_internal_device_block - block the sdev device -+ * @sdev: per device object -+ * @sas_device_priv_data : per device driver private data -+ * -+ * make sure device is blocked without error, if not -+ * print an error -+ */ -+static void -+_scsih_internal_device_block(struct scsi_device *sdev, -+ struct MPT3SAS_DEVICE *sas_device_priv_data) -+{ -+ int r = 0; -+ -+ sdev_printk(KERN_INFO, sdev, "device_block, handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle); -+ sas_device_priv_data->block = 1; -+ -+ r = scsi_internal_device_block(sdev); -+ if (r == -EINVAL) -+ sdev_printk(KERN_WARNING, sdev, -+ "device_block failed with return(%d) for handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle, r); -+} -+ -+/** -+ * _scsih_internal_device_unblock - unblock the sdev device -+ * @sdev: per device object -+ * @sas_device_priv_data : per device driver private data -+ * make sure device is unblocked without error, if not retry -+ * by blocking and then unblocking -+ */ -+ -+static void -+_scsih_internal_device_unblock(struct scsi_device *sdev, -+ struct MPT3SAS_DEVICE *sas_device_priv_data) -+{ -+ int r = 0; -+ -+ sdev_printk(KERN_WARNING, sdev, "device_unblock and setting to running, " -+ "handle(0x%04x)\n", sas_device_priv_data->sas_target->handle); -+ sas_device_priv_data->block = 0; -+ r = scsi_internal_device_unblock(sdev, SDEV_RUNNING); -+ if (r == -EINVAL) { -+ /* The device has been set to SDEV_RUNNING by SD layer during -+ * device addition but the request queue is still stopped by -+ * our earlier block call. We need to perform a block again -+ * to get the device to SDEV_BLOCK and then to SDEV_RUNNING */ -+ -+ sdev_printk(KERN_WARNING, sdev, -+ "device_unblock failed with return(%d) for handle(0x%04x) " -+ "performing a block followed by an unblock\n", -+ sas_device_priv_data->sas_target->handle, r); -+ sas_device_priv_data->block = 1; -+ r = scsi_internal_device_block(sdev); -+ if (r) -+ sdev_printk(KERN_WARNING, sdev, "retried device_block " -+ "failed with return(%d) for handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle, r); -+ -+ sas_device_priv_data->block = 0; -+ r = scsi_internal_device_unblock(sdev, SDEV_RUNNING); -+ if (r) -+ sdev_printk(KERN_WARNING, sdev, "retried device_unblock" -+ " failed with return(%d) for handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle, r); -+ } -+} -+ -+/** -+ * _scsih_ublock_io_all_device - unblock every device -+ * @ioc: per adapter object -+ * -+ * change the device state from block to running -+ */ -+static void -+_scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (!sas_device_priv_data->block) -+ continue; -+ -+ dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, -+ "device_running, handle(0x%04x)\n", -+ sas_device_priv_data->sas_target->handle)); -+ _scsih_internal_device_unblock(sdev, sas_device_priv_data); -+ } -+} -+ -+ -+/** -+ * _scsih_ublock_io_device - prepare device to be deleted -+ * @ioc: per adapter object -+ * @sas_addr: sas address -+ * -+ * unblock then put device in offline state -+ */ -+static void -+_scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->sas_target->sas_address -+ != sas_address) -+ continue; -+ if (sas_device_priv_data->block) -+ _scsih_internal_device_unblock(sdev, -+ sas_device_priv_data); -+ } -+} -+ -+/** -+ * _scsih_block_io_all_device - set the device state to SDEV_BLOCK -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * During device pull we need to appropiately set the sdev state. -+ */ -+static void -+_scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->block) -+ continue; -+ if (sas_device_priv_data->ignore_delay_remove) { -+ sdev_printk(KERN_INFO, sdev, -+ "%s skip device_block for SES handle(0x%04x)\n", -+ __func__, sas_device_priv_data->sas_target->handle); -+ continue; -+ } -+ _scsih_internal_device_block(sdev, sas_device_priv_data); -+ } -+} -+ -+/** -+ * _scsih_block_io_device - set the device state to SDEV_BLOCK -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * During device pull we need to appropiately set the sdev state. -+ */ -+static void -+_scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ struct _sas_device *sas_device; -+ -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (!sas_device) -+ return; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data) -+ continue; -+ if (sas_device_priv_data->sas_target->handle != handle) -+ continue; -+ if (sas_device_priv_data->block) -+ continue; -+ if (sas_device->pend_sas_rphy_add) -+ continue; -+ if (sas_device_priv_data->ignore_delay_remove) { -+ sdev_printk(KERN_INFO, sdev, -+ "%s skip device_block for SES handle(0x%04x)\n", -+ __func__, sas_device_priv_data->sas_target->handle); -+ continue; -+ } -+ _scsih_internal_device_block(sdev, sas_device_priv_data); -+ } -+ -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_block_io_to_children_attached_to_ex -+ * @ioc: per adapter object -+ * @sas_expander: the sas_device object -+ * -+ * This routine set sdev state to SDEV_BLOCK for all devices -+ * attached to this expander. This function called when expander is -+ * pulled. -+ */ -+static void -+_scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander) -+{ -+ struct _sas_port *mpt2sas_port; -+ struct _sas_device *sas_device; -+ struct _sas_node *expander_sibling; -+ unsigned long flags; -+ -+ if (!sas_expander) -+ return; -+ -+ list_for_each_entry(mpt2sas_port, -+ &sas_expander->sas_port_list, port_list) { -+ if (mpt2sas_port->remote_identify.device_type == -+ SAS_END_DEVICE) { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ if (sas_device) { -+ set_bit(sas_device->handle, -+ ioc->blocking_handles); -+ sas_device_put(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ } -+ } -+ -+ list_for_each_entry(mpt2sas_port, -+ &sas_expander->sas_port_list, port_list) { -+ -+ if (mpt2sas_port->remote_identify.device_type == -+ SAS_EDGE_EXPANDER_DEVICE || -+ mpt2sas_port->remote_identify.device_type == -+ SAS_FANOUT_EXPANDER_DEVICE) { -+ expander_sibling = -+ mpt2sas_scsih_expander_find_by_sas_address( -+ ioc, mpt2sas_port->remote_identify.sas_address); -+ _scsih_block_io_to_children_attached_to_ex(ioc, -+ expander_sibling); -+ } -+ } -+} -+ -+/** -+ * _scsih_block_io_to_children_attached_directly -+ * @ioc: per adapter object -+ * @event_data: topology change event data -+ * -+ * This routine set sdev state to SDEV_BLOCK for all devices -+ * direct attached during device pull. -+ */ -+static void -+_scsih_block_io_to_children_attached_directly(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasTopologyChangeList_t *event_data) -+{ -+ int i; -+ u16 handle; -+ u16 reason_code; -+ -+ for (i = 0; i < event_data->NumEntries; i++) { -+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); -+ if (!handle) -+ continue; -+ reason_code = event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_RC_MASK; -+ if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING) -+ _scsih_block_io_device(ioc, handle); -+ } -+} -+ -+/** -+ * _scsih_tm_tr_send - send task management request -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: interrupt time. -+ * -+ * This code is to initiate the device removal handshake protocol -+ * with controller firmware. This function will issue target reset -+ * using high priority request queue. It will send a sas iounit -+ * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. -+ * -+ * This is designed to send muliple task management request at the same -+ * time to the fifo. If the fifo is full, we will append the request, -+ * and process it in a future completion. -+ */ -+static void -+_scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ Mpi2SCSITaskManagementRequest_t *mpi_request; -+ u16 smid; -+ struct _sas_device *sas_device = NULL; -+ struct MPT3SAS_TARGET *sas_target_priv_data = NULL; -+ u64 sas_address = 0; -+ unsigned long flags; -+ struct _tr_list *delayed_tr; -+ u32 ioc_state; -+ -+ if (ioc->remove_host) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host has been removed: handle(0x%04x)\n", -+ __func__, ioc->name, handle)); -+ return; -+ } else if (ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host in pci error recovery: handle(0x%04x)\n", -+ __func__, ioc->name, -+ handle)); -+ return; -+ } -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host is not operational: handle(0x%04x)\n", -+ __func__, ioc->name, -+ handle)); -+ return; -+ } -+ -+ /* if PD, then return */ -+ if (test_bit(handle, ioc->pd_handles)) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device && sas_device->starget && -+ sas_device->starget->hostdata) { -+ sas_target_priv_data = sas_device->starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ sas_address = sas_device->sas_address; -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (sas_target_priv_data) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, handle, -+ (unsigned long long)sas_address)); -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting delete flag:enclosure logical id(0x%016llx)," -+ " slot(%d)\n", ioc->name, (unsigned long long) -+ sas_device->enclosure_logical_id, -+ sas_device->slot)); -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting delete flag: enclosure level(0x%04x)," -+ " connector name( %s)\n", ioc->name, -+ sas_device->enclosure_level, -+ sas_device->connector_name)); -+ _scsih_ublock_io_device(ioc, sas_address); -+ sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; -+ } -+ -+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); -+ if (!smid) { -+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); -+ if (!delayed_tr) -+ goto out; -+ INIT_LIST_HEAD(&delayed_tr->list); -+ delayed_tr->handle = handle; -+ list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED:tr:handle(0x%04x), (open)\n", -+ ioc->name, handle)); -+ goto out; -+ } -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", -+ ioc->name, handle, smid, -+ ioc->tm_tr_cb_idx)); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; -+ mpi_request->DevHandle = cpu_to_le16(handle); -+ mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; -+ mpt2sas_base_put_smid_hi_priority(ioc, smid, 0); -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); -+ -+out: -+ if (sas_device) -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_tm_tr_complete - -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt time. -+ * -+ * This is the target reset completion routine. -+ * This code is part of the code to initiate the device removal -+ * handshake protocol with controller firmware. -+ * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE) -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ u16 handle; -+ Mpi2SCSITaskManagementRequest_t *mpi_request_tm; -+ Mpi2SCSITaskManagementReply_t *mpi_reply = -+ mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ Mpi2SasIoUnitControlRequest_t *mpi_request; -+ u16 smid_sas_ctrl; -+ u32 ioc_state; -+ struct _sc_list *delayed_sc; -+ -+ if (ioc->remove_host) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host has been removed\n", __func__, ioc->name)); -+ return 1; -+ } else if (ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host in pci error recovery\n", __func__, -+ ioc->name)); -+ return 1; -+ } -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host is not operational\n", __func__, ioc->name)); -+ return 1; -+ } -+ if (unlikely(!mpi_reply)) { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 1; -+ } -+ mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); -+ handle = le16_to_cpu(mpi_request_tm->DevHandle); -+ if (handle != le16_to_cpu(mpi_reply->DevHandle)) { -+ dewtprintk(ioc, pr_err(MPT3SAS_FMT -+ "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n", -+ ioc->name, handle, -+ le16_to_cpu(mpi_reply->DevHandle), smid)); -+ return 0; -+ } -+ -+ mpt2sas_trigger_master(ioc, MASTER_TRIGGER_TASK_MANAGMENT); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " -+ "loginfo(0x%08x), completed(%d)\n", ioc->name, -+ handle, smid, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo), -+ le32_to_cpu(mpi_reply->TerminationCount))); -+ -+ smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); -+ if (!smid_sas_ctrl) { -+ delayed_sc = kzalloc(sizeof(*delayed_sc), GFP_ATOMIC); -+ if (!delayed_sc) -+ return _scsih_check_for_pending_tm(ioc, smid); -+ INIT_LIST_HEAD(&delayed_sc->list); -+ delayed_sc->handle = mpi_request_tm->DevHandle; -+ list_add_tail(&delayed_sc->list, &ioc->delayed_sc_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED:sc:handle(0x%04x), (open)\n", -+ ioc->name, handle)); -+ return _scsih_check_for_pending_tm(ioc, smid); -+ } -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", -+ ioc->name, handle, smid_sas_ctrl, -+ ioc->tm_sas_control_cb_idx)); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); -+ memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; -+ mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; -+ mpi_request->DevHandle = mpi_request_tm->DevHandle; -+ mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); -+ -+ return _scsih_check_for_pending_tm(ioc, smid); -+} -+ -+ -+/** -+ * _scsih_sas_control_complete - completion routine -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt time. -+ * -+ * This is the sas iounit control completion routine. -+ * This code is part of the code to initiate the device removal -+ * handshake protocol with controller firmware. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_sas_control_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u8 msix_index, u32 reply) -+{ -+ Mpi2SasIoUnitControlReply_t *mpi_reply = -+ mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ -+ if (likely(mpi_reply)) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "sc_complete:handle(0x%04x), (open) " -+ "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, -+ le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo))); -+ } else { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ } -+ return mpt2sas_check_for_pending_internal_cmds(ioc, smid); -+} -+ -+/** -+ * _scsih_tm_tr_volume_send - send target reset request for volumes -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: interrupt time. -+ * -+ * This is designed to send muliple task management request at the same -+ * time to the fifo. If the fifo is full, we will append the request, -+ * and process it in a future completion. -+ */ -+static void -+_scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ Mpi2SCSITaskManagementRequest_t *mpi_request; -+ u16 smid; -+ struct _tr_list *delayed_tr; -+ -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host reset in progress!\n", -+ __func__, ioc->name)); -+ return; -+ } -+ -+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx); -+ if (!smid) { -+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); -+ if (!delayed_tr) -+ return; -+ INIT_LIST_HEAD(&delayed_tr->list); -+ delayed_tr->handle = handle; -+ list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED:tr:handle(0x%04x), (open)\n", -+ ioc->name, handle)); -+ return; -+ } -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "tr_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", -+ ioc->name, handle, smid, -+ ioc->tm_tr_volume_cb_idx)); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; -+ mpi_request->DevHandle = cpu_to_le16(handle); -+ mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; -+ mpt2sas_base_put_smid_hi_priority(ioc, smid, 0); -+} -+ -+/** -+ * _scsih_tm_volume_tr_complete - target reset completion -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt time. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_tm_volume_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, -+ u8 msix_index, u32 reply) -+{ -+ u16 handle; -+ Mpi2SCSITaskManagementRequest_t *mpi_request_tm; -+ Mpi2SCSITaskManagementReply_t *mpi_reply = -+ mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ -+ if (ioc->shost_recovery || ioc->remove_host || -+ ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host reset in progress!\n", -+ __func__, ioc->name)); -+ return 1; -+ } -+ if (unlikely(!mpi_reply)) { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 1; -+ } -+ -+ mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); -+ handle = le16_to_cpu(mpi_request_tm->DevHandle); -+ if (handle != le16_to_cpu(mpi_reply->DevHandle)) { -+ dewtprintk(ioc, pr_err(MPT3SAS_FMT -+ "spurious interrupt: handle(0x%04x:0x%04x), smid(%d)!!!\n", -+ ioc->name, handle, -+ le16_to_cpu(mpi_reply->DevHandle), smid)); -+ return 0; -+ } -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " -+ "loginfo(0x%08x), completed(%d)\n", ioc->name, -+ handle, smid, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo), -+ le32_to_cpu(mpi_reply->TerminationCount))); -+ -+ return _scsih_check_for_pending_tm(ioc, smid); -+} -+ -+/** -+ * _scsih_issue_delayed_event_ack_mpt2sas - issue delayed Event ACK messages -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @event: Event ID -+ * @event_context: used to track events uniquely -+ * -+ * Context - processed in interrupt context. -+ */ -+void -+_scsih_issue_delayed_event_ack_mpt2sas(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 event, -+ u32 event_context) -+{ -+ Mpi2EventAckRequest_t *ack_request; -+ int i = smid - ioc->internal_smid; -+ unsigned long flags; -+ -+ /* Without releasing the smid just update the -+ * call back index and reuse the same smid for -+ * processing this delayed request -+ */ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ ioc->internal_lookup[i].cb_idx = ioc->base_cb_idx; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "EVENT ACK: event(0x%04x), smid(%d), cb(%d)\n", -+ ioc->name, le16_to_cpu(event), smid, -+ ioc->base_cb_idx)); -+ ack_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); -+ ack_request->Function = MPI2_FUNCTION_EVENT_ACK; -+ ack_request->Event = event; -+ ack_request->EventContext = event_context; -+ ack_request->VF_ID = 0; /* TODO */ -+ ack_request->VP_ID = 0; -+ mpt2sas_base_put_smid_default(ioc, smid); -+} -+ -+/** -+ * _scsih_issue_delayed_sas_io_unit_ctrl_mpt2sas - issue delayed -+ * sas_io_unit_ctrl messages -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @handle: device handle -+ * -+ * Context - processed in interrupt context. -+ */ -+void -+_scsih_issue_delayed_sas_io_unit_ctrl_mpt2sas(struct MPT3SAS_ADAPTER *ioc, -+ u16 smid, u16 handle) -+ { -+ Mpi2SasIoUnitControlRequest_t *mpi_request; -+ u32 ioc_state; -+ int i = smid - ioc->internal_smid; -+ unsigned long flags; -+ -+ if (ioc->remove_host) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host has been removed\n", -+ __func__, ioc->name)); -+ return; -+ } else if (ioc->pci_error_recovery) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host in pci error recovery\n", -+ __func__, ioc->name)); -+ return; -+ } -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: host is not operational\n", -+ __func__, ioc->name)); -+ return; -+ } -+ -+ /* Without releasing the smid just update the -+ * call back index and reuse the same smid for -+ * processing this delayed request -+ */ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ ioc->internal_lookup[i].cb_idx = ioc->tm_sas_control_cb_idx; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "sc_send:handle(0x%04x), (open), smid(%d), cb(%d)\n", -+ ioc->name, le16_to_cpu(handle), smid, -+ ioc->tm_sas_control_cb_idx)); -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; -+ mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; -+ mpi_request->DevHandle = handle; -+ mpt2sas_base_put_smid_default(ioc, smid); -+} -+ -+/** -+ * _scsih_check_for_pending_internal_cmds - check for pending internal messages -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Context: Executed in interrupt context -+ * -+ * This will check delayed internal messages list, and process the -+ * next request. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_check_for_pending_internal_cmds(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ struct _sc_list *delayed_sc; -+ struct _event_ack_list *delayed_event_ack; -+ -+ if (!list_empty(&ioc->delayed_event_ack_list)) { -+ delayed_event_ack = list_entry(ioc->delayed_event_ack_list.next, -+ struct _event_ack_list, list); -+ _scsih_issue_delayed_event_ack_mpt2sas(ioc, smid, -+ delayed_event_ack->Event, delayed_event_ack->EventContext); -+ list_del(&delayed_event_ack->list); -+ kfree(delayed_event_ack); -+ return 0; -+ } -+ -+ if (!list_empty(&ioc->delayed_sc_list)) { -+ delayed_sc = list_entry(ioc->delayed_sc_list.next, -+ struct _sc_list, list); -+ _scsih_issue_delayed_sas_io_unit_ctrl_mpt2sas(ioc, smid, -+ delayed_sc->handle); -+ list_del(&delayed_sc->list); -+ kfree(delayed_sc); -+ return 0; -+ } -+ return 1; -+} -+ -+/** -+ * _scsih_check_for_pending_tm - check for pending task management -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * This will check delayed target reset list, and feed the -+ * next reqeust. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ struct _tr_list *delayed_tr; -+ -+ if (!list_empty(&ioc->delayed_tr_volume_list)) { -+ delayed_tr = list_entry(ioc->delayed_tr_volume_list.next, -+ struct _tr_list, list); -+ mpt2sas_base_free_smid(ioc, smid); -+ _scsih_tm_tr_volume_send(ioc, delayed_tr->handle); -+ list_del(&delayed_tr->list); -+ kfree(delayed_tr); -+ return 0; -+ } -+ -+ if (!list_empty(&ioc->delayed_tr_list)) { -+ delayed_tr = list_entry(ioc->delayed_tr_list.next, -+ struct _tr_list, list); -+ mpt2sas_base_free_smid(ioc, smid); -+ _scsih_tm_tr_send(ioc, delayed_tr->handle); -+ list_del(&delayed_tr->list); -+ kfree(delayed_tr); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+/** -+ * _scsih_check_topo_delete_events - sanity check on topo events -+ * @ioc: per adapter object -+ * @event_data: the event data payload -+ * -+ * This routine added to better handle cable breaker. -+ * -+ * This handles the case where driver receives multiple expander -+ * add and delete events in a single shot. When there is a delete event -+ * the routine will void any pending add events waiting in the event queue. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_check_topo_delete_events(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasTopologyChangeList_t *event_data) -+{ -+ struct fw_event_work *fw_event; -+ Mpi2EventDataSasTopologyChangeList_t *local_event_data; -+ u16 expander_handle; -+ struct _sas_node *sas_expander; -+ unsigned long flags; -+ int i, reason_code; -+ u16 handle; -+ -+ for (i = 0 ; i < event_data->NumEntries; i++) { -+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); -+ if (!handle) -+ continue; -+ reason_code = event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_RC_MASK; -+ if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING) -+ _scsih_tm_tr_send(ioc, handle); -+ } -+ -+ expander_handle = le16_to_cpu(event_data->ExpanderDevHandle); -+ if (expander_handle < ioc->sas_hba.num_phys) { -+ _scsih_block_io_to_children_attached_directly(ioc, event_data); -+ return; -+ } -+ if (event_data->ExpStatus == -+ MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) { -+ /* put expander attached devices into blocking state */ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, -+ expander_handle); -+ _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ do { -+ handle = find_first_bit(ioc->blocking_handles, -+ ioc->facts.MaxDevHandle); -+ if (handle < ioc->facts.MaxDevHandle) -+ _scsih_block_io_device(ioc, handle); -+ } while (test_and_clear_bit(handle, ioc->blocking_handles)); -+ } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING) -+ _scsih_block_io_to_children_attached_directly(ioc, event_data); -+ -+ if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) -+ return; -+ -+ /* mark ignore flag for pending events */ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ list_for_each_entry(fw_event, &ioc->fw_event_list, list) { -+ if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || -+ fw_event->ignore) -+ continue; -+ local_event_data = (Mpi2EventDataSasTopologyChangeList_t *) -+ fw_event->event_data; -+ if (local_event_data->ExpStatus == -+ MPI2_EVENT_SAS_TOPO_ES_ADDED || -+ local_event_data->ExpStatus == -+ MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { -+ if (le16_to_cpu(local_event_data->ExpanderDevHandle) == -+ expander_handle) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting ignoring flag\n", ioc->name)); -+ fw_event->ignore = 1; -+ } -+ } -+ } -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+} -+ -+/** -+ * _scsih_set_volume_delete_flag - setting volume delete flag -+ * @ioc: per adapter object -+ * @handle: device handle -+ * -+ * This returns nothing. -+ */ -+static void -+_scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _raid_device *raid_device; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ if (raid_device && raid_device->starget && -+ raid_device->starget->hostdata) { -+ sas_target_priv_data = -+ raid_device->starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "setting delete flag: handle(0x%04x), " -+ "wwid(0x%016llx)\n", ioc->name, handle, -+ (unsigned long long) raid_device->wwid)); -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+} -+ -+/** -+ * _scsih_set_volume_handle_for_tr - set handle for target reset to volume -+ * @handle: input handle -+ * @a: handle for volume a -+ * @b: handle for volume b -+ * -+ * IR firmware only supports two raid volumes. The purpose of this -+ * routine is to set the volume handle in either a or b. When the given -+ * input handle is non-zero, or when a and b have not been set before. -+ */ -+static void -+_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b) -+{ -+ if (!handle || handle == *a || handle == *b) -+ return; -+ if (!*a) -+ *a = handle; -+ else if (!*b) -+ *b = handle; -+} -+ -+/** -+ * _scsih_check_ir_config_unhide_events - check for UNHIDE events -+ * @ioc: per adapter object -+ * @event_data: the event data payload -+ * Context: interrupt time. -+ * -+ * This routine will send target reset to volume, followed by target -+ * resets to the PDs. This is called when a PD has been removed, or -+ * volume has been deleted or removed. When the target reset is sent -+ * to volume, the PD target resets need to be queued to start upon -+ * completion of the volume target reset. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataIrConfigChangeList_t *event_data) -+{ -+ Mpi2EventIrConfigElement_t *element; -+ int i; -+ u16 handle, volume_handle, a, b; -+ struct _tr_list *delayed_tr; -+ -+ a = 0; -+ b = 0; -+ -+ if (ioc->is_warpdrive) -+ return; -+ -+ /* Volume Resets for Deleted or Removed */ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ if (le32_to_cpu(event_data->Flags) & -+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) -+ continue; -+ if (element->ReasonCode == -+ MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED || -+ element->ReasonCode == -+ MPI2_EVENT_IR_CHANGE_RC_REMOVED) { -+ volume_handle = le16_to_cpu(element->VolDevHandle); -+ _scsih_set_volume_delete_flag(ioc, volume_handle); -+ _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); -+ } -+ } -+ -+ /* Volume Resets for UNHIDE events */ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ if (le32_to_cpu(event_data->Flags) & -+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) -+ continue; -+ if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) { -+ volume_handle = le16_to_cpu(element->VolDevHandle); -+ _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); -+ } -+ } -+ -+ if (a) -+ _scsih_tm_tr_volume_send(ioc, a); -+ if (b) -+ _scsih_tm_tr_volume_send(ioc, b); -+ -+ /* PD target resets */ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) -+ continue; -+ handle = le16_to_cpu(element->PhysDiskDevHandle); -+ volume_handle = le16_to_cpu(element->VolDevHandle); -+ clear_bit(handle, ioc->pd_handles); -+ if (!volume_handle) -+ _scsih_tm_tr_send(ioc, handle); -+ else if (volume_handle == a || volume_handle == b) { -+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); -+ BUG_ON(!delayed_tr); -+ INIT_LIST_HEAD(&delayed_tr->list); -+ delayed_tr->handle = handle; -+ list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, -+ handle)); -+ } else -+ _scsih_tm_tr_send(ioc, handle); -+ } -+} -+ -+ -+/** -+ * _scsih_check_volume_delete_events - set delete flag for volumes -+ * @ioc: per adapter object -+ * @event_data: the event data payload -+ * Context: interrupt time. -+ * -+ * This will handle the case when the cable connected to entire volume is -+ * pulled. We will take care of setting the deleted flag so normal IO will -+ * not be sent. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_check_volume_delete_events(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataIrVolume_t *event_data) -+{ -+ u32 state; -+ -+ if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) -+ return; -+ state = le32_to_cpu(event_data->NewValue); -+ if (state == MPI2_RAID_VOL_STATE_MISSING || state == -+ MPI2_RAID_VOL_STATE_FAILED) -+ _scsih_set_volume_delete_flag(ioc, -+ le16_to_cpu(event_data->VolDevHandle)); -+} -+ -+/** -+ * _scsih_temp_threshold_events - display temperature threshold exceeded events -+ * @ioc: per adapter object -+ * @event_data: the temp threshold event data -+ * Context: interrupt time. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataTemperature_t *event_data) -+{ -+ if (ioc->temp_sensors_count >= event_data->SensorNum) { -+ pr_err(MPT3SAS_FMT "Temperature Threshold flags %s%s%s%s" -+ " exceeded for Sensor: %d !!!\n", ioc->name, -+ ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ", -+ ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ", -+ ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ", -+ ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ", -+ event_data->SensorNum); -+ pr_err(MPT3SAS_FMT "Current Temp In Celsius: %d\n", -+ ioc->name, event_data->CurrentTemperature); -+ } -+} -+ -+/** -+ * _scsih_flush_running_cmds - completing outstanding commands. -+ * @ioc: per adapter object -+ * -+ * The flushing out of all pending scmd commands following host reset, -+ * where all IO is dropped to the floor. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct scsi_cmnd *scmd; -+ u16 smid; -+ u16 count = 0; -+ -+ for (smid = 1; smid <= ioc->scsiio_depth; smid++) { -+ scmd = _scsih_scsi_lookup_get_clear(ioc, smid); -+ if (!scmd) -+ continue; -+ count++; -+ mpt2sas_base_free_smid(ioc, smid); -+ scsi_dma_unmap(scmd); -+ if (ioc->pci_error_recovery) -+ scmd->result = DID_NO_CONNECT << 16; -+ else -+ scmd->result = DID_RESET << 16; -+ scmd->scsi_done(scmd); -+ } -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT "completing %d cmds\n", -+ ioc->name, count)); -+} -+ -+/** -+ * _scsih_setup_eedp - setup MPI request for EEDP transfer -+ * @ioc: per adapter object -+ * @scmd: pointer to scsi command object -+ * @mpi_request: pointer to the SCSI_IO reqest message frame -+ * -+ * Supporting protection 1 and 3. -+ * -+ * Returns nothing -+ */ -+static void -+_scsih_setup_eedp(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, -+ Mpi2SCSIIORequest_t *mpi_request) -+{ -+ u16 eedp_flags; -+ unsigned char prot_op = scsi_get_prot_op(scmd); -+ unsigned char prot_type = scsi_get_prot_type(scmd); -+ Mpi25SCSIIORequest_t *mpi_request_3v = -+ (Mpi25SCSIIORequest_t *)mpi_request; -+ -+ if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL) -+ return; -+ -+ if (prot_op == SCSI_PROT_READ_STRIP) -+ eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP; -+ else if (prot_op == SCSI_PROT_WRITE_INSERT) -+ eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; -+ else -+ return; -+ -+ switch (prot_type) { -+ case SCSI_PROT_DIF_TYPE1: -+ case SCSI_PROT_DIF_TYPE2: -+ -+ /* -+ * enable ref/guard checking -+ * auto increment ref tag -+ */ -+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | -+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | -+ MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; -+ mpi_request->CDB.EEDP32.PrimaryReferenceTag = -+ cpu_to_be32(scsi_get_lba(scmd)); -+ break; -+ -+ case SCSI_PROT_DIF_TYPE3: -+ -+ /* -+ * enable guard checking -+ */ -+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; -+ -+ break; -+ } -+ -+ mpi_request_3v->EEDPBlockSize = -+ cpu_to_le16(scmd->device->sector_size); -+ mpi_request->EEDPFlags = cpu_to_le16(eedp_flags); -+} -+ -+/** -+ * _scsih_eedp_error_handling - return sense code for EEDP errors -+ * @scmd: pointer to scsi command object -+ * @ioc_status: ioc status -+ * -+ * Returns nothing -+ */ -+static void -+_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) -+{ -+ u8 ascq; -+ -+ switch (ioc_status) { -+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: -+ ascq = 0x01; -+ break; -+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: -+ ascq = 0x02; -+ break; -+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: -+ ascq = 0x03; -+ break; -+ default: -+ ascq = 0x00; -+ break; -+ } -+ scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x10, -+ ascq); -+ scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) | -+ SAM_STAT_CHECK_CONDITION; -+} -+ -+ -+ -+/** -+ * scsih_qcmd_mpt2sas - main scsi request entry point -+ * @scmd: pointer to scsi command object -+ * @done: function pointer to be invoked on completion -+ * -+ * The callback index is set inside `ioc->scsi_io_cb_idx`. -+ * -+ * Returns 0 on success. If there's a failure, return either: -+ * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or -+ * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full -+ */ -+int -+scsih_qcmd_mpt2sas(struct Scsi_Host *shost, struct scsi_cmnd *scmd) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct _raid_device *raid_device; -+ Mpi2SCSIIORequest_t *mpi_request; -+ u32 mpi_control; -+ u16 smid; -+ u16 handle; -+ -+ if (ioc->logging_level & MPT_DEBUG_SCSI) -+ scsi_print_command(scmd); -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ return 0; -+ } -+ -+ if (ioc->pci_error_recovery || ioc->remove_host) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ return 0; -+ } -+ -+ sas_target_priv_data = sas_device_priv_data->sas_target; -+ -+ /* invalid device handle */ -+ handle = sas_target_priv_data->handle; -+ if (handle == MPT3SAS_INVALID_DEVICE_HANDLE) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ return 0; -+ } -+ -+ -+ /* host recovery or link resets sent via IOCTLs */ -+ if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) -+ return SCSI_MLQUEUE_HOST_BUSY; -+ -+ /* device has been deleted */ -+ else if (sas_target_priv_data->deleted) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scmd->scsi_done(scmd); -+ return 0; -+ /* device busy with task managment */ -+ } else if (sas_target_priv_data->tm_busy || -+ sas_device_priv_data->block) -+ return SCSI_MLQUEUE_DEVICE_BUSY; -+ -+ if (scmd->sc_data_direction == DMA_FROM_DEVICE) -+ mpi_control = MPI2_SCSIIO_CONTROL_READ; -+ else if (scmd->sc_data_direction == DMA_TO_DEVICE) -+ mpi_control = MPI2_SCSIIO_CONTROL_WRITE; -+ else -+ mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; -+ -+ /* set tags */ -+ if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) { -+ if (scmd->device->tagged_supported) { -+ if (scmd->device->ordered_tags) -+ mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; -+ else -+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; -+ } else -+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; -+ } else -+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; -+ -+ /* Make sure Device is not raid volume. -+ * We do not expose raid functionality to upper layer for warpdrive. -+ */ -+ if (!ioc->is_warpdrive && !scsih_is_raid_mpt2sas(&scmd->device->sdev_gendev) -+ && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) -+ mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; -+ -+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ goto out; -+ } -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); -+ _scsih_setup_eedp(ioc, scmd, mpi_request); -+ -+ if (scmd->cmd_len == 32) -+ mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; -+ mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) -+ mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; -+ else -+ mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; -+ mpi_request->DevHandle = cpu_to_le16(handle); -+ mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); -+ mpi_request->Control = cpu_to_le32(mpi_control); -+ mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len); -+ mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; -+ mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; -+ mpi_request->SenseBufferLowAddress = -+ mpt2sas_base_get_sense_buffer_dma(ioc, smid); -+ mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; -+ int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *) -+ mpi_request->LUN); -+ memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); -+ -+ if (mpi_request->DataLength) { -+ if (ioc->build_sg_scmd(ioc, scmd, smid)) { -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ } else -+ ioc->build_zero_len_sge(ioc, &mpi_request->SGL); -+ -+ raid_device = sas_target_priv_data->raid_device; -+ if (raid_device && raid_device->direct_io_enabled) -+ mpt2sas_setup_direct_io(ioc, scmd, raid_device, mpi_request, -+ smid); -+ -+ if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) { -+ if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) { -+ mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len | -+ MPI25_SCSIIO_IOFLAGS_FAST_PATH); -+ mpt2sas_base_put_smid_fast_path(ioc, smid, handle); -+ } else -+ mpt2sas_base_put_smid_scsi_io(ioc, smid, -+ le16_to_cpu(mpi_request->DevHandle)); -+ } else -+ mpt2sas_base_put_smid_default(ioc, smid); -+ return 0; -+ -+ out: -+ return SCSI_MLQUEUE_HOST_BUSY; -+} -+ -+/** -+ * _scsih_normalize_sense - normalize descriptor and fixed format sense data -+ * @sense_buffer: sense data returned by target -+ * @data: normalized skey/asc/ascq -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_normalize_sense(char *sense_buffer, struct sense_info *data) -+{ -+ if ((sense_buffer[0] & 0x7F) >= 0x72) { -+ /* descriptor format */ -+ data->skey = sense_buffer[1] & 0x0F; -+ data->asc = sense_buffer[2]; -+ data->ascq = sense_buffer[3]; -+ } else { -+ /* fixed format */ -+ data->skey = sense_buffer[2] & 0x0F; -+ data->asc = sense_buffer[12]; -+ data->ascq = sense_buffer[13]; -+ } -+} -+ -+/** -+ * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request -+ * @ioc: per adapter object -+ * @scmd: pointer to scsi command object -+ * @mpi_reply: reply mf payload returned from firmware -+ * -+ * scsi_status - SCSI Status code returned from target device -+ * scsi_state - state info associated with SCSI_IO determined by ioc -+ * ioc_status - ioc supplied status info -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, -+ Mpi2SCSIIOReply_t *mpi_reply, u16 smid) -+{ -+ u32 response_info; -+ u8 *response_bytes; -+ u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ u8 scsi_state = mpi_reply->SCSIState; -+ u8 scsi_status = mpi_reply->SCSIStatus; -+ char *desc_ioc_state = NULL; -+ char *desc_scsi_status = NULL; -+ char *desc_scsi_state = ioc->tmp_string; -+ u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); -+ struct _sas_device *sas_device = NULL; -+ struct scsi_target *starget = scmd->device->sdev_target; -+ struct MPT3SAS_TARGET *priv_target = starget->hostdata; -+ char *device_str = NULL; -+ -+ if (!priv_target) -+ return; -+ if (ioc->hide_ir_msg) -+ device_str = "WarpDrive"; -+ else -+ device_str = "volume"; -+ -+ if (log_info == 0x31170000) -+ return; -+ -+ switch (ioc_status) { -+ case MPI2_IOCSTATUS_SUCCESS: -+ desc_ioc_state = "success"; -+ break; -+ case MPI2_IOCSTATUS_INVALID_FUNCTION: -+ desc_ioc_state = "invalid function"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: -+ desc_ioc_state = "scsi recovered error"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: -+ desc_ioc_state = "scsi invalid dev handle"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: -+ desc_ioc_state = "scsi device not there"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: -+ desc_ioc_state = "scsi data overrun"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: -+ desc_ioc_state = "scsi data underrun"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: -+ desc_ioc_state = "scsi io data error"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: -+ desc_ioc_state = "scsi protocol error"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: -+ desc_ioc_state = "scsi task terminated"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: -+ desc_ioc_state = "scsi residual mismatch"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: -+ desc_ioc_state = "scsi task mgmt failed"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: -+ desc_ioc_state = "scsi ioc terminated"; -+ break; -+ case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: -+ desc_ioc_state = "scsi ext terminated"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: -+ desc_ioc_state = "eedp guard error"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: -+ desc_ioc_state = "eedp ref tag error"; -+ break; -+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: -+ desc_ioc_state = "eedp app tag error"; -+ break; -+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER: -+ desc_ioc_state = "insufficient power"; -+ break; -+ default: -+ desc_ioc_state = "unknown"; -+ break; -+ } -+ -+ switch (scsi_status) { -+ case MPI2_SCSI_STATUS_GOOD: -+ desc_scsi_status = "good"; -+ break; -+ case MPI2_SCSI_STATUS_CHECK_CONDITION: -+ desc_scsi_status = "check condition"; -+ break; -+ case MPI2_SCSI_STATUS_CONDITION_MET: -+ desc_scsi_status = "condition met"; -+ break; -+ case MPI2_SCSI_STATUS_BUSY: -+ desc_scsi_status = "busy"; -+ break; -+ case MPI2_SCSI_STATUS_INTERMEDIATE: -+ desc_scsi_status = "intermediate"; -+ break; -+ case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: -+ desc_scsi_status = "intermediate condmet"; -+ break; -+ case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: -+ desc_scsi_status = "reservation conflict"; -+ break; -+ case MPI2_SCSI_STATUS_COMMAND_TERMINATED: -+ desc_scsi_status = "command terminated"; -+ break; -+ case MPI2_SCSI_STATUS_TASK_SET_FULL: -+ desc_scsi_status = "task set full"; -+ break; -+ case MPI2_SCSI_STATUS_ACA_ACTIVE: -+ desc_scsi_status = "aca active"; -+ break; -+ case MPI2_SCSI_STATUS_TASK_ABORTED: -+ desc_scsi_status = "task aborted"; -+ break; -+ default: -+ desc_scsi_status = "unknown"; -+ break; -+ } -+ -+ desc_scsi_state[0] = '\0'; -+ if (!scsi_state) -+ desc_scsi_state = " "; -+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) -+ strcat(desc_scsi_state, "response info "); -+ if (scsi_state & MPI2_SCSI_STATE_TERMINATED) -+ strcat(desc_scsi_state, "state terminated "); -+ if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) -+ strcat(desc_scsi_state, "no status "); -+ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) -+ strcat(desc_scsi_state, "autosense failed "); -+ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) -+ strcat(desc_scsi_state, "autosense valid "); -+ -+ scsi_print_command(scmd); -+ -+ if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { -+ pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name, -+ device_str, (unsigned long long)priv_target->sas_address); -+ } else { -+ sas_device = mpt2sas_get_sdev_from_target(ioc, priv_target); -+ if (sas_device) { -+ pr_warn(MPT3SAS_FMT -+ "\tsas_address(0x%016llx), phy(%d)\n", -+ ioc->name, (unsigned long long) -+ sas_device->sas_address, sas_device->phy); -+ if (sas_device->enclosure_handle != 0) -+ pr_warn(MPT3SAS_FMT -+ "\tenclosure_logical_id(0x%016llx)," -+ "slot(%d)\n", ioc->name, -+ (unsigned long long) -+ sas_device->enclosure_logical_id, -+ sas_device->slot); -+ if (sas_device->connector_name[0]) -+ pr_warn(MPT3SAS_FMT -+ "\tenclosure level(0x%04x)," -+ " connector name( %s)\n", ioc->name, -+ sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ sas_device_put(sas_device); -+ } -+ } -+ -+ pr_warn(MPT3SAS_FMT -+ "\thandle(0x%04x), ioc_status(%s)(0x%04x), smid(%d)\n", -+ ioc->name, le16_to_cpu(mpi_reply->DevHandle), -+ desc_ioc_state, ioc_status, smid); -+ pr_warn(MPT3SAS_FMT -+ "\trequest_len(%d), underflow(%d), resid(%d)\n", -+ ioc->name, scsi_bufflen(scmd), scmd->underflow, -+ scsi_get_resid(scmd)); -+ pr_warn(MPT3SAS_FMT -+ "\ttag(%d), transfer_count(%d), sc->result(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->TaskTag), -+ le32_to_cpu(mpi_reply->TransferCount), scmd->result); -+ pr_warn(MPT3SAS_FMT -+ "\tscsi_status(%s)(0x%02x), scsi_state(%s)(0x%02x)\n", -+ ioc->name, desc_scsi_status, -+ scsi_status, desc_scsi_state, scsi_state); -+ -+ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { -+ struct sense_info data; -+ _scsih_normalize_sense(scmd->sense_buffer, &data); -+ pr_warn(MPT3SAS_FMT -+ "\t[sense_key,asc,ascq]: [0x%02x,0x%02x,0x%02x], count(%d)\n", -+ ioc->name, data.skey, -+ data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); -+ } -+ -+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { -+ response_info = le32_to_cpu(mpi_reply->ResponseInfo); -+ response_bytes = (u8 *)&response_info; -+ _scsih_response_code(ioc, response_bytes[0]); -+ } -+} -+ -+/** -+ * _scsih_turn_on_pfa_led - illuminate PFA LED -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: process -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ Mpi2SepReply_t mpi_reply; -+ Mpi2SepRequest_t mpi_request; -+ struct _sas_device *sas_device; -+ -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (!sas_device) -+ return; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; -+ mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; -+ mpi_request.SlotStatus = -+ cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); -+ mpi_request.DevHandle = cpu_to_le16(handle); -+ mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; -+ if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, -+ &mpi_request)) != 0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ sas_device->pfa_led_on = 1; -+ -+ if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply.IOCStatus), -+ le32_to_cpu(mpi_reply.IOCLogInfo))); -+ goto out; -+ } -+out: -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_turn_off_pfa_led - turn off Fault LED -+ * @ioc: per adapter object -+ * @sas_device: sas device whose PFA LED has to turned off -+ * Context: process -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ Mpi2SepReply_t mpi_reply; -+ Mpi2SepRequest_t mpi_request; -+ -+ memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; -+ mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; -+ mpi_request.SlotStatus = 0; -+ mpi_request.Slot = cpu_to_le16(sas_device->slot); -+ mpi_request.DevHandle = 0; -+ mpi_request.EnclosureHandle = cpu_to_le16(sas_device->enclosure_handle); -+ mpi_request.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS; -+ if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, -+ &mpi_request)) != 0) { -+ printk(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { -+ dewtprintk(ioc, printk(MPT3SAS_FMT -+ "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply.IOCStatus), -+ le32_to_cpu(mpi_reply.IOCLogInfo))); -+ return; -+ } -+} -+ -+/** -+ * _scsih_send_event_to_turn_on_pfa_led - fire delayed event -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: interrupt. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_send_event_to_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct fw_event_work *fw_event; -+ -+ fw_event = alloc_fw_event_work(0); -+ if (!fw_event) -+ return; -+ fw_event->event = MPT3SAS_TURN_ON_PFA_LED; -+ fw_event->device_handle = handle; -+ fw_event->ioc = ioc; -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+} -+ -+/** -+ * _scsih_smart_predicted_fault - process smart errors -+ * @ioc: per adapter object -+ * @handle: device handle -+ * Context: interrupt. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct scsi_target *starget; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ Mpi2EventNotificationReply_t *event_reply; -+ Mpi2EventDataSasDeviceStatusChange_t *event_data; -+ struct _sas_device *sas_device; -+ ssize_t sz; -+ unsigned long flags; -+ -+ /* only handle non-raid devices */ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (!sas_device) -+ goto out_unlock; -+ -+ starget = sas_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ -+ if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) || -+ ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) -+ goto out_unlock; -+ -+ if (sas_device->enclosure_handle != 0) -+ starget_printk(KERN_INFO, starget, "predicted fault, " -+ "enclosure logical id(0x%016llx), slot(%d)\n", -+ (unsigned long long)sas_device->enclosure_logical_id, -+ sas_device->slot); -+ if (sas_device->connector_name[0] != '\0') -+ starget_printk(KERN_WARNING, starget, "predicted fault, " -+ "enclosure level(0x%04x), connector name( %s)\n", -+ sas_device->enclosure_level, -+ sas_device->connector_name); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) -+ _scsih_send_event_to_turn_on_pfa_led(ioc, handle); -+ -+ /* insert into event log */ -+ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + -+ sizeof(Mpi2EventDataSasDeviceStatusChange_t); -+ event_reply = kzalloc(sz, GFP_KERNEL); -+ if (!event_reply) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; -+ event_reply->Event = -+ cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); -+ event_reply->MsgLength = sz/4; -+ event_reply->EventDataLength = -+ cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4); -+ event_data = (Mpi2EventDataSasDeviceStatusChange_t *) -+ event_reply->EventData; -+ event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA; -+ event_data->ASC = 0x5D; -+ event_data->DevHandle = cpu_to_le16(handle); -+ event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); -+ mpt2sas_ctl_add_to_event_log(ioc, event_reply); -+ kfree(event_reply); -+out: -+ if (sas_device) -+ sas_device_put(sas_device); -+ return; -+ -+out_unlock: -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ goto out; -+} -+ -+/** -+ * _scsih_io_done - scsi request callback -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Callback handler when using _scsih_qcmd_mpt2sas. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -+{ -+ Mpi2SCSIIORequest_t *mpi_request; -+ Mpi2SCSIIOReply_t *mpi_reply; -+ struct scsi_cmnd *scmd; -+ u16 ioc_status; -+ u32 xfer_cnt; -+ u8 scsi_state; -+ u8 scsi_status; -+ u32 log_info; -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ u32 response_code = 0; -+ unsigned long flags; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ scmd = _scsih_scsi_lookup_get_clear(ioc, smid); -+ if (scmd == NULL) -+ return 1; -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ -+ if (mpi_reply == NULL) { -+ scmd->result = DID_OK << 16; -+ goto out; -+ } -+ -+ sas_device_priv_data = scmd->device->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target || -+ sas_device_priv_data->sas_target->deleted) { -+ scmd->result = DID_NO_CONNECT << 16; -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -+ -+ /* -+ * WARPDRIVE: If direct_io is set then it is directIO, -+ * the failed direct I/O should be redirected to volume -+ */ -+ if (mpt2sas_scsi_direct_io_get(ioc, smid) && -+ ((ioc_status & MPI2_IOCSTATUS_MASK) -+ != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ ioc->scsi_lookup[smid - 1].scmd = scmd; -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ mpt2sas_scsi_direct_io_set(ioc, smid, 0); -+ memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); -+ mpi_request->DevHandle = -+ cpu_to_le16(sas_device_priv_data->sas_target->handle); -+ mpt2sas_base_put_smid_scsi_io(ioc, smid, -+ sas_device_priv_data->sas_target->handle); -+ return 0; -+ } -+ /* turning off TLR */ -+ scsi_state = mpi_reply->SCSIState; -+ if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) -+ response_code = -+ le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; -+ if (!sas_device_priv_data->tlr_snoop_check) { -+ sas_device_priv_data->tlr_snoop_check++; -+ if (!ioc->is_warpdrive && -+ !scsih_is_raid_mpt2sas(&scmd->device->sdev_gendev) && -+ sas_is_tlr_enabled(scmd->device) && -+ response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { -+ sas_disable_tlr(scmd->device); -+ sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); -+ } -+ } -+ -+ xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); -+ scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); -+ if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) -+ log_info = le32_to_cpu(mpi_reply->IOCLogInfo); -+ else -+ log_info = 0; -+ ioc_status &= MPI2_IOCSTATUS_MASK; -+ scsi_status = mpi_reply->SCSIStatus; -+ -+ if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && -+ (scsi_status == MPI2_SCSI_STATUS_BUSY || -+ scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT || -+ scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) { -+ ioc_status = MPI2_IOCSTATUS_SUCCESS; -+ } -+ -+ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { -+ struct sense_info data; -+ const void *sense_data = mpt2sas_base_get_sense_buffer(ioc, -+ smid); -+ u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, -+ le32_to_cpu(mpi_reply->SenseCount)); -+ memcpy(scmd->sense_buffer, sense_data, sz); -+ _scsih_normalize_sense(scmd->sense_buffer, &data); -+ /* failure prediction threshold exceeded */ -+ if (data.asc == 0x5D) -+ _scsih_smart_predicted_fault(ioc, -+ le16_to_cpu(mpi_reply->DevHandle)); -+ mpt2sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq); -+ -+ if (!(ioc->logging_level & MPT_DEBUG_REPLY) && -+ ((scmd->sense_buffer[2] == UNIT_ATTENTION) || -+ (scmd->sense_buffer[2] == MEDIUM_ERROR) || -+ (scmd->sense_buffer[2] == HARDWARE_ERROR))) -+ _scsih_scsi_ioc_info(ioc, scmd, mpi_reply, smid); -+ } -+ switch (ioc_status) { -+ case MPI2_IOCSTATUS_BUSY: -+ case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: -+ scmd->result = SAM_STAT_BUSY; -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: -+ scmd->result = DID_NO_CONNECT << 16; -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: -+ if (sas_device_priv_data->block) { -+ scmd->result = DID_TRANSPORT_DISRUPTED << 16; -+ goto out; -+ } -+ if (log_info == 0x31110630) { -+ if (scmd->retries > 2) { -+ scmd->result = DID_NO_CONNECT << 16; -+ scsi_device_set_state(scmd->device, -+ SDEV_OFFLINE); -+ } else { -+ scmd->result = DID_SOFT_ERROR << 16; -+ scmd->device->expecting_cc_ua = 1; -+ } -+ break; -+ } else if (log_info == VIRTUAL_IO_FAILED_RETRY) { -+ scmd->result = DID_RESET << 16; -+ break; -+ } -+ scmd->result = DID_SOFT_ERROR << 16; -+ break; -+ case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: -+ case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: -+ scmd->result = DID_RESET << 16; -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: -+ if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt)) -+ scmd->result = DID_SOFT_ERROR << 16; -+ else -+ scmd->result = (DID_OK << 16) | scsi_status; -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: -+ scmd->result = (DID_OK << 16) | scsi_status; -+ -+ if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)) -+ break; -+ -+ if (xfer_cnt < scmd->underflow) { -+ if (scsi_status == SAM_STAT_BUSY) -+ scmd->result = SAM_STAT_BUSY; -+ else -+ scmd->result = DID_SOFT_ERROR << 16; -+ } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | -+ MPI2_SCSI_STATE_NO_SCSI_STATUS)) -+ scmd->result = DID_SOFT_ERROR << 16; -+ else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) -+ scmd->result = DID_RESET << 16; -+ else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) { -+ mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID; -+ mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION; -+ scmd->result = (DRIVER_SENSE << 24) | -+ SAM_STAT_CHECK_CONDITION; -+ scmd->sense_buffer[0] = 0x70; -+ scmd->sense_buffer[2] = ILLEGAL_REQUEST; -+ scmd->sense_buffer[12] = 0x20; -+ scmd->sense_buffer[13] = 0; -+ } -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: -+ scsi_set_resid(scmd, 0); -+ case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: -+ case MPI2_IOCSTATUS_SUCCESS: -+ scmd->result = (DID_OK << 16) | scsi_status; -+ if (response_code == -+ MPI2_SCSITASKMGMT_RSP_INVALID_FRAME || -+ (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | -+ MPI2_SCSI_STATE_NO_SCSI_STATUS))) -+ scmd->result = DID_SOFT_ERROR << 16; -+ else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) -+ scmd->result = DID_RESET << 16; -+ break; -+ -+ case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: -+ case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: -+ case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: -+ _scsih_eedp_error_handling(scmd, ioc_status); -+ break; -+ -+ case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: -+ case MPI2_IOCSTATUS_INVALID_FUNCTION: -+ case MPI2_IOCSTATUS_INVALID_SGL: -+ case MPI2_IOCSTATUS_INTERNAL_ERROR: -+ case MPI2_IOCSTATUS_INVALID_FIELD: -+ case MPI2_IOCSTATUS_INVALID_STATE: -+ case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: -+ case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: -+ case MPI2_IOCSTATUS_INSUFFICIENT_POWER: -+ default: -+ scmd->result = DID_SOFT_ERROR << 16; -+ break; -+ -+ } -+ -+ if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY)) -+ _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid); -+ -+ out: -+ -+ scsi_dma_unmap(scmd); -+ -+ scmd->scsi_done(scmd); -+ return 1; -+} -+ -+/** -+ * _scsih_sas_host_refresh - refreshing sas host object contents -+ * @ioc: per adapter object -+ * Context: user -+ * -+ * During port enable, fw will send topology events for every device. Its -+ * possible that the handles may change from the previous setting, so this -+ * code keeping handles updating if changed. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u16 sz; -+ u16 ioc_status; -+ int i; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; -+ u16 attached_handle; -+ u8 link_rate; -+ -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "updating handles for sas_host(0x%016llx)\n", -+ ioc->name, (unsigned long long)ioc->sas_hba.sas_address)); -+ -+ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys -+ * sizeof(Mpi2SasIOUnit0PhyData_t)); -+ sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, -+ sas_iounit_pg0, sz)) != 0) -+ goto out; -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ goto out; -+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) { -+ link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4; -+ if (i == 0) -+ ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> -+ PhyData[0].ControllerDevHandle); -+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; -+ attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. -+ AttachedDevHandle); -+ if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) -+ link_rate = MPI2_SAS_NEG_LINK_RATE_1_5; -+ mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, -+ attached_handle, i, link_rate); -+ } -+ out: -+ kfree(sas_iounit_pg0); -+} -+ -+/** -+ * _scsih_sas_host_add - create sas host object -+ * @ioc: per adapter object -+ * -+ * Creating host side data object, stored in ioc->sas_hba -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) -+{ -+ int i; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; -+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; -+ Mpi2SasPhyPage0_t phy_pg0; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2SasEnclosurePage0_t enclosure_pg0; -+ u16 ioc_status; -+ u16 sz; -+ u8 device_missing_delay; -+ -+ mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys); -+ if (!ioc->sas_hba.num_phys) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ /* sas_iounit page 0 */ -+ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit0PhyData_t)); -+ sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, -+ sas_iounit_pg0, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ /* sas_iounit page 1 */ -+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit1PhyData_t)); -+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg1) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, -+ sas_iounit_pg1, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ ioc->io_missing_delay = -+ sas_iounit_pg1->IODeviceMissingDelay; -+ device_missing_delay = -+ sas_iounit_pg1->ReportDeviceMissingDelay; -+ if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) -+ ioc->device_missing_delay = (device_missing_delay & -+ MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; -+ else -+ ioc->device_missing_delay = device_missing_delay & -+ MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; -+ -+ ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev; -+ ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys, -+ sizeof(struct _sas_phy), GFP_KERNEL); -+ if (!ioc->sas_hba.phy) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) { -+ if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, -+ i))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ -+ if (i == 0) -+ ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> -+ PhyData[0].ControllerDevHandle); -+ ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; -+ ioc->sas_hba.phy[i].phy_id = i; -+ mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], -+ phy_pg0, ioc->sas_hba.parent_dev); -+ } -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out; -+ } -+ ioc->sas_hba.enclosure_handle = -+ le16_to_cpu(sas_device_pg0.EnclosureHandle); -+ ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ pr_info(MPT3SAS_FMT -+ "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n", -+ ioc->name, ioc->sas_hba.handle, -+ (unsigned long long) ioc->sas_hba.sas_address, -+ ioc->sas_hba.num_phys) ; -+ -+ if (ioc->sas_hba.enclosure_handle) { -+ if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, -+ &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, -+ ioc->sas_hba.enclosure_handle))) -+ ioc->sas_hba.enclosure_logical_id = -+ le64_to_cpu(enclosure_pg0.EnclosureLogicalID); -+ } -+ -+ out: -+ kfree(sas_iounit_pg1); -+ kfree(sas_iounit_pg0); -+} -+ -+/** -+ * _scsih_expander_add - creating expander object -+ * @ioc: per adapter object -+ * @handle: expander handle -+ * -+ * Creating expander object, stored in ioc->sas_expander_list. -+ * -+ * Return 0 for success, else error. -+ */ -+static int -+_scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _sas_node *sas_expander; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2ExpanderPage0_t expander_pg0; -+ Mpi2ExpanderPage1_t expander_pg1; -+ Mpi2SasEnclosurePage0_t enclosure_pg0; -+ u32 ioc_status; -+ u16 parent_handle; -+ u64 sas_address, sas_address_parent = 0; -+ int i; -+ unsigned long flags; -+ struct _sas_port *mpt2sas_port = NULL; -+ -+ int rc = 0; -+ -+ if (!handle) -+ return -1; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) -+ return -1; -+ -+ if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, -+ MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ /* handle out of order topology events */ -+ parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle); -+ if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent) -+ != 0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ if (sas_address_parent != ioc->sas_hba.sas_address) { -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, -+ sas_address_parent); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ if (!sas_expander) { -+ rc = _scsih_expander_add(ioc, parent_handle); -+ if (rc != 0) -+ return rc; -+ } -+ } -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_address = le64_to_cpu(expander_pg0.SASAddress); -+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, -+ sas_address); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ if (sas_expander) -+ return 0; -+ -+ sas_expander = kzalloc(sizeof(struct _sas_node), -+ GFP_KERNEL); -+ if (!sas_expander) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ sas_expander->handle = handle; -+ sas_expander->num_phys = expander_pg0.NumPhys; -+ sas_expander->sas_address_parent = sas_address_parent; -+ sas_expander->sas_address = sas_address; -+ -+ pr_info(MPT3SAS_FMT "expander_add: handle(0x%04x)," \ -+ " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name, -+ handle, parent_handle, (unsigned long long) -+ sas_expander->sas_address, sas_expander->num_phys); -+ -+ if (!sas_expander->num_phys) -+ goto out_fail; -+ sas_expander->phy = kcalloc(sas_expander->num_phys, -+ sizeof(struct _sas_phy), GFP_KERNEL); -+ if (!sas_expander->phy) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -1; -+ goto out_fail; -+ } -+ -+ INIT_LIST_HEAD(&sas_expander->sas_port_list); -+ mpt2sas_port = mpt2sas_transport_port_add(ioc, handle, -+ sas_address_parent); -+ if (!mpt2sas_port) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -1; -+ goto out_fail; -+ } -+ sas_expander->parent_dev = &mpt2sas_port->rphy->dev; -+ -+ for (i = 0 ; i < sas_expander->num_phys ; i++) { -+ if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, -+ &expander_pg1, i, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -1; -+ goto out_fail; -+ } -+ sas_expander->phy[i].handle = handle; -+ sas_expander->phy[i].phy_id = i; -+ -+ if ((mpt2sas_transport_add_expander_phy(ioc, -+ &sas_expander->phy[i], expander_pg1, -+ sas_expander->parent_dev))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -1; -+ goto out_fail; -+ } -+ } -+ -+ if (sas_expander->enclosure_handle) { -+ if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, -+ &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, -+ sas_expander->enclosure_handle))) -+ sas_expander->enclosure_logical_id = -+ le64_to_cpu(enclosure_pg0.EnclosureLogicalID); -+ } -+ -+ _scsih_expander_node_add(ioc, sas_expander); -+ return 0; -+ -+ out_fail: -+ -+ if (mpt2sas_port) -+ mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, -+ sas_address_parent); -+ kfree(sas_expander); -+ return rc; -+} -+ -+/** -+ * mpt2sas_expander_remove - removing expander object -+ * @ioc: per adapter object -+ * @sas_address: expander sas_address -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) -+{ -+ struct _sas_node *sas_expander; -+ unsigned long flags; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, -+ sas_address); -+ if (sas_expander) -+ list_del(&sas_expander->list); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ if (sas_expander) -+ _scsih_expander_node_remove(ioc, sas_expander); -+} -+ -+/** -+ * _scsih_done - internal SCSI_IO callback handler. -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Callback handler when sending internal generated SCSI_IO. -+ * The callback index passed is `ioc->scsih_cb_idx` -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+static u8 -+_scsih_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (ioc->scsih_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->scsih_cmds.smid != smid) -+ return 1; -+ ioc->scsih_cmds.status |= MPT3_CMD_COMPLETE; -+ if (mpi_reply) { -+ memcpy(ioc->scsih_cmds.reply, mpi_reply, -+ mpi_reply->MsgLength*4); -+ ioc->scsih_cmds.status |= MPT3_CMD_REPLY_VALID; -+ } -+ ioc->scsih_cmds.status &= ~MPT3_CMD_PENDING; -+ complete(&ioc->scsih_cmds.done); -+ return 1; -+} -+ -+ -+ -+ -+#define MPT3_MAX_LUNS (255) -+ -+ -+/** -+ * _scsih_check_access_status - check access flags -+ * @ioc: per adapter object -+ * @sas_address: sas address -+ * @handle: sas device handle -+ * @access_flags: errors returned during discovery of the device -+ * -+ * Return 0 for success, else failure -+ */ -+static u8 -+_scsih_check_access_status(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, -+ u16 handle, u8 access_status) -+{ -+ u8 rc = 1; -+ char *desc = NULL; -+ -+ switch (access_status) { -+ case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: -+ case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: -+ rc = 0; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: -+ desc = "sata capability failed"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: -+ desc = "sata affiliation conflict"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: -+ desc = "route not addressable"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: -+ desc = "smp error not addressable"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: -+ desc = "device blocked"; -+ break; -+ case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: -+ case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: -+ desc = "sata initialization failed"; -+ break; -+ default: -+ desc = "unknown"; -+ break; -+ } -+ -+ if (!rc) -+ return 0; -+ -+ pr_err(MPT3SAS_FMT -+ "discovery errors(%s): sas_address(0x%016llx), handle(0x%04x)\n", -+ ioc->name, desc, (unsigned long long)sas_address, handle); -+ return rc; -+} -+ -+/** -+ * _scsih_check_device - checking device responsiveness -+ * @ioc: per adapter object -+ * @parent_sas_address: sas address of parent expander or sas host -+ * @handle: attached device handle -+ * @phy_numberv: phy number -+ * @link_rate: new link rate -+ * -+ * Returns nothing. -+ */ -+static void -+_scsih_check_device(struct MPT3SAS_ADAPTER *ioc, -+ u64 parent_sas_address, u16 handle, u8 phy_number, u8 link_rate) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ struct _sas_device *sas_device; -+ u32 ioc_status; -+ unsigned long flags; -+ u64 sas_address; -+ struct scsi_target *starget; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ u32 device_info; -+ -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) -+ return; -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ return; -+ -+ /* wide port handling ~ we need only handle device once for the phy that -+ * is matched in sas device page zero -+ */ -+ if (phy_number != sas_device_pg0.PhyNum) -+ return; -+ -+ /* check if this is end device */ -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ if (!(_scsih_is_end_device(device_info))) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_address); -+ -+ if (!sas_device) -+ goto out_unlock; -+ -+ if (unlikely(sas_device->handle != handle)) { -+ starget = sas_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ starget_printk(KERN_INFO, starget, -+ "handle changed from(0x%04x) to (0x%04x)!!!\n", -+ sas_device->handle, handle); -+ sas_target_priv_data->handle = handle; -+ sas_device->handle = handle; -+ if (sas_device_pg0.Flags & -+ MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { -+ sas_device->enclosure_level = -+ le16_to_cpu(sas_device_pg0.EnclosureLevel); -+ memcpy(&sas_device->connector_name[0], -+ &sas_device_pg0.ConnectorName[0], 4); -+ } else { -+ sas_device->enclosure_level = 0; -+ sas_device->connector_name[0] = '\0'; -+ } -+ } -+ -+ /* check if device is present */ -+ if (!(le16_to_cpu(sas_device_pg0.Flags) & -+ MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { -+ pr_err(MPT3SAS_FMT -+ "device is not present handle(0x%04x), flags!!!\n", -+ ioc->name, handle); -+ goto out_unlock; -+ } -+ -+ /* check if there were any issues with discovery */ -+ if (_scsih_check_access_status(ioc, sas_address, handle, -+ sas_device_pg0.AccessStatus)) -+ goto out_unlock; -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ _scsih_ublock_io_device(ioc, sas_address); -+ -+ if (sas_device) -+ sas_device_put(sas_device); -+ return; -+ -+out_unlock: -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (sas_device) -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_add_device - creating sas device object -+ * @ioc: per adapter object -+ * @handle: sas device handle -+ * @phy_num: phy number end device attached to -+ * @is_pd: is this hidden raid component -+ * -+ * Creating end device object, stored in ioc->sas_device_list. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, -+ u8 is_pd) -+{ -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2SasEnclosurePage0_t enclosure_pg0; -+ struct _sas_device *sas_device; -+ u32 ioc_status; -+ u64 sas_address; -+ u32 device_info; -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ -+ /* check if this is end device */ -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ if (!(_scsih_is_end_device(device_info))) -+ return -1; -+ sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ -+ /* check if device is present */ -+ if (!(le16_to_cpu(sas_device_pg0.Flags) & -+ MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { -+ pr_err(MPT3SAS_FMT "device is not present handle(0x04%x)!!!\n", -+ ioc->name, handle); -+ return -1; -+ } -+ -+ /* check if there were any issues with discovery */ -+ if (_scsih_check_access_status(ioc, sas_address, handle, -+ sas_device_pg0.AccessStatus)) -+ return -1; -+ -+ sas_device = mpt2sas_get_sdev_by_addr(ioc, -+ sas_address); -+ if (sas_device) { -+ sas_device_put(sas_device); -+ return -1; -+ } -+ -+ sas_device = kzalloc(sizeof(struct _sas_device), -+ GFP_KERNEL); -+ if (!sas_device) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 0; -+ } -+ -+ kref_init(&sas_device->refcount); -+ sas_device->handle = handle; -+ if (_scsih_get_sas_address(ioc, -+ le16_to_cpu(sas_device_pg0.ParentDevHandle), -+ &sas_device->sas_address_parent) != 0) -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_device->enclosure_handle = -+ le16_to_cpu(sas_device_pg0.EnclosureHandle); -+ if (sas_device->enclosure_handle != 0) -+ sas_device->slot = -+ le16_to_cpu(sas_device_pg0.Slot); -+ sas_device->device_info = device_info; -+ sas_device->sas_address = sas_address; -+ sas_device->phy = sas_device_pg0.PhyNum; -+ sas_device->fast_path = (le16_to_cpu(sas_device_pg0.Flags) & -+ MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0; -+ -+ if (sas_device_pg0.Flags & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { -+ sas_device->enclosure_level = -+ le16_to_cpu(sas_device_pg0.EnclosureLevel); -+ memcpy(&sas_device->connector_name[0], -+ &sas_device_pg0.ConnectorName[0], 4); -+ } else { -+ sas_device->enclosure_level = 0; -+ sas_device->connector_name[0] = '\0'; -+ } -+ /* get enclosure_logical_id */ -+ if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0( -+ ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, -+ sas_device->enclosure_handle))) -+ sas_device->enclosure_logical_id = -+ le64_to_cpu(enclosure_pg0.EnclosureLogicalID); -+ -+ /* get device name */ -+ sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); -+ -+ if (ioc->wait_for_discovery_to_complete) -+ _scsih_sas_device_init_add(ioc, sas_device); -+ else -+ _scsih_sas_device_add(ioc, sas_device); -+ -+ sas_device_put(sas_device); -+ return 0; -+} -+ -+/** -+ * _scsih_remove_device - removing sas device object -+ * @ioc: per adapter object -+ * @sas_device_delete: the sas_device object -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ -+ if ((ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) && -+ (sas_device->pfa_led_on)) { -+ _scsih_turn_off_pfa_led(ioc, sas_device); -+ sas_device->pfa_led_on = 0; -+ } -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, __func__, -+ sas_device->handle, (unsigned long long) -+ sas_device->sas_address)); -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_device->enclosure_logical_id, -+ sas_device->slot)); -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter: enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, __func__, -+ sas_device->enclosure_level, -+ sas_device->connector_name)); -+ -+ if (sas_device->starget && sas_device->starget->hostdata) { -+ sas_target_priv_data = sas_device->starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ _scsih_ublock_io_device(ioc, sas_device->sas_address); -+ sas_target_priv_data->handle = -+ MPT3SAS_INVALID_DEVICE_HANDLE; -+ } -+ -+ if (!ioc->hide_drives) -+ mpt2sas_transport_port_remove(ioc, -+ sas_device->sas_address, -+ sas_device->sas_address_parent); -+ -+ pr_info(MPT3SAS_FMT -+ "removing handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, sas_device->handle, -+ (unsigned long long) sas_device->sas_address); -+ if (sas_device->enclosure_handle != 0) -+ pr_info(MPT3SAS_FMT -+ "removing : enclosure logical id(0x%016llx), slot(%d)\n", -+ ioc->name, -+ (unsigned long long)sas_device->enclosure_logical_id, -+ sas_device->slot); -+ if (sas_device->connector_name[0] != '\0') -+ pr_info(MPT3SAS_FMT -+ "removing enclosure level(0x%04x), connector name( %s)\n", -+ ioc->name, sas_device->enclosure_level, -+ sas_device->connector_name); -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, __func__, -+ sas_device->handle, (unsigned long long) -+ sas_device->sas_address)); -+ if (sas_device->enclosure_handle != 0) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n", -+ ioc->name, __func__, -+ (unsigned long long)sas_device->enclosure_logical_id, -+ sas_device->slot)); -+ if (sas_device->connector_name[0] != '\0') -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: exit: enclosure level(0x%04x), connector name(%s)\n", -+ ioc->name, __func__, sas_device->enclosure_level, -+ sas_device->connector_name)); -+} -+ -+/** -+ * _scsih_sas_topology_change_event_debug - debug for topology event -+ * @ioc: per adapter object -+ * @event_data: event data payload -+ * Context: user. -+ */ -+static void -+_scsih_sas_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasTopologyChangeList_t *event_data) -+{ -+ int i; -+ u16 handle; -+ u16 reason_code; -+ u8 phy_number; -+ char *status_str = NULL; -+ u8 link_rate, prev_link_rate; -+ -+ switch (event_data->ExpStatus) { -+ case MPI2_EVENT_SAS_TOPO_ES_ADDED: -+ status_str = "add"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING: -+ status_str = "remove"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_ES_RESPONDING: -+ case 0: -+ status_str = "responding"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: -+ status_str = "remove delay"; -+ break; -+ default: -+ status_str = "unknown status"; -+ break; -+ } -+ pr_info(MPT3SAS_FMT "sas topology change: (%s)\n", -+ ioc->name, status_str); -+ pr_info("\thandle(0x%04x), enclosure_handle(0x%04x) " \ -+ "start_phy(%02d), count(%d)\n", -+ le16_to_cpu(event_data->ExpanderDevHandle), -+ le16_to_cpu(event_data->EnclosureHandle), -+ event_data->StartPhyNum, event_data->NumEntries); -+ for (i = 0; i < event_data->NumEntries; i++) { -+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); -+ if (!handle) -+ continue; -+ phy_number = event_data->StartPhyNum + i; -+ reason_code = event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_RC_MASK; -+ switch (reason_code) { -+ case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: -+ status_str = "target add"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: -+ status_str = "target remove"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: -+ status_str = "delay target remove"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: -+ status_str = "link rate change"; -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: -+ status_str = "target responding"; -+ break; -+ default: -+ status_str = "unknown"; -+ break; -+ } -+ link_rate = event_data->PHY[i].LinkRate >> 4; -+ prev_link_rate = event_data->PHY[i].LinkRate & 0xF; -+ pr_info("\tphy(%02d), attached_handle(0x%04x): %s:" \ -+ " link rate: new(0x%02x), old(0x%02x)\n", phy_number, -+ handle, status_str, link_rate, prev_link_rate); -+ -+ } -+} -+ -+/** -+ * _scsih_sas_topology_change_event - handle topology changes -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ */ -+static int -+_scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ int i; -+ u16 parent_handle, handle; -+ u16 reason_code; -+ u8 phy_number, max_phys; -+ struct _sas_node *sas_expander; -+ u64 sas_address; -+ unsigned long flags; -+ u8 link_rate, prev_link_rate; -+ Mpi2EventDataSasTopologyChangeList_t *event_data = -+ (Mpi2EventDataSasTopologyChangeList_t *) -+ fw_event->event_data; -+ -+ if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) -+ _scsih_sas_topology_change_event_debug(ioc, event_data); -+ -+ if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) -+ return 0; -+ -+ if (!ioc->sas_hba.num_phys) -+ _scsih_sas_host_add(ioc); -+ else -+ _scsih_sas_host_refresh(ioc); -+ -+ if (fw_event->ignore) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "ignoring expander event\n", ioc->name)); -+ return 0; -+ } -+ -+ parent_handle = le16_to_cpu(event_data->ExpanderDevHandle); -+ -+ /* handle expander add */ -+ if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) -+ if (_scsih_expander_add(ioc, parent_handle) != 0) -+ return 0; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, -+ parent_handle); -+ if (sas_expander) { -+ sas_address = sas_expander->sas_address; -+ max_phys = sas_expander->num_phys; -+ } else if (parent_handle < ioc->sas_hba.num_phys) { -+ sas_address = ioc->sas_hba.sas_address; -+ max_phys = ioc->sas_hba.num_phys; -+ } else { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return 0; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ /* handle siblings events */ -+ for (i = 0; i < event_data->NumEntries; i++) { -+ if (fw_event->ignore) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "ignoring expander event\n", ioc->name)); -+ return 0; -+ } -+ if (ioc->remove_host || ioc->pci_error_recovery) -+ return 0; -+ phy_number = event_data->StartPhyNum + i; -+ if (phy_number >= max_phys) -+ continue; -+ reason_code = event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_RC_MASK; -+ if ((event_data->PHY[i].PhyStatus & -+ MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != -+ MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) -+ continue; -+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); -+ if (!handle) -+ continue; -+ link_rate = event_data->PHY[i].LinkRate >> 4; -+ prev_link_rate = event_data->PHY[i].LinkRate & 0xF; -+ switch (reason_code) { -+ case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: -+ -+ if (ioc->shost_recovery) -+ break; -+ -+ if (link_rate == prev_link_rate) -+ break; -+ -+ mpt2sas_transport_update_links(ioc, sas_address, -+ handle, phy_number, link_rate); -+ -+ if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) -+ break; -+ -+ _scsih_check_device(ioc, sas_address, handle, -+ phy_number, link_rate); -+ -+ -+ case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: -+ -+ if (ioc->shost_recovery) -+ break; -+ -+ mpt2sas_transport_update_links(ioc, sas_address, -+ handle, phy_number, link_rate); -+ -+ _scsih_add_device(ioc, handle, phy_number, 0); -+ -+ break; -+ case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: -+ -+ _scsih_device_remove_by_handle(ioc, handle); -+ break; -+ } -+ } -+ -+ /* handle expander removal */ -+ if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && -+ sas_expander) -+ mpt2sas_expander_remove(ioc, sas_address); -+ -+ return 0; -+} -+ -+/** -+ * _scsih_sas_device_status_change_event_debug - debug for device event -+ * @event_data: event data payload -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasDeviceStatusChange_t *event_data) -+{ -+ char *reason_str = NULL; -+ -+ switch (event_data->ReasonCode) { -+ case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA: -+ reason_str = "smart data"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: -+ reason_str = "unsupported device discovered"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: -+ reason_str = "internal device reset"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: -+ reason_str = "internal task abort"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: -+ reason_str = "internal task abort set"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: -+ reason_str = "internal clear task set"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: -+ reason_str = "internal query task"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE: -+ reason_str = "sata init failure"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET: -+ reason_str = "internal device reset complete"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL: -+ reason_str = "internal task abort complete"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: -+ reason_str = "internal async notification"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY: -+ reason_str = "expander reduced functionality"; -+ break; -+ case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY: -+ reason_str = "expander reduced functionality complete"; -+ break; -+ default: -+ reason_str = "unknown reason"; -+ break; -+ } -+ pr_info(MPT3SAS_FMT "device status change: (%s)\n" -+ "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", -+ ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), -+ (unsigned long long)le64_to_cpu(event_data->SASAddress), -+ le16_to_cpu(event_data->TaskTag)); -+ if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) -+ pr_info(MPT3SAS_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, -+ event_data->ASC, event_data->ASCQ); -+ pr_info("\n"); -+} -+ -+/** -+ * _scsih_sas_device_status_change_event - handle device status change -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ struct MPT3SAS_TARGET *target_priv_data; -+ struct _sas_device *sas_device; -+ u64 sas_address; -+ unsigned long flags; -+ Mpi2EventDataSasDeviceStatusChange_t *event_data = -+ (Mpi2EventDataSasDeviceStatusChange_t *) -+ fw_event->event_data; -+ -+ if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) -+ _scsih_sas_device_status_change_event_debug(ioc, -+ event_data); -+ -+ /* In MPI Revision K (0xC), the internal device reset complete was -+ * implemented, so avoid setting tm_busy flag for older firmware. -+ */ -+ if ((ioc->facts.HeaderVersion >> 8) < 0xC) -+ return; -+ -+ if (event_data->ReasonCode != -+ MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && -+ event_data->ReasonCode != -+ MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_address = le64_to_cpu(event_data->SASAddress); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ sas_address); -+ -+ if (!sas_device || !sas_device->starget) -+ goto out; -+ -+ target_priv_data = sas_device->starget->hostdata; -+ if (!target_priv_data) -+ goto out; -+ -+ if (event_data->ReasonCode == -+ MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) -+ target_priv_data->tm_busy = 1; -+ else -+ target_priv_data->tm_busy = 0; -+ -+out: -+ if (sas_device) -+ sas_device_put(sas_device); -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+} -+ -+/** -+ * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure -+ * event -+ * @ioc: per adapter object -+ * @event_data: event data payload -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataSasEnclDevStatusChange_t *event_data) -+{ -+ char *reason_str = NULL; -+ -+ switch (event_data->ReasonCode) { -+ case MPI2_EVENT_SAS_ENCL_RC_ADDED: -+ reason_str = "enclosure add"; -+ break; -+ case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING: -+ reason_str = "enclosure remove"; -+ break; -+ default: -+ reason_str = "unknown reason"; -+ break; -+ } -+ -+ pr_info(MPT3SAS_FMT "enclosure status change: (%s)\n" -+ "\thandle(0x%04x), enclosure logical id(0x%016llx)" -+ " number slots(%d)\n", ioc->name, reason_str, -+ le16_to_cpu(event_data->EnclosureHandle), -+ (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID), -+ le16_to_cpu(event_data->StartSlot)); -+} -+ -+/** -+ * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) -+ _scsih_sas_enclosure_dev_status_change_event_debug(ioc, -+ (Mpi2EventDataSasEnclDevStatusChange_t *) -+ fw_event->event_data); -+} -+ -+/** -+ * _scsih_sas_broadcast_primitive_event - handle broadcast events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ struct scsi_cmnd *scmd; -+ struct scsi_device *sdev; -+ u16 smid, handle; -+ u32 lun; -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ u32 termination_count; -+ u32 query_count; -+ Mpi2SCSITaskManagementReply_t *mpi_reply; -+ Mpi2EventDataSasBroadcastPrimitive_t *event_data = -+ (Mpi2EventDataSasBroadcastPrimitive_t *) -+ fw_event->event_data; -+ u16 ioc_status; -+ unsigned long flags; -+ int r; -+ u8 max_retries = 0; -+ u8 task_abort_retries; -+ -+ mutex_lock(&ioc->tm_cmds.mutex); -+ pr_info(MPT3SAS_FMT -+ "%s: enter: phy number(%d), width(%d)\n", -+ ioc->name, __func__, event_data->PhyNum, -+ event_data->PortWidth); -+ -+ _scsih_block_io_all_device(ioc); -+ -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ mpi_reply = ioc->tm_cmds.reply; -+ broadcast_aen_retry: -+ -+ /* sanity checks for retrying this loop */ -+ if (max_retries++ == 5) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: giving up\n", -+ ioc->name, __func__)); -+ goto out; -+ } else if (max_retries > 1) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: %d retry\n", -+ ioc->name, __func__, max_retries - 1)); -+ -+ termination_count = 0; -+ query_count = 0; -+ for (smid = 1; smid <= ioc->scsiio_depth; smid++) { -+ if (ioc->shost_recovery) -+ goto out; -+ scmd = _scsih_scsi_lookup_get(ioc, smid); -+ if (!scmd) -+ continue; -+ sdev = scmd->device; -+ sas_device_priv_data = sdev->hostdata; -+ if (!sas_device_priv_data || !sas_device_priv_data->sas_target) -+ continue; -+ /* skip hidden raid components */ -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_RAID_COMPONENT) -+ continue; -+ /* skip volumes */ -+ if (sas_device_priv_data->sas_target->flags & -+ MPT_TARGET_FLAGS_VOLUME) -+ continue; -+ -+ handle = sas_device_priv_data->sas_target->handle; -+ lun = sas_device_priv_data->lun; -+ query_count++; -+ -+ if (ioc->shost_recovery) -+ goto out; -+ -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, -+ MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, -+ TM_MUTEX_OFF); -+ if (r == FAILED) { -+ sdev_printk(KERN_WARNING, sdev, -+ "mpt2sas_scsih_issue_tm: FAILED when sending " -+ "QUERY_TASK: scmd(%p)\n", scmd); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ goto broadcast_aen_retry; -+ } -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus) -+ & MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ sdev_printk(KERN_WARNING, sdev, -+ "query task: FAILED with IOCSTATUS(0x%04x), scmd(%p)\n", -+ ioc_status, scmd); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ goto broadcast_aen_retry; -+ } -+ -+ /* see if IO is still owned by IOC and target */ -+ if (mpi_reply->ResponseCode == -+ MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || -+ mpi_reply->ResponseCode == -+ MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) { -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ continue; -+ } -+ task_abort_retries = 0; -+ tm_retry: -+ if (task_abort_retries++ == 60) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: ABORT_TASK: giving up\n", ioc->name, -+ __func__)); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ goto broadcast_aen_retry; -+ } -+ -+ if (ioc->shost_recovery) -+ goto out_no_lock; -+ -+ r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, -+ sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, -+ TM_MUTEX_OFF); -+ if (r == FAILED) { -+ sdev_printk(KERN_WARNING, sdev, -+ "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : " -+ "scmd(%p)\n", scmd); -+ goto tm_retry; -+ } -+ -+ if (task_abort_retries > 1) -+ sdev_printk(KERN_WARNING, sdev, -+ "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):" -+ " scmd(%p)\n", -+ task_abort_retries - 1, scmd); -+ -+ termination_count += le32_to_cpu(mpi_reply->TerminationCount); -+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -+ } -+ -+ if (ioc->broadcast_aen_pending) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: loop back due to pending AEN\n", -+ ioc->name, __func__)); -+ ioc->broadcast_aen_pending = 0; -+ goto broadcast_aen_retry; -+ } -+ -+ out: -+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -+ out_no_lock: -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - exit, query_count = %d termination_count = %d\n", -+ ioc->name, __func__, query_count, termination_count)); -+ -+ ioc->broadcast_aen_busy = 0; -+ if (!ioc->shost_recovery) -+ _scsih_ublock_io_all_device(ioc); -+ mutex_unlock(&ioc->tm_cmds.mutex); -+} -+ -+/** -+ * _scsih_sas_discovery_event - handle discovery events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ Mpi2EventDataSasDiscovery_t *event_data = -+ (Mpi2EventDataSasDiscovery_t *) fw_event->event_data; -+ -+ if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { -+ pr_info(MPT3SAS_FMT "discovery event: (%s)", ioc->name, -+ (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? -+ "start" : "stop"); -+ if (event_data->DiscoveryStatus) -+ pr_info("discovery_status(0x%08x)", -+ le32_to_cpu(event_data->DiscoveryStatus)); -+ pr_info("\n"); -+ } -+ -+ if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && -+ !ioc->sas_hba.num_phys) { -+ if (disable_discovery > 0 && ioc->shost_recovery) { -+ /* Wait for the reset to complete */ -+ while (ioc->shost_recovery) -+ ssleep(1); -+ } -+ _scsih_sas_host_add(ioc); -+ } -+} -+ -+/** -+ * _scsih_ir_fastpath - turn on fastpath for IR physdisk -+ * @ioc: per adapter object -+ * @handle: device handle for physical disk -+ * @phys_disk_num: physical disk number -+ * -+ * Return 0 for success, else failure. -+ */ -+static int -+_scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) -+{ -+ Mpi2RaidActionRequest_t *mpi_request; -+ Mpi2RaidActionReply_t *mpi_reply; -+ u16 smid; -+ u8 issue_reset = 0; -+ int rc = 0; -+ u16 ioc_status; -+ u32 log_info; -+ -+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION) -+ return rc; -+ -+ mutex_lock(&ioc->scsih_cmds.mutex); -+ -+ if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: scsih_cmd in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->scsih_cmds.status = MPT3_CMD_PENDING; -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->scsih_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); -+ -+ mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; -+ mpi_request->Action = MPI2_RAID_ACTION_PHYSDISK_HIDDEN; -+ mpi_request->PhysDiskNum = phys_disk_num; -+ -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT "IR RAID_ACTION: turning fast "\ -+ "path on for handle(0x%04x), phys_disk_num (0x%02x)\n", ioc->name, -+ handle, phys_disk_num)); -+ -+ init_completion(&ioc->scsih_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); -+ -+ if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ if (!(ioc->scsih_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { -+ -+ mpi_reply = ioc->scsih_cmds.reply; -+ ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -+ if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) -+ log_info = le32_to_cpu(mpi_reply->IOCLogInfo); -+ else -+ log_info = 0; -+ ioc_status &= MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "IR RAID_ACTION: failed: ioc_status(0x%04x), " -+ "loginfo(0x%08x)!!!\n", ioc->name, ioc_status, -+ log_info)); -+ rc = -EFAULT; -+ } else -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "IR RAID_ACTION: completed successfully\n", -+ ioc->name)); -+ } -+ -+ out: -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_unlock(&ioc->scsih_cmds.mutex); -+ -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ return rc; -+} -+ -+/** -+ * _scsih_reprobe_lun - reprobing lun -+ * @sdev: scsi device struct -+ * @no_uld_attach: sdev->no_uld_attach flag setting -+ * -+ **/ -+static void -+_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach) -+{ -+ int rc; -+ sdev->no_uld_attach = no_uld_attach ? 1 : 0; -+ sdev_printk(KERN_INFO, sdev, "%s raid component\n", -+ sdev->no_uld_attach ? "hidding" : "exposing"); -+ rc = scsi_device_reprobe(sdev); -+} -+ -+/** -+ * _scsih_sas_volume_add - add new volume -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_volume_add(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ u64 wwid; -+ u16 handle = le16_to_cpu(element->VolDevHandle); -+ int rc; -+ -+ mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); -+ if (!wwid) { -+ pr_err(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ -+ if (raid_device) -+ return; -+ -+ raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); -+ if (!raid_device) { -+ pr_err(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ raid_device->id = ioc->sas_id++; -+ raid_device->channel = RAID_CHANNEL; -+ raid_device->handle = handle; -+ raid_device->wwid = wwid; -+ _scsih_raid_device_add(ioc, raid_device); -+ if (!ioc->wait_for_discovery_to_complete) { -+ rc = scsi_add_device(ioc->shost, RAID_CHANNEL, -+ raid_device->id, 0); -+ if (rc) -+ _scsih_raid_device_remove(ioc, raid_device); -+ } else { -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ _scsih_determine_boot_device(ioc, raid_device, 1); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ } -+} -+ -+/** -+ * _scsih_sas_volume_delete - delete volume -+ * @ioc: per adapter object -+ * @handle: volume device handle -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle) -+{ -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct scsi_target *starget = NULL; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ if (raid_device) { -+ if (raid_device->starget) { -+ starget = raid_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ } -+ pr_info(MPT3SAS_FMT "removing handle(0x%04x), wwid(0x%016llx)\n", -+ ioc->name, raid_device->handle, -+ (unsigned long long) raid_device->wwid); -+ list_del(&raid_device->list); -+ kfree(raid_device); -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ if (starget) -+ scsi_remove_target(&starget->dev); -+} -+ -+/** -+ * _scsih_sas_pd_expose - expose pd component to /dev/sdX -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ struct _sas_device *sas_device; -+ struct scsi_target *starget = NULL; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ unsigned long flags; -+ u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ sas_device->volume_handle = 0; -+ sas_device->volume_wwid = 0; -+ clear_bit(handle, ioc->pd_handles); -+ if (sas_device->starget && sas_device->starget->hostdata) { -+ starget = sas_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->flags &= -+ ~MPT_TARGET_FLAGS_RAID_COMPONENT; -+ } -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (!sas_device) -+ return; -+ -+ /* exposing raid component */ -+ if (starget) -+ starget_for_each_device(starget, NULL, _scsih_reprobe_lun); -+ -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_sas_pd_hide - hide pd component from /dev/sdX -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ struct _sas_device *sas_device; -+ struct scsi_target *starget = NULL; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ unsigned long flags; -+ u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -+ u16 volume_handle = 0; -+ u64 volume_wwid = 0; -+ -+ mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle); -+ if (volume_handle) -+ mpt2sas_config_get_volume_wwid(ioc, volume_handle, -+ &volume_wwid); -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ set_bit(handle, ioc->pd_handles); -+ if (sas_device->starget && sas_device->starget->hostdata) { -+ starget = sas_device->starget; -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->flags |= -+ MPT_TARGET_FLAGS_RAID_COMPONENT; -+ sas_device->volume_handle = volume_handle; -+ sas_device->volume_wwid = volume_wwid; -+ } -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ if (!sas_device) -+ return; -+ -+ /* hiding raid component */ -+ _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); -+ -+ if (starget) -+ starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); -+ -+ sas_device_put(sas_device); -+} -+ -+/** -+ * _scsih_sas_pd_delete - delete pd component -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_pd_delete(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -+ -+ _scsih_device_remove_by_handle(ioc, handle); -+} -+ -+/** -+ * _scsih_sas_pd_add - remove pd component -+ * @ioc: per adapter object -+ * @element: IR config element data -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventIrConfigElement_t *element) -+{ -+ struct _sas_device *sas_device; -+ u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ u32 ioc_status; -+ u64 sas_address; -+ u16 parent_handle; -+ -+ set_bit(handle, ioc->pd_handles); -+ -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); -+ sas_device_put(sas_device); -+ return; -+ } -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); -+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) -+ mpt2sas_transport_update_links(ioc, sas_address, handle, -+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); -+ -+ _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); -+ _scsih_add_device(ioc, handle, 0, 1); -+} -+ -+/** -+ * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events -+ * @ioc: per adapter object -+ * @event_data: event data payload -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_config_change_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataIrConfigChangeList_t *event_data) -+{ -+ Mpi2EventIrConfigElement_t *element; -+ u8 element_type; -+ int i; -+ char *reason_str = NULL, *element_str = NULL; -+ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ -+ pr_info(MPT3SAS_FMT "raid config change: (%s), elements(%d)\n", -+ ioc->name, (le32_to_cpu(event_data->Flags) & -+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? -+ "foreign" : "native", event_data->NumElements); -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ switch (element->ReasonCode) { -+ case MPI2_EVENT_IR_CHANGE_RC_ADDED: -+ reason_str = "add"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_REMOVED: -+ reason_str = "remove"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE: -+ reason_str = "no change"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_HIDE: -+ reason_str = "hide"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: -+ reason_str = "unhide"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: -+ reason_str = "volume_created"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: -+ reason_str = "volume_deleted"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: -+ reason_str = "pd_created"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: -+ reason_str = "pd_deleted"; -+ break; -+ default: -+ reason_str = "unknown reason"; -+ break; -+ } -+ element_type = le16_to_cpu(element->ElementFlags) & -+ MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK; -+ switch (element_type) { -+ case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT: -+ element_str = "volume"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT: -+ element_str = "phys disk"; -+ break; -+ case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT: -+ element_str = "hot spare"; -+ break; -+ default: -+ element_str = "unknown element"; -+ break; -+ } -+ pr_info("\t(%s:%s), vol handle(0x%04x), " \ -+ "pd handle(0x%04x), pd num(0x%02x)\n", element_str, -+ reason_str, le16_to_cpu(element->VolDevHandle), -+ le16_to_cpu(element->PhysDiskDevHandle), -+ element->PhysDiskNum); -+ } -+} -+ -+/** -+ * _scsih_sas_ir_config_change_event - handle ir configuration change events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ Mpi2EventIrConfigElement_t *element; -+ int i; -+ u8 foreign_config; -+ Mpi2EventDataIrConfigChangeList_t *event_data = -+ (Mpi2EventDataIrConfigChangeList_t *) -+ fw_event->event_data; -+ -+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) && -+ (!ioc->hide_ir_msg)) -+ _scsih_sas_ir_config_change_event_debug(ioc, event_data); -+ -+ foreign_config = (le32_to_cpu(event_data->Flags) & -+ MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; -+ -+ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; -+ if (ioc->shost_recovery && -+ ioc->hba_mpi_version_belonged != MPI2_VERSION) { -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_HIDE) -+ _scsih_ir_fastpath(ioc, -+ le16_to_cpu(element->PhysDiskDevHandle), -+ element->PhysDiskNum); -+ } -+ return; -+ } -+ -+ for (i = 0; i < event_data->NumElements; i++, element++) { -+ -+ switch (element->ReasonCode) { -+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: -+ case MPI2_EVENT_IR_CHANGE_RC_ADDED: -+ if (!foreign_config) -+ _scsih_sas_volume_add(ioc, element); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: -+ case MPI2_EVENT_IR_CHANGE_RC_REMOVED: -+ if (!foreign_config) -+ _scsih_sas_volume_delete(ioc, -+ le16_to_cpu(element->VolDevHandle)); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: -+ if (!ioc->is_warpdrive) -+ _scsih_sas_pd_hide(ioc, element); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: -+ if (!ioc->is_warpdrive) -+ _scsih_sas_pd_expose(ioc, element); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_HIDE: -+ if (!ioc->is_warpdrive) -+ _scsih_sas_pd_add(ioc, element); -+ break; -+ case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: -+ if (!ioc->is_warpdrive) -+ _scsih_sas_pd_delete(ioc, element); -+ break; -+ } -+ } -+} -+ -+/** -+ * _scsih_sas_ir_volume_event - IR volume event -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ u64 wwid; -+ unsigned long flags; -+ struct _raid_device *raid_device; -+ u16 handle; -+ u32 state; -+ int rc; -+ Mpi2EventDataIrVolume_t *event_data = -+ (Mpi2EventDataIrVolume_t *) fw_event->event_data; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) -+ return; -+ -+ handle = le16_to_cpu(event_data->VolDevHandle); -+ state = le32_to_cpu(event_data->NewValue); -+ if (!ioc->hide_ir_msg) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", -+ ioc->name, __func__, handle, -+ le32_to_cpu(event_data->PreviousValue), state)); -+ switch (state) { -+ case MPI2_RAID_VOL_STATE_MISSING: -+ case MPI2_RAID_VOL_STATE_FAILED: -+ _scsih_sas_volume_delete(ioc, handle); -+ break; -+ -+ case MPI2_RAID_VOL_STATE_ONLINE: -+ case MPI2_RAID_VOL_STATE_DEGRADED: -+ case MPI2_RAID_VOL_STATE_OPTIMAL: -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ -+ if (raid_device) -+ break; -+ -+ mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); -+ if (!wwid) { -+ pr_err(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ break; -+ } -+ -+ raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); -+ if (!raid_device) { -+ pr_err(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", ioc->name, -+ __FILE__, __LINE__, __func__); -+ break; -+ } -+ -+ raid_device->id = ioc->sas_id++; -+ raid_device->channel = RAID_CHANNEL; -+ raid_device->handle = handle; -+ raid_device->wwid = wwid; -+ _scsih_raid_device_add(ioc, raid_device); -+ rc = scsi_add_device(ioc->shost, RAID_CHANNEL, -+ raid_device->id, 0); -+ if (rc) -+ _scsih_raid_device_remove(ioc, raid_device); -+ break; -+ -+ case MPI2_RAID_VOL_STATE_INITIALIZING: -+ default: -+ break; -+ } -+} -+ -+/** -+ * _scsih_sas_ir_physical_disk_event - PD event -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ u16 handle, parent_handle; -+ u32 state; -+ struct _sas_device *sas_device; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ u32 ioc_status; -+ Mpi2EventDataIrPhysicalDisk_t *event_data = -+ (Mpi2EventDataIrPhysicalDisk_t *) fw_event->event_data; -+ u64 sas_address; -+ -+ if (ioc->shost_recovery) -+ return; -+ -+ if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED) -+ return; -+ -+ handle = le16_to_cpu(event_data->PhysDiskDevHandle); -+ state = le32_to_cpu(event_data->NewValue); -+ -+ if (!ioc->hide_ir_msg) -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", -+ ioc->name, __func__, handle, -+ le32_to_cpu(event_data->PreviousValue), state)); -+ -+ switch (state) { -+ case MPI2_RAID_PD_STATE_ONLINE: -+ case MPI2_RAID_PD_STATE_DEGRADED: -+ case MPI2_RAID_PD_STATE_REBUILDING: -+ case MPI2_RAID_PD_STATE_OPTIMAL: -+ case MPI2_RAID_PD_STATE_HOT_SPARE: -+ -+ if (!ioc->is_warpdrive) -+ set_bit(handle, ioc->pd_handles); -+ -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ sas_device_put(sas_device); -+ return; -+ } -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, -+ handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); -+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) -+ mpt2sas_transport_update_links(ioc, sas_address, handle, -+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); -+ -+ _scsih_add_device(ioc, handle, 0, 1); -+ -+ break; -+ -+ case MPI2_RAID_PD_STATE_OFFLINE: -+ case MPI2_RAID_PD_STATE_NOT_CONFIGURED: -+ case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: -+ default: -+ break; -+ } -+} -+ -+/** -+ * _scsih_sas_ir_operation_status_event_debug - debug for IR op event -+ * @ioc: per adapter object -+ * @event_data: event data payload -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_operation_status_event_debug(struct MPT3SAS_ADAPTER *ioc, -+ Mpi2EventDataIrOperationStatus_t *event_data) -+{ -+ char *reason_str = NULL; -+ -+ switch (event_data->RAIDOperation) { -+ case MPI2_EVENT_IR_RAIDOP_RESYNC: -+ reason_str = "resync"; -+ break; -+ case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION: -+ reason_str = "online capacity expansion"; -+ break; -+ case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK: -+ reason_str = "consistency check"; -+ break; -+ case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT: -+ reason_str = "background init"; -+ break; -+ case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT: -+ reason_str = "make data consistent"; -+ break; -+ } -+ -+ if (!reason_str) -+ return; -+ -+ pr_info(MPT3SAS_FMT "raid operational status: (%s)" \ -+ "\thandle(0x%04x), percent complete(%d)\n", -+ ioc->name, reason_str, -+ le16_to_cpu(event_data->VolDevHandle), -+ event_data->PercentComplete); -+} -+ -+/** -+ * _scsih_sas_ir_operation_status_event - handle RAID operation events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_sas_ir_operation_status_event(struct MPT3SAS_ADAPTER *ioc, -+ struct fw_event_work *fw_event) -+{ -+ Mpi2EventDataIrOperationStatus_t *event_data = -+ (Mpi2EventDataIrOperationStatus_t *) -+ fw_event->event_data; -+ static struct _raid_device *raid_device; -+ unsigned long flags; -+ u16 handle; -+ -+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) && -+ (!ioc->hide_ir_msg)) -+ _scsih_sas_ir_operation_status_event_debug(ioc, -+ event_data); -+ -+ /* code added for raid transport support */ -+ if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ handle = le16_to_cpu(event_data->VolDevHandle); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ if (raid_device) -+ raid_device->percent_complete = -+ event_data->PercentComplete; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ } -+} -+ -+/** -+ * _scsih_prep_device_scan - initialize parameters prior to device scan -+ * @ioc: per adapter object -+ * -+ * Set the deleted flag prior to device scan. If the device is found during -+ * the scan, then we clear the deleted flag. -+ */ -+static void -+_scsih_prep_device_scan(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct MPT3SAS_DEVICE *sas_device_priv_data; -+ struct scsi_device *sdev; -+ -+ shost_for_each_device(sdev, ioc->shost) { -+ sas_device_priv_data = sdev->hostdata; -+ if (sas_device_priv_data && sas_device_priv_data->sas_target) -+ sas_device_priv_data->sas_target->deleted = 1; -+ } -+} -+ -+/** -+ * _scsih_mark_responding_sas_device - mark a sas_devices as responding -+ * @ioc: per adapter object -+ * @sas_device_pg0: SAS Device page 0 -+ * -+ * After host reset, find out whether devices are still responding. -+ * Used in _scsih_remove_unresponsive_sas_devices. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, -+Mpi2SasDevicePage0_t *sas_device_pg0) -+{ -+ struct MPT3SAS_TARGET *sas_target_priv_data = NULL; -+ struct scsi_target *starget; -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ list_for_each_entry(sas_device, &ioc->sas_device_list, list) { -+ if ((sas_device->sas_address == sas_device_pg0->SASAddress) && -+ (sas_device->slot == sas_device_pg0->Slot)) { -+ sas_device->responding = 1; -+ starget = sas_device->starget; -+ if (starget && starget->hostdata) { -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->tm_busy = 0; -+ sas_target_priv_data->deleted = 0; -+ } else -+ sas_target_priv_data = NULL; -+ if (starget) { -+ starget_printk(KERN_INFO, starget, -+ "handle(0x%04x), sas_addr(0x%016llx)\n", -+ sas_device_pg0->DevHandle, -+ (unsigned long long) -+ sas_device->sas_address); -+ -+ if (sas_device->enclosure_handle != 0) -+ starget_printk(KERN_INFO, starget, -+ "enclosure logical id(0x%016llx)," -+ " slot(%d)\n", -+ (unsigned long long) -+ sas_device->enclosure_logical_id, -+ sas_device->slot); -+ } -+ if (sas_device_pg0->Flags & -+ MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { -+ sas_device->enclosure_level = -+ le16_to_cpu(sas_device_pg0->EnclosureLevel); -+ memcpy(&sas_device->connector_name[0], -+ &sas_device_pg0->ConnectorName[0], 4); -+ } else { -+ sas_device->enclosure_level = 0; -+ sas_device->connector_name[0] = '\0'; -+ } -+ -+ if (sas_device->handle == sas_device_pg0->DevHandle) -+ goto out; -+ pr_info("\thandle changed from(0x%04x)!!!\n", -+ sas_device->handle); -+ sas_device->handle = sas_device_pg0->DevHandle; -+ if (sas_target_priv_data) -+ sas_target_priv_data->handle = -+ sas_device_pg0->DevHandle; -+ goto out; -+ } -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+} -+ -+/** -+ * _scsih_search_responding_sas_devices - -+ * @ioc: per adapter object -+ * -+ * After host reset, find out whether devices are still responding. -+ * If not remove. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u16 handle; -+ u32 device_info; -+ -+ pr_info(MPT3SAS_FMT "search for end-devices: start\n", ioc->name); -+ -+ if (list_empty(&ioc->sas_device_list)) -+ goto out; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, -+ handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ break; -+ handle = sas_device_pg0.DevHandle = -+ le16_to_cpu(sas_device_pg0.DevHandle); -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ if (!(_scsih_is_end_device(device_info))) -+ continue; -+ sas_device_pg0.SASAddress = -+ le64_to_cpu(sas_device_pg0.SASAddress); -+ sas_device_pg0.Slot = le16_to_cpu(sas_device_pg0.Slot); -+ _scsih_mark_responding_sas_device(ioc, &sas_device_pg0); -+ } -+ -+ out: -+ pr_info(MPT3SAS_FMT "search for end-devices: complete\n", -+ ioc->name); -+} -+ -+/** -+ * _scsih_mark_responding_raid_device - mark a raid_device as responding -+ * @ioc: per adapter object -+ * @wwid: world wide identifier for raid volume -+ * @handle: device handle -+ * -+ * After host reset, find out whether devices are still responding. -+ * Used in _scsih_remove_unresponsive_raid_devices. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid, -+ u16 handle) -+{ -+ struct MPT3SAS_TARGET *sas_target_priv_data = NULL; -+ struct scsi_target *starget; -+ struct _raid_device *raid_device; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ list_for_each_entry(raid_device, &ioc->raid_device_list, list) { -+ if (raid_device->wwid == wwid && raid_device->starget) { -+ starget = raid_device->starget; -+ if (starget && starget->hostdata) { -+ sas_target_priv_data = starget->hostdata; -+ sas_target_priv_data->deleted = 0; -+ } else -+ sas_target_priv_data = NULL; -+ raid_device->responding = 1; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ starget_printk(KERN_INFO, raid_device->starget, -+ "handle(0x%04x), wwid(0x%016llx)\n", handle, -+ (unsigned long long)raid_device->wwid); -+ -+ /* -+ * WARPDRIVE: The handles of the PDs might have changed -+ * across the host reset so re-initialize the -+ * required data for Direct IO -+ */ -+ mpt2sas_init_warpdrive_properties(ioc, raid_device); -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ if (raid_device->handle == handle) { -+ spin_unlock_irqrestore(&ioc->raid_device_lock, -+ flags); -+ return; -+ } -+ pr_info("\thandle changed from(0x%04x)!!!\n", -+ raid_device->handle); -+ raid_device->handle = handle; -+ if (sas_target_priv_data) -+ sas_target_priv_data->handle = handle; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ return; -+ } -+ } -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+} -+ -+/** -+ * _scsih_search_responding_raid_devices - -+ * @ioc: per adapter object -+ * -+ * After host reset, find out whether devices are still responding. -+ * If not remove. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2RaidVolPage1_t volume_pg1; -+ Mpi2RaidVolPage0_t volume_pg0; -+ Mpi2RaidPhysDiskPage0_t pd_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u16 handle; -+ u8 phys_disk_num; -+ -+ if (!ioc->ir_firmware) -+ return; -+ -+ pr_info(MPT3SAS_FMT "search for raid volumes: start\n", -+ ioc->name); -+ -+ if (list_empty(&ioc->raid_device_list)) -+ goto out; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ break; -+ handle = le16_to_cpu(volume_pg1.DevHandle); -+ -+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, -+ &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, -+ sizeof(Mpi2RaidVolPage0_t))) -+ continue; -+ -+ if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || -+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || -+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) -+ _scsih_mark_responding_raid_device(ioc, -+ le64_to_cpu(volume_pg1.WWID), handle); -+ } -+ -+ /* refresh the pd_handles */ -+ if (!ioc->is_warpdrive) { -+ phys_disk_num = 0xFF; -+ memset(ioc->pd_handles, 0, ioc->pd_handles_sz); -+ while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, -+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, -+ phys_disk_num))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ break; -+ phys_disk_num = pd_pg0.PhysDiskNum; -+ handle = le16_to_cpu(pd_pg0.DevHandle); -+ set_bit(handle, ioc->pd_handles); -+ } -+ } -+ out: -+ pr_info(MPT3SAS_FMT "search for responding raid volumes: complete\n", -+ ioc->name); -+} -+ -+/** -+ * _scsih_mark_responding_expander - mark a expander as responding -+ * @ioc: per adapter object -+ * @sas_address: sas address -+ * @handle: -+ * -+ * After host reset, find out whether devices are still responding. -+ * Used in _scsih_remove_unresponsive_expanders. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_mark_responding_expander(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, -+ u16 handle) -+{ -+ struct _sas_node *sas_expander; -+ unsigned long flags; -+ int i; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { -+ if (sas_expander->sas_address != sas_address) -+ continue; -+ sas_expander->responding = 1; -+ if (sas_expander->handle == handle) -+ goto out; -+ pr_info("\texpander(0x%016llx): handle changed" \ -+ " from(0x%04x) to (0x%04x)!!!\n", -+ (unsigned long long)sas_expander->sas_address, -+ sas_expander->handle, handle); -+ sas_expander->handle = handle; -+ for (i = 0 ; i < sas_expander->num_phys ; i++) -+ sas_expander->phy[i].handle = handle; -+ goto out; -+ } -+ out: -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+} -+ -+/** -+ * _scsih_search_responding_expanders - -+ * @ioc: per adapter object -+ * -+ * After host reset, find out whether devices are still responding. -+ * If not remove. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_search_responding_expanders(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2ExpanderPage0_t expander_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u64 sas_address; -+ u16 handle; -+ -+ pr_info(MPT3SAS_FMT "search for expanders: start\n", ioc->name); -+ -+ if (list_empty(&ioc->sas_expander_list)) -+ goto out; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, -+ MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) -+ break; -+ -+ handle = le16_to_cpu(expander_pg0.DevHandle); -+ sas_address = le64_to_cpu(expander_pg0.SASAddress); -+ pr_info("\texpander present: handle(0x%04x), sas_addr(0x%016llx)\n", -+ handle, -+ (unsigned long long)sas_address); -+ _scsih_mark_responding_expander(ioc, sas_address, handle); -+ } -+ -+ out: -+ pr_info(MPT3SAS_FMT "search for expanders: complete\n", ioc->name); -+} -+ -+/** -+ * _scsih_remove_unresponding_sas_devices - removing unresponding devices -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct _sas_device *sas_device, *sas_device_next; -+ struct _sas_node *sas_expander, *sas_expander_next; -+ struct _raid_device *raid_device, *raid_device_next; -+ struct list_head tmp_list; -+ unsigned long flags; -+ LIST_HEAD(head); -+ -+ pr_info(MPT3SAS_FMT "removing unresponding devices: start\n", -+ ioc->name); -+ -+ /* removing unresponding end devices */ -+ pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n", -+ ioc->name); -+ /* -+ * Iterate, pulling off devices marked as non-responding. We become the -+ * owner for the reference the list had on any object we prune. -+ */ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ list_for_each_entry_safe(sas_device, sas_device_next, -+ &ioc->sas_device_list, list) { -+ if (!sas_device->responding) -+ list_move_tail(&sas_device->list, &head); -+ else -+ sas_device->responding = 0; -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ /* -+ * Now, uninitialize and remove the unresponding devices we pruned. -+ */ -+ list_for_each_entry_safe(sas_device, sas_device_next, &head, list) { -+ _scsih_remove_device(ioc, sas_device); -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ -+ /* removing unresponding volumes */ -+ if (ioc->ir_firmware) { -+ pr_info(MPT3SAS_FMT "removing unresponding devices: volumes\n", -+ ioc->name); -+ list_for_each_entry_safe(raid_device, raid_device_next, -+ &ioc->raid_device_list, list) { -+ if (!raid_device->responding) -+ _scsih_sas_volume_delete(ioc, -+ raid_device->handle); -+ else -+ raid_device->responding = 0; -+ } -+ } -+ -+ /* removing unresponding expanders */ -+ pr_info(MPT3SAS_FMT "removing unresponding devices: expanders\n", -+ ioc->name); -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ INIT_LIST_HEAD(&tmp_list); -+ list_for_each_entry_safe(sas_expander, sas_expander_next, -+ &ioc->sas_expander_list, list) { -+ if (!sas_expander->responding) -+ list_move_tail(&sas_expander->list, &tmp_list); -+ else -+ sas_expander->responding = 0; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list, -+ list) { -+ list_del(&sas_expander->list); -+ _scsih_expander_node_remove(ioc, sas_expander); -+ } -+ -+ pr_info(MPT3SAS_FMT "removing unresponding devices: complete\n", -+ ioc->name); -+ -+ /* unblock devices */ -+ _scsih_ublock_io_all_device(ioc); -+} -+ -+static void -+_scsih_refresh_expander_links(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander, u16 handle) -+{ -+ Mpi2ExpanderPage1_t expander_pg1; -+ Mpi2ConfigReply_t mpi_reply; -+ int i; -+ -+ for (i = 0 ; i < sas_expander->num_phys ; i++) { -+ if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, -+ &expander_pg1, i, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return; -+ } -+ -+ mpt2sas_transport_update_links(ioc, sas_expander->sas_address, -+ le16_to_cpu(expander_pg1.AttachedDevHandle), i, -+ expander_pg1.NegotiatedLinkRate >> 4); -+ } -+} -+ -+/** -+ * _scsih_scan_for_devices_after_reset - scan for devices after host reset -+ * @ioc: per adapter object -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2ExpanderPage0_t expander_pg0; -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2RaidVolPage1_t volume_pg1; -+ Mpi2RaidVolPage0_t volume_pg0; -+ Mpi2RaidPhysDiskPage0_t pd_pg0; -+ Mpi2EventIrConfigElement_t element; -+ Mpi2ConfigReply_t mpi_reply; -+ u8 phys_disk_num; -+ u16 ioc_status; -+ u16 handle, parent_handle; -+ u64 sas_address; -+ struct _sas_device *sas_device; -+ struct _sas_node *expander_device; -+ static struct _raid_device *raid_device; -+ u8 retry_count; -+ unsigned long flags; -+ -+ pr_info(MPT3SAS_FMT "scan devices: start\n", ioc->name); -+ -+ _scsih_sas_host_refresh(ioc); -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: expanders start\n", ioc->name); -+ -+ /* expanders */ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, -+ MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from expander scan: " \ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ handle = le16_to_cpu(expander_pg0.DevHandle); -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ expander_device = mpt2sas_scsih_expander_find_by_sas_address( -+ ioc, le64_to_cpu(expander_pg0.SASAddress)); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ if (expander_device) -+ _scsih_refresh_expander_links(ioc, expander_device, -+ handle); -+ else { -+ pr_info(MPT3SAS_FMT "\tBEFORE adding expander: " \ -+ "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ handle, (unsigned long long) -+ le64_to_cpu(expander_pg0.SASAddress)); -+ _scsih_expander_add(ioc, handle); -+ pr_info(MPT3SAS_FMT "\tAFTER adding expander: " \ -+ "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ handle, (unsigned long long) -+ le64_to_cpu(expander_pg0.SASAddress)); -+ } -+ } -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: expanders complete\n", -+ ioc->name); -+ -+ if (!ioc->ir_firmware) -+ goto skip_to_sas; -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: phys disk start\n", ioc->name); -+ -+ /* phys disk */ -+ phys_disk_num = 0xFF; -+ while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, -+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, -+ phys_disk_num))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from phys disk scan: "\ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ phys_disk_num = pd_pg0.PhysDiskNum; -+ handle = le16_to_cpu(pd_pg0.DevHandle); -+ sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); -+ if (sas_device) { -+ sas_device_put(sas_device); -+ continue; -+ } -+ if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, -+ handle) != 0) -+ continue; -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from phys disk scan " \ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); -+ if (!_scsih_get_sas_address(ioc, parent_handle, -+ &sas_address)) { -+ pr_info(MPT3SAS_FMT "\tBEFORE adding phys disk: " \ -+ " handle (0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, handle, (unsigned long long) -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ mpt2sas_transport_update_links(ioc, sas_address, -+ handle, sas_device_pg0.PhyNum, -+ MPI2_SAS_NEG_LINK_RATE_1_5); -+ set_bit(handle, ioc->pd_handles); -+ retry_count = 0; -+ /* This will retry adding the end device. -+ * _scsih_add_device() will decide on retries and -+ * return "1" when it should be retried -+ */ -+ while (_scsih_add_device(ioc, handle, retry_count++, -+ 1)) { -+ ssleep(1); -+ } -+ pr_info(MPT3SAS_FMT "\tAFTER adding phys disk: " \ -+ " handle (0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, handle, (unsigned long long) -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ } -+ } -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: phys disk complete\n", -+ ioc->name); -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: volumes start\n", ioc->name); -+ -+ /* volumes */ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ handle = le16_to_cpu(volume_pg1.DevHandle); -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = _scsih_raid_device_find_by_wwid(ioc, -+ le64_to_cpu(volume_pg1.WWID)); -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ if (raid_device) -+ continue; -+ if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, -+ &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, -+ sizeof(Mpi2RaidVolPage0_t))) -+ continue; -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from volume scan: " \ -+ "ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || -+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || -+ volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { -+ memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); -+ element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; -+ element.VolDevHandle = volume_pg1.DevHandle; -+ pr_info(MPT3SAS_FMT -+ "\tBEFORE adding volume: handle (0x%04x)\n", -+ ioc->name, volume_pg1.DevHandle); -+ _scsih_sas_volume_add(ioc, &element); -+ pr_info(MPT3SAS_FMT -+ "\tAFTER adding volume: handle (0x%04x)\n", -+ ioc->name, volume_pg1.DevHandle); -+ } -+ } -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: volumes complete\n", -+ ioc->name); -+ -+ skip_to_sas: -+ -+ pr_info(MPT3SAS_FMT "\tscan devices: end devices start\n", -+ ioc->name); -+ -+ /* sas devices */ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, -+ &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, -+ handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_info(MPT3SAS_FMT "\tbreak from end device scan:"\ -+ " ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, ioc_status, -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ break; -+ } -+ handle = le16_to_cpu(sas_device_pg0.DevHandle); -+ if (!(_scsih_is_end_device( -+ le32_to_cpu(sas_device_pg0.DeviceInfo)))) -+ continue; -+ sas_device = mpt2sas_get_sdev_by_addr(ioc, -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ if (sas_device) { -+ sas_device_put(sas_device); -+ continue; -+ } -+ parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); -+ if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { -+ pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \ -+ "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ handle, (unsigned long long) -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ mpt2sas_transport_update_links(ioc, sas_address, handle, -+ sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); -+ retry_count = 0; -+ /* This will retry adding the end device. -+ * _scsih_add_device() will decide on retries and -+ * return "1" when it should be retried -+ */ -+ while (_scsih_add_device(ioc, handle, retry_count++, -+ 0)) { -+ ssleep(1); -+ } -+ pr_info(MPT3SAS_FMT "\tAFTER adding end device: " \ -+ "handle (0x%04x), sas_addr(0x%016llx)\n", ioc->name, -+ handle, (unsigned long long) -+ le64_to_cpu(sas_device_pg0.SASAddress)); -+ } -+ } -+ pr_info(MPT3SAS_FMT "\tscan devices: end devices complete\n", -+ ioc->name); -+ -+ pr_info(MPT3SAS_FMT "scan devices: complete\n", ioc->name); -+} -+/** -+ * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) -+ * @ioc: per adapter object -+ * @reset_phase: phase -+ * -+ * The handler for doing any required cleanup or initialization. -+ * -+ * The reset phase can be MPT3_IOC_PRE_RESET, MPT3_IOC_AFTER_RESET, -+ * MPT3_IOC_DONE_RESET -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) -+{ -+ switch (reset_phase) { -+ case MPT3_IOC_PRE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__)); -+ break; -+ case MPT3_IOC_AFTER_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__)); -+ if (ioc->scsih_cmds.status & MPT3_CMD_PENDING) { -+ ioc->scsih_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); -+ complete(&ioc->scsih_cmds.done); -+ } -+ if (ioc->tm_cmds.status & MPT3_CMD_PENDING) { -+ ioc->tm_cmds.status |= MPT3_CMD_RESET; -+ mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); -+ complete(&ioc->tm_cmds.done); -+ } -+ -+ _scsih_fw_event_cleanup_queue(ioc); -+ _scsih_flush_running_cmds(ioc); -+ break; -+ case MPT3_IOC_DONE_RESET: -+ dtmprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: MPT3_IOC_DONE_RESET\n", ioc->name, __func__)); -+ if ((!ioc->is_driver_loading) && !(disable_discovery > 0 && -+ !ioc->sas_hba.num_phys)) { -+ _scsih_prep_device_scan(ioc); -+ _scsih_search_responding_sas_devices(ioc); -+ _scsih_search_responding_raid_devices(ioc); -+ _scsih_search_responding_expanders(ioc); -+ _scsih_error_recovery_delete_devices(ioc); -+ } -+ break; -+ } -+} -+ -+/** -+ * _mpt2sas_fw_work - delayed task for processing firmware events -+ * @ioc: per adapter object -+ * @fw_event: The fw_event_work object -+ * Context: user. -+ * -+ * Return nothing. -+ */ -+static void -+_mpt2sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) -+{ -+ _scsih_fw_event_del_from_list(ioc, fw_event); -+ -+ /* the queue is being flushed so ignore this event */ -+ if (ioc->remove_host || ioc->pci_error_recovery) { -+ fw_event_work_put(fw_event); -+ return; -+ } -+ -+ switch (fw_event->event) { -+ case MPT3SAS_PROCESS_TRIGGER_DIAG: -+ mpt2sas_process_trigger_data(ioc, -+ (struct SL_WH_TRIGGERS_EVENT_DATA_T *) -+ fw_event->event_data); -+ break; -+ case MPT3SAS_REMOVE_UNRESPONDING_DEVICES: -+ while (scsi_host_in_recovery(ioc->shost) || -+ ioc->shost_recovery) { -+ /* -+ * If we're unloading, bail. Otherwise, this can become -+ * an infinite loop. -+ */ -+ if (ioc->remove_host) -+ goto out; -+ ssleep(1); -+ } -+ _scsih_remove_unresponding_sas_devices(ioc); -+ _scsih_scan_for_devices_after_reset(ioc); -+ break; -+ case MPT3SAS_PORT_ENABLE_COMPLETE: -+ ioc->start_scan = 0; -+ if (missing_delay[0] != -1 && missing_delay[1] != -1) -+ mpt2sas_base_update_missing_delay(ioc, missing_delay[0], -+ missing_delay[1]); -+ dewtprintk(ioc, pr_info(MPT3SAS_FMT -+ "port enable: complete from worker thread\n", -+ ioc->name)); -+ break; -+ case MPT3SAS_TURN_ON_PFA_LED: -+ _scsih_turn_on_pfa_led(ioc, fw_event->device_handle); -+ break; -+ case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: -+ _scsih_sas_topology_change_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: -+ _scsih_sas_device_status_change_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_SAS_DISCOVERY: -+ _scsih_sas_discovery_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: -+ _scsih_sas_broadcast_primitive_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: -+ _scsih_sas_enclosure_dev_status_change_event(ioc, -+ fw_event); -+ break; -+ case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: -+ _scsih_sas_ir_config_change_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_IR_VOLUME: -+ _scsih_sas_ir_volume_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_IR_PHYSICAL_DISK: -+ _scsih_sas_ir_physical_disk_event(ioc, fw_event); -+ break; -+ case MPI2_EVENT_IR_OPERATION_STATUS: -+ _scsih_sas_ir_operation_status_event(ioc, fw_event); -+ break; -+ } -+out: -+ fw_event_work_put(fw_event); -+} -+ -+/** -+ * _firmware_event_work -+ * @ioc: per adapter object -+ * @work: The fw_event_work object -+ * Context: user. -+ * -+ * wrappers for the work thread handling firmware events -+ * -+ * Return nothing. -+ */ -+ -+static void -+_firmware_event_work(struct work_struct *work) -+{ -+ struct fw_event_work *fw_event = container_of(work, -+ struct fw_event_work, work); -+ -+ _mpt2sas_fw_work(fw_event->ioc, fw_event); -+} -+ -+/** -+ * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time) -+ * @ioc: per adapter object -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * Context: interrupt. -+ * -+ * This function merely adds a new work task into ioc->firmware_event_thread. -+ * The tasks are worked from _firmware_event_work in user context. -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, -+ u32 reply) -+{ -+ struct fw_event_work *fw_event; -+ Mpi2EventNotificationReply_t *mpi_reply; -+ u16 event; -+ u16 sz; -+ Mpi26EventDataActiveCableExcept_t *ActiveCableEventData; -+ -+ /* events turned off due to host reset or driver unloading */ -+ if (ioc->remove_host || ioc->pci_error_recovery) -+ return 1; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ -+ if (unlikely(!mpi_reply)) { -+ pr_err(MPT3SAS_FMT "mpi_reply not valid at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 1; -+ } -+ -+ event = le16_to_cpu(mpi_reply->Event); -+ -+ if (event != MPI2_EVENT_LOG_ENTRY_ADDED) -+ mpt2sas_trigger_event(ioc, event, 0); -+ -+ switch (event) { -+ /* handle these */ -+ case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: -+ { -+ Mpi2EventDataSasBroadcastPrimitive_t *baen_data = -+ (Mpi2EventDataSasBroadcastPrimitive_t *) -+ mpi_reply->EventData; -+ -+ if (baen_data->Primitive != -+ MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) -+ return 1; -+ -+ if (ioc->broadcast_aen_busy) { -+ ioc->broadcast_aen_pending++; -+ return 1; -+ } else -+ ioc->broadcast_aen_busy = 1; -+ break; -+ } -+ -+ case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: -+ _scsih_check_topo_delete_events(ioc, -+ (Mpi2EventDataSasTopologyChangeList_t *) -+ mpi_reply->EventData); -+ break; -+ case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: -+ _scsih_check_ir_config_unhide_events(ioc, -+ (Mpi2EventDataIrConfigChangeList_t *) -+ mpi_reply->EventData); -+ break; -+ case MPI2_EVENT_IR_VOLUME: -+ _scsih_check_volume_delete_events(ioc, -+ (Mpi2EventDataIrVolume_t *) -+ mpi_reply->EventData); -+ break; -+ case MPI2_EVENT_LOG_ENTRY_ADDED: -+ { -+ Mpi2EventDataLogEntryAdded_t *log_entry; -+ u32 *log_code; -+ -+ if (!ioc->is_warpdrive) -+ break; -+ -+ log_entry = (Mpi2EventDataLogEntryAdded_t *) -+ mpi_reply->EventData; -+ log_code = (u32 *)log_entry->LogData; -+ -+ if (le16_to_cpu(log_entry->LogEntryQualifier) -+ != MPT2_WARPDRIVE_LOGENTRY) -+ break; -+ -+ switch (le32_to_cpu(*log_code)) { -+ case MPT2_WARPDRIVE_LC_SSDT: -+ pr_warn(MPT3SAS_FMT "WarpDrive Warning: " -+ "IO Throttling has occurred in the WarpDrive " -+ "subsystem. Check WarpDrive documentation for " -+ "additional details.\n", ioc->name); -+ break; -+ case MPT2_WARPDRIVE_LC_SSDLW: -+ pr_warn(MPT3SAS_FMT "WarpDrive Warning: " -+ "Program/Erase Cycles for the WarpDrive subsystem " -+ "in degraded range. Check WarpDrive documentation " -+ "for additional details.\n", ioc->name); -+ break; -+ case MPT2_WARPDRIVE_LC_SSDLF: -+ pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " -+ "There are no Program/Erase Cycles for the " -+ "WarpDrive subsystem. The storage device will be " -+ "in read-only mode. Check WarpDrive documentation " -+ "for additional details.\n", ioc->name); -+ break; -+ case MPT2_WARPDRIVE_LC_BRMF: -+ pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " -+ "The Backup Rail Monitor has failed on the " -+ "WarpDrive subsystem. Check WarpDrive " -+ "documentation for additional details.\n", -+ ioc->name); -+ break; -+ } -+ -+ break; -+ } -+ case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: -+ case MPI2_EVENT_IR_OPERATION_STATUS: -+ case MPI2_EVENT_SAS_DISCOVERY: -+ case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: -+ case MPI2_EVENT_IR_PHYSICAL_DISK: -+ break; -+ -+ case MPI2_EVENT_TEMP_THRESHOLD: -+ _scsih_temp_threshold_events(ioc, -+ (Mpi2EventDataTemperature_t *) -+ mpi_reply->EventData); -+ break; -+ case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION: -+ ActiveCableEventData = -+ (Mpi26EventDataActiveCableExcept_t *) mpi_reply->EventData; -+ if (ActiveCableEventData->ReasonCode == -+ MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER) -+ pr_info(MPT3SAS_FMT "Currently an active cable with ReceptacleID %d", -+ ioc->name, ActiveCableEventData->ReceptacleID); -+ pr_info("cannot be powered and devices connected to this active cable"); -+ pr_info("will not be seen. This active cable"); -+ pr_info("requires %d mW of power", -+ ActiveCableEventData->ActiveCablePowerRequirement); -+ break; -+ -+ default: /* ignore the rest */ -+ return 1; -+ } -+ -+ sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; -+ fw_event = alloc_fw_event_work(sz); -+ if (!fw_event) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return 1; -+ } -+ -+ memcpy(fw_event->event_data, mpi_reply->EventData, sz); -+ fw_event->ioc = ioc; -+ fw_event->VF_ID = mpi_reply->VF_ID; -+ fw_event->VP_ID = mpi_reply->VP_ID; -+ fw_event->event = event; -+ _scsih_fw_event_add(ioc, fw_event); -+ fw_event_work_put(fw_event); -+ return 1; -+} -+ -+/** -+ * _scsih_expander_node_remove - removing expander device from list. -+ * @ioc: per adapter object -+ * @sas_expander: the sas_device object -+ * Context: Calling function should acquire ioc->sas_node_lock. -+ * -+ * Removing object and freeing associated memory from the -+ * ioc->sas_expander_list. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_expander) -+{ -+ struct _sas_port *mpt2sas_port, *next; -+ -+ /* remove sibling ports attached to this expander */ -+ list_for_each_entry_safe(mpt2sas_port, next, -+ &sas_expander->sas_port_list, port_list) { -+ if (ioc->shost_recovery) -+ return; -+ if (mpt2sas_port->remote_identify.device_type == -+ SAS_END_DEVICE) -+ mpt2sas_device_remove_by_sas_address(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ else if (mpt2sas_port->remote_identify.device_type == -+ SAS_EDGE_EXPANDER_DEVICE || -+ mpt2sas_port->remote_identify.device_type == -+ SAS_FANOUT_EXPANDER_DEVICE) -+ mpt2sas_expander_remove(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ } -+ -+ mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, -+ sas_expander->sas_address_parent); -+ -+ pr_info(MPT3SAS_FMT -+ "expander_remove: handle(0x%04x), sas_addr(0x%016llx)\n", -+ ioc->name, -+ sas_expander->handle, (unsigned long long) -+ sas_expander->sas_address); -+ -+ kfree(sas_expander->phy); -+ kfree(sas_expander); -+} -+ -+/** -+ * _scsih_ir_shutdown - IR shutdown notification -+ * @ioc: per adapter object -+ * -+ * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that -+ * the host system is shutting down. -+ * -+ * Return nothing. -+ */ -+static void -+_scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2RaidActionRequest_t *mpi_request; -+ Mpi2RaidActionReply_t *mpi_reply; -+ u16 smid; -+ -+ /* is IR firmware build loaded ? */ -+ if (!ioc->ir_firmware) -+ return; -+ -+ /* are there any volumes ? */ -+ if (list_empty(&ioc->raid_device_list)) -+ return; -+ -+ mutex_lock(&ioc->scsih_cmds.mutex); -+ -+ if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: scsih_cmd in use\n", -+ ioc->name, __func__); -+ goto out; -+ } -+ ioc->scsih_cmds.status = MPT3_CMD_PENDING; -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ goto out; -+ } -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->scsih_cmds.smid = smid; -+ memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); -+ -+ mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; -+ mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; -+ -+ if (!ioc->hide_ir_msg) -+ pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); -+ init_completion(&ioc->scsih_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); -+ -+ if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ goto out; -+ } -+ -+ if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { -+ mpi_reply = ioc->scsih_cmds.reply; -+ if (!ioc->hide_ir_msg) -+ pr_info(MPT3SAS_FMT "IR shutdown " -+ "(complete): ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus), -+ le32_to_cpu(mpi_reply->IOCLogInfo)); -+ } -+ -+ out: -+ ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_unlock(&ioc->scsih_cmds.mutex); -+} -+ -+/** -+ * scsih_remove_mpt2sas - detach and remove add host -+ * @pdev: PCI device struct -+ * -+ * Routine called when unloading the driver. -+ * Return nothing. -+ */ -+void scsih_remove_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct _sas_port *mpt2sas_port, *next_port; -+ struct _raid_device *raid_device, *next; -+ struct MPT3SAS_TARGET *sas_target_priv_data; -+ struct workqueue_struct *wq; -+ unsigned long flags; -+ -+ ioc->remove_host = 1; -+ _scsih_fw_event_cleanup_queue(ioc); -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ wq = ioc->firmware_event_thread; -+ ioc->firmware_event_thread = NULL; -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+ if (wq) -+ destroy_workqueue(wq); -+ -+ /* release all the volumes */ -+ _scsih_ir_shutdown(ioc); -+ list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, -+ list) { -+ if (raid_device->starget) { -+ sas_target_priv_data = -+ raid_device->starget->hostdata; -+ sas_target_priv_data->deleted = 1; -+ scsi_remove_target(&raid_device->starget->dev); -+ } -+ pr_info(MPT3SAS_FMT "removing handle(0x%04x), wwid(0x%016llx)\n", -+ ioc->name, raid_device->handle, -+ (unsigned long long) raid_device->wwid); -+ _scsih_raid_device_remove(ioc, raid_device); -+ } -+ -+ /* free ports attached to the sas_host */ -+ list_for_each_entry_safe(mpt2sas_port, next_port, -+ &ioc->sas_hba.sas_port_list, port_list) { -+ if (mpt2sas_port->remote_identify.device_type == -+ SAS_END_DEVICE) -+ mpt2sas_device_remove_by_sas_address(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ else if (mpt2sas_port->remote_identify.device_type == -+ SAS_EDGE_EXPANDER_DEVICE || -+ mpt2sas_port->remote_identify.device_type == -+ SAS_FANOUT_EXPANDER_DEVICE) -+ mpt2sas_expander_remove(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ } -+ -+ /* free phys attached to the sas_host */ -+ if (ioc->sas_hba.num_phys) { -+ kfree(ioc->sas_hba.phy); -+ ioc->sas_hba.phy = NULL; -+ ioc->sas_hba.num_phys = 0; -+ } -+ -+ sas_remove_host(shost); -+ scsi_remove_host(shost); -+ mpt2sas_base_detach(ioc); -+ spin_lock(&gioc_lock_mpt2sas); -+ list_del(&ioc->list); -+ spin_unlock(&gioc_lock_mpt2sas); -+ scsi_host_put(shost); -+} -+ -+/** -+ * scsih_shutdown_mpt2sas - routine call during system shutdown -+ * @pdev: PCI device struct -+ * -+ * Return nothing. -+ */ -+void -+scsih_shutdown_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ struct workqueue_struct *wq; -+ unsigned long flags; -+ -+ ioc->remove_host = 1; -+ _scsih_fw_event_cleanup_queue(ioc); -+ -+ spin_lock_irqsave(&ioc->fw_event_lock, flags); -+ wq = ioc->firmware_event_thread; -+ ioc->firmware_event_thread = NULL; -+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -+ if (wq) -+ destroy_workqueue(wq); -+ -+ _scsih_ir_shutdown(ioc); -+ mpt2sas_base_detach(ioc); -+} -+ -+ -+/** -+ * _scsih_probe_boot_devices - reports 1st device -+ * @ioc: per adapter object -+ * -+ * If specified in bios page 2, this routine reports the 1st -+ * device scsi-ml or sas transport for persistent boot device -+ * purposes. Please refer to function _scsih_determine_boot_device() -+ */ -+static void -+_scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u8 is_raid; -+ void *device; -+ struct _sas_device *sas_device; -+ struct _raid_device *raid_device; -+ u16 handle; -+ u64 sas_address_parent; -+ u64 sas_address; -+ unsigned long flags; -+ int rc; -+ -+ /* no Bios, return immediately */ -+ if (!ioc->bios_pg3.BiosVersion) -+ return; -+ -+ device = NULL; -+ is_raid = 0; -+ if (ioc->req_boot_device.device) { -+ device = ioc->req_boot_device.device; -+ is_raid = ioc->req_boot_device.is_raid; -+ } else if (ioc->req_alt_boot_device.device) { -+ device = ioc->req_alt_boot_device.device; -+ is_raid = ioc->req_alt_boot_device.is_raid; -+ } else if (ioc->current_boot_device.device) { -+ device = ioc->current_boot_device.device; -+ is_raid = ioc->current_boot_device.is_raid; -+ } -+ -+ if (!device) -+ return; -+ -+ if (is_raid) { -+ raid_device = device; -+ rc = scsi_add_device(ioc->shost, RAID_CHANNEL, -+ raid_device->id, 0); -+ if (rc) -+ _scsih_raid_device_remove(ioc, raid_device); -+ } else { -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = device; -+ handle = sas_device->handle; -+ sas_address_parent = sas_device->sas_address_parent; -+ sas_address = sas_device->sas_address; -+ list_move_tail(&sas_device->list, &ioc->sas_device_list); -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ if (ioc->hide_drives) -+ return; -+ if (!mpt2sas_transport_port_add(ioc, handle, -+ sas_address_parent)) { -+ _scsih_sas_device_remove(ioc, sas_device); -+ } else if (!sas_device->starget) { -+ if (!ioc->is_driver_loading) { -+ mpt2sas_transport_port_remove(ioc, -+ sas_address, -+ sas_address_parent); -+ _scsih_sas_device_remove(ioc, sas_device); -+ } -+ } -+ } -+} -+ -+/** -+ * _scsih_probe_raid - reporting raid volumes to scsi-ml -+ * @ioc: per adapter object -+ * -+ * Called during initial loading of the driver. -+ */ -+static void -+_scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct _raid_device *raid_device, *raid_next; -+ int rc; -+ -+ list_for_each_entry_safe(raid_device, raid_next, -+ &ioc->raid_device_list, list) { -+ if (raid_device->starget) -+ continue; -+ rc = scsi_add_device(ioc->shost, RAID_CHANNEL, -+ raid_device->id, 0); -+ if (rc) -+ _scsih_raid_device_remove(ioc, raid_device); -+ } -+} -+ -+static struct _sas_device *get_next_sas_device(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct _sas_device *sas_device = NULL; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ if (!list_empty(&ioc->sas_device_init_list)) { -+ sas_device = list_first_entry(&ioc->sas_device_init_list, -+ struct _sas_device, list); -+ sas_device_get(sas_device); -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ -+ return sas_device; -+} -+ -+static void sas_device_make_active(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_device *sas_device) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ -+ /* -+ * Since we dropped the lock during the call to port_add(), we need to -+ * be careful here that somebody else didn't move or delete this item -+ * while we were busy with other things. -+ * -+ * If it was on the list, we need a put() for the reference the list -+ * had. Either way, we need a get() for the destination list. -+ */ -+ if (!list_empty(&sas_device->list)) { -+ list_del_init(&sas_device->list); -+ sas_device_put(sas_device); -+ } -+ -+ sas_device_get(sas_device); -+ list_add_tail(&sas_device->list, &ioc->sas_device_list); -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+} -+ -+/** -+ * _scsih_probe_sas - reporting sas devices to sas transport -+ * @ioc: per adapter object -+ * -+ * Called during initial loading of the driver. -+ */ -+static void -+_scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) -+{ -+ struct _sas_device *sas_device; -+ -+ if (ioc->hide_drives) -+ return; -+ -+ while ((sas_device = get_next_sas_device(ioc))) { -+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle, -+ sas_device->sas_address_parent)) { -+ _scsih_sas_device_remove(ioc, sas_device); -+ sas_device_put(sas_device); -+ continue; -+ } else if (!sas_device->starget) { -+ /* -+ * When asyn scanning is enabled, its not possible to -+ * remove devices while scanning is turned on due to an -+ * oops in scsi_sysfs_add_sdev()->add_device()-> -+ * sysfs_addrm_start() -+ */ -+ if (!ioc->is_driver_loading) { -+ mpt2sas_transport_port_remove(ioc, -+ sas_device->sas_address, -+ sas_device->sas_address_parent); -+ _scsih_sas_device_remove(ioc, sas_device); -+ sas_device_put(sas_device); -+ continue; -+ } -+ } -+ sas_device_make_active(ioc, sas_device); -+ sas_device_put(sas_device); -+ } -+} -+ -+/** -+ * _scsih_probe_devices - probing for devices -+ * @ioc: per adapter object -+ * -+ * Called during initial loading of the driver. -+ */ -+static void -+_scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc) -+{ -+ u16 volume_mapping_flags; -+ -+ if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR)) -+ return; /* return when IOC doesn't support initiator mode */ -+ -+ _scsih_probe_boot_devices(ioc); -+ -+ if (ioc->ir_firmware) { -+ volume_mapping_flags = -+ le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & -+ MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; -+ if (volume_mapping_flags == -+ MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { -+ _scsih_probe_raid(ioc); -+ _scsih_probe_sas(ioc); -+ } else { -+ _scsih_probe_sas(ioc); -+ _scsih_probe_raid(ioc); -+ } -+ } else -+ _scsih_probe_sas(ioc); -+} -+ -+/** -+ * scsih_scan_start_mpt2sas - scsi lld callback for .scan_start -+ * @shost: SCSI host pointer -+ * -+ * The shost has the ability to discover targets on its own instead -+ * of scanning the entire bus. In our implemention, we will kick off -+ * firmware discovery. -+ */ -+void -+scsih_scan_start_mpt2sas(struct Scsi_Host *shost) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int rc; -+ if (diag_buffer_enable != -1 && diag_buffer_enable != 0) -+ mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); -+ -+ if (disable_discovery > 0) -+ return; -+ -+ ioc->start_scan = 1; -+ rc = mpt2sas_port_enable(ioc); -+ -+ if (rc != 0) -+ pr_info(MPT3SAS_FMT "port enable: FAILED\n", ioc->name); -+} -+ -+/** -+ * scsih_scan_finished_mpt2sas - scsi lld callback for .scan_finished -+ * @shost: SCSI host pointer -+ * @time: elapsed time of the scan in jiffies -+ * -+ * This function will be called periodicallyn until it returns 1 with the -+ * scsi_host and the elapsed time of the scan in jiffies. In our implemention, -+ * we wait for firmware discovery to complete, then return 1. -+ */ -+int -+scsih_scan_finished_mpt2sas(struct Scsi_Host *shost, unsigned long time) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ if (disable_discovery > 0) { -+ ioc->is_driver_loading = 0; -+ ioc->wait_for_discovery_to_complete = 0; -+ return 1; -+ } -+ -+ if (time >= (300 * HZ)) { -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ pr_info(MPT3SAS_FMT -+ "port enable: FAILED with timeout (timeout=300s)\n", -+ ioc->name); -+ ioc->is_driver_loading = 0; -+ return 1; -+ } -+ -+ if (ioc->start_scan) -+ return 0; -+ -+ if (ioc->start_scan_failed) { -+ pr_info(MPT3SAS_FMT -+ "port enable: FAILED with (ioc_status=0x%08x)\n", -+ ioc->name, ioc->start_scan_failed); -+ ioc->is_driver_loading = 0; -+ ioc->wait_for_discovery_to_complete = 0; -+ ioc->remove_host = 1; -+ return 1; -+ } -+ -+ pr_info(MPT3SAS_FMT "port enable: SUCCESS\n", ioc->name); -+ ioc->base_cmds.status = MPT3_CMD_NOT_USED; -+ -+ if (ioc->wait_for_discovery_to_complete) { -+ ioc->wait_for_discovery_to_complete = 0; -+ _scsih_probe_devices(ioc); -+ } -+ mpt2sas_base_start_watchdog(ioc); -+ ioc->is_driver_loading = 0; -+ return 1; -+} -+ -+/* shost template for SAS 2.0 HBA devices */ -+static struct scsi_host_template mpt2sas_driver_template_mpt2sas = { -+ .module = THIS_MODULE, -+ .name = "Fusion MPT SAS Host", -+ .proc_name = MPT2SAS_DRIVER_NAME, -+ .queuecommand = scsih_qcmd_mpt2sas, -+ .target_alloc = scsih_target_alloc_mpt2sas, -+ .slave_alloc = scsih_slave_alloc_mpt2sas, -+ .slave_configure = scsih_slave_configure_mpt2sas, -+ .target_destroy = scsih_target_destroy_mpt2sas, -+ .slave_destroy = scsih_slave_destroy_mpt2sas, -+ .scan_finished = scsih_scan_finished_mpt2sas, -+ .scan_start = scsih_scan_start_mpt2sas, -+ .change_queue_depth = scsih_change_queue_depth_mpt2sas, -+ .change_queue_type = _scsih_change_queue_type_mpt2sas, -+ .eh_abort_handler = scsih_abort_mpt2sas, -+ .eh_device_reset_handler = scsih_dev_reset_mpt2sas, -+ .eh_target_reset_handler = scsih_target_reset_mpt2sas, -+ .eh_host_reset_handler = scsih_host_reset_mpt2sas, -+ .bios_param = scsih_bios_param_mpt2sas, -+ .can_queue = 1, -+ .this_id = -1, -+ .sg_tablesize = MPT2SAS_SG_DEPTH, -+ .max_sectors = 32767, -+ .cmd_per_lun = 7, -+ .use_clustering = ENABLE_CLUSTERING, -+ .shost_attrs = mpt2sas_host_attrs, -+ .sdev_attrs = mpt2sas_dev_attrs, -+}; -+ -+#ifdef MPT2SAS_SCSI -+/* raid transport support for SAS 2.0 HBA devices */ -+static struct raid_function_template mpt2sas_raid_functions = { -+ .cookie = &mpt2sas_driver_template_mpt2sas, -+ .is_raid = scsih_is_raid_mpt2sas, -+ .get_resync = scsih_get_resync_mpt2sas, -+ .get_state = scsih_get_state_mpt2sas, -+}; -+#endif /* MPT2SAS_SCSI */ -+ -+/* shost template for SAS 3.0 HBA devices */ -+static struct scsi_host_template mpt3sas_driver_template_mpt2sas = { -+ .module = THIS_MODULE, -+ .name = "Fusion MPT SAS Host", -+ .proc_name = MPT3SAS_DRIVER_NAME, -+ .queuecommand = scsih_qcmd_mpt2sas, -+ .target_alloc = scsih_target_alloc_mpt2sas, -+ .slave_alloc = scsih_slave_alloc_mpt2sas, -+ .slave_configure = scsih_slave_configure_mpt2sas, -+ .target_destroy = scsih_target_destroy_mpt2sas, -+ .slave_destroy = scsih_slave_destroy_mpt2sas, -+ .scan_finished = scsih_scan_finished_mpt2sas, -+ .scan_start = scsih_scan_start_mpt2sas, -+ .change_queue_depth = scsih_change_queue_depth_mpt2sas, -+ .change_queue_type = _scsih_change_queue_type_mpt2sas, -+ .eh_abort_handler = scsih_abort_mpt2sas, -+ .eh_device_reset_handler = scsih_dev_reset_mpt2sas, -+ .eh_target_reset_handler = scsih_target_reset_mpt2sas, -+ .eh_host_reset_handler = scsih_host_reset_mpt2sas, -+ .bios_param = scsih_bios_param_mpt2sas, -+ .can_queue = 1, -+ .this_id = -1, -+ .sg_tablesize = MPT3SAS_SG_DEPTH, -+ .max_sectors = 32767, -+ .cmd_per_lun = 7, -+ .use_clustering = ENABLE_CLUSTERING, -+ .shost_attrs = mpt2sas_host_attrs, -+ .sdev_attrs = mpt2sas_dev_attrs, -+}; -+ -+#ifndef MPT2SAS_SCSI -+/* raid transport support for SAS 3.0 HBA devices */ -+static struct raid_function_template mpt3sas_raid_functions = { -+ .cookie = &mpt3sas_driver_template_mpt2sas, -+ .is_raid = scsih_is_raid_mpt2sas, -+ .get_resync = scsih_get_resync_mpt2sas, -+ .get_state = scsih_get_state_mpt2sas, -+}; -+#endif /* MPT2SAS_SCSI */ -+ -+/** -+ * _scsih_determine_hba_mpi_version_mpt2sas - determine in which MPI version class -+ * this device belongs to. -+ * @pdev: PCI device struct -+ * -+ * return MPI2_VERSION for SAS 2.0 HBA devices, -+ * MPI25_VERSION for SAS 3.0 HBA devices, and -+ * MPI26 VERSION for Cutlass & Invader SAS 3.0 HBA devices -+ */ -+u16 -+_scsih_determine_hba_mpi_version_mpt2sas(struct pci_dev *pdev) -+{ -+ -+ switch (pdev->device) { -+ case MPI2_MFGPAGE_DEVID_SSS6200: -+ case MPI2_MFGPAGE_DEVID_SAS2004: -+ case MPI2_MFGPAGE_DEVID_SAS2008: -+ case MPI2_MFGPAGE_DEVID_SAS2108_1: -+ case MPI2_MFGPAGE_DEVID_SAS2108_2: -+ case MPI2_MFGPAGE_DEVID_SAS2108_3: -+ case MPI2_MFGPAGE_DEVID_SAS2116_1: -+ case MPI2_MFGPAGE_DEVID_SAS2116_2: -+ case MPI2_MFGPAGE_DEVID_SAS2208_1: -+ case MPI2_MFGPAGE_DEVID_SAS2208_2: -+ case MPI2_MFGPAGE_DEVID_SAS2208_3: -+ case MPI2_MFGPAGE_DEVID_SAS2208_4: -+ case MPI2_MFGPAGE_DEVID_SAS2208_5: -+ case MPI2_MFGPAGE_DEVID_SAS2208_6: -+ case MPI2_MFGPAGE_DEVID_SAS2308_1: -+ case MPI2_MFGPAGE_DEVID_SAS2308_2: -+ case MPI2_MFGPAGE_DEVID_SAS2308_3: -+ return MPI2_VERSION; -+ case MPI25_MFGPAGE_DEVID_SAS3004: -+ case MPI25_MFGPAGE_DEVID_SAS3008: -+ case MPI25_MFGPAGE_DEVID_SAS3108_1: -+ case MPI25_MFGPAGE_DEVID_SAS3108_2: -+ case MPI25_MFGPAGE_DEVID_SAS3108_5: -+ case MPI25_MFGPAGE_DEVID_SAS3108_6: -+ return MPI25_VERSION; -+ case MPI26_MFGPAGE_DEVID_SAS3216: -+ case MPI26_MFGPAGE_DEVID_SAS3224: -+ case MPI26_MFGPAGE_DEVID_SAS3316_1: -+ case MPI26_MFGPAGE_DEVID_SAS3316_2: -+ case MPI26_MFGPAGE_DEVID_SAS3316_3: -+ case MPI26_MFGPAGE_DEVID_SAS3316_4: -+ case MPI26_MFGPAGE_DEVID_SAS3324_1: -+ case MPI26_MFGPAGE_DEVID_SAS3324_2: -+ case MPI26_MFGPAGE_DEVID_SAS3324_3: -+ case MPI26_MFGPAGE_DEVID_SAS3324_4: -+ return MPI26_VERSION; -+ } -+ return 0; -+} -+ -+/** -+ * _scsih_probe_mpt2sas - attach and add scsi host -+ * @pdev: PCI device struct -+ * @id: pci device id -+ * -+ * Returns 0 success, anything else error. -+ */ -+int -+_scsih_probe_mpt2sas(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ struct MPT3SAS_ADAPTER *ioc; -+ struct Scsi_Host *shost = NULL; -+ int rv; -+ u16 hba_mpi_version; -+ -+ /* Determine in which MPI version class this pci device belongs */ -+ hba_mpi_version = _scsih_determine_hba_mpi_version_mpt2sas(pdev); -+ if (hba_mpi_version == 0) -+ return -ENODEV; -+ -+ switch (hba_mpi_version) { -+ case MPI2_VERSION: -+ /* Use mpt2sas driver host template for SAS 2.0 HBA's */ -+ shost = scsi_host_alloc(&mpt2sas_driver_template_mpt2sas, -+ sizeof(struct MPT3SAS_ADAPTER)); -+ if (!shost) -+ return -ENODEV; -+ ioc = shost_priv(shost); -+ memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); -+ ioc->hba_mpi_version_belonged = hba_mpi_version; -+ ioc->id = mpt2_ids++; -+ sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME); -+ if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) { -+ ioc->is_warpdrive = 1; -+ ioc->hide_ir_msg = 1; -+ } else -+ ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; -+ break; -+ case MPI25_VERSION: -+ case MPI26_VERSION: -+ /* Use mpt3sas driver host template for SAS 3.0 HBA's */ -+ shost = scsi_host_alloc(&mpt3sas_driver_template_mpt2sas, -+ sizeof(struct MPT3SAS_ADAPTER)); -+ if (!shost) -+ return -ENODEV; -+ ioc = shost_priv(shost); -+ memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); -+ ioc->hba_mpi_version_belonged = hba_mpi_version; -+ ioc->id = mpt3_ids++; -+ sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME); -+ if ((ioc->hba_mpi_version_belonged == MPI25_VERSION && -+ pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION) || -+ (ioc->hba_mpi_version_belonged == MPI26_VERSION)) -+ ioc->msix96_vector = 1; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ INIT_LIST_HEAD(&ioc->list); -+ spin_lock(&gioc_lock_mpt2sas); -+ list_add_tail(&ioc->list, &mpt2sas_ioc_list); -+ spin_unlock(&gioc_lock_mpt2sas); -+ ioc->shost = shost; -+ ioc->pdev = pdev; -+ ioc->scsi_io_cb_idx = scsi_io_cb_idx; -+ ioc->tm_cb_idx = tm_cb_idx; -+ ioc->ctl_cb_idx = ctl_cb_idx; -+ ioc->base_cb_idx = base_cb_idx; -+ ioc->port_enable_cb_idx = port_enable_cb_idx; -+ ioc->transport_cb_idx = transport_cb_idx; -+ ioc->scsih_cb_idx = scsih_cb_idx; -+ ioc->config_cb_idx = config_cb_idx; -+ ioc->tm_tr_cb_idx = tm_tr_cb_idx; -+ ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx; -+ ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; -+ ioc->logging_level = logging_level; -+ ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; -+ /* misc semaphores and spin locks */ -+ mutex_init(&ioc->reset_in_progress_mutex); -+ /* initializing pci_access_mutex lock */ -+ mutex_init(&ioc->pci_access_mutex); -+ spin_lock_init(&ioc->ioc_reset_in_progress_lock); -+ spin_lock_init(&ioc->scsi_lookup_lock); -+ spin_lock_init(&ioc->sas_device_lock); -+ spin_lock_init(&ioc->sas_node_lock); -+ spin_lock_init(&ioc->fw_event_lock); -+ spin_lock_init(&ioc->raid_device_lock); -+ spin_lock_init(&ioc->diag_trigger_lock); -+ -+ INIT_LIST_HEAD(&ioc->sas_device_list); -+ INIT_LIST_HEAD(&ioc->sas_device_init_list); -+ INIT_LIST_HEAD(&ioc->sas_expander_list); -+ INIT_LIST_HEAD(&ioc->fw_event_list); -+ INIT_LIST_HEAD(&ioc->raid_device_list); -+ INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); -+ INIT_LIST_HEAD(&ioc->delayed_tr_list); -+ INIT_LIST_HEAD(&ioc->delayed_sc_list); -+ INIT_LIST_HEAD(&ioc->delayed_event_ack_list); -+ INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); -+ INIT_LIST_HEAD(&ioc->reply_queue_list); -+ -+ sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id); -+ -+ /* init shost parameters */ -+ shost->max_cmd_len = 32; -+ shost->max_lun = max_lun; -+ shost->transportt = mpt2sas_transport_template; -+ shost->unique_id = ioc->id; -+ -+ if (max_sectors != 0xFFFF) { -+ if (max_sectors < 64) { -+ shost->max_sectors = 64; -+ pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ -+ "for max_sectors, range is 64 to 32767. Assigning " -+ "value of 64.\n", ioc->name, max_sectors); -+ } else if (max_sectors > 32767) { -+ shost->max_sectors = 32767; -+ pr_warn(MPT3SAS_FMT "Invalid value %d passed " \ -+ "for max_sectors, range is 64 to 32767. Assigning " -+ "default value of 32767.\n", ioc->name, -+ max_sectors); -+ } else { -+ shost->max_sectors = max_sectors & 0xFFFE; -+ pr_info(MPT3SAS_FMT -+ "The max_sectors value is set to %d\n", -+ ioc->name, shost->max_sectors); -+ } -+ } -+ -+ /* register EEDP capabilities with SCSI layer */ -+ if (prot_mask > 0) -+ scsi_host_set_prot(shost, prot_mask); -+ else -+ scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION -+ | SHOST_DIF_TYPE2_PROTECTION -+ | SHOST_DIF_TYPE3_PROTECTION); -+ -+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); -+ -+ /* event thread */ -+ snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), -+ "fw_event_%s%d", ioc->driver_name, ioc->id); -+ ioc->firmware_event_thread = alloc_ordered_workqueue( -+ ioc->firmware_event_name, WQ_MEM_RECLAIM); -+ if (!ioc->firmware_event_thread) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rv = -ENODEV; -+ goto out_thread_fail; -+ } -+ -+ ioc->is_driver_loading = 1; -+ if ((mpt2sas_base_attach(ioc))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rv = -ENODEV; -+ goto out_attach_fail; -+ } -+ -+ if (ioc->is_warpdrive) { -+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) -+ ioc->hide_drives = 0; -+ else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) -+ ioc->hide_drives = 1; -+ else { -+ if (mpt2sas_get_num_volumes(ioc)) -+ ioc->hide_drives = 1; -+ else -+ ioc->hide_drives = 0; -+ } -+ } else -+ ioc->hide_drives = 0; -+ -+ rv = scsi_add_host(shost, &pdev->dev); -+ if (rv) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_add_shost_fail; -+ } -+ -+ scsi_scan_host(shost); -+ return 0; -+out_add_shost_fail: -+ mpt2sas_base_detach(ioc); -+ out_attach_fail: -+ destroy_workqueue(ioc->firmware_event_thread); -+ out_thread_fail: -+ spin_lock(&gioc_lock_mpt2sas); -+ list_del(&ioc->list); -+ spin_unlock(&gioc_lock_mpt2sas); -+ scsi_host_put(shost); -+ return rv; -+} -+ -+#ifdef CONFIG_PM -+/** -+ * scsih_suspend_mpt2sas - power management suspend main entry point -+ * @pdev: PCI device struct -+ * @state: PM state change to (usually PCI_D3) -+ * -+ * Returns 0 success, anything else error. -+ */ -+int -+scsih_suspend_mpt2sas(struct pci_dev *pdev, pm_message_t state) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ pci_power_t device_state; -+ -+ mpt2sas_base_stop_watchdog(ioc); -+ flush_scheduled_work(); -+ scsi_block_requests(shost); -+ device_state = pci_choose_state(pdev, state); -+ pr_info(MPT3SAS_FMT -+ "pdev=0x%p, slot=%s, entering operating state [D%d]\n", -+ ioc->name, pdev, pci_name(pdev), device_state); -+ -+ pci_save_state(pdev); -+ mpt2sas_base_free_resources(ioc); -+ pci_set_power_state(pdev, device_state); -+ return 0; -+} -+ -+/** -+ * scsih_resume_mpt2sas - power management resume main entry point -+ * @pdev: PCI device struct -+ * -+ * Returns 0 success, anything else error. -+ */ -+int -+scsih_resume_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ pci_power_t device_state = pdev->current_state; -+ int r; -+ -+ pr_info(MPT3SAS_FMT -+ "pdev=0x%p, slot=%s, previous operating state [D%d]\n", -+ ioc->name, pdev, pci_name(pdev), device_state); -+ -+ pci_set_power_state(pdev, PCI_D0); -+ pci_enable_wake(pdev, PCI_D0, 0); -+ pci_restore_state(pdev); -+ ioc->pdev = pdev; -+ r = mpt2sas_base_map_resources(ioc); -+ if (r) -+ return r; -+ -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET); -+ scsi_unblock_requests(shost); -+ mpt2sas_base_start_watchdog(ioc); -+ return 0; -+} -+#endif /* CONFIG_PM */ -+ -+/** -+ * scsih_pci_error_detected_mpt2sas - Called when a PCI error is detected. -+ * @pdev: PCI device struct -+ * @state: PCI channel state -+ * -+ * Description: Called when a PCI error is detected. -+ * -+ * Return value: -+ * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT -+ */ -+pci_ers_result_t -+scsih_pci_error_detected_mpt2sas(struct pci_dev *pdev, pci_channel_state_t state) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ pr_info(MPT3SAS_FMT "PCI error: detected callback, state(%d)!!\n", -+ ioc->name, state); -+ -+ switch (state) { -+ case pci_channel_io_normal: -+ return PCI_ERS_RESULT_CAN_RECOVER; -+ case pci_channel_io_frozen: -+ /* Fatal error, prepare for slot reset */ -+ ioc->pci_error_recovery = 1; -+ scsi_block_requests(ioc->shost); -+ mpt2sas_base_stop_watchdog(ioc); -+ mpt2sas_base_free_resources(ioc); -+ return PCI_ERS_RESULT_NEED_RESET; -+ case pci_channel_io_perm_failure: -+ /* Permanent error, prepare for device removal */ -+ ioc->pci_error_recovery = 1; -+ mpt2sas_base_stop_watchdog(ioc); -+ _scsih_flush_running_cmds(ioc); -+ return PCI_ERS_RESULT_DISCONNECT; -+ } -+ return PCI_ERS_RESULT_NEED_RESET; -+} -+ -+/** -+ * scsih_pci_slot_reset_mpt2sas - Called when PCI slot has been reset. -+ * @pdev: PCI device struct -+ * -+ * Description: This routine is called by the pci error recovery -+ * code after the PCI slot has been reset, just before we -+ * should resume normal operations. -+ */ -+pci_ers_result_t -+scsih_pci_slot_reset_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ int rc; -+ -+ pr_info(MPT3SAS_FMT "PCI error: slot reset callback!!\n", -+ ioc->name); -+ -+ ioc->pci_error_recovery = 0; -+ ioc->pdev = pdev; -+ pci_restore_state(pdev); -+ rc = mpt2sas_base_map_resources(ioc); -+ if (rc) -+ return PCI_ERS_RESULT_DISCONNECT; -+ -+ rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ -+ pr_warn(MPT3SAS_FMT "hard reset: %s\n", ioc->name, -+ (rc == 0) ? "success" : "failed"); -+ -+ if (!rc) -+ return PCI_ERS_RESULT_RECOVERED; -+ else -+ return PCI_ERS_RESULT_DISCONNECT; -+} -+ -+/** -+ * scsih_pci_resume_mpt2sas() - resume normal ops after PCI reset -+ * @pdev: pointer to PCI device -+ * -+ * Called when the error recovery driver tells us that its -+ * OK to resume normal operation. Use completion to allow -+ * halted scsi ops to resume. -+ */ -+void -+scsih_pci_resume_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ pr_info(MPT3SAS_FMT "PCI error: resume callback!!\n", ioc->name); -+ -+ pci_cleanup_aer_uncorrect_error_status(pdev); -+ mpt2sas_base_start_watchdog(ioc); -+ scsi_unblock_requests(ioc->shost); -+} -+ -+/** -+ * scsih_pci_mmio_enabled_mpt2sas - Enable MMIO and dump debug registers -+ * @pdev: pointer to PCI device -+ */ -+pci_ers_result_t -+scsih_pci_mmio_enabled_mpt2sas(struct pci_dev *pdev) -+{ -+ struct Scsi_Host *shost = pci_get_drvdata(pdev); -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ -+ pr_info(MPT3SAS_FMT "PCI error: mmio enabled callback!!\n", -+ ioc->name); -+ -+ /* TODO - dump whatever for debugging purposes */ -+ -+ /* This called only if scsih_pci_error_detected_mpt2sas returns -+ * PCI_ERS_RESULT_CAN_RECOVER. Read/write to the device still -+ * works, no need to reset slot. -+ */ -+ return PCI_ERS_RESULT_RECOVERED; -+} -+ -+/* -+ * The pci device ids are defined in mpi/mpi2_cnfg.h. -+ */ -+static const struct pci_device_id mpt2sas_pci_table[] = { -+#ifdef MPT2SAS_SCSI -+ /* Spitfire ~ 2004 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Falcon ~ 2008 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Liberator ~ 2108 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Meteor ~ 2116 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Thunderbolt ~ 2208 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Mustang ~ 2308 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* SSS6200 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, -+ PCI_ANY_ID, PCI_ANY_ID }, -+#else -+ /* Fury ~ 3004 and 3008 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Invader ~ 3108 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Cutlass ~ 3216 and 3224 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ /* Intruder ~ 3316 and 3324 */ -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_4, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_1, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_2, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_3, -+ PCI_ANY_ID, PCI_ANY_ID }, -+ { MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_4, -+ PCI_ANY_ID, PCI_ANY_ID }, -+#endif /* MPT2SAS_SCSI */ -+ {0} /* Terminating entry */ -+}; -+MODULE_DEVICE_TABLE(pci, mpt2sas_pci_table); -+ -+static struct pci_error_handlers _mpt2sas_err_handler = { -+ .error_detected = scsih_pci_error_detected_mpt2sas, -+ .mmio_enabled = scsih_pci_mmio_enabled_mpt2sas, -+ .slot_reset = scsih_pci_slot_reset_mpt2sas, -+ .resume = scsih_pci_resume_mpt2sas, -+}; -+ -+static struct pci_driver mpt3sas_driver = { -+#ifdef MPT2SAS_SCSI -+ .name = MPT2SAS_DRIVER_NAME, -+#else -+ .name = MPT3SAS_DRIVER_NAME, -+#endif /* MPT2SAS_SCSI */ -+ .id_table = mpt2sas_pci_table, -+ .probe = _scsih_probe_mpt2sas, -+ .remove = scsih_remove_mpt2sas, -+ .shutdown = scsih_shutdown_mpt2sas, -+ .err_handler = &_mpt2sas_err_handler, -+#ifdef CONFIG_PM -+ .suspend = scsih_suspend_mpt2sas, -+ .resume = scsih_resume_mpt2sas, -+#endif -+}; -+ -+/** -+ * scsih_init_mpt2sas - main entry point for this driver. -+ * -+ * Returns 0 success, anything else error. -+ */ -+int -+scsih_init_mpt2sas(void) -+{ -+ mpt2_ids = 0; -+ mpt3_ids = 0; -+ -+ mpt2sas_base_initialize_callback_handler(); -+ -+ /* queuecommand callback hander */ -+ scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done); -+ -+ /* task managment callback handler */ -+ tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done); -+ -+ /* base internal commands callback handler */ -+ base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done); -+ port_enable_cb_idx = mpt2sas_base_register_callback_handler( -+ mpt2sas_port_enable_done); -+ -+ /* transport internal commands callback handler */ -+ transport_cb_idx = mpt2sas_base_register_callback_handler( -+ mpt2sas_transport_done); -+ -+ /* scsih internal commands callback handler */ -+ scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done); -+ -+ /* configuration page API internal commands callback handler */ -+ config_cb_idx = mpt2sas_base_register_callback_handler( -+ mpt2sas_config_done); -+ -+ /* ctl module callback handler */ -+ ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done); -+ -+ tm_tr_cb_idx = mpt2sas_base_register_callback_handler( -+ _scsih_tm_tr_complete); -+ -+ tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler( -+ _scsih_tm_volume_tr_complete); -+ -+ tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler( -+ _scsih_sas_control_complete); -+ -+ return 0; -+} -+ -+/** -+ * scsih_exit_mpt2sas - exit point for this driver (when it is a module). -+ * -+ * Returns 0 success, anything else error. -+ */ -+void -+scsih_exit_mpt2sas(void) -+{ -+ -+ mpt2sas_base_release_callback_handler(scsi_io_cb_idx); -+ mpt2sas_base_release_callback_handler(tm_cb_idx); -+ mpt2sas_base_release_callback_handler(base_cb_idx); -+ mpt2sas_base_release_callback_handler(port_enable_cb_idx); -+ mpt2sas_base_release_callback_handler(transport_cb_idx); -+ mpt2sas_base_release_callback_handler(scsih_cb_idx); -+ mpt2sas_base_release_callback_handler(config_cb_idx); -+ mpt2sas_base_release_callback_handler(ctl_cb_idx); -+ -+ mpt2sas_base_release_callback_handler(tm_tr_cb_idx); -+ mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx); -+ mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); -+ -+/* raid transport support */ -+#ifdef MPT2SAS_SCSI -+ raid_class_release(mpt2sas_raid_template_mpt2sas); -+#else -+ raid_class_release(mpt3sas_raid_template_mpt2sas); -+#endif /* MPT2SAS_SCSI */ -+ sas_release_transport(mpt2sas_transport_template); -+} -+ -+/** -+ * _mpt2sas_init - main entry point for this driver. -+ * -+ * Returns 0 success, anything else error. -+ */ -+static int __init -+_mpt2sas_init(void) -+{ -+ int error; -+ -+#ifdef MPT2SAS_SCSI -+ pr_info("%s version %s loaded\n", MPT2SAS_DRIVER_NAME, -+ MPT2SAS_DRIVER_VERSION); -+#else -+ pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME, -+ MPT3SAS_DRIVER_VERSION); -+#endif /* MPT2SAS_SCSI */ -+ -+ mpt2sas_transport_template = -+ sas_attach_transport(&mpt2sas_transport_functions); -+ if (!mpt2sas_transport_template) -+ return -ENODEV; -+ -+#ifdef MPT2SAS_SCSI -+ mpt2sas_raid_template_mpt2sas = raid_class_attach(&mpt2sas_raid_functions); -+ if (!mpt2sas_raid_template_mpt2sas) { -+ sas_release_transport(mpt2sas_transport_template); -+ return -ENODEV; -+ } -+#else -+ mpt3sas_raid_template_mpt2sas = raid_class_attach(&mpt3sas_raid_functions); -+ if (!mpt3sas_raid_template_mpt2sas) { -+ sas_release_transport(mpt2sas_transport_template); -+ return -ENODEV; -+ } -+#endif /* MPT2SAS_SCSI */ -+ -+ error = scsih_init_mpt2sas(); -+ if (error) { -+ scsih_exit_mpt2sas(); -+ return error; -+ } -+ -+ -+#ifdef MPT2SAS_SCSI -+ mpt2sas_ctl_init(1); -+#else -+ mpt2sas_ctl_init(2); -+#endif /* MPT2SAS_SCSI */ -+ -+ error = pci_register_driver(&mpt3sas_driver); -+ if (error) -+ scsih_exit_mpt2sas(); -+ -+ return error; -+} -+ -+/** -+ * _mpt2sas_exit - exit point for this driver (when it is a module). -+ * -+ */ -+static void __exit -+_mpt2sas_exit(void) -+{ -+ pr_info("mpt3sas version %s unloading\n", -+ MPT3SAS_DRIVER_VERSION); -+ -+ pci_unregister_driver(&mpt3sas_driver); -+ -+#ifdef MPT2SAS_SCSI -+ mpt2sas_ctl_exit(1); -+#else -+ mpt2sas_ctl_exit(2); -+#endif /* MPT2SAS_SCSI */ -+ -+ scsih_exit_mpt2sas(); -+} -+ -+module_init(_mpt2sas_init); -+module_exit(_mpt2sas_exit); -diff --git a/drivers/scsi/mpt2sas/mpt3sas_transport.c b/drivers/scsi/mpt2sas/mpt3sas_transport.c -new file mode 100644 -index 0000000..690afa5 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_transport.c -@@ -0,0 +1,2138 @@ -+/* -+ * SAS Transport Layer for MPT (Message Passing Technology) based controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+/** -+ * _transport_sas_node_find_by_sas_address - sas node search -+ * @ioc: per adapter object -+ * @sas_address: sas address of expander or sas host -+ * Context: Calling function should acquire ioc->sas_node_lock. -+ * -+ * Search for either hba phys or expander device based on handle, then returns -+ * the sas_node object. -+ */ -+static struct _sas_node * -+_transport_sas_node_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address) -+{ -+ if (ioc->sas_hba.sas_address == sas_address) -+ return &ioc->sas_hba; -+ else -+ return mpt2sas_scsih_expander_find_by_sas_address(ioc, -+ sas_address); -+} -+ -+/** -+ * _transport_convert_phy_link_rate - -+ * @link_rate: link rate returned from mpt firmware -+ * -+ * Convert link_rate from mpi fusion into sas_transport form. -+ */ -+static enum sas_linkrate -+_transport_convert_phy_link_rate(u8 link_rate) -+{ -+ enum sas_linkrate rc; -+ -+ switch (link_rate) { -+ case MPI2_SAS_NEG_LINK_RATE_1_5: -+ rc = SAS_LINK_RATE_1_5_GBPS; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_3_0: -+ rc = SAS_LINK_RATE_3_0_GBPS; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_6_0: -+ rc = SAS_LINK_RATE_6_0_GBPS; -+ break; -+ case MPI25_SAS_NEG_LINK_RATE_12_0: -+ rc = SAS_LINK_RATE_12_0_GBPS; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED: -+ rc = SAS_PHY_DISABLED; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED: -+ rc = SAS_LINK_RATE_FAILED; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR: -+ rc = SAS_SATA_PORT_SELECTOR; -+ break; -+ case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS: -+ rc = SAS_PHY_RESET_IN_PROGRESS; -+ break; -+ -+ default: -+ case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE: -+ case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE: -+ rc = SAS_LINK_RATE_UNKNOWN; -+ break; -+ } -+ return rc; -+} -+ -+/** -+ * _transport_set_identify - set identify for phys and end devices -+ * @ioc: per adapter object -+ * @handle: device handle -+ * @identify: sas identify info -+ * -+ * Populates sas identify info. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_set_identify(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ struct sas_identify *identify) -+{ -+ Mpi2SasDevicePage0_t sas_device_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u32 device_info; -+ u32 ioc_status; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -+ MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -ENXIO; -+ } -+ -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT -+ "handle(0x%04x), ioc_status(0x%04x)\nfailure at %s:%d/%s()!\n", -+ ioc->name, handle, ioc_status, -+ __FILE__, __LINE__, __func__); -+ return -EIO; -+ } -+ -+ memset(identify, 0, sizeof(struct sas_identify)); -+ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); -+ -+ /* sas_address */ -+ identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -+ -+ /* phy number of the parent device this device is linked to */ -+ identify->phy_identifier = sas_device_pg0.PhyNum; -+ -+ /* device_type */ -+ switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { -+ case MPI2_SAS_DEVICE_INFO_NO_DEVICE: -+ identify->device_type = SAS_PHY_UNUSED; -+ break; -+ case MPI2_SAS_DEVICE_INFO_END_DEVICE: -+ identify->device_type = SAS_END_DEVICE; -+ break; -+ case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER: -+ identify->device_type = SAS_EDGE_EXPANDER_DEVICE; -+ break; -+ case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER: -+ identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; -+ break; -+ } -+ -+ /* initiator_port_protocols */ -+ if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR) -+ identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR) -+ identify->initiator_port_protocols |= SAS_PROTOCOL_STP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR) -+ identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST) -+ identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; -+ -+ /* target_port_protocols */ -+ if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) -+ identify->target_port_protocols |= SAS_PROTOCOL_SSP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) -+ identify->target_port_protocols |= SAS_PROTOCOL_STP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) -+ identify->target_port_protocols |= SAS_PROTOCOL_SMP; -+ if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -+ identify->target_port_protocols |= SAS_PROTOCOL_SATA; -+ -+ return 0; -+} -+ -+/** -+ * mpt2sas_transport_done - internal transport layer callback handler. -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @msix_index: MSIX table index supplied by the OS -+ * @reply: reply message frame(lower 32bit addr) -+ * -+ * Callback handler when sending internal generated transport cmds. -+ * The callback index passed is `ioc->transport_cb_idx` -+ * -+ * Return 1 meaning mf should be freed from _base_interrupt -+ * 0 means the mf is freed from this function. -+ */ -+u8 -+mpt2sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, -+ u32 reply) -+{ -+ MPI2DefaultReply_t *mpi_reply; -+ -+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -+ if (ioc->transport_cmds.status == MPT3_CMD_NOT_USED) -+ return 1; -+ if (ioc->transport_cmds.smid != smid) -+ return 1; -+ ioc->transport_cmds.status |= MPT3_CMD_COMPLETE; -+ if (mpi_reply) { -+ memcpy(ioc->transport_cmds.reply, mpi_reply, -+ mpi_reply->MsgLength*4); -+ ioc->transport_cmds.status |= MPT3_CMD_REPLY_VALID; -+ } -+ ioc->transport_cmds.status &= ~MPT3_CMD_PENDING; -+ complete(&ioc->transport_cmds.done); -+ return 1; -+} -+ -+/* report manufacture request structure */ -+struct rep_manu_request { -+ u8 smp_frame_type; -+ u8 function; -+ u8 reserved; -+ u8 request_length; -+}; -+ -+/* report manufacture reply structure */ -+struct rep_manu_reply { -+ u8 smp_frame_type; /* 0x41 */ -+ u8 function; /* 0x01 */ -+ u8 function_result; -+ u8 response_length; -+ u16 expander_change_count; -+ u8 reserved0[2]; -+ u8 sas_format; -+ u8 reserved2[3]; -+ u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; -+ u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; -+ u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; -+ u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; -+ u16 component_id; -+ u8 component_revision_id; -+ u8 reserved3; -+ u8 vendor_specific[8]; -+}; -+ -+/** -+ * transport_expander_report_manufacture - obtain SMP report_manufacture -+ * @ioc: per adapter object -+ * @sas_address: expander sas address -+ * @edev: the sas_expander_device object -+ * -+ * Fills in the sas_expander_device object when SMP port is created. -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address, struct sas_expander_device *edev) -+{ -+ Mpi2SmpPassthroughRequest_t *mpi_request; -+ Mpi2SmpPassthroughReply_t *mpi_reply; -+ struct rep_manu_reply *manufacture_reply; -+ struct rep_manu_request *manufacture_request; -+ int rc; -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ void *psge; -+ u8 issue_reset = 0; -+ void *data_out = NULL; -+ dma_addr_t data_out_dma; -+ dma_addr_t data_in_dma; -+ size_t data_in_sz; -+ size_t data_out_sz; -+ u16 wait_state_count; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ mutex_lock(&ioc->transport_cmds.mutex); -+ -+ if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->transport_cmds.status = MPT3_CMD_PENDING; -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ rc = 0; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->transport_cmds.smid = smid; -+ -+ data_out_sz = sizeof(struct rep_manu_request); -+ data_in_sz = sizeof(struct rep_manu_reply); -+ data_out = pci_alloc_consistent(ioc->pdev, data_out_sz + data_in_sz, -+ &data_out_dma); -+ -+ if (!data_out) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ rc = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ -+ data_in_dma = data_out_dma + sizeof(struct rep_manu_request); -+ -+ manufacture_request = data_out; -+ manufacture_request->smp_frame_type = 0x40; -+ manufacture_request->function = 1; -+ manufacture_request->reserved = 0; -+ manufacture_request->request_length = 0; -+ -+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; -+ mpi_request->PhysicalPort = 0xFF; -+ mpi_request->SASAddress = cpu_to_le64(sas_address); -+ mpi_request->RequestDataLength = cpu_to_le16(data_out_sz); -+ psge = &mpi_request->SGL; -+ -+ ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, -+ data_in_sz); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "report_manufacture - send to sas_addr(0x%016llx)\n", -+ ioc->name, (unsigned long long)sas_address)); -+ init_completion(&ioc->transport_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, -+ 10*HZ); -+ -+ if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SmpPassthroughRequest_t)/4); -+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "report_manufacture - complete\n", ioc->name)); -+ -+ if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { -+ u8 *tmp; -+ -+ mpi_reply = ioc->transport_cmds.reply; -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "report_manufacture - reply data transfer size(%d)\n", -+ ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); -+ -+ if (le16_to_cpu(mpi_reply->ResponseDataLength) != -+ sizeof(struct rep_manu_reply)) -+ goto out; -+ -+ manufacture_reply = data_out + sizeof(struct rep_manu_request); -+ strncpy(edev->vendor_id, manufacture_reply->vendor_id, -+ SAS_EXPANDER_VENDOR_ID_LEN); -+ strncpy(edev->product_id, manufacture_reply->product_id, -+ SAS_EXPANDER_PRODUCT_ID_LEN); -+ strncpy(edev->product_rev, manufacture_reply->product_rev, -+ SAS_EXPANDER_PRODUCT_REV_LEN); -+ edev->level = manufacture_reply->sas_format & 1; -+ if (edev->level) { -+ strncpy(edev->component_vendor_id, -+ manufacture_reply->component_vendor_id, -+ SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); -+ tmp = (u8 *)&manufacture_reply->component_id; -+ edev->component_id = tmp[0] << 8 | tmp[1]; -+ edev->component_revision_id = -+ manufacture_reply->component_revision_id; -+ } -+ } else -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "report_manufacture - no reply\n", ioc->name)); -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ out: -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ if (data_out) -+ pci_free_consistent(ioc->pdev, data_out_sz + data_in_sz, -+ data_out, data_out_dma); -+ -+ mutex_unlock(&ioc->transport_cmds.mutex); -+ return rc; -+} -+ -+ -+/** -+ * _transport_delete_port - helper function to removing a port -+ * @ioc: per adapter object -+ * @mpt2sas_port: mpt3sas per port object -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_delete_port(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_port *mpt2sas_port) -+{ -+ u64 sas_address = mpt2sas_port->remote_identify.sas_address; -+ enum sas_device_type device_type = -+ mpt2sas_port->remote_identify.device_type; -+ -+ dev_printk(KERN_INFO, &mpt2sas_port->port->dev, -+ "remove: sas_addr(0x%016llx)\n", -+ (unsigned long long) sas_address); -+ -+ ioc->logging_level |= MPT_DEBUG_TRANSPORT; -+ if (device_type == SAS_END_DEVICE) -+ mpt2sas_device_remove_by_sas_address(ioc, sas_address); -+ else if (device_type == SAS_EDGE_EXPANDER_DEVICE || -+ device_type == SAS_FANOUT_EXPANDER_DEVICE) -+ mpt2sas_expander_remove(ioc, sas_address); -+ ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; -+} -+ -+/** -+ * _transport_delete_phy - helper function to removing single phy from port -+ * @ioc: per adapter object -+ * @mpt2sas_port: mpt3sas per port object -+ * @mpt2sas_phy: mpt3sas per phy object -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_delete_phy(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy) -+{ -+ u64 sas_address = mpt2sas_port->remote_identify.sas_address; -+ -+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, -+ "remove: sas_addr(0x%016llx), phy(%d)\n", -+ (unsigned long long) sas_address, mpt2sas_phy->phy_id); -+ -+ list_del(&mpt2sas_phy->port_siblings); -+ mpt2sas_port->num_phys--; -+ sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); -+ mpt2sas_phy->phy_belongs_to_port = 0; -+} -+ -+/** -+ * _transport_add_phy - helper function to adding single phy to port -+ * @ioc: per adapter object -+ * @mpt2sas_port: mpt3sas per port object -+ * @mpt2sas_phy: mpt3sas per phy object -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_add_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port, -+ struct _sas_phy *mpt2sas_phy) -+{ -+ u64 sas_address = mpt2sas_port->remote_identify.sas_address; -+ -+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, -+ "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) -+ sas_address, mpt2sas_phy->phy_id); -+ -+ list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list); -+ mpt2sas_port->num_phys++; -+ sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy); -+ mpt2sas_phy->phy_belongs_to_port = 1; -+} -+ -+/** -+ * _transport_add_phy_to_an_existing_port - adding new phy to existing port -+ * @ioc: per adapter object -+ * @sas_node: sas node object (either expander or sas host) -+ * @mpt2sas_phy: mpt3sas per phy object -+ * @sas_address: sas address of device/expander were phy needs to be added to -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, -+ u64 sas_address) -+{ -+ struct _sas_port *mpt2sas_port; -+ struct _sas_phy *phy_srch; -+ -+ if (mpt2sas_phy->phy_belongs_to_port == 1) -+ return; -+ -+ list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, -+ port_list) { -+ if (mpt2sas_port->remote_identify.sas_address != -+ sas_address) -+ continue; -+ list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, -+ port_siblings) { -+ if (phy_srch == mpt2sas_phy) -+ return; -+ } -+ _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy); -+ return; -+ } -+ -+} -+ -+/** -+ * _transport_del_phy_from_an_existing_port - delete phy from existing port -+ * @ioc: per adapter object -+ * @sas_node: sas node object (either expander or sas host) -+ * @mpt2sas_phy: mpt3sas per phy object -+ * -+ * Returns nothing. -+ */ -+static void -+_transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc, -+ struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy) -+{ -+ struct _sas_port *mpt2sas_port, *next; -+ struct _sas_phy *phy_srch; -+ -+ if (mpt2sas_phy->phy_belongs_to_port == 0) -+ return; -+ -+ list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, -+ port_list) { -+ list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, -+ port_siblings) { -+ if (phy_srch != mpt2sas_phy) -+ continue; -+ -+ if (mpt2sas_port->num_phys == 1) -+ _transport_delete_port(ioc, mpt2sas_port); -+ else -+ _transport_delete_phy(ioc, mpt2sas_port, -+ mpt2sas_phy); -+ return; -+ } -+ } -+} -+ -+/** -+ * _transport_sanity_check - sanity check when adding a new port -+ * @ioc: per adapter object -+ * @sas_node: sas node object (either expander or sas host) -+ * @sas_address: sas address of device being added -+ * -+ * See the explanation above from _transport_delete_duplicate_port -+ */ -+static void -+_transport_sanity_check(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node, -+ u64 sas_address) -+{ -+ int i; -+ -+ for (i = 0; i < sas_node->num_phys; i++) { -+ if (sas_node->phy[i].remote_identify.sas_address != sas_address) -+ continue; -+ if (sas_node->phy[i].phy_belongs_to_port == 1) -+ _transport_del_phy_from_an_existing_port(ioc, sas_node, -+ &sas_node->phy[i]); -+ } -+} -+ -+/** -+ * mpt2sas_transport_port_add - insert port to the list -+ * @ioc: per adapter object -+ * @handle: handle of attached device -+ * @sas_address: sas address of parent expander or sas host -+ * Context: This function will acquire ioc->sas_node_lock. -+ * -+ * Adding new port object to the sas_node->sas_port_list. -+ * -+ * Returns mpt2sas_port. -+ */ -+struct _sas_port * -+mpt2sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, -+ u64 sas_address) -+{ -+ struct _sas_phy *mpt2sas_phy, *next; -+ struct _sas_port *mpt2sas_port; -+ unsigned long flags; -+ struct _sas_node *sas_node; -+ struct sas_rphy *rphy; -+ struct _sas_device *sas_device = NULL; -+ int i; -+ struct sas_port *port; -+ -+ mpt2sas_port = kzalloc(sizeof(struct _sas_port), -+ GFP_KERNEL); -+ if (!mpt2sas_port) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return NULL; -+ } -+ -+ INIT_LIST_HEAD(&mpt2sas_port->port_list); -+ INIT_LIST_HEAD(&mpt2sas_port->phy_list); -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ if (!sas_node) { -+ pr_err(MPT3SAS_FMT -+ "%s: Could not find parent sas_address(0x%016llx)!\n", -+ ioc->name, __func__, (unsigned long long)sas_address); -+ goto out_fail; -+ } -+ -+ if ((_transport_set_identify(ioc, handle, -+ &mpt2sas_port->remote_identify))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_fail; -+ } -+ -+ if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_fail; -+ } -+ -+ _transport_sanity_check(ioc, sas_node, -+ mpt2sas_port->remote_identify.sas_address); -+ -+ for (i = 0; i < sas_node->num_phys; i++) { -+ if (sas_node->phy[i].remote_identify.sas_address != -+ mpt2sas_port->remote_identify.sas_address) -+ continue; -+ list_add_tail(&sas_node->phy[i].port_siblings, -+ &mpt2sas_port->phy_list); -+ mpt2sas_port->num_phys++; -+ } -+ -+ if (!mpt2sas_port->num_phys) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_fail; -+ } -+ -+ port = sas_port_alloc_num(sas_node->parent_dev); -+ if ((sas_port_add(port))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ goto out_fail; -+ } -+ -+ list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, -+ port_siblings) { -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &port->dev, -+ "add: handle(0x%04x), sas_addr(0x%016llx), phy(%d)\n", -+ handle, (unsigned long long) -+ mpt2sas_port->remote_identify.sas_address, -+ mpt2sas_phy->phy_id); -+ sas_port_add_phy(port, mpt2sas_phy->phy); -+ mpt2sas_phy->phy_belongs_to_port = 1; -+ } -+ -+ mpt2sas_port->port = port; -+ if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) -+ rphy = sas_end_device_alloc(port); -+ else -+ rphy = sas_expander_alloc(port, -+ mpt2sas_port->remote_identify.device_type); -+ -+ rphy->identify = mpt2sas_port->remote_identify; -+ -+ if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) { -+ sas_device = mpt2sas_get_sdev_by_addr(ioc, -+ mpt2sas_port->remote_identify.sas_address); -+ if (!sas_device) { -+ dfailprintk(ioc, printk(MPT3SAS_FMT -+ "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__)); -+ goto out_fail; -+ } -+ sas_device->pend_sas_rphy_add = 1; -+ } -+ -+ if ((sas_rphy_add(rphy))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ } -+ -+ if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) { -+ sas_device->pend_sas_rphy_add = 0; -+ sas_device_put(sas_device); -+ } -+ -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &rphy->dev, -+ "add: handle(0x%04x), sas_addr(0x%016llx)\n", -+ handle, (unsigned long long) -+ mpt2sas_port->remote_identify.sas_address); -+ mpt2sas_port->rphy = rphy; -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list); -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ /* fill in report manufacture */ -+ if (mpt2sas_port->remote_identify.device_type == -+ MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || -+ mpt2sas_port->remote_identify.device_type == -+ MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) -+ _transport_expander_report_manufacture(ioc, -+ mpt2sas_port->remote_identify.sas_address, -+ rphy_to_expander_device(rphy)); -+ return mpt2sas_port; -+ -+ out_fail: -+ list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list, -+ port_siblings) -+ list_del(&mpt2sas_phy->port_siblings); -+ kfree(mpt2sas_port); -+ return NULL; -+} -+ -+/** -+ * mpt2sas_transport_port_remove - remove port from the list -+ * @ioc: per adapter object -+ * @sas_address: sas address of attached device -+ * @sas_address_parent: sas address of parent expander or sas host -+ * Context: This function will acquire ioc->sas_node_lock. -+ * -+ * Removing object and freeing associated memory from the -+ * ioc->sas_port_list. -+ * -+ * Return nothing. -+ */ -+void -+mpt2sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, -+ u64 sas_address_parent) -+{ -+ int i; -+ unsigned long flags; -+ struct _sas_port *mpt2sas_port, *next; -+ struct _sas_node *sas_node; -+ u8 found = 0; -+ struct _sas_phy *mpt2sas_phy, *next_phy; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_node = _transport_sas_node_find_by_sas_address(ioc, -+ sas_address_parent); -+ if (!sas_node) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return; -+ } -+ list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, -+ port_list) { -+ if (mpt2sas_port->remote_identify.sas_address != sas_address) -+ continue; -+ found = 1; -+ list_del(&mpt2sas_port->port_list); -+ goto out; -+ } -+ out: -+ if (!found) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return; -+ } -+ -+ for (i = 0; i < sas_node->num_phys; i++) { -+ if (sas_node->phy[i].remote_identify.sas_address == sas_address) -+ memset(&sas_node->phy[i].remote_identify, 0 , -+ sizeof(struct sas_identify)); -+ } -+ -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ list_for_each_entry_safe(mpt2sas_phy, next_phy, -+ &mpt2sas_port->phy_list, port_siblings) { -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &mpt2sas_port->port->dev, -+ "remove: sas_addr(0x%016llx), phy(%d)\n", -+ (unsigned long long) -+ mpt2sas_port->remote_identify.sas_address, -+ mpt2sas_phy->phy_id); -+ mpt2sas_phy->phy_belongs_to_port = 0; -+ sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); -+ list_del(&mpt2sas_phy->port_siblings); -+ } -+ sas_port_delete(mpt2sas_port->port); -+ kfree(mpt2sas_port); -+} -+ -+/** -+ * mpt2sas_transport_add_host_phy - report sas_host phy to transport -+ * @ioc: per adapter object -+ * @mpt2sas_phy: mpt3sas per phy object -+ * @phy_pg0: sas phy page 0 -+ * @parent_dev: parent device class object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy -+ *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev) -+{ -+ struct sas_phy *phy; -+ int phy_index = mpt2sas_phy->phy_id; -+ -+ -+ INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); -+ phy = sas_phy_alloc(parent_dev, phy_index); -+ if (!phy) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ if ((_transport_set_identify(ioc, mpt2sas_phy->handle, -+ &mpt2sas_phy->identify))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_phy_free(phy); -+ return -1; -+ } -+ phy->identify = mpt2sas_phy->identify; -+ mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle); -+ if (mpt2sas_phy->attached_handle) -+ _transport_set_identify(ioc, mpt2sas_phy->attached_handle, -+ &mpt2sas_phy->remote_identify); -+ phy->identify.phy_identifier = mpt2sas_phy->phy_id; -+ phy->negotiated_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); -+ phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( -+ phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( -+ phy_pg0.HwLinkRate >> 4); -+ phy->minimum_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.ProgrammedLinkRate >> 4); -+ -+ if ((sas_phy_add(phy))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_phy_free(phy); -+ return -1; -+ } -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &phy->dev, -+ "add: handle(0x%04x), sas_addr(0x%016llx)\n" -+ "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", -+ mpt2sas_phy->handle, (unsigned long long) -+ mpt2sas_phy->identify.sas_address, -+ mpt2sas_phy->attached_handle, -+ (unsigned long long) -+ mpt2sas_phy->remote_identify.sas_address); -+ mpt2sas_phy->phy = phy; -+ return 0; -+} -+ -+ -+/** -+ * mpt2sas_transport_add_expander_phy - report expander phy to transport -+ * @ioc: per adapter object -+ * @mpt2sas_phy: mpt3sas per phy object -+ * @expander_pg1: expander page 1 -+ * @parent_dev: parent device class object -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+int -+mpt2sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy -+ *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, -+ struct device *parent_dev) -+{ -+ struct sas_phy *phy; -+ int phy_index = mpt2sas_phy->phy_id; -+ -+ INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); -+ phy = sas_phy_alloc(parent_dev, phy_index); -+ if (!phy) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -1; -+ } -+ if ((_transport_set_identify(ioc, mpt2sas_phy->handle, -+ &mpt2sas_phy->identify))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_phy_free(phy); -+ return -1; -+ } -+ phy->identify = mpt2sas_phy->identify; -+ mpt2sas_phy->attached_handle = -+ le16_to_cpu(expander_pg1.AttachedDevHandle); -+ if (mpt2sas_phy->attached_handle) -+ _transport_set_identify(ioc, mpt2sas_phy->attached_handle, -+ &mpt2sas_phy->remote_identify); -+ phy->identify.phy_identifier = mpt2sas_phy->phy_id; -+ phy->negotiated_linkrate = _transport_convert_phy_link_rate( -+ expander_pg1.NegotiatedLinkRate & -+ MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); -+ phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( -+ expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( -+ expander_pg1.HwLinkRate >> 4); -+ phy->minimum_linkrate = _transport_convert_phy_link_rate( -+ expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate = _transport_convert_phy_link_rate( -+ expander_pg1.ProgrammedLinkRate >> 4); -+ -+ if ((sas_phy_add(phy))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ sas_phy_free(phy); -+ return -1; -+ } -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &phy->dev, -+ "add: handle(0x%04x), sas_addr(0x%016llx)\n" -+ "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", -+ mpt2sas_phy->handle, (unsigned long long) -+ mpt2sas_phy->identify.sas_address, -+ mpt2sas_phy->attached_handle, -+ (unsigned long long) -+ mpt2sas_phy->remote_identify.sas_address); -+ mpt2sas_phy->phy = phy; -+ return 0; -+} -+ -+/** -+ * mpt2sas_transport_update_links - refreshing phy link changes -+ * @ioc: per adapter object -+ * @sas_address: sas address of parent expander or sas host -+ * @handle: attached device handle -+ * @phy_numberv: phy number -+ * @link_rate: new link rate -+ * -+ * Returns nothing. -+ */ -+void -+mpt2sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, -+ u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) -+{ -+ unsigned long flags; -+ struct _sas_node *sas_node; -+ struct _sas_phy *mpt2sas_phy; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) -+ return; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); -+ if (!sas_node) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return; -+ } -+ -+ mpt2sas_phy = &sas_node->phy[phy_number]; -+ mpt2sas_phy->attached_handle = handle; -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { -+ _transport_set_identify(ioc, handle, -+ &mpt2sas_phy->remote_identify); -+ _transport_add_phy_to_an_existing_port(ioc, sas_node, -+ mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address); -+ } else -+ memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct -+ sas_identify)); -+ -+ if (mpt2sas_phy->phy) -+ mpt2sas_phy->phy->negotiated_linkrate = -+ _transport_convert_phy_link_rate(link_rate); -+ -+ if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) -+ dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, -+ "refresh: parent sas_addr(0x%016llx),\n" -+ "\tlink_rate(0x%02x), phy(%d)\n" -+ "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", -+ (unsigned long long)sas_address, -+ link_rate, phy_number, handle, (unsigned long long) -+ mpt2sas_phy->remote_identify.sas_address); -+} -+ -+static inline void * -+phy_to_ioc(struct sas_phy *phy) -+{ -+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); -+ return shost_priv(shost); -+} -+ -+static inline void * -+rphy_to_ioc(struct sas_rphy *rphy) -+{ -+ struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); -+ return shost_priv(shost); -+} -+ -+/* report phy error log structure */ -+struct phy_error_log_request { -+ u8 smp_frame_type; /* 0x40 */ -+ u8 function; /* 0x11 */ -+ u8 allocated_response_length; -+ u8 request_length; /* 02 */ -+ u8 reserved_1[5]; -+ u8 phy_identifier; -+ u8 reserved_2[2]; -+}; -+ -+/* report phy error log reply structure */ -+struct phy_error_log_reply { -+ u8 smp_frame_type; /* 0x41 */ -+ u8 function; /* 0x11 */ -+ u8 function_result; -+ u8 response_length; -+ __be16 expander_change_count; -+ u8 reserved_1[3]; -+ u8 phy_identifier; -+ u8 reserved_2[2]; -+ __be32 invalid_dword; -+ __be32 running_disparity_error; -+ __be32 loss_of_dword_sync; -+ __be32 phy_reset_problem; -+}; -+ -+/** -+ * _transport_get_expander_phy_error_log - return expander counters -+ * @ioc: per adapter object -+ * @phy: The sas phy object -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ */ -+static int -+_transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, -+ struct sas_phy *phy) -+{ -+ Mpi2SmpPassthroughRequest_t *mpi_request; -+ Mpi2SmpPassthroughReply_t *mpi_reply; -+ struct phy_error_log_request *phy_error_log_request; -+ struct phy_error_log_reply *phy_error_log_reply; -+ int rc; -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ void *psge; -+ u8 issue_reset = 0; -+ void *data_out = NULL; -+ dma_addr_t data_out_dma; -+ u32 sz; -+ u16 wait_state_count; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ mutex_lock(&ioc->transport_cmds.mutex); -+ -+ if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->transport_cmds.status = MPT3_CMD_PENDING; -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->transport_cmds.smid = smid; -+ -+ sz = sizeof(struct phy_error_log_request) + -+ sizeof(struct phy_error_log_reply); -+ data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); -+ if (!data_out) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ rc = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ -+ rc = -EINVAL; -+ memset(data_out, 0, sz); -+ phy_error_log_request = data_out; -+ phy_error_log_request->smp_frame_type = 0x40; -+ phy_error_log_request->function = 0x11; -+ phy_error_log_request->request_length = 2; -+ phy_error_log_request->allocated_response_length = 0; -+ phy_error_log_request->phy_identifier = phy->number; -+ -+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; -+ mpi_request->PhysicalPort = 0xFF; -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); -+ mpi_request->RequestDataLength = -+ cpu_to_le16(sizeof(struct phy_error_log_request)); -+ psge = &mpi_request->SGL; -+ -+ ioc->build_sg(ioc, psge, data_out_dma, -+ sizeof(struct phy_error_log_request), -+ data_out_dma + sizeof(struct phy_error_log_request), -+ sizeof(struct phy_error_log_reply)); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - send to sas_addr(0x%016llx), phy(%d)\n", -+ ioc->name, (unsigned long long)phy->identify.sas_address, -+ phy->number)); -+ init_completion(&ioc->transport_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, -+ 10*HZ); -+ -+ if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SmpPassthroughRequest_t)/4); -+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - complete\n", ioc->name)); -+ -+ if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { -+ -+ mpi_reply = ioc->transport_cmds.reply; -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - reply data transfer size(%d)\n", -+ ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); -+ -+ if (le16_to_cpu(mpi_reply->ResponseDataLength) != -+ sizeof(struct phy_error_log_reply)) -+ goto out; -+ -+ phy_error_log_reply = data_out + -+ sizeof(struct phy_error_log_request); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - function_result(%d)\n", -+ ioc->name, phy_error_log_reply->function_result)); -+ -+ phy->invalid_dword_count = -+ be32_to_cpu(phy_error_log_reply->invalid_dword); -+ phy->running_disparity_error_count = -+ be32_to_cpu(phy_error_log_reply->running_disparity_error); -+ phy->loss_of_dword_sync_count = -+ be32_to_cpu(phy_error_log_reply->loss_of_dword_sync); -+ phy->phy_reset_problem_count = -+ be32_to_cpu(phy_error_log_reply->phy_reset_problem); -+ rc = 0; -+ } else -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_error_log - no reply\n", ioc->name)); -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ out: -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ if (data_out) -+ pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); -+ -+ mutex_unlock(&ioc->transport_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * _transport_get_linkerrors - return phy counters for both hba and expanders -+ * @phy: The sas phy object -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ */ -+static int -+_transport_get_linkerrors(struct sas_phy *phy) -+{ -+ struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); -+ unsigned long flags; -+ Mpi2ConfigReply_t mpi_reply; -+ Mpi2SasPhyPage1_t phy_pg1; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ if (_transport_sas_node_find_by_sas_address(ioc, -+ phy->identify.sas_address) == NULL) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return -EINVAL; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) -+ return _transport_get_expander_phy_error_log(ioc, phy); -+ -+ /* get hba phy error logs */ -+ if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, -+ phy->number))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -ENXIO; -+ } -+ -+ if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) -+ pr_info(MPT3SAS_FMT -+ "phy(%d), ioc_status (0x%04x), loginfo(0x%08x)\n", -+ ioc->name, phy->number, -+ le16_to_cpu(mpi_reply.IOCStatus), -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ -+ phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount); -+ phy->running_disparity_error_count = -+ le32_to_cpu(phy_pg1.RunningDisparityErrorCount); -+ phy->loss_of_dword_sync_count = -+ le32_to_cpu(phy_pg1.LossDwordSynchCount); -+ phy->phy_reset_problem_count = -+ le32_to_cpu(phy_pg1.PhyResetProblemCount); -+ return 0; -+} -+ -+/** -+ * _transport_get_enclosure_identifier - -+ * @phy: The sas phy object -+ * -+ * Obtain the enclosure logical id for an expander. -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) -+{ -+ struct MPT3SAS_ADAPTER *ioc = rphy_to_ioc(rphy); -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ int rc; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ rphy->identify.sas_address); -+ if (sas_device) { -+ *identifier = sas_device->enclosure_logical_id; -+ rc = 0; -+ sas_device_put(sas_device); -+ } else { -+ *identifier = 0; -+ rc = -ENXIO; -+ } -+ -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ return rc; -+} -+ -+/** -+ * _transport_get_bay_identifier - -+ * @phy: The sas phy object -+ * -+ * Returns the slot id for a device that resides inside an enclosure. -+ */ -+static int -+_transport_get_bay_identifier(struct sas_rphy *rphy) -+{ -+ struct MPT3SAS_ADAPTER *ioc = rphy_to_ioc(rphy); -+ struct _sas_device *sas_device; -+ unsigned long flags; -+ int rc; -+ -+ spin_lock_irqsave(&ioc->sas_device_lock, flags); -+ sas_device = __mpt2sas_get_sdev_by_addr(ioc, -+ rphy->identify.sas_address); -+ if (sas_device) { -+ rc = sas_device->slot; -+ sas_device_put(sas_device); -+ } else { -+ rc = -ENXIO; -+ } -+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -+ return rc; -+} -+ -+/* phy control request structure */ -+struct phy_control_request { -+ u8 smp_frame_type; /* 0x40 */ -+ u8 function; /* 0x91 */ -+ u8 allocated_response_length; -+ u8 request_length; /* 0x09 */ -+ u16 expander_change_count; -+ u8 reserved_1[3]; -+ u8 phy_identifier; -+ u8 phy_operation; -+ u8 reserved_2[13]; -+ u64 attached_device_name; -+ u8 programmed_min_physical_link_rate; -+ u8 programmed_max_physical_link_rate; -+ u8 reserved_3[6]; -+}; -+ -+/* phy control reply structure */ -+struct phy_control_reply { -+ u8 smp_frame_type; /* 0x41 */ -+ u8 function; /* 0x11 */ -+ u8 function_result; -+ u8 response_length; -+}; -+ -+#define SMP_PHY_CONTROL_LINK_RESET (0x01) -+#define SMP_PHY_CONTROL_HARD_RESET (0x02) -+#define SMP_PHY_CONTROL_DISABLE (0x03) -+ -+/** -+ * _transport_expander_phy_control - expander phy control -+ * @ioc: per adapter object -+ * @phy: The sas phy object -+ * -+ * Returns 0 for success, non-zero for failure. -+ * -+ */ -+static int -+_transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, -+ struct sas_phy *phy, u8 phy_operation) -+{ -+ Mpi2SmpPassthroughRequest_t *mpi_request; -+ Mpi2SmpPassthroughReply_t *mpi_reply; -+ struct phy_control_request *phy_control_request; -+ struct phy_control_reply *phy_control_reply; -+ int rc; -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ void *psge; -+ u8 issue_reset = 0; -+ void *data_out = NULL; -+ dma_addr_t data_out_dma; -+ u32 sz; -+ u16 wait_state_count; -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ mutex_lock(&ioc->transport_cmds.mutex); -+ -+ if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->transport_cmds.status = MPT3_CMD_PENDING; -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto out; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->transport_cmds.smid = smid; -+ -+ sz = sizeof(struct phy_control_request) + -+ sizeof(struct phy_control_reply); -+ data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); -+ if (!data_out) { -+ pr_err("failure at %s:%d/%s()!\n", __FILE__, -+ __LINE__, __func__); -+ rc = -ENOMEM; -+ mpt2sas_base_free_smid(ioc, smid); -+ goto out; -+ } -+ -+ rc = -EINVAL; -+ memset(data_out, 0, sz); -+ phy_control_request = data_out; -+ phy_control_request->smp_frame_type = 0x40; -+ phy_control_request->function = 0x91; -+ phy_control_request->request_length = 9; -+ phy_control_request->allocated_response_length = 0; -+ phy_control_request->phy_identifier = phy->number; -+ phy_control_request->phy_operation = phy_operation; -+ phy_control_request->programmed_min_physical_link_rate = -+ phy->minimum_linkrate << 4; -+ phy_control_request->programmed_max_physical_link_rate = -+ phy->maximum_linkrate << 4; -+ -+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; -+ mpi_request->PhysicalPort = 0xFF; -+ mpi_request->VF_ID = 0; /* TODO */ -+ mpi_request->VP_ID = 0; -+ mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); -+ mpi_request->RequestDataLength = -+ cpu_to_le16(sizeof(struct phy_error_log_request)); -+ psge = &mpi_request->SGL; -+ -+ ioc->build_sg(ioc, psge, data_out_dma, -+ sizeof(struct phy_control_request), -+ data_out_dma + sizeof(struct phy_control_request), -+ sizeof(struct phy_control_reply)); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", -+ ioc->name, (unsigned long long)phy->identify.sas_address, -+ phy->number, phy_operation)); -+ init_completion(&ioc->transport_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, -+ 10*HZ); -+ -+ if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s: timeout\n", -+ ioc->name, __func__); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SmpPassthroughRequest_t)/4); -+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - complete\n", ioc->name)); -+ -+ if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { -+ -+ mpi_reply = ioc->transport_cmds.reply; -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - reply data transfer size(%d)\n", -+ ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); -+ -+ if (le16_to_cpu(mpi_reply->ResponseDataLength) != -+ sizeof(struct phy_control_reply)) -+ goto out; -+ -+ phy_control_reply = data_out + -+ sizeof(struct phy_control_request); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - function_result(%d)\n", -+ ioc->name, phy_control_reply->function_result)); -+ -+ rc = 0; -+ } else -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "phy_control - no reply\n", ioc->name)); -+ -+ issue_host_reset: -+ if (issue_reset) -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ out: -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ if (data_out) -+ pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); -+ -+ mutex_unlock(&ioc->transport_cmds.mutex); -+ return rc; -+} -+ -+/** -+ * _transport_phy_reset - -+ * @phy: The sas phy object -+ * @hard_reset: -+ * -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_phy_reset(struct sas_phy *phy, int hard_reset) -+{ -+ struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); -+ Mpi2SasIoUnitControlReply_t mpi_reply; -+ Mpi2SasIoUnitControlRequest_t mpi_request; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ if (_transport_sas_node_find_by_sas_address(ioc, -+ phy->identify.sas_address) == NULL) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return -EINVAL; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ /* handle expander phys */ -+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) -+ return _transport_expander_phy_control(ioc, phy, -+ (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET : -+ SMP_PHY_CONTROL_LINK_RESET); -+ -+ /* handle hba phys */ -+ memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); -+ mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; -+ mpi_request.Operation = hard_reset ? -+ MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET; -+ mpi_request.PhyNum = phy->number; -+ -+ if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ return -ENXIO; -+ } -+ -+ if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) -+ pr_info(MPT3SAS_FMT -+ "phy(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", -+ ioc->name, phy->number, le16_to_cpu(mpi_reply.IOCStatus), -+ le32_to_cpu(mpi_reply.IOCLogInfo)); -+ -+ return 0; -+} -+ -+/** -+ * _transport_phy_enable - enable/disable phys -+ * @phy: The sas phy object -+ * @enable: enable phy when true -+ * -+ * Only support sas_host direct attached phys. -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_phy_enable(struct sas_phy *phy, int enable) -+{ -+ struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); -+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; -+ Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u16 sz; -+ int rc = 0; -+ unsigned long flags; -+ int i, discovery_active; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ if (_transport_sas_node_find_by_sas_address(ioc, -+ phy->identify.sas_address) == NULL) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return -EINVAL; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ /* handle expander phys */ -+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) -+ return _transport_expander_phy_control(ioc, phy, -+ (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET : -+ SMP_PHY_CONTROL_DISABLE); -+ -+ /* handle hba phys */ -+ -+ /* read sas_iounit page 0 */ -+ sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit0PhyData_t)); -+ sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg0) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENOMEM; -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, -+ sas_iounit_pg0, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENXIO; -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -EIO; -+ goto out; -+ } -+ -+ /* unable to enable/disable phys when when discovery is active */ -+ for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) { -+ if (sas_iounit_pg0->PhyData[i].PortFlags & -+ MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) { -+ pr_err(MPT3SAS_FMT "discovery is active on " \ -+ "port = %d, phy = %d: unable to enable/disable " -+ "phys, try again later!\n", ioc->name, -+ sas_iounit_pg0->PhyData[i].Port, i); -+ discovery_active = 1; -+ } -+ } -+ -+ if (discovery_active) { -+ rc = -EAGAIN; -+ goto out; -+ } -+ -+ /* read sas_iounit page 1 */ -+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit1PhyData_t)); -+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg1) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENOMEM; -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, -+ sas_iounit_pg1, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENXIO; -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -EIO; -+ goto out; -+ } -+ -+ /* copy Port/PortFlags/PhyFlags from page 0 */ -+ for (i = 0; i < ioc->sas_hba.num_phys ; i++) { -+ sas_iounit_pg1->PhyData[i].Port = -+ sas_iounit_pg0->PhyData[i].Port; -+ sas_iounit_pg1->PhyData[i].PortFlags = -+ (sas_iounit_pg0->PhyData[i].PortFlags & -+ MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG); -+ sas_iounit_pg1->PhyData[i].PhyFlags = -+ (sas_iounit_pg0->PhyData[i].PhyFlags & -+ (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED + -+ MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)); -+ } -+ -+ if (enable) -+ sas_iounit_pg1->PhyData[phy->number].PhyFlags -+ &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; -+ else -+ sas_iounit_pg1->PhyData[phy->number].PhyFlags -+ |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; -+ -+ mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); -+ -+ /* link reset */ -+ if (enable) -+ _transport_phy_reset(phy, 0); -+ -+ out: -+ kfree(sas_iounit_pg1); -+ kfree(sas_iounit_pg0); -+ return rc; -+} -+ -+/** -+ * _transport_phy_speed - set phy min/max link rates -+ * @phy: The sas phy object -+ * @rates: rates defined in sas_phy_linkrates -+ * -+ * Only support sas_host direct attached phys. -+ * Returns 0 for success, non-zero for failure. -+ */ -+static int -+_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) -+{ -+ struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy); -+ Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; -+ Mpi2SasPhyPage0_t phy_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 ioc_status; -+ u16 sz; -+ int i; -+ int rc = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ioc->sas_node_lock, flags); -+ if (_transport_sas_node_find_by_sas_address(ioc, -+ phy->identify.sas_address) == NULL) { -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ return -EINVAL; -+ } -+ spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -+ -+ if (!rates->minimum_linkrate) -+ rates->minimum_linkrate = phy->minimum_linkrate; -+ else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) -+ rates->minimum_linkrate = phy->minimum_linkrate_hw; -+ -+ if (!rates->maximum_linkrate) -+ rates->maximum_linkrate = phy->maximum_linkrate; -+ else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) -+ rates->maximum_linkrate = phy->maximum_linkrate_hw; -+ -+ /* handle expander phys */ -+ if (phy->identify.sas_address != ioc->sas_hba.sas_address) { -+ phy->minimum_linkrate = rates->minimum_linkrate; -+ phy->maximum_linkrate = rates->maximum_linkrate; -+ return _transport_expander_phy_control(ioc, phy, -+ SMP_PHY_CONTROL_LINK_RESET); -+ } -+ -+ /* handle hba phys */ -+ -+ /* sas_iounit page 1 */ -+ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * -+ sizeof(Mpi2SasIOUnit1PhyData_t)); -+ sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); -+ if (!sas_iounit_pg1) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENOMEM; -+ goto out; -+ } -+ if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, -+ sas_iounit_pg1, sz))) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENXIO; -+ goto out; -+ } -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -EIO; -+ goto out; -+ } -+ -+ for (i = 0; i < ioc->sas_hba.num_phys; i++) { -+ if (phy->number != i) { -+ sas_iounit_pg1->PhyData[i].MaxMinLinkRate = -+ (ioc->sas_hba.phy[i].phy->minimum_linkrate + -+ (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); -+ } else { -+ sas_iounit_pg1->PhyData[i].MaxMinLinkRate = -+ (rates->minimum_linkrate + -+ (rates->maximum_linkrate << 4)); -+ } -+ } -+ -+ if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, -+ sz)) { -+ pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", -+ ioc->name, __FILE__, __LINE__, __func__); -+ rc = -ENXIO; -+ goto out; -+ } -+ -+ /* link reset */ -+ _transport_phy_reset(phy, 0); -+ -+ /* read phy page 0, then update the rates in the sas transport phy */ -+ if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, -+ phy->number)) { -+ phy->minimum_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); -+ phy->maximum_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.ProgrammedLinkRate >> 4); -+ phy->negotiated_linkrate = _transport_convert_phy_link_rate( -+ phy_pg0.NegotiatedLinkRate & -+ MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); -+ } -+ -+ out: -+ kfree(sas_iounit_pg1); -+ return rc; -+} -+ -+/** -+ * _transport_smp_handler - transport portal for smp passthru -+ * @shost: shost object -+ * @rphy: sas transport rphy object -+ * @req: -+ * -+ * This used primarily for smp_utils. -+ * Example: -+ * smp_rep_general /sys/class/bsg/expander-5:0 -+ */ -+static int -+_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, -+ struct request *req) -+{ -+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); -+ Mpi2SmpPassthroughRequest_t *mpi_request; -+ Mpi2SmpPassthroughReply_t *mpi_reply; -+ int rc, i; -+ u16 smid; -+ u32 ioc_state; -+ unsigned long timeleft; -+ void *psge; -+ u8 issue_reset = 0; -+ dma_addr_t dma_addr_in = 0; -+ dma_addr_t dma_addr_out = 0; -+ dma_addr_t pci_dma_in = 0; -+ dma_addr_t pci_dma_out = 0; -+ void *pci_addr_in = NULL; -+ void *pci_addr_out = NULL; -+ u16 wait_state_count; -+ struct request *rsp = req->next_rq; -+ struct bio_vec *bvec = NULL; -+ -+ if (!rsp) { -+ pr_err(MPT3SAS_FMT "%s: the smp response space is missing\n", -+ ioc->name, __func__); -+ return -EINVAL; -+ } -+ -+ if (ioc->shost_recovery || ioc->pci_error_recovery) { -+ pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", -+ __func__, ioc->name); -+ return -EFAULT; -+ } -+ -+ rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); -+ if (rc) -+ return rc; -+ -+ if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { -+ pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name, -+ __func__); -+ rc = -EAGAIN; -+ goto out; -+ } -+ ioc->transport_cmds.status = MPT3_CMD_PENDING; -+ -+ /* Check if the request is split across multiple segments */ -+ if (req->bio->bi_vcnt > 1) { -+ u32 offset = 0; -+ -+ /* Allocate memory and copy the request */ -+ pci_addr_out = pci_alloc_consistent(ioc->pdev, -+ blk_rq_bytes(req), &pci_dma_out); -+ if (!pci_addr_out) { -+ pr_info(MPT3SAS_FMT "%s(): PCI Addr out = NULL\n", -+ ioc->name, __func__); -+ rc = -ENOMEM; -+ goto out; -+ } -+ -+ bio_for_each_segment(bvec, req->bio, i) { -+ memcpy(pci_addr_out + offset, -+ page_address(bvec->bv_page) + bvec->bv_offset, -+ bvec->bv_len); -+ offset += bvec->bv_len; -+ } -+ } else { -+ dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), -+ blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); -+ if (pci_dma_mapping_error(ioc->pdev, dma_addr_out)) { -+ pr_info(MPT3SAS_FMT "%s(): DMA Addr out = NULL\n", -+ ioc->name, __func__); -+ rc = -ENOMEM; -+ goto free_pci; -+ } -+ } -+ -+ /* Check if the response needs to be populated across -+ * multiple segments */ -+ if (rsp->bio->bi_vcnt > 1) { -+ pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), -+ &pci_dma_in); -+ if (!pci_addr_in) { -+ pr_info(MPT3SAS_FMT "%s(): PCI Addr in = NULL\n", -+ ioc->name, __func__); -+ rc = -ENOMEM; -+ goto unmap; -+ } -+ } else { -+ dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), -+ blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); -+ if (pci_dma_mapping_error(ioc->pdev, dma_addr_in)) { -+ pr_info(MPT3SAS_FMT "%s(): DMA Addr in = NULL\n", -+ ioc->name, __func__); -+ rc = -ENOMEM; -+ goto unmap; -+ } -+ } -+ -+ wait_state_count = 0; -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { -+ if (wait_state_count++ == 10) { -+ pr_err(MPT3SAS_FMT -+ "%s: failed due to ioc not operational\n", -+ ioc->name, __func__); -+ rc = -EFAULT; -+ goto unmap; -+ } -+ ssleep(1); -+ ioc_state = mpt2sas_base_get_iocstate(ioc, 1); -+ pr_info(MPT3SAS_FMT -+ "%s: waiting for operational state(count=%d)\n", -+ ioc->name, __func__, wait_state_count); -+ } -+ if (wait_state_count) -+ pr_info(MPT3SAS_FMT "%s: ioc is operational\n", -+ ioc->name, __func__); -+ -+ smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); -+ if (!smid) { -+ pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", -+ ioc->name, __func__); -+ rc = -EAGAIN; -+ goto unmap; -+ } -+ -+ rc = 0; -+ mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -+ ioc->transport_cmds.smid = smid; -+ -+ memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); -+ mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; -+ mpi_request->PhysicalPort = 0xFF; -+ mpi_request->SASAddress = (rphy) ? -+ cpu_to_le64(rphy->identify.sas_address) : -+ cpu_to_le64(ioc->sas_hba.sas_address); -+ mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); -+ psge = &mpi_request->SGL; -+ -+ if (req->bio->bi_vcnt > 1) -+ ioc->build_sg(ioc, psge, pci_dma_out, (blk_rq_bytes(req) - 4), -+ pci_dma_in, (blk_rq_bytes(rsp) + 4)); -+ else -+ ioc->build_sg(ioc, psge, dma_addr_out, (blk_rq_bytes(req) - 4), -+ dma_addr_in, (blk_rq_bytes(rsp) + 4)); -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - sending smp request\n", ioc->name, __func__)); -+ -+ init_completion(&ioc->transport_cmds.done); -+ mpt2sas_base_put_smid_default(ioc, smid); -+ timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, -+ 10*HZ); -+ -+ if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { -+ pr_err(MPT3SAS_FMT "%s : timeout\n", -+ __func__, ioc->name); -+ _debug_dump_mf(mpi_request, -+ sizeof(Mpi2SmpPassthroughRequest_t)/4); -+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) -+ issue_reset = 1; -+ goto issue_host_reset; -+ } -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - complete\n", ioc->name, __func__)); -+ -+ if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { -+ -+ mpi_reply = ioc->transport_cmds.reply; -+ -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - reply data transfer size(%d)\n", -+ ioc->name, __func__, -+ le16_to_cpu(mpi_reply->ResponseDataLength))); -+ -+ memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); -+ req->sense_len = sizeof(*mpi_reply); -+ req->resid_len = 0; -+ rsp->resid_len -= -+ le16_to_cpu(mpi_reply->ResponseDataLength); -+ -+ /* check if the resp needs to be copied from the allocated -+ * pci mem */ -+ if (rsp->bio->bi_vcnt > 1) { -+ u32 offset = 0; -+ u32 bytes_to_copy = -+ le16_to_cpu(mpi_reply->ResponseDataLength); -+ bio_for_each_segment(bvec, rsp->bio, i) { -+ if (bytes_to_copy <= bvec->bv_len) { -+ memcpy(page_address(bvec->bv_page) + -+ bvec->bv_offset, pci_addr_in + -+ offset, bytes_to_copy); -+ break; -+ } else { -+ memcpy(page_address(bvec->bv_page) + -+ bvec->bv_offset, pci_addr_in + -+ offset, bvec->bv_len); -+ bytes_to_copy -= bvec->bv_len; -+ } -+ offset += bvec->bv_len; -+ } -+ } -+ } else { -+ dtransportprintk(ioc, pr_info(MPT3SAS_FMT -+ "%s - no reply\n", ioc->name, __func__)); -+ rc = -ENXIO; -+ } -+ -+ issue_host_reset: -+ if (issue_reset) { -+ mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, -+ FORCE_BIG_HAMMER); -+ rc = -ETIMEDOUT; -+ } -+ -+ unmap: -+ if (dma_addr_out) -+ pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req), -+ PCI_DMA_BIDIRECTIONAL); -+ if (dma_addr_in) -+ pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), -+ PCI_DMA_BIDIRECTIONAL); -+ -+ free_pci: -+ if (pci_addr_out) -+ pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out, -+ pci_dma_out); -+ -+ if (pci_addr_in) -+ pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in, -+ pci_dma_in); -+ -+ out: -+ ioc->transport_cmds.status = MPT3_CMD_NOT_USED; -+ mutex_unlock(&ioc->transport_cmds.mutex); -+ return rc; -+} -+ -+struct sas_function_template mpt2sas_transport_functions = { -+ .get_linkerrors = _transport_get_linkerrors, -+ .get_enclosure_identifier = _transport_get_enclosure_identifier, -+ .get_bay_identifier = _transport_get_bay_identifier, -+ .phy_reset = _transport_phy_reset, -+ .phy_enable = _transport_phy_enable, -+ .set_phy_speed = _transport_phy_speed, -+ .smp_handler = _transport_smp_handler, -+}; -+ -+struct scsi_transport_template *mpt2sas_transport_template; -diff --git a/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c -new file mode 100644 -index 0000000..d5038ec ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.c -@@ -0,0 +1,434 @@ -+/* -+ * This module provides common API to set Diagnostic trigger for MPT -+ * (Message Passing Technology) based controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+/** -+ * _mpt2sas_raise_sigio - notifiy app -+ * @ioc: per adapter object -+ * @event_data: -+ */ -+static void -+_mpt2sas_raise_sigio(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) -+{ -+ Mpi2EventNotificationReply_t *mpi_reply; -+ u16 sz, event_data_sz; -+ unsigned long flags; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", -+ ioc->name, __func__)); -+ -+ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + -+ sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4; -+ mpi_reply = kzalloc(sz, GFP_KERNEL); -+ if (!mpi_reply) -+ goto out; -+ mpi_reply->Event = cpu_to_le16(MPI3_EVENT_DIAGNOSTIC_TRIGGER_FIRED); -+ event_data_sz = (sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T) + 4) / 4; -+ mpi_reply->EventDataLength = cpu_to_le16(event_data_sz); -+ memcpy(&mpi_reply->EventData, event_data, -+ sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: add to driver event log\n", -+ ioc->name, __func__)); -+ mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); -+ kfree(mpi_reply); -+ out: -+ -+ /* clearing the diag_trigger_active flag */ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: clearing diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ ioc->diag_trigger_active = 0; -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_process_trigger_data - process the event data for the trigger -+ * @ioc: per adapter object -+ * @event_data: -+ */ -+void -+mpt2sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc, -+ struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) -+{ -+ u8 issue_reset = 0; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: enter\n", -+ ioc->name, __func__)); -+ -+ /* release the diag buffer trace */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: release trace diag buffer\n", ioc->name, __func__)); -+ mpt2sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, -+ &issue_reset); -+ } -+ -+ _mpt2sas_raise_sigio(ioc, event_data); -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_trigger_master - Master trigger handler -+ * @ioc: per adapter object -+ * @trigger_bitmask: -+ * -+ */ -+void -+mpt2sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, u32 trigger_bitmask) -+{ -+ struct SL_WH_TRIGGERS_EVENT_DATA_T event_data; -+ unsigned long flags; -+ u8 found_match = 0; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ -+ if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT || -+ trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET) -+ goto by_pass_checks; -+ -+ /* check to see if trace buffers are currently registered */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ /* check to see if trace buffers are currently released */ -+ if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ by_pass_checks: -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter - trigger_bitmask = 0x%08x\n", -+ ioc->name, __func__, trigger_bitmask)); -+ -+ /* don't send trigger if an trigger is currently active */ -+ if (ioc->diag_trigger_active) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ goto out; -+ } -+ -+ /* check for the trigger condition */ -+ if (ioc->diag_trigger_master.MasterData & trigger_bitmask) { -+ found_match = 1; -+ ioc->diag_trigger_active = 1; -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ } -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ if (!found_match) -+ goto out; -+ -+ memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ event_data.trigger_type = MPT3SAS_TRIGGER_MASTER; -+ event_data.u.master.MasterData = trigger_bitmask; -+ -+ if (trigger_bitmask & MASTER_TRIGGER_FW_FAULT || -+ trigger_bitmask & MASTER_TRIGGER_ADAPTER_RESET) -+ _mpt2sas_raise_sigio(ioc, &event_data); -+ else -+ mpt2sas_send_trigger_data_event(ioc, &event_data); -+ -+ out: -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_trigger_event - Event trigger handler -+ * @ioc: per adapter object -+ * @event: -+ * @log_entry_qualifier: -+ * -+ */ -+void -+mpt2sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event, -+ u16 log_entry_qualifier) -+{ -+ struct SL_WH_TRIGGERS_EVENT_DATA_T event_data; -+ struct SL_WH_EVENT_TRIGGER_T *event_trigger; -+ int i; -+ unsigned long flags; -+ u8 found_match; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ -+ /* check to see if trace buffers are currently registered */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ /* check to see if trace buffers are currently released */ -+ if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter - event = 0x%04x, log_entry_qualifier = 0x%04x\n", -+ ioc->name, __func__, event, log_entry_qualifier)); -+ -+ /* don't send trigger if an trigger is currently active */ -+ if (ioc->diag_trigger_active) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ goto out; -+ } -+ -+ /* check for the trigger condition */ -+ event_trigger = ioc->diag_trigger_event.EventTriggerEntry; -+ for (i = 0 , found_match = 0; i < ioc->diag_trigger_event.ValidEntries -+ && !found_match; i++, event_trigger++) { -+ if (event_trigger->EventValue != event) -+ continue; -+ if (event == MPI2_EVENT_LOG_ENTRY_ADDED) { -+ if (event_trigger->LogEntryQualifier == -+ log_entry_qualifier) -+ found_match = 1; -+ continue; -+ } -+ found_match = 1; -+ ioc->diag_trigger_active = 1; -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ } -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ if (!found_match) -+ goto out; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ event_data.trigger_type = MPT3SAS_TRIGGER_EVENT; -+ event_data.u.event.EventValue = event; -+ event_data.u.event.LogEntryQualifier = log_entry_qualifier; -+ mpt2sas_send_trigger_data_event(ioc, &event_data); -+ out: -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_trigger_scsi - SCSI trigger handler -+ * @ioc: per adapter object -+ * @sense_key: -+ * @asc: -+ * @ascq: -+ * -+ */ -+void -+mpt2sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc, -+ u8 ascq) -+{ -+ struct SL_WH_TRIGGERS_EVENT_DATA_T event_data; -+ struct SL_WH_SCSI_TRIGGER_T *scsi_trigger; -+ int i; -+ unsigned long flags; -+ u8 found_match; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ -+ /* check to see if trace buffers are currently registered */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ /* check to see if trace buffers are currently released */ -+ if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter - sense_key = 0x%02x, asc = 0x%02x, ascq = 0x%02x\n", -+ ioc->name, __func__, sense_key, asc, ascq)); -+ -+ /* don't send trigger if an trigger is currently active */ -+ if (ioc->diag_trigger_active) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ goto out; -+ } -+ -+ /* check for the trigger condition */ -+ scsi_trigger = ioc->diag_trigger_scsi.SCSITriggerEntry; -+ for (i = 0 , found_match = 0; i < ioc->diag_trigger_scsi.ValidEntries -+ && !found_match; i++, scsi_trigger++) { -+ if (scsi_trigger->SenseKey != sense_key) -+ continue; -+ if (!(scsi_trigger->ASC == 0xFF || scsi_trigger->ASC == asc)) -+ continue; -+ if (!(scsi_trigger->ASCQ == 0xFF || scsi_trigger->ASCQ == ascq)) -+ continue; -+ found_match = 1; -+ ioc->diag_trigger_active = 1; -+ } -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ if (!found_match) -+ goto out; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ event_data.trigger_type = MPT3SAS_TRIGGER_SCSI; -+ event_data.u.scsi.SenseKey = sense_key; -+ event_data.u.scsi.ASC = asc; -+ event_data.u.scsi.ASCQ = ascq; -+ mpt2sas_send_trigger_data_event(ioc, &event_data); -+ out: -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -+ -+/** -+ * mpt2sas_trigger_mpi - MPI trigger handler -+ * @ioc: per adapter object -+ * @ioc_status: -+ * @loginfo: -+ * -+ */ -+void -+mpt2sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo) -+{ -+ struct SL_WH_TRIGGERS_EVENT_DATA_T event_data; -+ struct SL_WH_MPI_TRIGGER_T *mpi_trigger; -+ int i; -+ unsigned long flags; -+ u8 found_match; -+ -+ spin_lock_irqsave(&ioc->diag_trigger_lock, flags); -+ -+ /* check to see if trace buffers are currently registered */ -+ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ /* check to see if trace buffers are currently released */ -+ if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & -+ MPT3_DIAG_BUFFER_IS_RELEASED) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ return; -+ } -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: enter - ioc_status = 0x%04x, loginfo = 0x%08x\n", -+ ioc->name, __func__, ioc_status, loginfo)); -+ -+ /* don't send trigger if an trigger is currently active */ -+ if (ioc->diag_trigger_active) { -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ goto out; -+ } -+ -+ /* check for the trigger condition */ -+ mpi_trigger = ioc->diag_trigger_mpi.MPITriggerEntry; -+ for (i = 0 , found_match = 0; i < ioc->diag_trigger_mpi.ValidEntries -+ && !found_match; i++, mpi_trigger++) { -+ if (mpi_trigger->IOCStatus != ioc_status) -+ continue; -+ if (!(mpi_trigger->IocLogInfo == 0xFFFFFFFF || -+ mpi_trigger->IocLogInfo == loginfo)) -+ continue; -+ found_match = 1; -+ ioc->diag_trigger_active = 1; -+ } -+ spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); -+ -+ if (!found_match) -+ goto out; -+ -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT -+ "%s: setting diag_trigger_active flag\n", -+ ioc->name, __func__)); -+ memset(&event_data, 0, sizeof(struct SL_WH_TRIGGERS_EVENT_DATA_T)); -+ event_data.trigger_type = MPT3SAS_TRIGGER_MPI; -+ event_data.u.mpi.IOCStatus = ioc_status; -+ event_data.u.mpi.IocLogInfo = loginfo; -+ mpt2sas_send_trigger_data_event(ioc, &event_data); -+ out: -+ dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, -+ __func__)); -+} -diff --git a/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h b/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h -new file mode 100644 -index 0000000..6586a46 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_trigger_diag.h -@@ -0,0 +1,194 @@ -+/* -+ * This is the Fusion MPT base driver providing common API layer interface -+ * to set Diagnostic triggers for MPT (Message Passing Technology) based -+ * controllers -+ * -+ * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2014 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -+ * USA. -+ */ -+ /* Diagnostic Trigger Configuration Data Structures */ -+ -+#ifndef MPT3SAS_TRIGGER_DIAG_H_INCLUDED -+#define MPT3SAS_TRIGGER_DIAG_H_INCLUDED -+ -+/* limitation on number of entries */ -+#define NUM_VALID_ENTRIES (20) -+ -+/* trigger types */ -+#define MPT3SAS_TRIGGER_MASTER (1) -+#define MPT3SAS_TRIGGER_EVENT (2) -+#define MPT3SAS_TRIGGER_SCSI (3) -+#define MPT3SAS_TRIGGER_MPI (4) -+ -+/* trigger names */ -+#define MASTER_TRIGGER_FILE_NAME "diag_trigger_master" -+#define EVENT_TRIGGERS_FILE_NAME "diag_trigger_event" -+#define SCSI_TRIGGERS_FILE_NAME "diag_trigger_scsi" -+#define MPI_TRIGGER_FILE_NAME "diag_trigger_mpi" -+ -+/* master trigger bitmask */ -+#define MASTER_TRIGGER_FW_FAULT (0x00000001) -+#define MASTER_TRIGGER_ADAPTER_RESET (0x00000002) -+#define MASTER_TRIGGER_TASK_MANAGMENT (0x00000004) -+#define MASTER_TRIGGER_DEVICE_REMOVAL (0x00000008) -+ -+/* fake firmware event for tigger */ -+#define MPI3_EVENT_DIAGNOSTIC_TRIGGER_FIRED (0x6E) -+ -+/** -+ * MasterTrigger is a single U32 passed to/from sysfs. -+ * -+ * Bit Flags (enables) include: -+ * 1. FW Faults -+ * 2. Adapter Reset issued by driver -+ * 3. TMs -+ * 4. Device Remove Event sent by FW -+ */ -+ -+struct SL_WH_MASTER_TRIGGER_T { -+ uint32_t MasterData; -+}; -+ -+/** -+ * struct SL_WH_EVENT_TRIGGER_T - Definition of an event trigger element -+ * @EventValue: Event Code to trigger on -+ * @LogEntryQualifier: Type of FW event that logged (Log Entry Added Event only) -+ * -+ * Defines an event that should induce a DIAG_TRIGGER driver event if observed. -+ */ -+struct SL_WH_EVENT_TRIGGER_T { -+ uint16_t EventValue; -+ uint16_t LogEntryQualifier; -+}; -+ -+/** -+ * struct SL_WH_EVENT_TRIGGERS_T - Structure passed to/from sysfs containing a -+ * list of Event Triggers to be monitored for. -+ * @ValidEntries: Number of _SL_WH_EVENT_TRIGGER_T structures contained in this -+ * structure. -+ * @EventTriggerEntry: List of Event trigger elements. -+ * -+ * This binary structure is transferred via sysfs to get/set Event Triggers -+ * in the Linux Driver. -+ */ -+ -+struct SL_WH_EVENT_TRIGGERS_T { -+ uint32_t ValidEntries; -+ struct SL_WH_EVENT_TRIGGER_T EventTriggerEntry[NUM_VALID_ENTRIES]; -+}; -+ -+/** -+ * struct SL_WH_SCSI_TRIGGER_T - Definition of a SCSI trigger element -+ * @ASCQ: Additional Sense Code Qualifier. Can be specific or 0xFF for -+ * wildcard. -+ * @ASC: Additional Sense Code. Can be specific or 0xFF for wildcard -+ * @SenseKey: SCSI Sense Key -+ * -+ * Defines a sense key (single or many variants) that should induce a -+ * DIAG_TRIGGER driver event if observed. -+ */ -+struct SL_WH_SCSI_TRIGGER_T { -+ U8 ASCQ; -+ U8 ASC; -+ U8 SenseKey; -+ U8 Reserved; -+}; -+ -+/** -+ * struct SL_WH_SCSI_TRIGGERS_T - Structure passed to/from sysfs containing a -+ * list of SCSI sense codes that should trigger a DIAG_SERVICE event when -+ * observed. -+ * @ValidEntries: Number of _SL_WH_SCSI_TRIGGER_T structures contained in this -+ * structure. -+ * @SCSITriggerEntry: List of SCSI Sense Code trigger elements. -+ * -+ * This binary structure is transferred via sysfs to get/set SCSI Sense Code -+ * Triggers in the Linux Driver. -+ */ -+struct SL_WH_SCSI_TRIGGERS_T { -+ uint32_t ValidEntries; -+ struct SL_WH_SCSI_TRIGGER_T SCSITriggerEntry[NUM_VALID_ENTRIES]; -+}; -+ -+/** -+ * struct SL_WH_MPI_TRIGGER_T - Definition of an MPI trigger element -+ * @IOCStatus: MPI IOCStatus -+ * @IocLogInfo: MPI IocLogInfo. Can be specific or 0xFFFFFFFF for wildcard -+ * -+ * Defines a MPI IOCStatus/IocLogInfo pair that should induce a DIAG_TRIGGER -+ * driver event if observed. -+ */ -+struct SL_WH_MPI_TRIGGER_T { -+ uint16_t IOCStatus; -+ uint16_t Reserved; -+ uint32_t IocLogInfo; -+}; -+ -+/** -+ * struct SL_WH_MPI_TRIGGERS_T - Structure passed to/from sysfs containing a -+ * list of MPI IOCStatus/IocLogInfo pairs that should trigger a DIAG_SERVICE -+ * event when observed. -+ * @ValidEntries: Number of _SL_WH_MPI_TRIGGER_T structures contained in this -+ * structure. -+ * @MPITriggerEntry: List of MPI IOCStatus/IocLogInfo trigger elements. -+ * -+ * This binary structure is transferred via sysfs to get/set MPI Error Triggers -+ * in the Linux Driver. -+ */ -+struct SL_WH_MPI_TRIGGERS_T { -+ uint32_t ValidEntries; -+ struct SL_WH_MPI_TRIGGER_T MPITriggerEntry[NUM_VALID_ENTRIES]; -+}; -+ -+/** -+ * struct SL_WH_TRIGGERS_EVENT_DATA_T - event data for trigger -+ * @trigger_type: trigger type (see MPT3SAS_TRIGGER_XXXX) -+ * @u: trigger condition that caused trigger to be sent -+ */ -+struct SL_WH_TRIGGERS_EVENT_DATA_T { -+ uint32_t trigger_type; -+ union { -+ struct SL_WH_MASTER_TRIGGER_T master; -+ struct SL_WH_EVENT_TRIGGER_T event; -+ struct SL_WH_SCSI_TRIGGER_T scsi; -+ struct SL_WH_MPI_TRIGGER_T mpi; -+ } u; -+}; -+#endif /* MPT3SAS_TRIGGER_DIAG_H_INCLUDED */ -diff --git a/drivers/scsi/mpt2sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt2sas/mpt3sas_warpdrive.c -new file mode 100644 -index 0000000..2542263 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/mpt3sas_warpdrive.c -@@ -0,0 +1,344 @@ -+/* -+ * Scsi Host Layer for MPT (Message Passing Technology) based controllers -+ * -+ * Copyright (C) 2012-2014 LSI Corporation -+ * Copyright (C) 2013-2015 Avago Technologies -+ * (mailto: MPT-FusionLinux.pdl@avagotech.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * NO WARRANTY -+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -+ * solely responsible for determining the appropriateness of using and -+ * distributing the Program and assumes all risks associated with its -+ * exercise of rights under this Agreement, including but not limited to -+ * the risks and costs of program errors, damage to or loss of data, -+ * programs or equipment, and unavailability or interruption of operations. -+ -+ * DISCLAIMER OF LIABILITY -+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES -+ -+ * You should have received a copy of the GNU General Public License -+ * along with this program. -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include "mpt3sas_base.h" -+ -+/** -+ * _warpdrive_disable_ddio - Disable direct I/O for all the volumes -+ * @ioc: per adapter object -+ */ -+static void -+_warpdrive_disable_ddio(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2RaidVolPage1_t vol_pg1; -+ Mpi2ConfigReply_t mpi_reply; -+ struct _raid_device *raid_device; -+ u16 handle; -+ u16 ioc_status; -+ unsigned long flags; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) -+ break; -+ handle = le16_to_cpu(vol_pg1.DevHandle); -+ spin_lock_irqsave(&ioc->raid_device_lock, flags); -+ raid_device = mpt2sas_raid_device_find_by_handle(ioc, handle); -+ if (raid_device) -+ raid_device->direct_io_enabled = 0; -+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -+ } -+ return; -+} -+ -+ -+/** -+ * mpt2sas_get_num_volumes - Get number of volumes in the ioc -+ * @ioc: per adapter object -+ */ -+u8 -+mpt2sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc) -+{ -+ Mpi2RaidVolPage1_t vol_pg1; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 handle; -+ u8 vol_cnt = 0; -+ u16 ioc_status; -+ -+ handle = 0xFFFF; -+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, -+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { -+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & -+ MPI2_IOCSTATUS_MASK; -+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) -+ break; -+ vol_cnt++; -+ handle = le16_to_cpu(vol_pg1.DevHandle); -+ } -+ return vol_cnt; -+} -+ -+ -+/** -+ * mpt2sas_init_warpdrive_properties - Set properties for warpdrive direct I/O. -+ * @ioc: per adapter object -+ * @raid_device: the raid_device object -+ */ -+void -+mpt2sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, -+ struct _raid_device *raid_device) -+{ -+ Mpi2RaidVolPage0_t *vol_pg0; -+ Mpi2RaidPhysDiskPage0_t pd_pg0; -+ Mpi2ConfigReply_t mpi_reply; -+ u16 sz; -+ u8 num_pds, count; -+ unsigned long stripe_sz, block_sz; -+ u8 stripe_exp, block_exp; -+ u64 dev_max_lba; -+ -+ if (!ioc->is_warpdrive) -+ return; -+ -+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "globally as drives are exposed\n", ioc->name); -+ return; -+ } -+ if (mpt2sas_get_num_volumes(ioc) > 1) { -+ _warpdrive_disable_ddio(ioc); -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "globally as number of drives > 1\n", ioc->name); -+ return; -+ } -+ if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, -+ &num_pds)) || !num_pds) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "Failure in computing number of drives\n", ioc->name); -+ return; -+ } -+ -+ sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * -+ sizeof(Mpi2RaidVol0PhysDisk_t)); -+ vol_pg0 = kzalloc(sz, GFP_KERNEL); -+ if (!vol_pg0) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "Memory allocation failure for RVPG0\n", ioc->name); -+ return; -+ } -+ -+ if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, -+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "Failure in retrieving RVPG0\n", ioc->name); -+ kfree(vol_pg0); -+ return; -+ } -+ -+ /* -+ * WARPDRIVE:If number of physical disks in a volume exceeds the max pds -+ * assumed for WARPDRIVE, disable direct I/O -+ */ -+ if (num_pds > MPT_MAX_WARPDRIVE_PDS) { -+ pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "for the drive with handle(0x%04x): num_mem=%d, " -+ "max_mem_allowed=%d\n", ioc->name, raid_device->handle, -+ num_pds, MPT_MAX_WARPDRIVE_PDS); -+ kfree(vol_pg0); -+ return; -+ } -+ for (count = 0; count < num_pds; count++) { -+ if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, -+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, -+ vol_pg0->PhysDisk[count].PhysDiskNum) || -+ pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " -+ "disabled for the drive with handle(0x%04x) member" -+ "handle retrieval failed for member number=%d\n", -+ ioc->name, raid_device->handle, -+ vol_pg0->PhysDisk[count].PhysDiskNum); -+ goto out_error; -+ } -+ /* Disable direct I/O if member drive lba exceeds 4 bytes */ -+ dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); -+ if (dev_max_lba >> 32) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " -+ "disabled for the drive with handle(0x%04x) member" -+ " handle (0x%04x) unsupported max lba 0x%016llx\n", -+ ioc->name, raid_device->handle, -+ le16_to_cpu(pd_pg0.DevHandle), -+ (unsigned long long)dev_max_lba); -+ goto out_error; -+ } -+ -+ raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); -+ } -+ -+ /* -+ * Assumption for WD: Direct I/O is not supported if the volume is -+ * not RAID0 -+ */ -+ if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "for the drive with handle(0x%04x): type=%d, " -+ "s_sz=%uK, blk_size=%u\n", ioc->name, -+ raid_device->handle, raid_device->volume_type, -+ (le32_to_cpu(vol_pg0->StripeSize) * -+ le16_to_cpu(vol_pg0->BlockSize)) / 1024, -+ le16_to_cpu(vol_pg0->BlockSize)); -+ goto out_error; -+ } -+ -+ stripe_sz = le32_to_cpu(vol_pg0->StripeSize); -+ stripe_exp = find_first_bit(&stripe_sz, 32); -+ if (stripe_exp == 32) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "for the drive with handle(0x%04x) invalid stripe sz %uK\n", -+ ioc->name, raid_device->handle, -+ (le32_to_cpu(vol_pg0->StripeSize) * -+ le16_to_cpu(vol_pg0->BlockSize)) / 1024); -+ goto out_error; -+ } -+ raid_device->stripe_exponent = stripe_exp; -+ block_sz = le16_to_cpu(vol_pg0->BlockSize); -+ block_exp = find_first_bit(&block_sz, 16); -+ if (block_exp == 16) { -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " -+ "for the drive with handle(0x%04x) invalid block sz %u\n", -+ ioc->name, raid_device->handle, -+ le16_to_cpu(vol_pg0->BlockSize)); -+ goto out_error; -+ } -+ raid_device->block_exponent = block_exp; -+ raid_device->direct_io_enabled = 1; -+ -+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive" -+ " with handle(0x%04x)\n", ioc->name, raid_device->handle); -+ /* -+ * WARPDRIVE: Though the following fields are not used for direct IO, -+ * stored for future purpose: -+ */ -+ raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); -+ raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); -+ raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); -+ -+ -+ kfree(vol_pg0); -+ return; -+ -+out_error: -+ raid_device->direct_io_enabled = 0; -+ for (count = 0; count < num_pds; count++) -+ raid_device->pd_handle[count] = 0; -+ kfree(vol_pg0); -+ return; -+} -+ -+/** -+ * mpt2sas_scsi_direct_io_get - returns direct io flag -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * -+ * Returns the smid stored scmd pointer. -+ */ -+inline u8 -+mpt2sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid) -+{ -+ return ioc->scsi_lookup[smid - 1].direct_io; -+} -+ -+/** -+ * mpt2sas_scsi_direct_io_set - sets direct io flag -+ * @ioc: per adapter object -+ * @smid: system request message index -+ * @direct_io: Zero or non-zero value to set in the direct_io flag -+ * -+ * Returns Nothing. -+ */ -+inline void -+mpt2sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io) -+{ -+ ioc->scsi_lookup[smid - 1].direct_io = direct_io; -+} -+ -+/** -+ * mpt2sas_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O -+ * @ioc: per adapter object -+ * @scmd: pointer to scsi command object -+ * @raid_device: pointer to raid device data structure -+ * @mpi_request: pointer to the SCSI_IO reqest message frame -+ * @smid: system request message index -+ * -+ * Returns nothing -+ */ -+void -+mpt2sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, -+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, -+ u16 smid) -+{ -+ sector_t v_lba, p_lba, stripe_off, column, io_size; -+ u32 stripe_sz, stripe_exp; -+ u8 num_pds, cmd = scmd->cmnd[0]; -+ -+ if (cmd != READ_10 && cmd != WRITE_10 && -+ cmd != READ_16 && cmd != WRITE_16) -+ return; -+ -+ if (cmd == READ_10 || cmd == WRITE_10) -+ v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]); -+ else -+ v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]); -+ -+ io_size = scsi_bufflen(scmd) >> raid_device->block_exponent; -+ -+ if (v_lba + io_size - 1 > raid_device->max_lba) -+ return; -+ -+ stripe_sz = raid_device->stripe_sz; -+ stripe_exp = raid_device->stripe_exponent; -+ stripe_off = v_lba & (stripe_sz - 1); -+ -+ /* Return unless IO falls within a stripe */ -+ if (stripe_off + io_size > stripe_sz) -+ return; -+ -+ num_pds = raid_device->num_pds; -+ p_lba = v_lba >> stripe_exp; -+ column = sector_div(p_lba, num_pds); -+ p_lba = (p_lba << stripe_exp) + stripe_off; -+ mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]); -+ -+ if (cmd == READ_10 || cmd == WRITE_10) -+ put_unaligned_be32(lower_32_bits(p_lba), -+ &mpi_request->CDB.CDB32[2]); -+ else -+ put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]); -+ -+ mpt2sas_scsi_direct_io_set(ioc, smid, 1); -+} -diff --git a/drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c b/drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c -new file mode 100644 -index 0000000..7852050 ---- /dev/null -+++ b/drivers/scsi/mpt2sas/wrapper_mpt3sas_scsih.c -@@ -0,0 +1,4 @@ -+#define MPT2SAS_SCSI -+/* This directive is used to create the mpt2sas driver from the mpt3sas sources */ -+ -+#include "mpt3sas_scsih.c" -diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig -index 5743420..9aa67e2 100644 ---- a/drivers/scsi/mpt3sas/Kconfig -+++ b/drivers/scsi/mpt3sas/Kconfig -@@ -40,14 +40,6 @@ - # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - # USA. - --config SCSI_MPT2SAS -- tristate "LSI MPT Fusion SAS 2.0 Device Driver" -- depends on PCI && SCSI -- select SCSI_SAS_ATTRS -- select RAID_ATTRS -- ---help--- -- This driver supports PCI-Express SAS 6Gb/s Host Adapters. -- - config SCSI_MPT3SAS - tristate "LSI MPT Fusion SAS 3.0 Device Driver" - depends on PCI && SCSI -@@ -56,18 +48,6 @@ config SCSI_MPT3SAS - ---help--- - This driver supports PCI-Express SAS 12Gb/s Host Adapters. - --config SCSI_MPT2SAS_MAX_SGE -- int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)" -- depends on PCI && SCSI && SCSI_MPT3SAS -- default "128" -- range 16 256 -- ---help--- -- This option allows you to specify the maximum number of scatter- -- gather entries per I/O. The driver default is 128, which matches -- MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this -- can be 256. However, it may decreased down to 16. Decreasing this -- parameter will reduce memory requirements on a per controller instance. -- - config SCSI_MPT3SAS_MAX_SGE - int "LSI MPT Fusion SAS 3.0 Max number of SG Entries (16 - 256)" - depends on PCI && SCSI && SCSI_MPT3SAS -diff --git a/drivers/scsi/mpt3sas/Makefile b/drivers/scsi/mpt3sas/Makefile -index 0b90877..450b84b 100644 ---- a/drivers/scsi/mpt3sas/Makefile -+++ b/drivers/scsi/mpt3sas/Makefile -@@ -1,6 +1,5 @@ - # mpt2-3sas makefile - --obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o - obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas.o - - obj-m += mpt3sas.o -@@ -12,11 +11,3 @@ mpt3sas-y += mpt3sas_base.o \ - mpt3sas_trigger_diag.o \ - mpt3sas_warpdrive.o - --obj-m += mpt2sas.o --mpt2sas-y += mpt3sas_base.o \ -- mpt3sas_config.o \ -- wrapper_mpt3sas_scsih.o \ -- mpt3sas_transport.o \ -- mpt3sas_ctl.o \ -- mpt3sas_trigger_diag.o \ -- mpt3sas_warpdrive.o --- -1.8.3.1 - diff --git a/kernel/kernel-std/centos/patches/kernel-3.10.0-x86_64.config.tis_extra b/kernel/kernel-std/centos/patches/kernel-3.10.0-x86_64.config.tis_extra index 59dcb2596..254ca1b6c 100644 --- a/kernel/kernel-std/centos/patches/kernel-3.10.0-x86_64.config.tis_extra +++ b/kernel/kernel-std/centos/patches/kernel-3.10.0-x86_64.config.tis_extra @@ -24,8 +24,9 @@ CONFIG_SCSI_PMCRAID=y CONFIG_SCSI_HPSA=y CONFIG_MEGARAID_SAS=y CONFIG_SCSI_SMARTPQI=y -CONFIG_SCSI_MPT2SAS=y -CONFIG_SCSI_MPT3SAS=y +# These two will only build as modules +CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_MPT3SAS=m CONFIG_SCSI_VIRTIO=y CONFIG_FUSION_SAS=y CONFIG_SCSI_AIC94XX=y