diff options
Diffstat (limited to 'drivers/scsi/mpt3sas')
| -rw-r--r-- | drivers/scsi/mpt3sas/Kconfig | 67 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/Makefile | 8 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2.h | 1170 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 3334 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_init.h | 560 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_ioc.h | 1669 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_raid.h | 350 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_sas.h | 295 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_tool.h | 439 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpi/mpi2_type.h | 56 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_base.c | 4864 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_base.h | 1139 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_config.c | 1649 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_ctl.c | 3282 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_ctl.h | 418 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_debug.h | 219 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_scsih.c | 8168 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_transport.c | 2132 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c | 433 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h | 193 | 
20 files changed, 30445 insertions, 0 deletions
diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig new file mode 100644 index 00000000000..d53e1b02e89 --- /dev/null +++ b/drivers/scsi/mpt3sas/Kconfig @@ -0,0 +1,67 @@ +# +# Kernel configuration file for the MPT3SAS +# +# This code is based on drivers/scsi/mpt3sas/Kconfig +# Copyright (C) 2012-2013  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_MPT3SAS +	tristate "LSI MPT Fusion SAS 3.0 Device Driver" +	depends on PCI && SCSI +	select SCSI_SAS_ATTRS +	select RAID_ATTRS +	---help--- +	This driver supports PCI-Express SAS 12Gb/s Host Adapters. + +config SCSI_MPT3SAS_MAX_SGE +	int "LSI MPT Fusion 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_LOGGING +	bool "LSI MPT Fusion logging facility" +	depends on PCI && SCSI && SCSI_MPT3SAS +	---help--- +	This turns on a logging facility. diff --git a/drivers/scsi/mpt3sas/Makefile b/drivers/scsi/mpt3sas/Makefile new file mode 100644 index 00000000000..efb0c4c2e31 --- /dev/null +++ b/drivers/scsi/mpt3sas/Makefile @@ -0,0 +1,8 @@ +# mpt3sas makefile +obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas.o +mpt3sas-y +=  mpt3sas_base.o     \ +		mpt3sas_config.o \ +		mpt3sas_scsih.o      \ +		mpt3sas_transport.o     \ +		mpt3sas_ctl.o	\ +		mpt3sas_trigger_diag.o diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h new file mode 100644 index 00000000000..20da8f907c0 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2.h @@ -0,0 +1,1170 @@ +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + *          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.29 + * + * 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. + * -------------------------------------------------------------------------- + */ + +#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) + +/*Unit and Dev versioning for this MPI header set */ +#define MPI2_HEADER_VERSION_UNIT            (0x1D) +#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[16];	/*0x80 */ +	U32 RequestDescriptorPostLow;	/*0xC0 */ +	U32 RequestDescriptorPostHigh;	/*0xC4 */ +	U32 Reserved7[14];	/*0xC8 */ +} 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_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 Request Queue + */ +#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET     (0x000000C0) +#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET    (0x000000C4) + +/*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               (0x0E) +#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; + +/*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_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) + +/**************************************************************************** +* 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 products only */ +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) + +/*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) + +/**************************************************************************** +* 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 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/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h new file mode 100644 index 00000000000..889aa706789 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -0,0 +1,3334 @@ +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + *          Name:  mpi2_cnfg.h + *         Title:  MPI Configuration messages and pages + * Creation Date:  November 10, 2006 + * + *   mpi2_cnfg.h Version:  02.00.24 + * + * 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. + * -------------------------------------------------------------------------- + */ + +#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) + + + + +/*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_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 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      (0xFF00) +#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 */ +} MPI2_CONFIG_PAGE_IO_UNIT_7, +	*PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, +	Mpi2IOUnitPage7_t, *pMpi2IOUnitPage7_t; + +#define MPI2_IOUNITPAGE7_PAGEVERSION                    (0x02) + +/*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) + + +/*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) + + + +/**************************************************************************** +*  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 */ +	U32                     Reserved1;                  /*0x0C */ +	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                      (0x05) + +/*values for BIOS Page 1 BiosOptions field */ +#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 */ + +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_CONFIG_PAGE_BIOS_3 { +	MPI2_CONFIG_PAGE_HEADER Header;              /*0x00 */ +	U32                     GlobalFlags;         /*0x04 */ +	U32                     BiosVersion;         /*0x08 */ +	MPI2_ADAPTER_INFO       AdapterOrder[4];     /*0x0C */ +	U32                     Reserved1;           /*0x1C */ +} MPI2_CONFIG_PAGE_BIOS_3, +	*PTR_MPI2_CONFIG_PAGE_BIOS_3, +	Mpi2BiosPage3_t, *pMpi2BiosPage3_t; + +#define MPI2_BIOSPAGE3_PAGEVERSION                      (0x00) + +/*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_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_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_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 */ + +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 +		Reserved4;                      /*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 +		Reserved1;              /*0x2F */ +	U32 +		Reserved2;              /*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         (0x08) + +/*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_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) + +/*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 */ +	U16 +		Reserved2;                  /*0x1C */ +	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      (0x03) + +/*values for SAS Enclosure Page 0 Flags field */ +#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/mpt3sas/mpi/mpi2_init.h b/drivers/scsi/mpt3sas/mpi/mpi2_init.h new file mode 100644 index 00000000000..f7928bf6647 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2_init.h @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + *          Name:  mpi2_init.h + *         Title:  MPI SCSI initiator mode messages and structures + * Creation Date:  June 23, 2006 + * + * mpi2_init.h Version:  02.00.14 + * + * 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. + * -------------------------------------------------------------------------- + */ + +#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) + +/*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 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 MPI25_SCSIIO_IOFLAGS_LARGE_CDB                  (0x1000) +#define MPI25_SCSIIO_IOFLAGS_BIDIRECTIONAL              (0x0800) +#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 Reserved4;		/*0x22 */ +	U32 BidirectionalTransferCount;	/*0x24 */ +	U32 EEDPErrorOffset;	/*0x28 *//*MPI 2.5 only; Reserved in MPI 2.0*/ +	U32 Reserved6;		/*0x2C */ +} 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_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_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/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h new file mode 100644 index 00000000000..e2bb8214372 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h @@ -0,0 +1,1669 @@ +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + *          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.22 + * + * 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. + * -------------------------------------------------------------------------- + */ + +#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 Reserved6;		/*0x14 */ +	U8 Reserved7;		/*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) + +/*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 the Reply Descriptor Post Queue */ +#define MPI2_RDPQ_DEPTH_MIN                     (16) + +/*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 */ +	U16 Reserved4;		/*0x3E */ +} 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 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_TARGET              (0x0001) +#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR           (0x0002) + +/**************************************************************************** +* 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_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 */ + +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) + +/*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_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) + +/*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 Reserved60;		/*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) + +/*Signature0 field */ +#define MPI2_FW_HEADER_SIGNATURE0_OFFSET        (0x04) +#define MPI2_FW_HEADER_SIGNATURE0               (0x5AFAA55A) + +/*Signature1 field */ +#define MPI2_FW_HEADER_SIGNATURE1_OFFSET        (0x08) +#define MPI2_FW_HEADER_SIGNATURE1               (0xA55AFAA5) + +/*Signature2 field */ +#define MPI2_FW_HEADER_SIGNATURE2_OFFSET        (0x0C) +#define MPI2_FW_HEADER_SIGNATURE2               (0x5AA55AFA) + +/*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) + +/*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 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_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_INIT                  (0x0A) + +/*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) + +/**************************************************************************** +* 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; + +#endif diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_raid.h b/drivers/scsi/mpt3sas/mpi/mpi2_raid.h new file mode 100644 index 00000000000..71765236afe --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2_raid.h @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + *          Name:  mpi2_raid.h + *         Title:  MPI Integrated RAID messages and structures + * Creation Date:  April 26, 2007 + * + *   mpi2_raid.h Version:  02.00.09 + * + * 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. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_RAID_H +#define MPI2_RAID_H + +/***************************************************************************** +* +*              Integrated RAID Messages +* +*****************************************************************************/ + +/**************************************************************************** +* RAID Action messages +****************************************************************************/ + +/*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/mpt3sas/mpi/mpi2_sas.h b/drivers/scsi/mpt3sas/mpi/mpi2_sas.h new file mode 100644 index 00000000000..cba046f6a4b --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2_sas.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + *          Name:  mpi2_sas.h + *         Title:  MPI Serial Attached SCSI structures and definitions + * Creation Date:  February 9, 2007 + * + * mpi2_sas.h Version:  02.00.07 + * + * 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. + * -------------------------------------------------------------------------- + */ + +#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_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 +****************************************************************************/ + +/*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) +#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/mpt3sas/mpi/mpi2_tool.h b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h new file mode 100644 index 00000000000..34e9a7ba76b --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2000-2013 LSI Corporation. + * + * + *          Name:  mpi2_tool.h + *         Title:  MPI diagnostic tool structures and definitions + * Creation Date:  March 26, 2007 + * + *   mpi2_tool.h Version:  02.00.10 + * + * 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. + * -------------------------------------------------------------------------- + */ + +#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) + +/**************************************************************************** +* 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_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; + +/***************************************************************************** +* +*      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/mpt3sas/mpi/mpi2_type.h b/drivers/scsi/mpt3sas/mpi/mpi2_type.h new file mode 100644 index 00000000000..ba1fed50966 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpi/mpi2_type.h @@ -0,0 +1,56 @@ +/* + *  Copyright (c) 2000-2013 LSI Corporation. + * + * + *           Name:  mpi2_type.h + *          Title:  MPI basic type definitions + *  Creation Date:  August 16, 2006 + * + *    mpi2_type.h Version:  02.00.00 + * + *  Version History + *  --------------- + * + *  Date      Version   Description + *  --------  --------  ------------------------------------------------------ + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  -------------------------------------------------------------------------- + */ + +#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/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c new file mode 100644 index 00000000000..0cf4f7000f9 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -0,0 +1,4864 @@ +/* + * 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-2013  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. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/time.h> +#include <linux/kthread.h> +#include <linux/aer.h> + + +#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 max_msix_vectors = 8; +module_param(max_msix_vectors, int, 0); +MODULE_PARM_DESC(max_msix_vectors, +	" max msix vectors - (default=8)"); + +static int mpt3sas_fwfault_debug; +MODULE_PARM_DESC(mpt3sas_fwfault_debug, +	" enable detection of firmware fault and halt firmware - (default=0)"); + + +/** + * _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; + +	pr_info("setting fwfault_debug(%d)\n", mpt3sas_fwfault_debug); +	list_for_each_entry(ioc, &mpt3sas_ioc_list, list) +		ioc->fwfault_debug = mpt3sas_fwfault_debug; +	return 0; +} +module_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug, +	param_get_int, &mpt3sas_fwfault_debug, 0644); + +/** + *  mpt3sas_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 mpt3sas_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) +		goto rearm_timer; +	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + +	doorbell = mpt3sas_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); + +		/* +		 * 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(mpt3sas_remove_dead_ioc_func, ioc, +		    "mpt3sas_dead_ioc_%d", ioc->id); +		if (IS_ERR(p)) +			pr_err(MPT3SAS_FMT +			"%s: Running mpt3sas_dead_ioc thread failed !!!!\n", +			ioc->name, __func__); +		else +			pr_err(MPT3SAS_FMT +			"%s: Running mpt3sas_dead_ioc thread success !!!!\n", +			ioc->name, __func__); +		return; /* don't rearm timer */ +	} + +	if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) { +		rc = mpt3sas_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 = mpt3sas_base_get_iocstate(ioc, 0); +		if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) +			mpt3sas_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); +} + +/** + * mpt3sas_base_start_watchdog - start the fault_reset_work_q + * @ioc: per adapter object + * Context: sleep. + * + * Return nothing. + */ +void +mpt3sas_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_%d_status", 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); +} + +/** + * mpt3sas_base_stop_watchdog - stop the fault_reset_work_q + * @ioc: per adapter object + * Context: sleep. + * + * Return nothing. + */ +void +mpt3sas_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(&ioc->fault_reset_work)) +			flush_workqueue(wq); +		destroy_workqueue(wq); +	} +} + +/** + * mpt3sas_base_fault_info - verbose translation of firmware FAULT code + * @ioc: per adapter object + * @fault_code: fault code + * + * Return nothing. + */ +void +mpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code) +{ +	pr_err(MPT3SAS_FMT "fault_state(0x%04x)!\n", +	    ioc->name, fault_code); +} + +/** + * mpt3sas_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 +mpt3sas_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) +		mpt3sas_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__); +} + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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_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: +		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: +		desc = "IR Volume"; +		break; +	case MPI2_EVENT_IR_PHYSICAL_DISK: +		desc = "IR Physical Disk"; +		break; +	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: +		desc = "IR Configuration Change List"; +		break; +	case MPI2_EVENT_LOG_ENTRY_ADDED: +		desc = "Log Entry Added"; +		break; +	} + +	if (!desc) +		return; + +	pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc); +} +#endif + +/** + * _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: +		originator_str = "IR"; +		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 = mpt3sas_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); +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	if ((ioc_status & MPI2_IOCSTATUS_MASK) && +	    (ioc->logging_level & MPT_DEBUG_REPLY)) { +		_base_sas_ioc_info(ioc , mpi_reply, +		   mpt3sas_base_get_msg_frame(ioc, smid)); +	} +#endif +	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; +		mpt3sas_trigger_mpi(ioc, ioc_status, loginfo); +	} +} + +/** + * mpt3sas_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 +mpt3sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply) +{ +	MPI2DefaultReply_t *mpi_reply; + +	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); +	if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) +		return 1; + +	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; + +	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); +	if (!mpi_reply) +		return 1; +	if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) +		return 1; +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	_base_display_event_data(ioc, mpi_reply); +#endif +	if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) +		goto out; +	smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); +	if (!smid) { +		pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", +		    ioc->name, __func__); +		goto out; +	} + +	ack_request = mpt3sas_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; +	mpt3sas_base_put_smid_default(ioc, smid); + + out: + +	/* scsih callback handler */ +	mpt3sas_scsih_event_callback(ioc, msix_index, reply); + +	/* ctl callback handler */ +	mpt3sas_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) +					mpt3sas_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) +						mpt3sas_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(); +	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; +} + +/** + * mpt3sas_base_flush_reply_queues - flushing the MSIX reply queues + * @ioc: per adapter object + * Context: ISR conext + * + * Called when a Task Management request has completed. We want + * to flush the other reply queues so all the outstanding IO has been + * completed back to OS before we process the TM completetion. + * + * Return nothing. + */ +void +mpt3sas_base_flush_reply_queues(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) +			return; +		/* TMs are on msix_index == 0 */ +		if (reply_q->msix_index == 0) +			continue; +		_base_interrupt(reply_q->vector, (void *)reply_q); +	} +} + +/** + * mpt3sas_base_release_callback_handler - clear interrupt callback handler + * @cb_idx: callback index + * + * Return nothing. + */ +void +mpt3sas_base_release_callback_handler(u8 cb_idx) +{ +	mpt_callbacks[cb_idx] = NULL; +} + +/** + * mpt3sas_base_register_callback_handler - obtain index for the interrupt callback handler + * @cb_func: callback function + * + * Returns cb_func. + */ +u8 +mpt3sas_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; +} + +/** + * mpt3sas_base_initialize_callback_handler - initialize the interrupt callback handler + * + * Return nothing. + */ +void +mpt3sas_base_initialize_callback_handler(void) +{ +	u8 cb_idx; + +	for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++) +		mpt3sas_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_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 = mpt3sas_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) { +		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) { +		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; +	char *desc = NULL; + +	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, DMA_BIT_MASK(64))) { +			ioc->base_add_sg_single = &_base_add_sg_single_64; +			ioc->sge_size = sizeof(Mpi2SGESimple64_t); +			desc = "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); +		desc = "32"; +	} else +		return -ENODEV; + + out: +	si_meminfo(&s); +	pr_info(MPT3SAS_FMT +		"%s BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", +		ioc->name, desc, convert_to_kb(s.totalram)); + +	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; + +	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 */ + +	pci_read_config_word(ioc->pdev, base + 2, &message_control); +	ioc->msix_vector_count = (message_control & 0x3FF) + 1; +	if (ioc->msix_vector_count > 8) +		ioc->msix_vector_count = 8; +	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); +		synchronize_irq(reply_q->vector); +		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; +	atomic_set(&reply_q->busy, 0); +	if (ioc->msix_enable) +		snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", +		    MPT3SAS_DRIVER_NAME, ioc->id, index); +	else +		snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", +		    MPT3SAS_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); +		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) +{ +	struct adapter_reply_queue *reply_q; +	int cpu_id; +	int cpu_grouping, loop, grouping, grouping_mod; +	int reply_queue; + +	if (!_base_is_controller_msix_enabled(ioc)) +		return; + +	memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); + +	/* NUMA Hardware bug workaround - drop to less reply queues */ +	if (ioc->reply_queue_count > ioc->facts.MaxMSIxVectors) { +		ioc->reply_queue_count = ioc->facts.MaxMSIxVectors; +		reply_queue = 0; +		list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { +			reply_q->msix_index = reply_queue; +			if (++reply_queue == ioc->reply_queue_count) +				reply_queue = 0; +		} +	} + +	/* when there are more cpus than available msix vectors, +	 * then group cpus togeather on same irq +	 */ +	if (ioc->cpu_count > ioc->msix_vector_count) { +		grouping = ioc->cpu_count / ioc->msix_vector_count; +		grouping_mod = ioc->cpu_count % ioc->msix_vector_count; +		if (grouping < 2 || (grouping == 2 && !grouping_mod)) +			cpu_grouping = 2; +		else if (grouping < 4 || (grouping == 4 && !grouping_mod)) +			cpu_grouping = 4; +		else if (grouping < 8 || (grouping == 8 && !grouping_mod)) +			cpu_grouping = 8; +		else +			cpu_grouping = 16; +	} else +		cpu_grouping = 0; + +	loop = 0; +	reply_q = list_entry(ioc->reply_queue_list.next, +	     struct adapter_reply_queue, list); +	for_each_online_cpu(cpu_id) { +		if (!cpu_grouping) { +			ioc->cpu_msix_table[cpu_id] = reply_q->msix_index; +			reply_q = list_entry(reply_q->list.next, +			    struct adapter_reply_queue, list); +		} else { +			if (loop < cpu_grouping) { +				ioc->cpu_msix_table[cpu_id] = +				    reply_q->msix_index; +				loop++; +			} else { +				reply_q = list_entry(reply_q->list.next, +				    struct adapter_reply_queue, list); +				ioc->cpu_msix_table[cpu_id] = +				    reply_q->msix_index; +				loop = 1; +			} +		} +	} +} + +/** + * _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 (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; +	} + +	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(ioc->pdev, entries, ioc->reply_queue_count); +	if (r) { +		dfailprintk(ioc, pr_info(MPT3SAS_FMT +			"pci_enable_msix 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: + +	r = _base_request_irq(ioc, 0, ioc->pdev->irq); + +	return r; +} + +/** + * mpt3sas_base_map_resources - map in controller resources (io/irq/memap) + * @ioc: per adapter object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_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, +	    MPT3SAS_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; 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!\n", +					ioc->name); +				r = -EINVAL; +				goto out_fail; +			} +		} +	} + +	_base_mask_interrupts(ioc); +	r = _base_enable_msix(ioc); +	if (r) +		goto out_fail; + +	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: +	if (ioc->chip_phys) +		iounmap(ioc->chip); +	ioc->chip_phys = 0; +	pci_release_selected_regions(ioc->pdev, ioc->bars); +	pci_disable_pcie_error_reporting(pdev); +	pci_disable_device(pdev); +	return r; +} + +/** + * mpt3sas_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 * +mpt3sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ +	return (void *)(ioc->request + (smid * ioc->request_sz)); +} + +/** + * mpt3sas_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 * +mpt3sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ +	return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); +} + +/** + * mpt3sas_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 +mpt3sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ +	return cpu_to_le32(ioc->sense_dma + ((smid - 1) * +	    SCSI_SENSE_BUFFERSIZE)); +} + +/** + * mpt3sas_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 * +mpt3sas_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); +} + +/** + * mpt3sas_base_get_smid - obtain a free smid from internal queue + * @ioc: per adapter object + * @cb_idx: callback index + * + * Returns smid (zero is invalid) + */ +u16 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +	list_del(&request->tracker_list); +	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +	return smid; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_base_free_smid - put smid back on free_list + * @ioc: per adapter object + * @smid: system request message index + * + * Return nothing. + */ +void +mpt3sas_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; +		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 + +static inline u8 +_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc) +{ +	return ioc->cpu_msix_table[raw_smp_processor_id()]; +} + +/** + * mpt3sas_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 +mpt3sas_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); +} + +/** + * mpt3sas_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 +mpt3sas_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); +} + +/** + * mpt3sas_base_put_smid_hi_priority - send Task Managment request to firmware + * @ioc: per adapter object + * @smid: system request message index + * + * Return nothing. + */ +void +mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ +	Mpi2RequestDescriptorUnion_t descriptor; +	u64 *request = (u64 *)&descriptor; + +	descriptor.HighPriority.RequestFlags = +	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; +	descriptor.HighPriority.MSIxIndex =  0; +	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); +} + +/** + * mpt3sas_base_put_smid_default - Default, primarily used for config pages + * @ioc: per adapter object + * @smid: system request message index + * + * Return nothing. + */ +void +mpt3sas_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_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); + +	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->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"); +} + +/** + * mpt3sas_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 +mpt3sas_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; + +	mpt3sas_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 ((mpt3sas_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 (!mpt3sas_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; + +	mpt3sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); +	if (ioc->ir_firmware) +		mpt3sas_config_get_manufacturing_pg10(ioc, &mpi_reply, +		    &ioc->manu_pg10); + +	/* +	 * Ensure correct T10 PI operation if vendor left EEDPTagMode +	 * flag unset in NVDATA. +	 */ +	mpt3sas_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; +		mpt3sas_config_set_manufacturing_pg11(ioc, &mpi_reply, +		    &ioc->manu_pg11); +	} + +	mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); +	mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); +	mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); +	mpt3sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); +	mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); +	_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); +	mpt3sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); +} + +/** + * _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; + +	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_free) { +		pci_pool_free(ioc->reply_post_free_dma_pool, +		    ioc->reply_post_free, ioc->reply_post_free_dma); +		if (ioc->reply_post_free_dma_pool) +			pci_pool_destroy(ioc->reply_post_free_dma_pool); +		dexitprintk(ioc, pr_info(MPT3SAS_FMT +		    "reply_post_free_pool(0x%p): free\n", ioc->name, +		    ioc->reply_post_free)); +		ioc->reply_post_free = NULL; +	} + +	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 mpt3sas_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 +		sg_tablesize = MPT3SAS_SG_DEPTH; + +	if (sg_tablesize < MPT3SAS_MIN_PHYS_SEGMENTS) +		sg_tablesize = MPT3SAS_MIN_PHYS_SEGMENTS; +	else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) +		sg_tablesize = MPT3SAS_MAX_PHYS_SEGMENTS; +	ioc->shost->sg_tablesize = sg_tablesize; + +	ioc->hi_priority_depth = facts->HighPriorityCredit; +	ioc->internal_depth = ioc->hi_priority_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->hi_priority_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); + +	ioc->hba_queue_depth = max_request_credit; + +	/* request frame size */ +	ioc->request_sz = facts->IOCRequestFrameSize * 4; + +	/* reply frame size */ +	ioc->reply_sz = facts->ReplyFrameSize * 4; + +	/* 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->request_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)); + +	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; +	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 = max_request_credit - retry_sz; +		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->request_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->request_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->request_sz, +		((ioc->chain_depth *  ioc->request_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; + +	/* reply post queue, 16 byte align */ +	reply_post_free_sz = ioc->reply_post_queue_depth * +	    sizeof(Mpi2DefaultReplyDescriptor_t); +	if (_base_is_controller_msix_enabled(ioc)) +		sz = reply_post_free_sz * ioc->reply_queue_count; +	else +		sz = reply_post_free_sz; +	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; +	} +	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool , +	    GFP_KERNEL, &ioc->reply_post_free_dma); +	if (!ioc->reply_post_free) { +		pr_err(MPT3SAS_FMT +			"reply_post_free pool: pci_pool_alloc failed\n", +			ioc->name); +		goto out; +	} +	memset(ioc->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_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_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; +} + +/** + * mpt3sas_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 +mpt3sas_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 = mpt3sas_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_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) { +				mpt3sas_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<<MPI2_DOORBELL_FUNCTION_SHIFT) | +	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)), +	    &ioc->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; +} + +/** + * mpt3sas_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 +mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, +	Mpi2SasIoUnitControlReply_t *mpi_reply, +	Mpi2SasIoUnitControlRequest_t *mpi_request) +{ +	u16 smid; +	u32 ioc_state; +	unsigned long timeleft; +	u8 issue_reset; +	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 = mpt3sas_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 = mpt3sas_base_get_iocstate(ioc, 1); +		pr_info(MPT3SAS_FMT +			"%s: waiting for operational state(count=%d)\n", +			ioc->name, __func__, wait_state_count); +	} + +	smid = mpt3sas_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 = mpt3sas_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); +	mpt3sas_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 = 1; +		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) +		mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, +	Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request) +{ +	u16 smid; +	u32 ioc_state; +	unsigned long timeleft; +	u8 issue_reset; +	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 = mpt3sas_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 = mpt3sas_base_get_iocstate(ioc, 1); +		pr_info(MPT3SAS_FMT +			"%s: waiting for operational state(count=%d)\n", +			ioc->name, +		    __func__, wait_state_count); +	} + +	smid = mpt3sas_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 = mpt3sas_base_get_msg_frame(ioc, smid); +	ioc->base_cmds.smid = smid; +	memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); +	init_completion(&ioc->base_cmds.done); +	mpt3sas_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 = 1; +		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) +		mpt3sas_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 mpt3sas_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 mpt3sas_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_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 mpt3sas_facts *facts; +	int mpi_reply_sz, mpi_request_sz, r; + +	dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, +	    __func__)); + +	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 mpt3sas_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; +	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); +	facts->IOCRequestFrameSize = +	    le16_to_cpu(mpi_reply.IOCRequestFrameSize); +	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 r; +	struct timeval current_time; +	u16 ioc_status; + +	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(MPI2_VERSION); +	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); +	mpi_request.ReplyDescriptorPostQueueAddress = +	    cpu_to_le64((u64)ioc->reply_post_free_dma); + + +	/* This time stamp specifies number of milliseconds +	 * since epoch ~ midnight January 1, 1970. +	 */ +	do_gettimeofday(¤t_time); +	mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 + +	    (current_time.tv_usec / 1000)); + +	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); +		return r; +	} + +	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; +	} + +	return 0; +} + +/** + * mpt3sas_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 +mpt3sas_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 = mpt3sas_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) { +			mpt3sas_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 = mpt3sas_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 = mpt3sas_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); +	mpt3sas_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; +} + +/** + * mpt3sas_port_enable - initiate firmware discovery (don't wait for reply) + * @ioc: per adapter object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_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 = mpt3sas_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 = mpt3sas_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; + +	mpt3sas_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 = mpt3sas_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 = mpt3sas_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); +	mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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 = mpt3sas_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 = mpt3sas_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) { +		mpt3sas_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; +	unsigned long	flags; +	u32 reply_address; +	u16 smid; +	struct _tr_list *delayed_tr, *delayed_tr_next; +	struct adapter_reply_queue *reply_q; +	long reply_post_free; +	u32 reply_post_free_sz; + +	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); +	} + +	/* 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; +		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 */ +	reply_post_free = (long)ioc->reply_post_free; +	reply_post_free_sz = ioc->reply_post_queue_depth * +	    sizeof(Mpi2DefaultReplyDescriptor_t); +	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { +		reply_q->reply_post_host_index = 0; +		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *) +		    reply_post_free; +		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; +		reply_post_free += reply_post_free_sz; +	} + 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) { +		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) { +		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; +} + +/** + * mpt3sas_base_free_resources - free resources controller resources + * @ioc: per adapter object + * + * Return nothing. + */ +void +mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) +{ +	struct pci_dev *pdev = ioc->pdev; + +	dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, +	    __func__)); + +	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; +	} + +	_base_free_irq(ioc); +	_base_disable_msix(ioc); + +	if (ioc->chip_phys && ioc->chip) +		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); +	} +	return; +} + +/** + * mpt3sas_base_attach - attach controller instance + * @ioc: per adapter object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_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; +	} + +	r = mpt3sas_base_map_resources(ioc); +	if (r) +		goto out_free_resources; + + +	pci_set_drvdata(ioc->pdev, ioc->shost); +	r = _base_get_ioc_facts(ioc, CAN_SLEEP); +	if (r) +		goto out_free_resources; + +	/* +	 * 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->mpi25 = 1; +	ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); + +	/* +	 * 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 mpt3sas_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 = mpt3sas_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); + +	r = _base_make_ioc_operational(ioc, CAN_SLEEP); +	if (r) +		goto out_free_resources; + +	return 0; + + out_free_resources: + +	ioc->remove_host = 1; + +	mpt3sas_base_free_resources(ioc); +	_base_release_memory_pools(ioc); +	pci_set_drvdata(ioc->pdev, NULL); +	kfree(ioc->cpu_msix_table); +	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; +} + + +/** + * mpt3sas_base_detach - remove controller instance + * @ioc: per adapter object + * + * Return nothing. + */ +void +mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc) +{ +	dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, +	    __func__)); + +	mpt3sas_base_stop_watchdog(ioc); +	mpt3sas_base_free_resources(ioc); +	_base_release_memory_pools(ioc); +	pci_set_drvdata(ioc->pdev, NULL); +	kfree(ioc->cpu_msix_table); +	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) +{ +	mpt3sas_scsih_reset_handler(ioc, reset_phase); +	mpt3sas_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; +			mpt3sas_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; +			mpt3sas_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; +			mpt3sas_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; +			mpt3sas_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 = mpt3sas_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); +} + +/** + * mpt3sas_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 +mpt3sas_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 (mpt3sas_fwfault_debug) +		mpt3sas_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 = mpt3sas_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; +	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) +			mpt3sas_trigger_master(ioc, MASTER_TRIGGER_FW_FAULT); +		else +			mpt3sas_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/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h new file mode 100644 index 00000000000..9b90a6fef70 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -0,0 +1,1139 @@ +/* + * 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-2013  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. + */ + +#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 <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_tcq.h> +#include <scsi/scsi_transport_sas.h> +#include <scsi/scsi_dbg.h> +#include <scsi/scsi_eh.h> + +#include "mpt3sas_debug.h" +#include "mpt3sas_trigger_diag.h" + +/* driver versioning info */ +#define MPT3SAS_DRIVER_NAME		"mpt3sas" +#define MPT3SAS_AUTHOR	"LSI Corporation <DL-MPTFusionLinux@lsi.com>" +#define MPT3SAS_DESCRIPTION	"LSI MPT Fusion SAS 3.0 Device Driver" +#define MPT3SAS_DRIVER_VERSION		"02.100.00.00" +#define MPT3SAS_MAJOR_VERSION		2 +#define MPT3SAS_MINOR_VERSION		100 +#define MPT3SAS_BUILD_VERSION		0 +#define MPT3SAS_RELEASE_VERSION	00 + +/* + * Set MPT3SAS_SG_DEPTH value based on user input. + */ +#define MPT3SAS_MAX_PHYS_SEGMENTS	SCSI_MAX_SG_SEGMENTS +#define MPT3SAS_MIN_PHYS_SEGMENTS	16 +#ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE +#define MPT3SAS_SG_DEPTH		CONFIG_SCSI_MPT3SAS_MAX_SGE +#else +#define MPT3SAS_SG_DEPTH		MPT3SAS_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 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 */ + +#define MPI3_HIM_MASK			0xFFFFFFFF /* mask every bit*/ + +#define MPT3SAS_INVALID_DEVICE_HANDLE	0xFFFF + +/* + * 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: " + +/* + * 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 + + + +/* + * 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) + + +/* 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) + +/* 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 + * @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. + */ +struct MPT3SAS_TARGET { +	struct scsi_target *starget; +	u64	sas_address; +	u16	handle; +	int	num_luns; +	u32	flags; +	u8	deleted; +	u8	tm_busy; +}; + + +/* + * per device private data + */ +#define MPT_DEVICE_FLAGS_INIT		0x01 +#define MPT_DEVICE_TLR_ON		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; +}; + +#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 + * @fast_path: fast path feature enable bit + * @responding: used in _scsih_sas_device_mark_responding + */ +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; +}; + +/** + * 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 + * @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 + */ +#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; +	int	id; +	int	channel; +	u8	volume_type; +	u8	num_pds; +	u8	responding; +	u8	percent_complete; +	u32	device_info; +}; + +/** + * 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 + * @tracker_list: list of free request (ioc->free_list) + */ +struct scsiio_tracker { +	u16	smid; +	struct scsi_cmnd *scmd; +	u8	cb_idx; +	struct list_head chain_list; +	struct list_head tracker_list; +}; + +/** + * 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 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; +	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 mpt3sas_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			Reserved3; +	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 mpt3sas_port_facts { +	u8			PortNumber; +	u8			VP_ID; +	u8			VF_ID; +	u8			PortType; +	u16			MaxPostedCmdBuffers; +}; + +/** + * 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 + * @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 _mpt3sas_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 + * @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 + * @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_free: pool for reply post (64bit descriptor) + * @reply_post_free_dma: + * @reply_queue_count: number of reply queue's + * @reply_queue_list: link list contaning the reply queue info + * @reply_post_host_index: head index in the pool where FW completes IO + * @delayed_tr_list: target reset link list + * @delayed_tr_volume_list: volume target reset link list + */ +struct MPT3SAS_ADAPTER { +	struct list_head list; +	struct Scsi_Host *shost; +	u8		id; +	int		cpu_count; +	char		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; + +	/* 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; +	u32		ioc_reset_count; +	MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; + +	/* 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; +	u8              mpi25; +	u16             sge_size_ieee; + +	/* 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 mpt3sas_facts facts; +	struct mpt3sas_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; + +	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; + +	/* 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; +	Mpi2ReplyDescriptorsUnion_t *reply_post_free; +	dma_addr_t	reply_post_free_dma; +	struct dma_pool *reply_post_free_dma_pool; +	u8		reply_queue_count; +	struct list_head reply_queue_list; + +	struct list_head delayed_tr_list; +	struct list_head delayed_tr_volume_list; + +	/* 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; +	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 mpt3sas_ioc_list; +void mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc); +void mpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc); + +int mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc); +void mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc); +int mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc); +void mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc); +int mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, int sleep_flag, +	enum reset_type type); + +void *mpt3sas_base_get_msg_frame(struct MPT3SAS_ADAPTER *ioc, u16 smid); +void *mpt3sas_base_get_sense_buffer(struct MPT3SAS_ADAPTER *ioc, u16 smid); +__le32 mpt3sas_base_get_sense_buffer_dma(struct MPT3SAS_ADAPTER *ioc, +	u16 smid); +void mpt3sas_base_flush_reply_queues(struct MPT3SAS_ADAPTER *ioc); + +/* hi-priority queue */ +u16 mpt3sas_base_get_smid_hpr(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx); +u16 mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, +	struct scsi_cmnd *scmd); + +u16 mpt3sas_base_get_smid(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx); +void mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid); +void mpt3sas_base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, +	u16 handle); +void mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, +	u16 handle); +void mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid); +void mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid); +void mpt3sas_base_initialize_callback_handler(void); +u8 mpt3sas_base_register_callback_handler(MPT_CALLBACK cb_func); +void mpt3sas_base_release_callback_handler(u8 cb_idx); + +u8 mpt3sas_base_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply); +u8 mpt3sas_port_enable_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, +	u8 msix_index, u32 reply); +void *mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, +	u32 phys_addr); + +u32 mpt3sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked); + +void mpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code); +int mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, +	Mpi2SasIoUnitControlReply_t *mpi_reply, +	Mpi2SasIoUnitControlRequest_t *mpi_request); +int mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, +	Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); + +void mpt3sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, +	u32 *event_type); + +void mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc); + +void mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, +	u16 device_missing_delay, u8 io_missing_delay); + +int mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc); + + +/* scsih shared API */ +u8 mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, +	u32 reply); +void mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase); + +int mpt3sas_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 mpt3sas_scsih_set_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle); +void mpt3sas_scsih_clear_tm_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle); +void mpt3sas_expander_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address); +void mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, +	u64 sas_address); + +struct _sas_node *mpt3sas_scsih_expander_find_by_handle( +	struct MPT3SAS_ADAPTER *ioc, u16 handle); +struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address( +	struct MPT3SAS_ADAPTER *ioc, u64 sas_address); +struct _sas_device *mpt3sas_scsih_sas_device_find_by_sas_address( +	struct MPT3SAS_ADAPTER *ioc, u64 sas_address); + +void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); + +/* config shared API */ +u8 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply); +int mpt3sas_config_get_number_hba_phys(struct MPT3SAS_ADAPTER *ioc, +	u8 *num_phys); +int mpt3sas_config_get_manufacturing_pg0(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page); +int mpt3sas_config_get_manufacturing_pg7(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage7_t *config_page, +	u16 sz); +int mpt3sas_config_get_manufacturing_pg10(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, +	struct Mpi2ManufacturingPage10_t *config_page); + +int mpt3sas_config_get_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, +	struct Mpi2ManufacturingPage11_t  *config_page); +int mpt3sas_config_set_manufacturing_pg11(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, +	struct Mpi2ManufacturingPage11_t *config_page); + +int mpt3sas_config_get_bios_pg2(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t +	*mpi_reply, Mpi2BiosPage2_t *config_page); +int mpt3sas_config_get_bios_pg3(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t +	*mpi_reply, Mpi2BiosPage3_t *config_page); +int mpt3sas_config_get_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t +	*mpi_reply, Mpi2IOUnitPage0_t *config_page); +int mpt3sas_config_get_sas_device_pg0(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage0_t *config_page, +	u32 form, u32 handle); +int mpt3sas_config_get_sas_device_pg1(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2SasDevicePage1_t *config_page, +	u32 form, u32 handle); +int mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, +	u16 sz); +int mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t +	*mpi_reply, Mpi2IOUnitPage1_t *config_page); +int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t +	*mpi_reply, Mpi2IOUnitPage1_t *config_page); +int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, +	u16 sz); +int mpt3sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, +	u16 sz); +int mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t +	*mpi_reply, Mpi2IOCPage8_t *config_page); +int mpt3sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2ExpanderPage0_t *config_page, +	u32 form, u32 handle); +int mpt3sas_config_get_expander_pg1(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2ExpanderPage1_t *config_page, +	u32 phy_number, u16 handle); +int mpt3sas_config_get_enclosure_pg0(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, +	u32 form, u32 handle); +int mpt3sas_config_get_phy_pg0(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t +	*mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number); +int mpt3sas_config_get_phy_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t +	*mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number); +int mpt3sas_config_get_raid_volume_pg1(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, +	u32 handle); +int mpt3sas_config_get_number_pds(struct MPT3SAS_ADAPTER *ioc, u16 handle, +	u8 *num_pds); +int mpt3sas_config_get_raid_volume_pg0(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, +	u32 handle, u16 sz); +int mpt3sas_config_get_phys_disk_pg0(struct MPT3SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, +	u32 form, u32 form_specific); +int mpt3sas_config_get_volume_handle(struct MPT3SAS_ADAPTER *ioc, u16 pd_handle, +	u16 *volume_handle); +int mpt3sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, +	u16 volume_handle, u64 *wwid); + +/* ctl shared API */ +extern struct device_attribute *mpt3sas_host_attrs[]; +extern struct device_attribute *mpt3sas_dev_attrs[]; +void mpt3sas_ctl_init(void); +void mpt3sas_ctl_exit(void); +u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply); +void mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase); +u8 mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, +	u8 msix_index, u32 reply); +void mpt3sas_ctl_add_to_event_log(struct MPT3SAS_ADAPTER *ioc, +	Mpi2EventNotificationReply_t *mpi_reply); + +void mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, +	u8 bits_to_regsiter); +int mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, +	u8 *issue_reset); + +/* transport shared API */ +u8 mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply); +struct _sas_port *mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, +	u16 handle, u64 sas_address); +void mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, +	u64 sas_address_parent); +int mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy +	*mpt3sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); +int mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, +	struct _sas_phy *mpt3sas_phy, Mpi2ExpanderPage1_t expander_pg1, +	struct device *parent_dev); +void mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc, +	u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); +extern struct sas_function_template mpt3sas_transport_functions; +extern struct scsi_transport_template *mpt3sas_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 mpt3sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, +	struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data); +void mpt3sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc, +	struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data); +void mpt3sas_trigger_master(struct MPT3SAS_ADAPTER *ioc, +	u32 tigger_bitmask); +void mpt3sas_trigger_event(struct MPT3SAS_ADAPTER *ioc, u16 event, +	u16 log_entry_qualifier); +void mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, +	u8 asc, u8 ascq); +void mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, +	u32 loginfo); +#endif /* MPT3SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c new file mode 100644 index 00000000000..936ec039199 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -0,0 +1,1649 @@ +/* + * This module provides common API for accessing firmware configuration pages + * + * This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c + * Copyright (C) 2012-2013  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. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/blkdev.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#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; +}; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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 = mpt3sas_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)); +} +#endif + +/** + * _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); +} + +/** + * mpt3sas_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 +mpt3sas_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 =  mpt3sas_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; +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	_config_display_some_debug(ioc, smid, "config_done", mpi_reply); +#endif +	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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_base_get_msg_frame(ioc, smid); +	ioc->config_cmds.smid = smid; +	memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	_config_display_some_debug(ioc, smid, "config_request", NULL); +#endif +	init_completion(&ioc->config_cmds.done); +	mpt3sas_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) +			mpt3sas_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) +		mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, +		    FORCE_BIG_HAMMER); +	return r; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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 (!(mpt3sas_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/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c new file mode 100644 index 00000000000..ba9cbe598a9 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -0,0 +1,3282 @@ +/* + * Management Module Support for MPT (Message Passing Technology) based + * controllers + * + * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.c + * Copyright (C) 2012-2013  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. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/compat.h> +#include <linux/poll.h> + +#include <linux/io.h> +#include <linux/uaccess.h> + +#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, +}; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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 = mpt3sas_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); +	} +} + +#endif + +/** + * mpt3sas_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 +mpt3sas_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 = mpt3sas_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 = mpt3sas_base_get_sense_buffer(ioc, +				    smid); +				memcpy(ioc->ctl_cmds.sense, sense_data, sz); +			} +		} +	} +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	_ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); +#endif +	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]; +} + +/** + * mpt3sas_ctl_add_to_event_log - add event + * @ioc: per adapter object + * @mpi_reply: reply message frame + * + * Return nothing. + */ +void +mpt3sas_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); +	} +} + +/** + * mpt3sas_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 +mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, +	u32 reply) +{ +	Mpi2EventNotificationReply_t *mpi_reply; + +	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); +	mpt3sas_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. + * + * Return (-1) means error, else ioc_number. + */ +static int +_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp) +{ +	struct MPT3SAS_ADAPTER *ioc; + +	list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { +		if (ioc->id != ioc_number) +			continue; +		*iocpp = ioc; +		return ioc_number; +	} +	*iocpp = NULL; +	return -1; +} + +/** + * mpt3sas_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 +mpt3sas_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; +			mpt3sas_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; +			mpt3sas_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 - + * @fd - + * @filep - + * @mode - + * + * Called when application request fasyn callback handler. + */ +static int +_ctl_fasync(int fd, struct file *filep, int mode) +{ +	return fasync_helper(fd, filep, mode, &async_queue); +} + +/** + * _ctl_poll - + * @file - + * @wait - + * + */ +static unsigned int +_ctl_poll(struct file *filep, poll_table *wait) +{ +	struct MPT3SAS_ADAPTER *ioc; + +	poll_wait(filep, &ctl_poll_wait, wait); + +	list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { +		if (ioc->aen_event_read_flag) +			return POLLIN | POLLRDNORM; +	} +	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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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; +			mpt3sas_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; +			mpt3sas_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; +			mpt3sas_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; +			mpt3sas_base_free_smid(ioc, smid); +			goto out; +		} +	} + +	psge = (void *)request + (karg.data_sge_offset*4); + +	/* send command to firmware */ +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	_ctl_display_some_debug(ioc, smid, "ctl_request", NULL); +#endif + +	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 = +		    mpt3sas_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) +			mpt3sas_base_put_smid_scsi_io(ioc, smid, +			    le16_to_cpu(mpi_request->FunctionDependent1)); +		else +			mpt3sas_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)) { +				mpt3sas_base_free_smid(ioc, smid); +				goto out; +			} +		} + +		mpt3sas_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); +		mpt3sas_base_put_smid_hi_priority(ioc, smid); +		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__); +				mpt3sas_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); +		mpt3sas_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); +		mpt3sas_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); +		} +		mpt3sas_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); +		mpt3sas_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; +		mpt3sas_scsih_clear_tm_flag(ioc, le16_to_cpu( +		    tm_request->DevHandle)); +		mpt3sas_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; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	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)); +	} +#endif +	/* 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)); +			mpt3sas_halt_firmware(ioc); +			mpt3sas_scsih_issue_tm(ioc, +			    le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, +			    0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, +			    TM_MUTEX_ON); +		} else +			mpt3sas_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)); +	karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3; +	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, MPT3SAS_DRIVER_NAME); +	strcat(karg.driver_version, "-"); +	strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION); +	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)); +	mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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); +			mpt3sas_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); +	mpt3sas_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) +		mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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); +	mpt3sas_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 = mpt3sas_send_diag_release(ioc, buffer_type, &issue_reset); + +	if (issue_reset) +		mpt3sas_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 = mpt3sas_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 = mpt3sas_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); +	mpt3sas_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) +		mpt3sas_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 - + * compat - handles 32 bit applications in 64bit os + */ +static long +_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, +	u8 compat) +{ +	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) == -1 || !ioc) +		return -ENODEV; + +	if (ioc->shost_recovery || ioc->pci_error_recovery || +	    ioc->is_driver_loading) +		return -EAGAIN; + +	state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; +	if (state == NON_BLOCKING) { +		if (!mutex_trylock(&ioc->ctl_cmds.mutex)) +			return -EAGAIN; +	} else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) +		return -ERESTARTSYS; + + +	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); +	return ret; +} + +/** + * _ctl_ioctl - main ioctl entry point (unlocked) + * @file - (struct file) + * @cmd - ioctl opcode + * @arg - + */ +static long +_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ +	long ret; + +	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0); +	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. + */ +static long +_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) +{ +	long ret; + +	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1); +	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 + * + * mpt3sas_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); + +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); +		mpt3sas_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 *mpt3sas_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, +	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 *mpt3sas_dev_attrs[] = { +	&dev_attr_sas_address, +	&dev_attr_sas_device_handle, +	NULL, +}; + +static const struct file_operations ctl_fops = { +	.owner = THIS_MODULE, +	.unlocked_ioctl = _ctl_ioctl, +	.poll = _ctl_poll, +	.fasync = _ctl_fasync, +#ifdef CONFIG_COMPAT +	.compat_ioctl = _ctl_ioctl_compat, +#endif +}; + +static struct miscdevice ctl_dev = { +	.minor  = MPT3SAS_MINOR, +	.name   = MPT3SAS_DEV_NAME, +	.fops   = &ctl_fops, +}; + +/** + * mpt3sas_ctl_init - main entry point for ctl. + * + */ +void +mpt3sas_ctl_init(void) +{ +	async_queue = NULL; +	if (misc_register(&ctl_dev) < 0) +		pr_err("%s can't register misc device [minor=%d]\n", +		    MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR); + +	init_waitqueue_head(&ctl_poll_wait); +} + +/** + * mpt3sas_ctl_exit - exit point for ctl + * + */ +void +mpt3sas_ctl_exit(void) +{ +	struct MPT3SAS_ADAPTER *ioc; +	int i; + +	list_for_each_entry(ioc, &mpt3sas_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); +	} +	misc_deregister(&ctl_dev); +} diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h new file mode 100644 index 00000000000..53b0c480d98 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h @@ -0,0 +1,418 @@ +/* + * Management Module Support for MPT (Message Passing Technology) based + * controllers + * + * This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.h + * Copyright (C) 2012-2013  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. + */ + +#ifndef MPT3SAS_CTL_H_INCLUDED +#define MPT3SAS_CTL_H_INCLUDED + +#ifdef __KERNEL__ +#include <linux/miscdevice.h> +#endif + + +#ifndef MPT3SAS_MINOR +#define MPT3SAS_MINOR		(MPT_MINOR + 2) +#endif +#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 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/mpt3sas/mpt3sas_debug.h b/drivers/scsi/mpt3sas/mpt3sas_debug.h new file mode 100644 index 00000000000..545b22d2cbd --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_debug.h @@ -0,0 +1,219 @@ +/* + * Logging Support for MPT (Message Passing Technology) based controllers + * + * This code is based on drivers/scsi/mpt3sas/mpt3sas_debug.c + * Copyright (C) 2012-2013  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. + */ + +#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 + + +/* + * CONFIG_SCSI_MPT3SAS_LOGGING - enabled in Kconfig + */ + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +#define MPT_CHECK_LOGGING(IOC, CMD, BITS)			\ +{								\ +	if (IOC->logging_level & BITS)				\ +		CMD;						\ +} +#else +#define MPT_CHECK_LOGGING(IOC, CMD, BITS) +#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */ + + +/* + * 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*/ +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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"); +} +#else +#define _debug_dump_mf(mpi_request, sz) +#define _debug_dump_reply(mpi_request, sz) +#define _debug_dump_config(mpi_request, sz) +#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */ + +#endif /* MPT3SAS_DEBUG_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c new file mode 100644 index 00000000000..18e713db1d3 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -0,0 +1,8168 @@ +/* + * Scsi Host Layer for MPT (Message Passing Technology) based controllers + * + * This code is based on drivers/scsi/mpt3sas/mpt3sas_scsih.c + * Copyright (C) 2012-2013  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. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/blkdev.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/aer.h> +#include <linux/raid_class.h> + +#include "mpt3sas_base.h" + +MODULE_AUTHOR(MPT3SAS_AUTHOR); +MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MPT3SAS_DRIVER_VERSION); + +#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); + +static void _scsih_scan_start(struct Scsi_Host *shost); +static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); + +/* global parameters */ +LIST_HEAD(mpt3sas_ioc_list); + +/* 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 mpt_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 */ + +static struct raid_template *mpt3sas_raid_template; + + +/** + * 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_FAULT_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) + * @cancel_pending_work: flag set during reset handling + * @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 mpt2_ioc.h + * @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; +	u8			cancel_pending_work; +	struct delayed_work	delayed_work; + +	struct MPT3SAS_ADAPTER *ioc; +	u16			device_handle; +	u8			VF_ID; +	u8			VP_ID; +	u8			ignore; +	u16			event; +	void			*event_data; +}; + +/* raid transport support */ +static struct raid_template *mpt3sas_raid_template; + +/** + * 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; +}; + +/* + * The pci device ids are defined in mpi/mpi2_cnfg.h. + */ +static DEFINE_PCI_DEVICE_TABLE(scsih_pci_table) = { +	/* 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 }, +	{0}	/* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, scsih_pci_table); + +/** + * _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); +	list_for_each_entry(ioc, &mpt3sas_ioc_list, list) +		ioc->logging_level = logging_level; +	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 ((mpt3sas_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; +		} +	} +} + +/** + * mpt3sas_scsih_sas_device_find_by_sas_address - 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 * +mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, +	u64 sas_address) +{ +	struct _sas_device *sas_device; + +	list_for_each_entry(sas_device, &ioc->sas_device_list, list) +		if (sas_device->sas_address == sas_address) +			return sas_device; + +	list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) +		if (sas_device->sas_address == sas_address) +			return sas_device; + +	return NULL; +} + +/** + * _scsih_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 * +_scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ +	struct _sas_device *sas_device; + +	list_for_each_entry(sas_device, &ioc->sas_device_list, list) +		if (sas_device->handle == handle) +			return sas_device; + +	list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) +		if (sas_device->handle == handle) +			return sas_device; + +	return NULL; +} + +/** + * _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. + * + * Removing object and freeing associated memory from the ioc->sas_device_list. + */ +static void +_scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, +	struct _sas_device *sas_device) +{ +	unsigned long flags; + +	if (!sas_device) +		return; + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	list_del(&sas_device->list); +	kfree(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 = _scsih_sas_device_find_by_handle(ioc, handle); +	if (sas_device) +		list_del(&sas_device->list); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	if (sas_device) +		_scsih_remove_device(ioc, sas_device); +} + +/** + * mpt3sas_device_remove_by_sas_address - removing device object by sas address + * @ioc: per adapter object + * @sas_address: device sas_address + * + * Return nothing. + */ +void +mpt3sas_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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_address); +	if (sas_device) +		list_del(&sas_device->list); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	if (sas_device) +		_scsih_remove_device(ioc, 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)); + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	list_add_tail(&sas_device->list, &ioc->sas_device_list); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	if (!mpt3sas_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) { +			mpt3sas_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)); + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	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; +} + +/** + * _scsih_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. + */ +static struct _raid_device * +_scsih_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); +} + +/** + * mpt3sas_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 * +mpt3sas_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; +} + +/** + * mpt3sas_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 * +mpt3sas_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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +	   sas_device_priv_data->sas_target->sas_address); +	if (sas_device && sas_device->device_info & +	    MPI2_SAS_DEVICE_INFO_SATA_DEVICE) +		max_depth = MPT3SAS_SATA_QUEUE_DEPTH; +	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 - 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. + */ +static int +_scsih_change_queue_depth(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 - changing device queue tag type + * @sdev: scsi device struct + * @tag_type: requested tag type + * + * Returns queue tag type. + */ +static int +_scsih_change_queue_type(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 - 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. + */ +static int +_scsih_target_alloc(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(struct scsi_target), 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; +			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 = mpt3sas_scsih_sas_device_find_by_sas_address(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_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 - target destroy routine + * @starget: scsi target struct + * + * Returns nothing. + */ +static void +_scsih_target_destroy(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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +	   rphy->identify.sas_address); +	if (sas_device && (sas_device->starget == starget) && +	    (sas_device->id == starget->id) && +	    (sas_device->channel == starget->channel)) +		sas_device->starget = NULL; + +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + out: +	kfree(sas_target_priv_data); +	starget->hostdata = NULL; +} + +/** + * _scsih_slave_alloc - 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. + */ +static int +_scsih_slave_alloc(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(struct scsi_device), 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 = mpt3sas_scsih_sas_device_find_by_sas_address(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; +		} +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	} + +	return 0; +} + +/** + * _scsih_slave_destroy - device destroy routine + * @sdev: scsi device struct + * + * Returns nothing. + */ +static void +_scsih_slave_destroy(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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +		   sas_target_priv_data->sas_address); +		if (sas_device && !sas_target_priv_data->num_luns) +			sas_device->starget = NULL; +		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 ((mpt3sas_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 - return boolean indicating device is raid volume + * @dev the device struct object + */ +static int +_scsih_is_raid(struct device *dev) +{ +	struct scsi_device *sdev = to_scsi_device(dev); + +	return (sdev->channel == RAID_CHANNEL) ? 1 : 0; +} + +/** + * _scsih_get_resync - get raid volume resync percent complete + * @dev the device struct object + */ +static void +_scsih_get_resync(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; +	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 (mpt3sas_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: +	raid_set_resync(mpt3sas_raid_template, dev, percent_complete); +} + +/** + * _scsih_get_state - get raid volume level + * @dev the device struct object + */ +static void +_scsih_get_state(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 (mpt3sas_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: +	raid_set_state(mpt3sas_raid_template, dev, state); +} + +/** + * _scsih_set_level - set raid level + * @sdev: scsi device struct + * @volume_type: volume type + */ +static void +_scsih_set_level(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; +	} + +	raid_set_level(mpt3sas_raid_template, &sdev->sdev_gendev, level); +} + + +/** + * _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 ((mpt3sas_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 ((mpt3sas_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 (!(mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply, +	    &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, +	    vol_pg0->PhysDisk[0].PhysDiskNum))) { +		if (!(mpt3sas_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 - 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. + */ +static int +_scsih_slave_configure(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 = _scsih_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; +		} + + +		/* 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; +		} + +		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); + + +		_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + +/* raid transport support */ +		_scsih_set_level(sdev, raid_device->volume_type); +		return 0; +	} + +	/* non-raid handling */ +	if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { +		if (mpt3sas_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 && mpt3sas_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 = mpt3sas_scsih_sas_device_find_by_sas_address(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; +		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); +	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); + +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	if (!ssp_target) +		_scsih_display_sata_capabilities(ioc, handle, sdev); + + +	_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + +	if (ssp_target) { +		sas_read_port_mode_page(sdev); +		_scsih_enable_tlr(ioc, sdev); +	} + +	return 0; +} + +/** + * _scsih_bios_param - 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. + */ +static int +_scsih_bios_param(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; +	mpt3sas_base_flush_reply_queues(ioc); +	ioc->tm_cmds.status |= MPT3_CMD_COMPLETE; +	mpi_reply =  mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_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; +		} +	} +} + +/** + * mpt3sas_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 +mpt3sas_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; +		} +	} +} + +/** + * mpt3sas_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 +mpt3sas_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; + +	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 = mpt3sas_base_get_iocstate(ioc, 0); +	if (ioc_state & MPI2_DOORBELL_USED) { +		dhsprintk(ioc, pr_info(MPT3SAS_FMT +			"unexpected doorbell active!\n", ioc->name)); +		rc = mpt3sas_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) { +		mpt3sas_base_fault_info(ioc, ioc_state & +		    MPI2_DOORBELL_DATA_MASK); +		rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, +		    FORCE_BIG_HAMMER); +		rc = (!rc) ? SUCCESS : FAILED; +		goto err_out; +	} + +	smid = mpt3sas_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 = mpt3sas_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); +	mpt3sas_scsih_set_tm_flag(ioc, handle); +	init_completion(&ioc->tm_cmds.done); +	mpt3sas_base_put_smid_hi_priority(ioc, smid); +	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 = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, +			    FORCE_BIG_HAMMER); +			rc = (!rc) ? SUCCESS : FAILED; +			ioc->tm_cmds.status = MPT3_CMD_NOT_USED; +			mpt3sas_scsih_clear_tm_flag(ioc, handle); +			goto err_out; +		} +	} + +	if (ioc->tm_cmds.status & MPT3_CMD_REPLY_VALID) { +		mpt3sas_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; +	} + +	mpt3sas_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; +	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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +		    priv_target->sas_address); +		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); +			starget_printk(KERN_INFO, starget, +			    "enclosure_logical_id(0x%016llx), slot(%d)\n", +			   (unsigned long long)sas_device->enclosure_logical_id, +			    sas_device->slot); +		} +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	} +} + +/** + * _scsih_abort - eh threads main abort routine + * @scmd: pointer to scsi command object + * + * Returns SUCCESS if command aborted else FAILED + */ +static int +_scsih_abort(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; +	} + +	mpt3sas_halt_firmware(ioc); + +	handle = sas_device_priv_data->sas_target->handle; +	r = mpt3sas_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 - eh threads main device reset routine + * @scmd: pointer to scsi command object + * + * Returns SUCCESS if command aborted else FAILED + */ +static int +_scsih_dev_reset(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; +	unsigned long flags; +	u16	handle; +	int r; + +	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) { +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = _scsih_sas_device_find_by_handle(ioc, +		   sas_device_priv_data->sas_target->handle); +		if (sas_device) +			handle = sas_device->volume_handle; +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	} else +		handle = sas_device_priv_data->sas_target->handle; + +	if (!handle) { +		scmd->result = DID_RESET << 16; +		r = FAILED; +		goto out; +	} + +	r = mpt3sas_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); +	return r; +} + +/** + * _scsih_target_reset - eh threads main target reset routine + * @scmd: pointer to scsi command object + * + * Returns SUCCESS if command aborted else FAILED + */ +static int +_scsih_target_reset(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; +	unsigned long flags; +	u16	handle; +	int r; +	struct scsi_target *starget = scmd->device->sdev_target; + +	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) { +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = _scsih_sas_device_find_by_handle(ioc, +		   sas_device_priv_data->sas_target->handle); +		if (sas_device) +			handle = sas_device->volume_handle; +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	} else +		handle = sas_device_priv_data->sas_target->handle; + +	if (!handle) { +		scmd->result = DID_RESET << 16; +		r = FAILED; +		goto out; +	} + +	r = mpt3sas_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); +	return r; +} + + +/** + * _scsih_host_reset - eh threads main host reset routine + * @scmd: pointer to scsi command object + * + * Returns SUCCESS if command aborted else FAILED + */ +static int +_scsih_host_reset(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); + +	retval = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, +	    FORCE_BIG_HAMMER); +	r = (retval < 0) ? FAILED : SUCCESS; +	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); +	INIT_LIST_HEAD(&fw_event->list); +	list_add_tail(&fw_event->list, &ioc->fw_event_list); +	INIT_WORK(&fw_event->work, _firmware_event_work); +	queue_work(ioc->firmware_event_thread, &fw_event->work); +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/** + * _scsih_fw_event_free - delete fw_event + * @ioc: per adapter object + * @fw_event: object describing the event + * Context: This function will acquire ioc->fw_event_lock. + * + * This removes firmware event object from link list, frees associated memory. + * + * Return nothing. + */ +static void +_scsih_fw_event_free(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work +	*fw_event) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ioc->fw_event_lock, flags); +	list_del(&fw_event->list); +	kfree(fw_event->event_data); +	kfree(fw_event); +	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + + + /** + * mpt3sas_send_trigger_data_event - send event for processing trigger data + * @ioc: per adapter object + * @event_data: trigger event data + * + * Return nothing. + */ +void +mpt3sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, +	struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) +{ +	struct fw_event_work *fw_event; + +	if (ioc->is_driver_loading) +		return; +	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) +		return; +	fw_event->event_data = kzalloc(sizeof(*event_data), GFP_ATOMIC); +	if (!fw_event->event_data) +		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); +} + +/** + * _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 = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) +		return; +	fw_event->event = MPT3SAS_REMOVE_UNRESPONDING_DEVICES; +	fw_event->ioc = ioc; +	_scsih_fw_event_add(ioc, fw_event); +} + +/** + * mpt3sas_port_enable_complete - port enable completed (fake event) + * @ioc: per adapter object + * + * Return nothing. + */ +void +mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc) +{ +	struct fw_event_work *fw_event; + +	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) +		return; +	fw_event->event = MPT3SAS_PORT_ENABLE_COMPLETE; +	fw_event->ioc = ioc; +	_scsih_fw_event_add(ioc, 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, *next; + +	if (list_empty(&ioc->fw_event_list) || +	     !ioc->firmware_event_thread || in_interrupt()) +		return; + +	list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { +		if (cancel_delayed_work(&fw_event->delayed_work)) { +			_scsih_fw_event_free(ioc, fw_event); +			continue; +		} +		fw_event->cancel_pending_work = 1; +	} +} + +/** + * _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; + +		sas_device_priv_data->block = 0; +		dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, +			"device_running, handle(0x%04x)\n", +		    sas_device_priv_data->sas_target->handle)); +		scsi_internal_device_unblock(sdev, SDEV_RUNNING); +	} +} + + +/** + * _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) { +			sas_device_priv_data->block = 0; +			scsi_internal_device_unblock(sdev, SDEV_RUNNING); +		} +	} +} + +/** + * _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; +		sas_device_priv_data->block = 1; +		scsi_internal_device_block(sdev); +		sdev_printk(KERN_INFO, sdev, "device_blocked, handle(0x%04x)\n", +		    sas_device_priv_data->sas_target->handle); +	} +} + +/** + * _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; + +	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; +		sas_device_priv_data->block = 1; +		scsi_internal_device_block(sdev); +		sdev_printk(KERN_INFO, sdev, +			"device_blocked, handle(0x%04x)\n", handle); +	} +} + +/** + * _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 *mpt3sas_port; +	struct _sas_device *sas_device; +	struct _sas_node *expander_sibling; +	unsigned long flags; + +	if (!sas_expander) +		return; + +	list_for_each_entry(mpt3sas_port, +	   &sas_expander->sas_port_list, port_list) { +		if (mpt3sas_port->remote_identify.device_type == +		    SAS_END_DEVICE) { +			spin_lock_irqsave(&ioc->sas_device_lock, flags); +			sas_device = +			    mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +			   mpt3sas_port->remote_identify.sas_address); +			if (sas_device) +				set_bit(sas_device->handle, +				    ioc->blocking_handles); +			spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		} +	} + +	list_for_each_entry(mpt3sas_port, +	   &sas_expander->sas_port_list, port_list) { + +		if (mpt3sas_port->remote_identify.device_type == +		    SAS_EDGE_EXPANDER_DEVICE || +		    mpt3sas_port->remote_identify.device_type == +		    SAS_FANOUT_EXPANDER_DEVICE) { +			expander_sibling = +			    mpt3sas_scsih_expander_find_by_sas_address( +			    ioc, mpt3sas_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; +	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 = mpt3sas_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 = _scsih_sas_device_find_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)); +		_scsih_ublock_io_device(ioc, sas_address); +		sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; +	} + +	smid = mpt3sas_base_get_smid_hpr(ioc, ioc->tm_tr_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_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_cb_idx)); +	mpi_request = mpt3sas_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; +	mpt3sas_base_put_smid_hi_priority(ioc, smid); +	mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); +} + +/** + * _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 = +	    mpt3sas_base_get_reply_virt_addr(ioc, reply); +	Mpi2SasIoUnitControlRequest_t *mpi_request; +	u16 smid_sas_ctrl; +	u32 ioc_state; + +	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 = mpt3sas_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 = mpt3sas_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; +	} + +	mpt3sas_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 = mpt3sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); +	if (!smid_sas_ctrl) { +		pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", +		    ioc->name, __func__); +		return 1; +	} + +	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 = mpt3sas_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; +	mpt3sas_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 = +	    mpt3sas_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 1; +} + +/** + * _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 = mpt3sas_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 = mpt3sas_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; +	mpt3sas_base_put_smid_hi_priority(ioc, smid); +} + +/** + * _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 = +	    mpt3sas_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 = mpt3sas_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_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); +		mpt3sas_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); +		mpt3sas_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 = mpt3sas_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 = 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 = _scsih_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; + +	/* 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_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++; +		mpt3sas_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 - 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 + */ +static int +_scsih_qcmd(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; +	Mpi2SCSIIORequest_t *mpi_request; +	u32 mpi_control; +	u16 smid; +	u16 handle; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	if (ioc->logging_level & MPT_DEBUG_SCSI) +		scsi_print_command(scmd); +#endif + +	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; + +	if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && +	    scmd->cmd_len != 32) +		mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; + +	smid = mpt3sas_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 = mpt3sas_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 = +	    mpt3sas_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)) { +			mpt3sas_base_free_smid(ioc, smid); +			goto out; +		} +	} else +		ioc->build_zero_len_sge(ioc, &mpi_request->SGL); + +	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); +			mpt3sas_base_put_smid_fast_path(ioc, smid, handle); +		} else +			mpt3sas_base_put_smid_scsi_io(ioc, smid, handle); +	} else +		mpt3sas_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]; +	} +} + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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; +	unsigned long flags; +	struct scsi_target *starget = scmd->device->sdev_target; +	struct MPT3SAS_TARGET *priv_target = starget->hostdata; +	char *device_str = NULL; + +	if (!priv_target) +		return; +	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; +	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 { +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +		    priv_target->sas_address); +		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); +	} + +	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]); +	} +} +#endif + +/** + * _scsih_turn_on_fault_led - illuminate Fault LED + * @ioc: per adapter object + * @handle: device handle + * Context: process + * + * Return nothing. + */ +static void +_scsih_turn_on_fault_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ +	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 = +	    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 ((mpt3sas_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__); +		return; +	} + +	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))); +		return; +	} +} + +/** + * _scsih_send_event_to_turn_on_fault_led - fire delayed event + * @ioc: per adapter object + * @handle: device handle + * Context: interrupt. + * + * Return nothing. + */ +static void +_scsih_send_event_to_turn_on_fault_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) +{ +	struct fw_event_work *fw_event; + +	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) +		return; +	fw_event->event = MPT3SAS_TURN_ON_FAULT_LED; +	fw_event->device_handle = handle; +	fw_event->ioc = ioc; +	_scsih_fw_event_add(ioc, 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 = _scsih_sas_device_find_by_handle(ioc, handle); +	if (!sas_device) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} +	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))) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} +	starget_printk(KERN_WARNING, starget, "predicted fault\n"); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) +		_scsih_send_event_to_turn_on_fault_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__); +		return; +	} + +	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); +	mpt3sas_ctl_add_to_event_log(ioc, event_reply); +	kfree(event_reply); +} + +/** + * _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. + * + * 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; + +	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); +	scmd = _scsih_scsi_lookup_get_clear(ioc, smid); +	if (scmd == NULL) +		return 1; + +	mpi_request = mpt3sas_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); + +	/* 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 ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && +		    response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) +			sas_device_priv_data->flags &= +			    ~MPT_DEVICE_TLR_ON; +	} + +	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 = mpt3sas_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)); +		mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq); +	} + +	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; +		} +		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: +	default: +		scmd->result = DID_SOFT_ERROR << 16; +		break; + +	} + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY)) +		_scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid); +#endif + + 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 ((mpt3sas_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; +		mpt3sas_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; + +	mpt3sas_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 ((mpt3sas_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 ((mpt3sas_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 ((mpt3sas_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; +		mpt3sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], +		    phy_pg0, ioc->sas_hba.parent_dev); +	} +	if ((mpt3sas_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 (!(mpt3sas_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 *mpt3sas_port = NULL; + +	int rc = 0; + +	if (!handle) +		return -1; + +	if (ioc->shost_recovery || ioc->pci_error_recovery) +		return -1; + +	if ((mpt3sas_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 = mpt3sas_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 = mpt3sas_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); +	mpt3sas_port = mpt3sas_transport_port_add(ioc, handle, +	    sas_address_parent); +	if (!mpt3sas_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 = &mpt3sas_port->rphy->dev; + +	for (i = 0 ; i < sas_expander->num_phys ; i++) { +		if ((mpt3sas_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 ((mpt3sas_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 (!(mpt3sas_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 (mpt3sas_port) +		mpt3sas_transport_port_remove(ioc, sas_expander->sas_address, +		    sas_address_parent); +	kfree(sas_expander); +	return rc; +} + +/** + * mpt3sas_expander_remove - removing expander object + * @ioc: per adapter object + * @sas_address: expander sas_address + * + * Return nothing. + */ +void +mpt3sas_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 = mpt3sas_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 =  mpt3sas_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 ((mpt3sas_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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_address); + +	if (!sas_device) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} + +	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; +	} + +	/* 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); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} + +	/* check if there were any issues with discovery */ +	if (_scsih_check_access_status(ioc, sas_address, handle, +	    sas_device_pg0.AccessStatus)) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} + +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	_scsih_ublock_io_device(ioc, sas_address); + +} + +/** + * _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; +	unsigned long flags; + +	if ((mpt3sas_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; + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_address); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	if (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; +	} + +	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); +	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; + +	/* get enclosure_logical_id */ +	if (sas_device->enclosure_handle && !(mpt3sas_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); + +	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; + + +	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->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; +	} +	mpt3sas_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); + +	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)); + +	kfree(sas_device); +} + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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); + +	} +} +#endif + +/** + * _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 = fw_event->event_data; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +		_scsih_sas_topology_change_event_debug(ioc, event_data); +#endif + +	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 = mpt3sas_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; + +			mpt3sas_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; + +			mpt3sas_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) +		mpt3sas_expander_remove(ioc, sas_address); + +	return 0; +} + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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"); +} +#endif + +/** + * _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 = +	    fw_event->event_data; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +		_scsih_sas_device_status_change_event_debug(ioc, +		     event_data); +#endif + +	/* 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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_address); + +	if (!sas_device || !sas_device->starget) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} + +	target_priv_data = sas_device->starget->hostdata; +	if (!target_priv_data) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		return; +	} + +	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; +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +} + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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)); +} +#endif + +/** + * _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) +{ +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +		_scsih_sas_enclosure_dev_status_change_event_debug(ioc, +		     fw_event->event_data); +#endif +} + +/** + * _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 = 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 = mpt3sas_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, +			    "mpt3sas_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 = mpt3sas_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, +			    "mpt3sas_scsih_issue_tm: ABORT_TASK: FAILED : " +			    "scmd(%p)\n", scmd); +			goto tm_retry; +		} + +		if (task_abort_retries > 1) +			sdev_printk(KERN_WARNING, sdev, +			    "mpt3sas_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 = fw_event->event_data; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	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"); +	} +#endif + +	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; + + +	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 = mpt3sas_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 = mpt3sas_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); +	mpt3sas_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) +		mpt3sas_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; + +	mpt3sas_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 = _scsih_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 = _scsih_sas_device_find_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); +} + +/** + * _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; + +	mpt3sas_config_get_volume_handle(ioc, handle, &volume_handle); +	if (volume_handle) +		mpt3sas_config_get_volume_wwid(ioc, volume_handle, +		    &volume_wwid); + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_device = _scsih_sas_device_find_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); +} + +/** + * _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; +	unsigned long flags; +	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); + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	if (sas_device) { +		_scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); +		return; +	} + +	if ((mpt3sas_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)) +		mpt3sas_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); +} + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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); +	} +} +#endif + +/** + * _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 = fw_event->event_data; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +		_scsih_sas_ir_config_change_event_debug(ioc, event_data); + +#endif + +	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) { + +		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: +			_scsih_sas_pd_hide(ioc, element); +			break; +		case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: +			_scsih_sas_pd_expose(ioc, element); +			break; +		case MPI2_EVENT_IR_CHANGE_RC_HIDE: +			_scsih_sas_pd_add(ioc, element); +			break; +		case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: +			_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 = 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); +	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 = _scsih_raid_device_find_by_handle(ioc, handle); +		spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + +		if (raid_device) +			break; + +		mpt3sas_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; +	unsigned long flags; +	Mpi2ConfigReply_t mpi_reply; +	Mpi2SasDevicePage0_t sas_device_pg0; +	u32 ioc_status; +	Mpi2EventDataIrPhysicalDisk_t *event_data = 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); + +	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: + +		set_bit(handle, ioc->pd_handles); +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +		if (sas_device) +			return; + +		if ((mpt3sas_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)) +			mpt3sas_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; +	} +} + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +/** + * _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); +} +#endif + +/** + * _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 = fw_event->event_data; +	static struct _raid_device *raid_device; +	unsigned long flags; +	u16 handle; + +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING +	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +		_scsih_sas_ir_operation_status_event_debug(ioc, +		     event_data); +#endif + +	/* 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 = _scsih_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_address: sas address + * @slot: enclosure slot id + * @handle: device handle + * + * 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, u64 sas_address, +	u16 slot, u16 handle) +{ +	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_address && +		    sas_device->slot == 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), " +				    "enclosure logical id(0x%016llx), " +				    "slot(%d)\n", handle, +				    (unsigned long long)sas_device->sas_address, +				    (unsigned long long) +				    sas_device->enclosure_logical_id, +				    sas_device->slot); +			if (sas_device->handle == handle) +				goto out; +			pr_info("\thandle changed from(0x%04x)!!!\n", +			    sas_device->handle); +			sas_device->handle = handle; +			if (sas_target_priv_data) +				sas_target_priv_data->handle = handle; +			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 (!(mpt3sas_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 = le16_to_cpu(sas_device_pg0.DevHandle); +		device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); +		if (!(_scsih_is_end_device(device_info))) +			continue; +		_scsih_mark_responding_sas_device(ioc, +		    le64_to_cpu(sas_device_pg0.SASAddress), +		    le16_to_cpu(sas_device_pg0.Slot), handle); +	} + + 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; +	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); +			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 (!(mpt3sas_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 (mpt3sas_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 */ +		phys_disk_num = 0xFF; +		memset(ioc->pd_handles, 0, ioc->pd_handles_sz); +		while (!(mpt3sas_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 (!(mpt3sas_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; + +	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); +	list_for_each_entry_safe(sas_device, sas_device_next, +	    &ioc->sas_device_list, list) { +		if (!sas_device->responding) +			mpt3sas_device_remove_by_sas_address(ioc, +			    sas_device->sas_address); +		else +			sas_device->responding = 0; +	} + +	/* 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 ((mpt3sas_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; +		} + +		mpt3sas_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 (!(mpt3sas_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 = mpt3sas_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 (!(mpt3sas_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); +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		if (sas_device) +			continue; +		if (mpt3sas_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)); +			mpt3sas_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 (!(mpt3sas_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 (mpt3sas_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 (!(mpt3sas_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; +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +		    le64_to_cpu(sas_device_pg0.SASAddress)); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		if (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)); +			mpt3sas_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); +} +/** + * mpt3sas_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 +mpt3sas_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; +			mpt3sas_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; +			mpt3sas_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; +	} +} + +/** + * _mpt3sas_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 +_mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) +{ +	/* the queue is being flushed so ignore this event */ +	if (ioc->remove_host || fw_event->cancel_pending_work || +	    ioc->pci_error_recovery) { +		_scsih_fw_event_free(ioc, fw_event); +		return; +	} + +	switch (fw_event->event) { +	case MPT3SAS_PROCESS_TRIGGER_DIAG: +		mpt3sas_process_trigger_data(ioc, fw_event->event_data); +		break; +	case MPT3SAS_REMOVE_UNRESPONDING_DEVICES: +		while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery) +			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) +			mpt3sas_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_FAULT_LED: +		_scsih_turn_on_fault_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; +	} +	_scsih_fw_event_free(ioc, 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); + +	_mpt3sas_fw_work(fw_event->ioc, fw_event); +} + +/** + * mpt3sas_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 +mpt3sas_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; + +	/* events turned off due to host reset or driver unloading */ +	if (ioc->remove_host || ioc->pci_error_recovery) +		return 1; + +	mpi_reply = mpt3sas_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) +		mpt3sas_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_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; + +	default: /* ignore the rest */ +		return 1; +	} + +	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) { +		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		return 1; +	} +	sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; +	fw_event->event_data = kzalloc(sz, GFP_ATOMIC); +	if (!fw_event->event_data) { +		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		kfree(fw_event); +		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); +	return 1; +} + +/* shost template */ +static struct scsi_host_template scsih_driver_template = { +	.module				= THIS_MODULE, +	.name				= "Fusion MPT SAS Host", +	.proc_name			= MPT3SAS_DRIVER_NAME, +	.queuecommand			= _scsih_qcmd, +	.target_alloc			= _scsih_target_alloc, +	.slave_alloc			= _scsih_slave_alloc, +	.slave_configure		= _scsih_slave_configure, +	.target_destroy			= _scsih_target_destroy, +	.slave_destroy			= _scsih_slave_destroy, +	.scan_finished			= _scsih_scan_finished, +	.scan_start			= _scsih_scan_start, +	.change_queue_depth		= _scsih_change_queue_depth, +	.change_queue_type		= _scsih_change_queue_type, +	.eh_abort_handler		= _scsih_abort, +	.eh_device_reset_handler	= _scsih_dev_reset, +	.eh_target_reset_handler	= _scsih_target_reset, +	.eh_host_reset_handler		= _scsih_host_reset, +	.bios_param			= _scsih_bios_param, +	.can_queue			= 1, +	.this_id			= -1, +	.sg_tablesize			= MPT3SAS_SG_DEPTH, +	.max_sectors			= 32767, +	.cmd_per_lun			= 7, +	.use_clustering			= ENABLE_CLUSTERING, +	.shost_attrs			= mpt3sas_host_attrs, +	.sdev_attrs			= mpt3sas_dev_attrs, +}; + +/** + * _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 *mpt3sas_port, *next; + +	/* remove sibling ports attached to this expander */ +	list_for_each_entry_safe(mpt3sas_port, next, +	   &sas_expander->sas_port_list, port_list) { +		if (ioc->shost_recovery) +			return; +		if (mpt3sas_port->remote_identify.device_type == +		    SAS_END_DEVICE) +			mpt3sas_device_remove_by_sas_address(ioc, +			    mpt3sas_port->remote_identify.sas_address); +		else if (mpt3sas_port->remote_identify.device_type == +		    SAS_EDGE_EXPANDER_DEVICE || +		    mpt3sas_port->remote_identify.device_type == +		    SAS_FANOUT_EXPANDER_DEVICE) +			mpt3sas_expander_remove(ioc, +			    mpt3sas_port->remote_identify.sas_address); +	} + +	mpt3sas_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 = mpt3sas_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 = mpt3sas_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; + +	pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); +	init_completion(&ioc->scsih_cmds.done); +	mpt3sas_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; +		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 - detach and remove add host + * @pdev: PCI device struct + * + * Routine called when unloading the driver. + * Return nothing. + */ +static void _scsih_remove(struct pci_dev *pdev) +{ +	struct Scsi_Host *shost = pci_get_drvdata(pdev); +	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); +	struct _sas_port *mpt3sas_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(mpt3sas_port, next_port, +	   &ioc->sas_hba.sas_port_list, port_list) { +		if (mpt3sas_port->remote_identify.device_type == +		    SAS_END_DEVICE) +			mpt3sas_device_remove_by_sas_address(ioc, +			    mpt3sas_port->remote_identify.sas_address); +		else if (mpt3sas_port->remote_identify.device_type == +		    SAS_EDGE_EXPANDER_DEVICE || +		    mpt3sas_port->remote_identify.device_type == +		    SAS_FANOUT_EXPANDER_DEVICE) +			mpt3sas_expander_remove(ioc, +			    mpt3sas_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); +	mpt3sas_base_detach(ioc); +	list_del(&ioc->list); +	scsi_remove_host(shost); +	scsi_host_put(shost); +} + +/** + * _scsih_shutdown - routine call during system shutdown + * @pdev: PCI device struct + * + * Return nothing. + */ +static void +_scsih_shutdown(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); +	mpt3sas_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 (!mpt3sas_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) { +				mpt3sas_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); +	} +} + +/** + * _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, *next; +	unsigned long flags; + +	/* SAS Device List */ +	list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, +	    list) { + +		if (!mpt3sas_transport_port_add(ioc, sas_device->handle, +		    sas_device->sas_address_parent)) { +			list_del(&sas_device->list); +			kfree(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) { +				mpt3sas_transport_port_remove(ioc, +				    sas_device->sas_address, +				    sas_device->sas_address_parent); +				list_del(&sas_device->list); +				kfree(sas_device); +				continue; +			} +		} + +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		list_move_tail(&sas_device->list, &ioc->sas_device_list); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	} +} + +/** + * _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 - 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. + */ +static void +_scsih_scan_start(struct Scsi_Host *shost) +{ +	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); +	int rc; +	if (diag_buffer_enable != -1 && diag_buffer_enable != 0) +		mpt3sas_enable_diag_buffer(ioc, diag_buffer_enable); + +	if (disable_discovery > 0) +		return; + +	ioc->start_scan = 1; +	rc = mpt3sas_port_enable(ioc); + +	if (rc != 0) +		pr_info(MPT3SAS_FMT "port enable: FAILED\n", ioc->name); +} + +/** + * _scsih_scan_finished - 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. + */ +static int +_scsih_scan_finished(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); +	} +	mpt3sas_base_start_watchdog(ioc); +	ioc->is_driver_loading = 0; +	return 1; +} + +/** + * _scsih_probe - attach and add scsi host + * @pdev: PCI device struct + * @id: pci device id + * + * Returns 0 success, anything else error. + */ +static int +_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ +	struct MPT3SAS_ADAPTER *ioc; +	struct Scsi_Host *shost; + +	shost = scsi_host_alloc(&scsih_driver_template, +	    sizeof(struct MPT3SAS_ADAPTER)); +	if (!shost) +		return -ENODEV; + +	/* init local params */ +	ioc = shost_priv(shost); +	memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); +	INIT_LIST_HEAD(&ioc->list); +	list_add_tail(&ioc->list, &mpt3sas_ioc_list); +	ioc->shost = shost; +	ioc->id = mpt_ids++; +	sprintf(ioc->name, "%s%d", MPT3SAS_DRIVER_NAME, ioc->id); +	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); +	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_tr_volume_list); +	INIT_LIST_HEAD(&ioc->reply_queue_list); + +	/* init shost parameters */ +	shost->max_cmd_len = 32; +	shost->max_lun = max_lun; +	shost->transportt = mpt3sas_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); +		} +	} + +	if ((scsi_add_host(shost, &pdev->dev))) { +		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		list_del(&ioc->list); +		goto out_add_shost_fail; +	} + +	/* 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%d", ioc->id); +	ioc->firmware_event_thread = create_singlethread_workqueue( +	    ioc->firmware_event_name); +	if (!ioc->firmware_event_thread) { +		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		goto out_thread_fail; +	} + +	ioc->is_driver_loading = 1; +	if ((mpt3sas_base_attach(ioc))) { +		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		goto out_attach_fail; +	} +	scsi_scan_host(shost); +	return 0; + + out_attach_fail: +	destroy_workqueue(ioc->firmware_event_thread); + out_thread_fail: +	list_del(&ioc->list); +	scsi_remove_host(shost); + out_add_shost_fail: +	scsi_host_put(shost); +	return -ENODEV; +} + +#ifdef CONFIG_PM +/** + * _scsih_suspend - power management suspend main entry point + * @pdev: PCI device struct + * @state: PM state change to (usually PCI_D3) + * + * Returns 0 success, anything else error. + */ +static int +_scsih_suspend(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; + +	mpt3sas_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); +	mpt3sas_base_free_resources(ioc); +	pci_set_power_state(pdev, device_state); +	return 0; +} + +/** + * _scsih_resume - power management resume main entry point + * @pdev: PCI device struct + * + * Returns 0 success, anything else error. + */ +static int +_scsih_resume(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 = mpt3sas_base_map_resources(ioc); +	if (r) +		return r; + +	mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET); +	scsi_unblock_requests(shost); +	mpt3sas_base_start_watchdog(ioc); +	return 0; +} +#endif /* CONFIG_PM */ + +/** + * _scsih_pci_error_detected - 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 + */ +static pci_ers_result_t +_scsih_pci_error_detected(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); +		mpt3sas_base_stop_watchdog(ioc); +		mpt3sas_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; +		mpt3sas_base_stop_watchdog(ioc); +		_scsih_flush_running_cmds(ioc); +		return PCI_ERS_RESULT_DISCONNECT; +	} +	return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * _scsih_pci_slot_reset - 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. + */ +static pci_ers_result_t +_scsih_pci_slot_reset(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 = mpt3sas_base_map_resources(ioc); +	if (rc) +		return PCI_ERS_RESULT_DISCONNECT; + +	rc = mpt3sas_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() - 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. + */ +static void +_scsih_pci_resume(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); +	mpt3sas_base_start_watchdog(ioc); +	scsi_unblock_requests(ioc->shost); +} + +/** + * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers + * @pdev: pointer to PCI device + */ +static pci_ers_result_t +_scsih_pci_mmio_enabled(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 */ + +	/* Request a slot reset. */ +	return PCI_ERS_RESULT_NEED_RESET; +} + +/* raid transport support */ +static struct raid_function_template mpt3sas_raid_functions = { +	.cookie		= &scsih_driver_template, +	.is_raid	= _scsih_is_raid, +	.get_resync	= _scsih_get_resync, +	.get_state	= _scsih_get_state, +}; + +static struct pci_error_handlers _scsih_err_handler = { +	.error_detected = _scsih_pci_error_detected, +	.mmio_enabled = _scsih_pci_mmio_enabled, +	.slot_reset =	_scsih_pci_slot_reset, +	.resume =	_scsih_pci_resume, +}; + +static struct pci_driver scsih_driver = { +	.name		= MPT3SAS_DRIVER_NAME, +	.id_table	= scsih_pci_table, +	.probe		= _scsih_probe, +	.remove		= _scsih_remove, +	.shutdown	= _scsih_shutdown, +	.err_handler	= &_scsih_err_handler, +#ifdef CONFIG_PM +	.suspend	= _scsih_suspend, +	.resume		= _scsih_resume, +#endif +}; + + +/** + * _scsih_init - main entry point for this driver. + * + * Returns 0 success, anything else error. + */ +static int __init +_scsih_init(void) +{ +	int error; + +	mpt_ids = 0; + +	pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME, +	    MPT3SAS_DRIVER_VERSION); + +	mpt3sas_transport_template = +	    sas_attach_transport(&mpt3sas_transport_functions); +	if (!mpt3sas_transport_template) +		return -ENODEV; + +/* raid transport support */ +	mpt3sas_raid_template = raid_class_attach(&mpt3sas_raid_functions); +	if (!mpt3sas_raid_template) { +		sas_release_transport(mpt3sas_transport_template); +		return -ENODEV; +	} + +	mpt3sas_base_initialize_callback_handler(); + +	 /* queuecommand callback hander */ +	scsi_io_cb_idx = mpt3sas_base_register_callback_handler(_scsih_io_done); + +	/* task managment callback handler */ +	tm_cb_idx = mpt3sas_base_register_callback_handler(_scsih_tm_done); + +	/* base internal commands callback handler */ +	base_cb_idx = mpt3sas_base_register_callback_handler(mpt3sas_base_done); +	port_enable_cb_idx = mpt3sas_base_register_callback_handler( +	    mpt3sas_port_enable_done); + +	/* transport internal commands callback handler */ +	transport_cb_idx = mpt3sas_base_register_callback_handler( +	    mpt3sas_transport_done); + +	/* scsih internal commands callback handler */ +	scsih_cb_idx = mpt3sas_base_register_callback_handler(_scsih_done); + +	/* configuration page API internal commands callback handler */ +	config_cb_idx = mpt3sas_base_register_callback_handler( +	    mpt3sas_config_done); + +	/* ctl module callback handler */ +	ctl_cb_idx = mpt3sas_base_register_callback_handler(mpt3sas_ctl_done); + +	tm_tr_cb_idx = mpt3sas_base_register_callback_handler( +	    _scsih_tm_tr_complete); + +	tm_tr_volume_cb_idx = mpt3sas_base_register_callback_handler( +	    _scsih_tm_volume_tr_complete); + +	tm_sas_control_cb_idx = mpt3sas_base_register_callback_handler( +	    _scsih_sas_control_complete); + +	mpt3sas_ctl_init(); + +	error = pci_register_driver(&scsih_driver); +	if (error) { +		/* raid transport support */ +		raid_class_release(mpt3sas_raid_template); +		sas_release_transport(mpt3sas_transport_template); +	} + +	return error; +} + +/** + * _scsih_exit - exit point for this driver (when it is a module). + * + * Returns 0 success, anything else error. + */ +static void __exit +_scsih_exit(void) +{ +	pr_info("mpt3sas version %s unloading\n", +	    MPT3SAS_DRIVER_VERSION); + +	mpt3sas_ctl_exit(); + +	pci_unregister_driver(&scsih_driver); + + +	mpt3sas_base_release_callback_handler(scsi_io_cb_idx); +	mpt3sas_base_release_callback_handler(tm_cb_idx); +	mpt3sas_base_release_callback_handler(base_cb_idx); +	mpt3sas_base_release_callback_handler(port_enable_cb_idx); +	mpt3sas_base_release_callback_handler(transport_cb_idx); +	mpt3sas_base_release_callback_handler(scsih_cb_idx); +	mpt3sas_base_release_callback_handler(config_cb_idx); +	mpt3sas_base_release_callback_handler(ctl_cb_idx); + +	mpt3sas_base_release_callback_handler(tm_tr_cb_idx); +	mpt3sas_base_release_callback_handler(tm_tr_volume_cb_idx); +	mpt3sas_base_release_callback_handler(tm_sas_control_cb_idx); + +/* raid transport support */ +	raid_class_release(mpt3sas_raid_template); +	sas_release_transport(mpt3sas_transport_template); +} + +module_init(_scsih_init); +module_exit(_scsih_exit); diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c new file mode 100644 index 00000000000..65170cb1a00 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -0,0 +1,2132 @@ +/* + * SAS Transport Layer for MPT (Message Passing Technology) based controllers + * + * This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c + * Copyright (C) 2012-2013  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. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_transport_sas.h> +#include <scsi/scsi_dbg.h> + +#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 mpt3sas_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 ((mpt3sas_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; +} + +/** + * mpt3sas_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 +mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply) +{ +	MPI2DefaultReply_t *mpi_reply; + +	mpi_reply =  mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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; +		mpt3sas_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); +	mpt3sas_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) +		mpt3sas_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 + * @mpt3sas_port: mpt3sas per port object + * + * Returns nothing. + */ +static void +_transport_delete_port(struct MPT3SAS_ADAPTER *ioc, +	struct _sas_port *mpt3sas_port) +{ +	u64 sas_address = mpt3sas_port->remote_identify.sas_address; +	enum sas_device_type device_type = +	    mpt3sas_port->remote_identify.device_type; + +	dev_printk(KERN_INFO, &mpt3sas_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) +		mpt3sas_device_remove_by_sas_address(ioc, sas_address); +	else if (device_type == SAS_EDGE_EXPANDER_DEVICE || +	    device_type == SAS_FANOUT_EXPANDER_DEVICE) +		mpt3sas_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 + * @mpt3sas_port: mpt3sas per port object + * @mpt3sas_phy: mpt3sas per phy object + * + * Returns nothing. + */ +static void +_transport_delete_phy(struct MPT3SAS_ADAPTER *ioc, +	struct _sas_port *mpt3sas_port, struct _sas_phy *mpt3sas_phy) +{ +	u64 sas_address = mpt3sas_port->remote_identify.sas_address; + +	dev_printk(KERN_INFO, &mpt3sas_phy->phy->dev, +	    "remove: sas_addr(0x%016llx), phy(%d)\n", +	    (unsigned long long) sas_address, mpt3sas_phy->phy_id); + +	list_del(&mpt3sas_phy->port_siblings); +	mpt3sas_port->num_phys--; +	sas_port_delete_phy(mpt3sas_port->port, mpt3sas_phy->phy); +	mpt3sas_phy->phy_belongs_to_port = 0; +} + +/** + * _transport_add_phy - helper function to adding single phy to port + * @ioc: per adapter object + * @mpt3sas_port: mpt3sas per port object + * @mpt3sas_phy: mpt3sas per phy object + * + * Returns nothing. + */ +static void +_transport_add_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt3sas_port, +	struct _sas_phy *mpt3sas_phy) +{ +	u64 sas_address = mpt3sas_port->remote_identify.sas_address; + +	dev_printk(KERN_INFO, &mpt3sas_phy->phy->dev, +	    "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) +	    sas_address, mpt3sas_phy->phy_id); + +	list_add_tail(&mpt3sas_phy->port_siblings, &mpt3sas_port->phy_list); +	mpt3sas_port->num_phys++; +	sas_port_add_phy(mpt3sas_port->port, mpt3sas_phy->phy); +	mpt3sas_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) + * @mpt3sas_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 *mpt3sas_phy, +	u64 sas_address) +{ +	struct _sas_port *mpt3sas_port; +	struct _sas_phy *phy_srch; + +	if (mpt3sas_phy->phy_belongs_to_port == 1) +		return; + +	list_for_each_entry(mpt3sas_port, &sas_node->sas_port_list, +	    port_list) { +		if (mpt3sas_port->remote_identify.sas_address != +		    sas_address) +			continue; +		list_for_each_entry(phy_srch, &mpt3sas_port->phy_list, +		    port_siblings) { +			if (phy_srch == mpt3sas_phy) +				return; +		} +		_transport_add_phy(ioc, mpt3sas_port, mpt3sas_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) + * @mpt3sas_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 *mpt3sas_phy) +{ +	struct _sas_port *mpt3sas_port, *next; +	struct _sas_phy *phy_srch; + +	if (mpt3sas_phy->phy_belongs_to_port == 0) +		return; + +	list_for_each_entry_safe(mpt3sas_port, next, &sas_node->sas_port_list, +	    port_list) { +		list_for_each_entry(phy_srch, &mpt3sas_port->phy_list, +		    port_siblings) { +			if (phy_srch != mpt3sas_phy) +				continue; + +			if (mpt3sas_port->num_phys == 1) +				_transport_delete_port(ioc, mpt3sas_port); +			else +				_transport_delete_phy(ioc, mpt3sas_port, +				    mpt3sas_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]); +	} +} + +/** + * mpt3sas_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 mpt3sas_port. + */ +struct _sas_port * +mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, +	u64 sas_address) +{ +	struct _sas_phy *mpt3sas_phy, *next; +	struct _sas_port *mpt3sas_port; +	unsigned long flags; +	struct _sas_node *sas_node; +	struct sas_rphy *rphy; +	int i; +	struct sas_port *port; + +	mpt3sas_port = kzalloc(sizeof(struct _sas_port), +	    GFP_KERNEL); +	if (!mpt3sas_port) { +		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		return NULL; +	} + +	INIT_LIST_HEAD(&mpt3sas_port->port_list); +	INIT_LIST_HEAD(&mpt3sas_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, +	    &mpt3sas_port->remote_identify))) { +		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		goto out_fail; +	} + +	if (mpt3sas_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, +	    mpt3sas_port->remote_identify.sas_address); + +	for (i = 0; i < sas_node->num_phys; i++) { +		if (sas_node->phy[i].remote_identify.sas_address != +		    mpt3sas_port->remote_identify.sas_address) +			continue; +		list_add_tail(&sas_node->phy[i].port_siblings, +		    &mpt3sas_port->phy_list); +		mpt3sas_port->num_phys++; +	} + +	if (!mpt3sas_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(mpt3sas_phy, &mpt3sas_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) +			    mpt3sas_port->remote_identify.sas_address, +			    mpt3sas_phy->phy_id); +		sas_port_add_phy(port, mpt3sas_phy->phy); +		mpt3sas_phy->phy_belongs_to_port = 1; +	} + +	mpt3sas_port->port = port; +	if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) +		rphy = sas_end_device_alloc(port); +	else +		rphy = sas_expander_alloc(port, +		    mpt3sas_port->remote_identify.device_type); + +	rphy->identify = mpt3sas_port->remote_identify; +	if ((sas_rphy_add(rphy))) { +		pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +	} +	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) +		    mpt3sas_port->remote_identify.sas_address); +	mpt3sas_port->rphy = rphy; +	spin_lock_irqsave(&ioc->sas_node_lock, flags); +	list_add_tail(&mpt3sas_port->port_list, &sas_node->sas_port_list); +	spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + +	/* fill in report manufacture */ +	if (mpt3sas_port->remote_identify.device_type == +	    MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || +	    mpt3sas_port->remote_identify.device_type == +	    MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) +		_transport_expander_report_manufacture(ioc, +		    mpt3sas_port->remote_identify.sas_address, +		    rphy_to_expander_device(rphy)); +	return mpt3sas_port; + + out_fail: +	list_for_each_entry_safe(mpt3sas_phy, next, &mpt3sas_port->phy_list, +	    port_siblings) +		list_del(&mpt3sas_phy->port_siblings); +	kfree(mpt3sas_port); +	return NULL; +} + +/** + * mpt3sas_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 +mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, +	u64 sas_address_parent) +{ +	int i; +	unsigned long flags; +	struct _sas_port *mpt3sas_port, *next; +	struct _sas_node *sas_node; +	u8 found = 0; +	struct _sas_phy *mpt3sas_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(mpt3sas_port, next, &sas_node->sas_port_list, +	    port_list) { +		if (mpt3sas_port->remote_identify.sas_address != sas_address) +			continue; +		found = 1; +		list_del(&mpt3sas_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(mpt3sas_phy, next_phy, +	    &mpt3sas_port->phy_list, port_siblings) { +		if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) +			dev_printk(KERN_INFO, &mpt3sas_port->port->dev, +			    "remove: sas_addr(0x%016llx), phy(%d)\n", +			    (unsigned long long) +			    mpt3sas_port->remote_identify.sas_address, +			    mpt3sas_phy->phy_id); +		mpt3sas_phy->phy_belongs_to_port = 0; +		sas_port_delete_phy(mpt3sas_port->port, mpt3sas_phy->phy); +		list_del(&mpt3sas_phy->port_siblings); +	} +	sas_port_delete(mpt3sas_port->port); +	kfree(mpt3sas_port); +} + +/** + * mpt3sas_transport_add_host_phy - report sas_host phy to transport + * @ioc: per adapter object + * @mpt3sas_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 +mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy +	*mpt3sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev) +{ +	struct sas_phy *phy; +	int phy_index = mpt3sas_phy->phy_id; + + +	INIT_LIST_HEAD(&mpt3sas_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, mpt3sas_phy->handle, +	    &mpt3sas_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 = mpt3sas_phy->identify; +	mpt3sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle); +	if (mpt3sas_phy->attached_handle) +		_transport_set_identify(ioc, mpt3sas_phy->attached_handle, +		    &mpt3sas_phy->remote_identify); +	phy->identify.phy_identifier = mpt3sas_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", +		    mpt3sas_phy->handle, (unsigned long long) +		    mpt3sas_phy->identify.sas_address, +		    mpt3sas_phy->attached_handle, +		    (unsigned long long) +		    mpt3sas_phy->remote_identify.sas_address); +	mpt3sas_phy->phy = phy; +	return 0; +} + + +/** + * mpt3sas_transport_add_expander_phy - report expander phy to transport + * @ioc: per adapter object + * @mpt3sas_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 +mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy +	*mpt3sas_phy, Mpi2ExpanderPage1_t expander_pg1, +	struct device *parent_dev) +{ +	struct sas_phy *phy; +	int phy_index = mpt3sas_phy->phy_id; + +	INIT_LIST_HEAD(&mpt3sas_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, mpt3sas_phy->handle, +	    &mpt3sas_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 = mpt3sas_phy->identify; +	mpt3sas_phy->attached_handle = +	    le16_to_cpu(expander_pg1.AttachedDevHandle); +	if (mpt3sas_phy->attached_handle) +		_transport_set_identify(ioc, mpt3sas_phy->attached_handle, +		    &mpt3sas_phy->remote_identify); +	phy->identify.phy_identifier = mpt3sas_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", +		    mpt3sas_phy->handle, (unsigned long long) +		    mpt3sas_phy->identify.sas_address, +		    mpt3sas_phy->attached_handle, +		    (unsigned long long) +		    mpt3sas_phy->remote_identify.sas_address); +	mpt3sas_phy->phy = phy; +	return 0; +} + +/** + * mpt3sas_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 +mpt3sas_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 *mpt3sas_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; +	} + +	mpt3sas_phy = &sas_node->phy[phy_number]; +	mpt3sas_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, +		    &mpt3sas_phy->remote_identify); +		_transport_add_phy_to_an_existing_port(ioc, sas_node, +		    mpt3sas_phy, mpt3sas_phy->remote_identify.sas_address); +	} else { +		memset(&mpt3sas_phy->remote_identify, 0 , sizeof(struct +		    sas_identify)); +		_transport_del_phy_from_an_existing_port(ioc, sas_node, +		    mpt3sas_phy); +	} + +	if (mpt3sas_phy->phy) +		mpt3sas_phy->phy->negotiated_linkrate = +		    _transport_convert_phy_link_rate(link_rate); + +	if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) +		dev_printk(KERN_INFO, &mpt3sas_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) +		    mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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; +		mpt3sas_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); +	mpt3sas_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) +		mpt3sas_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 ((mpt3sas_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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +	    rphy->identify.sas_address); +	if (sas_device) { +		*identifier = sas_device->enclosure_logical_id; +		rc = 0; +	} 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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, +	    rphy->identify.sas_address); +	if (sas_device) +		rc = sas_device->slot; +	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; +	u32 sgl_flags; +	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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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; +		mpt3sas_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; + +	/* 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 | +	    sizeof(struct phy_control_request), 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 | +	    sizeof(struct phy_control_reply), data_out_dma + +	    sizeof(struct phy_control_request)); + +	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); +	mpt3sas_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) +		mpt3sas_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(Mpi2SasIoUnitControlReply_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 ((mpt3sas_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 ((mpt3sas_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 ((mpt3sas_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; + +	mpt3sas_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 ((mpt3sas_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 (mpt3sas_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 (!mpt3sas_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; +	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; +	struct bvec_iter iter; + +	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 (bio_multiple_segments(req->bio)) { +		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, iter) { +			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 (!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 (bio_multiple_segments(rsp->bio)) { +		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 (!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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 = mpt3sas_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 (bio_multiple_segments(req->bio)) +		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); +	mpt3sas_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 (bio_multiple_segments(rsp->bio)) { +			u32 offset = 0; +			u32 bytes_to_copy = +			    le16_to_cpu(mpi_reply->ResponseDataLength); +			bio_for_each_segment(bvec, rsp->bio, iter) { +				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) { +		mpt3sas_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 mpt3sas_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 *mpt3sas_transport_template; diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c new file mode 100644 index 00000000000..f6533ab2036 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c @@ -0,0 +1,433 @@ +/* + * 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-2013  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. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/compat.h> +#include <linux/poll.h> + +#include <linux/io.h> +#include <linux/uaccess.h> + +#include "mpt3sas_base.h" + +/** + * _mpt3sas_raise_sigio - notifiy app + * @ioc: per adapter object + * @event_data: + */ +static void +_mpt3sas_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__)); +	mpt3sas_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__)); +} + +/** + * mpt3sas_process_trigger_data - process the event data for the trigger + * @ioc: per adapter object + * @event_data: + */ +void +mpt3sas_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__)); +		mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, +		    &issue_reset); +	} + +	_mpt3sas_raise_sigio(ioc, event_data); + +	dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, +	    __func__)); +} + +/** + * mpt3sas_trigger_master - Master trigger handler + * @ioc: per adapter object + * @trigger_bitmask: + * + */ +void +mpt3sas_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) +		_mpt3sas_raise_sigio(ioc, &event_data); +	else +		mpt3sas_send_trigger_data_event(ioc, &event_data); + + out: +	dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, +	    __func__)); +} + +/** + * mpt3sas_trigger_event - Event trigger handler + * @ioc: per adapter object + * @event: + * @log_entry_qualifier: + * + */ +void +mpt3sas_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; +	mpt3sas_send_trigger_data_event(ioc, &event_data); + out: +	dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, +	    __func__)); +} + +/** + * mpt3sas_trigger_scsi - SCSI trigger handler + * @ioc: per adapter object + * @sense_key: + * @asc: + * @ascq: + * + */ +void +mpt3sas_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; +	mpt3sas_send_trigger_data_event(ioc, &event_data); + out: +	dTriggerDiagPrintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name, +	    __func__)); +} + +/** + * mpt3sas_trigger_mpi - MPI trigger handler + * @ioc: per adapter object + * @ioc_status: + * @loginfo: + * + */ +void +mpt3sas_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; +	mpt3sas_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/mpt3sas/mpt3sas_trigger_diag.h b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h new file mode 100644 index 00000000000..bb693923bef --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h @@ -0,0 +1,193 @@ +/* + * 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-2013  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. + */ +  /* 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 */  | 
