Commit 635374e7 authored by Eric Moore's avatar Eric Moore Committed by James Bottomley

[SCSI] mpt2sas v00.100.11.15

* This is new scsi lld device driver from LSI supporting the SAS 2.0
  standard. I have split patchs by filename.

* Here is list of new 6gb host controllers:

  LSI SAS2004
  LSI SAS2008
  LSI SAS2108
  LSI SAS2116

* Here are the changes in the 4th posting of this patch set:

(1) fix compile errors when SCSI_MPT2SAS_LOGGING is not enabled
(2) add mpt2sas to the SCSI Mid Layer Makefile
(3) append mpt2sas_ to the naming of all non-static functions
(4) fix oops for SMP_PASSTHRU
(5) doorbell algorithm imported changes from windows driver

* Here are the changes in the 3rd posting of this patch set:

(1) add readl following writel from the function that disables interrupts
(2) replace 0xFFFFFFFFFFFFFFFFULL with ~0ULL
(3) when calling pci_enable_msix, only pass one msix entry (instead of 15).
(4) remove the "current HW implementation uses..... " comment in the sources
(5) merged bug fix for SIGIO/POLLIN notifcation; reported by the storlib team.

* Here are the changes in the 2nd posting of this patch set:

(1) use little endian types in the mpi headers
(2) merged in bug fix's from inhouse drivers.
Signed-off-by: default avatarEric Moore <eric.moore@lsi.com>
Tested-by: default avatarpeter Bogdanovic <pbog@us.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent dec3f959
......@@ -571,6 +571,7 @@ config SCSI_ARCMSR_AER
To enable this function, choose Y here.
source "drivers/scsi/megaraid/Kconfig.megaraid"
source "drivers/scsi/mpt2sas/Kconfig"
config SCSI_HPTIOP
tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
......
......@@ -99,6 +99,7 @@ obj-$(CONFIG_SCSI_DC390T) += tmscsim.o
obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
obj-$(CONFIG_SCSI_SUNESP) += esp_scsi.o sun_esp.o
obj-$(CONFIG_SCSI_GDTH) += gdth.o
......
#
# Kernel configuration file for the MPT2SAS
#
# This code is based on drivers/scsi/mpt2sas/Kconfig
# Copyright (C) 2007-2008 LSI Corporation
# (mailto:DL-MPTFusionLinux@lsi.com)
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# NO WARRANTY
# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
# solely responsible for determining the appropriateness of using and
# distributing the Program and assumes all risks associated with its
# exercise of rights under this Agreement, including but not limited to
# the risks and costs of program errors, damage to or loss of data,
# programs or equipment, and unavailability or interruption of operations.
# DISCLAIMER OF LIABILITY
# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
config SCSI_MPT2SAS
tristate "LSI MPT Fusion SAS 2.0 Device Driver"
depends on PCI && SCSI
select SCSI_SAS_ATTRS
---help---
This driver supports PCI-Express SAS 6Gb/s Host Adapters.
config SCSI_MPT2SAS_MAX_SGE
int "LSI MPT Fusion Max number of SG Entries (16 - 128)"
depends on PCI && SCSI && SCSI_MPT2SAS
default "128"
range 16 128
---help---
This option allows you to specify the maximum number of scatter-
gather entries per I/O. The driver default is 128, which matches
SAFE_PHYS_SEGMENTS. However, it may decreased down to 16.
Decreasing this parameter will reduce memory requirements
on a per controller instance.
config SCSI_MPT2SAS_LOGGING
bool "LSI MPT Fusion logging facility"
depends on PCI && SCSI && SCSI_MPT2SAS
---help---
This turns on a logging facility.
# mpt2sas makefile
obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o
mpt2sas-y += mpt2sas_base.o \
mpt2sas_config.o \
mpt2sas_scsih.o \
mpt2sas_transport.o \
mpt2sas_ctl.o
/*
* Copyright (c) 2000-2009 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.11
*
* 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.
* --------------------------------------------------------------------------
*/
#ifndef MPI2_H
#define MPI2_H
/*****************************************************************************
*
* MPI Version Definitions
*
*****************************************************************************/
#define MPI2_VERSION_MAJOR (0x02)
#define MPI2_VERSION_MINOR (0x00)
#define MPI2_VERSION_MAJOR_MASK (0xFF00)
#define MPI2_VERSION_MAJOR_SHIFT (8)
#define MPI2_VERSION_MINOR_MASK (0x00FF)
#define MPI2_VERSION_MINOR_SHIFT (0)
#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
MPI2_VERSION_MINOR)
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
#define MPI2_HEADER_VERSION_UNIT (0x0B)
#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, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS,
Mpi2SystemInterfaceRegs_t, MPI2_POINTER 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)
/*
* Offset for the Reply Descriptor Post Queue
*/
#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C)
/*
* 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)
/*****************************************************************************
*
* Message Descriptors
*
*****************************************************************************/
/* Request Descriptors */
/* Default Request Descriptor */
typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
U8 VF_ID; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 DescriptorTypeDependent; /* 0x06 */
} MPI2_DEFAULT_REQUEST_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR,
Mpi2DefaultRequestDescriptor_t, MPI2_POINTER 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_IOC_FIFO_MARKER (0x01)
/* High Priority Request Descriptor */
typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
U8 VF_ID; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 Reserved1; /* 0x06 */
} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
Mpi2HighPriorityRequestDescriptor_t,
MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t;
/* SCSI IO Request Descriptor */
typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
U8 VF_ID; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 DevHandle; /* 0x06 */
} MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t;
/* SCSI Target Request Descriptor */
typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
U8 VF_ID; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 IoIndex; /* 0x06 */
} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
Mpi2SCSITargetRequestDescriptor_t,
MPI2_POINTER pMpi2SCSITargetRequestDescriptor_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;
U64 Words;
} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
/* Reply Descriptors */
/* Default Reply Descriptor */
typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
U8 VF_ID; /* 0x01 */
U16 DescriptorTypeDependent1; /* 0x02 */
U32 DescriptorTypeDependent2; /* 0x04 */
} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR,
Mpi2DefaultReplyDescriptor_t, MPI2_POINTER 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_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 VF_ID; /* 0x01 */
U16 SMID; /* 0x02 */
U32 ReplyFrameAddress; /* 0x04 */
} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR,
Mpi2AddressReplyDescriptor_t, MPI2_POINTER 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 VF_ID; /* 0x01 */
U16 SMID; /* 0x02 */
U16 TaskTag; /* 0x04 */
U16 DevHandle; /* 0x06 */
} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
Mpi2SCSIIOSuccessReplyDescriptor_t,
MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t;
/* TargetAssist Success Reply Descriptor */
typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
U8 VF_ID; /* 0x01 */
U16 SMID; /* 0x02 */
U8 SequenceNumber; /* 0x04 */
U8 Reserved1; /* 0x05 */
U16 IoIndex; /* 0x06 */
} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
Mpi2TargetAssistSuccessReplyDescriptor_t,
MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t;
/* Target Command Buffer Reply Descriptor */
typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
U8 VF_ID; /* 0x01 */
U8 VP_ID; /* 0x02 */
U8 Flags; /* 0x03 */
U16 InitiatorDevHandle; /* 0x04 */
U16 IoIndex; /* 0x06 */
} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
Mpi2TargetCommandBufferReplyDescriptor_t,
MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t;
/* defines for Flags field */
#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F)
/* 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;
U64 Words;
} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
/*****************************************************************************
*
* Message Functions
* 0x80 -> 0x8F reserved for private message use per product
*
*
*****************************************************************************/
#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */
#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */
#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */
#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */
#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */
#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */
#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */
#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */
#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */
#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */
#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */
#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */
#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */
#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */
#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */
#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */
#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */
#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */
#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */
#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */
#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */
#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */
#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */
#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */
/* Doorbell functions */
#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40)
/* #define MPI2_FUNCTION_IO_UNIT_RESET (0x41) */
#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)
/****************************************************************************
* 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, MPI2_POINTER PTR_MPI2_REQUEST_HEADER,
MPI2RequestHeader_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY,
MPI2DefaultReply_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32,
Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t;
typedef struct _MPI2_SGE_SIMPLE64
{
U32 FlagsLength;
U64 Address;
} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64,
Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t;
typedef struct _MPI2_SGE_SIMPLE_UNION
{
U32 FlagsLength;
union
{
U32 Address32;
U64 Address64;
} u;
} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION,
Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t;
/****************************************************************************
* MPI Chain Element structures
****************************************************************************/
typedef struct _MPI2_SGE_CHAIN32
{
U16 Length;
U8 NextChainOffset;
U8 Flags;
U32 Address;
} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32,
Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t;
typedef struct _MPI2_SGE_CHAIN64
{
U16 Length;
U8 NextChainOffset;
U8 Flags;
U64 Address;
} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64,
Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t;
typedef struct _MPI2_SGE_CHAIN_UNION
{
U16 Length;
U8 NextChainOffset;
U8 Flags;
union
{
U32 Address32;
U64 Address64;
} u;
} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION,
Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t;
/****************************************************************************
* MPI Transaction Context Element structures
****************************************************************************/
typedef struct _MPI2_SGE_TRANSACTION32
{
U8 Reserved;
U8 ContextSize;
U8 DetailsLength;
U8 Flags;
U32 TransactionContext[1];
U32 TransactionDetails[1];
} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32,
Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t;
typedef struct _MPI2_SGE_TRANSACTION64
{
U8 Reserved;
U8 ContextSize;
U8 DetailsLength;
U8 Flags;
U32 TransactionContext[2];
U32 TransactionDetails[1];
} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64,
Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t;
typedef struct _MPI2_SGE_TRANSACTION96
{
U8 Reserved;
U8 ContextSize;
U8 DetailsLength;
U8 Flags;
U32 TransactionContext[3];
U32 TransactionDetails[1];
} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96,
Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t;
typedef struct _MPI2_SGE_TRANSACTION128
{
U8 Reserved;
U8 ContextSize;
U8 DetailsLength;
U8 Flags;
U32 TransactionContext[4];
U32 TransactionDetails[1];
} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128,
Mpi2SGETransaction_t128, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION,
Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t;
/****************************************************************************
* MPI SGE union for IO SGL's
****************************************************************************/
typedef struct _MPI2_MPI_SGE_IO_UNION
{
union
{
MPI2_SGE_SIMPLE_UNION Simple;
MPI2_SGE_CHAIN_UNION Chain;
} u;
} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION,
Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t;
/****************************************************************************
* MPI SGE union for SGL's with Simple and Transaction elements
****************************************************************************/
typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION
{
union
{
MPI2_SGE_SIMPLE_UNION Simple;
MPI2_SGE_TRANSACTION_UNION Transaction;
} u;
} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION,
Mpi2SGETransSimpleUnion_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION,
Mpi2MpiSgeUnion_t, MPI2_POINTER 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)
/* 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
****************************************************************************/
typedef struct _MPI2_IEEE_SGE_SIMPLE32
{
U32 Address;
U32 FlagsLength;
} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32,
Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t;
typedef struct _MPI2_IEEE_SGE_SIMPLE64
{
U64 Address;
U32 Length;
U16 Reserved1;
U8 Reserved2;
U8 Flags;
} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64,
Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t;
typedef union _MPI2_IEEE_SGE_SIMPLE_UNION
{
MPI2_IEEE_SGE_SIMPLE32 Simple32;
MPI2_IEEE_SGE_SIMPLE64 Simple64;
} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION,
Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t;
/****************************************************************************
* IEEE Chain Element structures
****************************************************************************/
typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32;
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, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION,
Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t;
/****************************************************************************
* All IEEE SGE types union
****************************************************************************/
typedef struct _MPI2_IEEE_SGE_UNION
{
union
{
MPI2_IEEE_SGE_SIMPLE_UNION Simple;
MPI2_IEEE_SGE_CHAIN_UNION Chain;
} u;
} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION,
Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t;
/****************************************************************************
* IEEE SGE field definitions and masks
****************************************************************************/
/* Flags field bit definitions */
#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80)
#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)
/****************************************************************************
* 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, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION,
Mpi2SimpleSgeUntion_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_SGE_IO_UNION,
Mpi2SGEIOUnion_t, MPI2_POINTER 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
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright (c) 2000-2008 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.06
*
* 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.
* --------------------------------------------------------------------------
*/
#ifndef MPI2_INIT_H
#define MPI2_INIT_H
/*****************************************************************************
*
* SCSI Initiator Messages
*
*****************************************************************************/
/****************************************************************************
* SCSI IO messages and associated structures
****************************************************************************/
typedef struct
{
U8 CDB[20]; /* 0x00 */
U32 PrimaryReferenceTag; /* 0x14 */
U16 PrimaryApplicationTag; /* 0x18 */
U16 PrimaryApplicationTagMask; /* 0x1A */
U32 TransferLength; /* 0x1C */
} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
/* TBD: I don't think this is needed for MPI2/Gen2 */
#if 0
typedef struct
{
U8 CDB[16]; /* 0x00 */
U32 DataLength; /* 0x10 */
U32 PrimaryReferenceTag; /* 0x14 */
U16 PrimaryApplicationTag; /* 0x18 */
U16 PrimaryApplicationTagMask; /* 0x1A */
U32 TransferLength; /* 0x1C */
} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16,
Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t;
#endif
typedef union
{
U8 CDB32[32];
MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
MPI2_SGE_SIMPLE_UNION SGE;
} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION,
Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t;
/* 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 */
MPI2_SGE_IO_UNION SGL; /* 0x60 */
} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
Mpi2SCSIIORequest_t, MPI2_POINTER 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)
/* 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_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)
#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)
/* 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 Reserved5; /* 0x28 */
U32 Reserved6; /* 0x2C */
} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY,
Mpi2SCSIIOReply_t, MPI2_POINTER 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)
#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,
MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST,
Mpi2SCSITaskManagementRequest_t,
MPI2_POINTER 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_UNIT_ATTENTION (0x0A)
/* 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 */
} MPI2_SCSI_TASK_MANAGE_REPLY,
MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY,
Mpi2SCSITaskManagementReply_t, MPI2_POINTER 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_IO_QUEUED_ON_IOC (0x80)
/****************************************************************************
* 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, MPI2_POINTER PTR_MPI2_SEP_REQUEST,
Mpi2SepRequest_t, MPI2_POINTER 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_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, MPI2_POINTER PTR_MPI2_SEP_REPLY,
Mpi2SepReply_t, MPI2_POINTER 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_DEV_REBUILDING (0x00000004)
#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002)
#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001)
#endif
/*
* Copyright (c) 2000-2009 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.10
*
* 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.
* --------------------------------------------------------------------------
*/
#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 */
U32 Reserved6; /* 0x14 */
U16 Reserved7; /* 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, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST,
Mpi2IOCInitRequest_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY,
Mpi2IOCInitReply_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST,
Mpi2IOCFactsRequest_t, MPI2_POINTER 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 Reserved2; /* 0x17 */
U16 RequestCredit; /* 0x18 */
U16 ProductID; /* 0x1A */
U32 IOCCapabilities; /* 0x1C */
MPI2_VERSION_UNION FWVersion; /* 0x20 */
U16 IOCRequestFrameSize; /* 0x24 */
U16 Reserved3; /* 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 */
U32 Reserved4; /* 0x3C */
} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY,
Mpi2IOCFactsReply_t, MPI2_POINTER 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_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 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_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, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST,
Mpi2PortFactsRequest_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY,
Mpi2PortFactsReply_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST,
Mpi2PortEnableRequest_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY,
Mpi2PortEnableReply_t, MPI2_POINTER 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 Reserved7; /* 0x26 */
U32 Reserved8; /* 0x28 */
} MPI2_EVENT_NOTIFICATION_REQUEST,
MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST,
Mpi2EventNotificationRequest_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY,
Mpi2EventNotificationReply_t, MPI2_POINTER 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)
#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)
/* 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t;
/* 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
Mpi2EventDataHardResetReceived_t,
MPI2_POINTER pMpi2EventDataHardResetReceived_t;
/* Task Set Full Event data */
typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
{
U16 DevHandle; /* 0x00 */
U16 CurrentDepth; /* 0x02 */
} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL,
Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t;
/* SAS Device Status Change Event data */
typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
{
U16 TaskTag; /* 0x00 */
U8 ReasonCode; /* 0x02 */
U8 Reserved1; /* 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
Mpi2EventDataSasDeviceStatusChange_t,
MPI2_POINTER 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)
/* 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 Resereved3; /* 0x08 */
} MPI2_EVENT_DATA_IR_OPERATION_STATUS,
MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS,
Mpi2EventDataIrOperationStatus_t,
MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME,
Mpi2EventDataIrVolume_t, MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT,
Mpi2EventIrConfigElement_t, MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
Mpi2EventDataIrConfigChangeList_t,
MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY,
Mpi2EventDataSasDiscovery_t, MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
Mpi2EventDataSasBroadcastPrimitive_t,
MPI2_POINTER 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 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
Mpi2EventDataSasInitDevStatusChange_t,
MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
Mpi2EventDataSasInitTableOverflow_t,
MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY,
Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
Mpi2EventDataSasTopologyChangeList_t,
MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t;
/* values for the ExpStatus field */
#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_RATE_1_5 (0x08)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A)
/* 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,
MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
Mpi2EventDataSasEnclDevStatusChange_t,
MPI2_POINTER 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)
/****************************************************************************
* 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, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST,
Mpi2EventAckRequest_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY,
Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t;
/****************************************************************************
* FWDownload message
****************************************************************************/
/* 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, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST,
Mpi2FWDownloadRequest, MPI2_POINTER 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_COMMON_BOOT_BLOCK (0x0B)
/* 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, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE,
Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t;
/* 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, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY,
Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t;
/****************************************************************************
* FWUpload message
****************************************************************************/
/* 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, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST,
Mpi2FWUploadRequest_t, MPI2_POINTER 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)
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, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE,
Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_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, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY,
Mpi2FWUploadReply_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER,
Mpi2FWImageHeader_t, MPI2_POINTER 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_FAMILY_MASK (0x00FF)
/* SAS */
#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010)
/* 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, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER,
Mpi2ExtImageHeader_t, MPI2_POINTER 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_MAX (MPI2_EXT_IMAGE_TYPE_MEGARAID)
/* 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, MPI2_POINTER PTR_MPI2_FLASH_REGION,
Mpi2FlashRegion_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT,
Mpi2FlashLayout_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA,
Mpi2FlashLayoutData_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE,
Mpi2SupportedDevice_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA,
Mpi2SupportedDevicesData_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER,
Mpi2InitImageFooter_t, MPI2_POINTER 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)
#endif
/*
* Copyright (c) 2000-2008 LSI Corporation.
*
*
* Name: mpi2_raid.h
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
* mpi2_raid.h Version: 02.00.03
*
* 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.
* --------------------------------------------------------------------------
*/
#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, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA,
Mpi2RaidActionRateData_t, MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION,
Mpi2RaidActionStartRaidFunction_t,
MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
Mpi2RaidActionStopRaidFunction_t,
MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE,
Mpi2RaidActionHotSpare_t, MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE,
Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA,
Mpi2RaidActionData_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST,
Mpi2RaidActionRequest_t, MPI2_POINTER 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)
/* 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, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK,
Mpi2RaidVolumePhysDisk_t, MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT,
Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t;
/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */
/* defines for the VolumeCreationFlags field */
#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80)
#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x04)
#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x02)
#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x01)
/* 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,
MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
Mpi2RaidOnlineCapacityExpansion_t,
MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t;
/* RAID Volume Indicator Structure */
typedef struct _MPI2_RAID_VOL_INDICATOR
{
U64 TotalBlocks; /* 0x00 */
U64 BlocksRemaining; /* 0x08 */
U32 Flags; /* 0x10 */
} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR,
Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t;
/* defines for RAID Volume Indicator Flags field */
#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)
/* RAID Action Reply ActionData union */
typedef union _MPI2_RAID_ACTION_REPLY_DATA
{
U32 Word[5];
MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator;
U16 VolDevHandle;
U8 VolumeState;
U8 PhysDiskNum;
} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA,
Mpi2RaidActionReplyData_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY,
Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t;
#endif
/*
* Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi2_sas.h
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: February 9, 2007
*
* mpi2.h Version: 02.00.02
*
* 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.
* --------------------------------------------------------------------------
*/
#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 */
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, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST,
Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t;
/* values for PassthroughFlags field */
#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80)
/* values for SGLFlags field are in the SGL section of mpi2.h */
/* 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, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY,
Mpi2SmpPassthroughReply_t, MPI2_POINTER 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
****************************************************************************/
/* 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 */
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_SIMPLE_SGE_UNION SGL; /* 0x20 */
} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
Mpi2SataPassthroughRequest_t, MPI2_POINTER 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)
/* values for SGLFlags field are in the SGL section of mpi2.h */
/* 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, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY,
Mpi2SataPassthroughReply_t, MPI2_POINTER 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,
MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST,
Mpi2SasIoUnitControlRequest_t, MPI2_POINTER 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 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,
MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY,
Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t;
#endif
/*
* Copyright (c) 2000-2008 LSI Corporation.
*
*
* Name: mpi2_tool.h
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
* mpi2_tool.h Version: 02.00.02
*
* 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.
* --------------------------------------------------------------------------
*/
#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_BEACON_TOOL (0x05)
/****************************************************************************
* 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, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY,
Mpi2ToolboxReply_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST,
Mpi2ToolboxCleanRequest_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST,
Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_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, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST,
Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t;
/* values for the Flags field */
#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00)
#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01)
/*****************************************************************************
*
* Diagnostic Buffer Messages
*
*****************************************************************************/
/****************************************************************************
* Diagnostic Buffer Post request
****************************************************************************/
typedef struct _MPI2_DIAG_BUFFER_POST_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 */
U64 BufferAddress; /* 0x0C */
U32 BufferLength; /* 0x14 */
U32 Reserved5; /* 0x18 */
U32 Reserved6; /* 0x1C */
U32 Flags; /* 0x20 */
U32 ProductSpecific[23]; /* 0x24 */
} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST,
Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t;
/* values for the BufferType field */
#define MPI2_DIAG_BUF_TYPE_TRACE (0x00)
#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01)
/* count of the number of buffer types */
#define MPI2_DIAG_BUF_TYPE_COUNT (0x02)
/****************************************************************************
* Diagnostic Buffer Post reply
****************************************************************************/
typedef struct _MPI2_DIAG_BUFFER_POST_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 */
U32 TransferLength; /* 0x14 */
} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY,
Mpi2DiagBufferPostReply_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST,
Mpi2DiagReleaseRequest_t, MPI2_POINTER 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, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY,
Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t;
#endif
/*
* Copyright (c) 2000-2007 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 MPI2_POINTER if it hasn't already been defined. By default
* MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as
* a far pointer by defining MPI2_POINTER as "far *" before this header file is
* included.
*/
#ifndef MPI2_POINTER
#define MPI2_POINTER *
#endif
/* 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
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* 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/mpt2sas/mpt2_base.h
* Copyright (C) 2007-2008 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 MPT2SAS_BASE_H_INCLUDED
#define MPT2SAS_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 "mpt2sas_debug.h"
/* driver versioning info */
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
#define MPT2SAS_DRIVER_VERSION "00.100.11.15"
#define MPT2SAS_MAJOR_VERSION 00
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 11
#define MPT2SAS_RELEASE_VERSION 15
/*
* Set MPT2SAS_SG_DEPTH value based on user input.
*/
#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE
#if CONFIG_SCSI_MPT2SAS_MAX_SGE < 16
#define MPT2SAS_SG_DEPTH 16
#elif CONFIG_SCSI_MPT2SAS_MAX_SGE > 128
#define MPT2SAS_SG_DEPTH 128
#else
#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE
#endif
#else
#define MPT2SAS_SG_DEPTH 128 /* MAX_HW_SEGMENTS */
#endif
/*
* Generic Defines
*/
#define MPT2SAS_SATA_QUEUE_DEPTH 32
#define MPT2SAS_SAS_QUEUE_DEPTH 254
#define MPT2SAS_RAID_QUEUE_DEPTH 128
#define MPT_NAME_LENGTH 32 /* generic length of strings */
#define MPT_STRING_LENGTH 64
#define MPT_MAX_CALLBACKS 16
#define CAN_SLEEP 1
#define NO_SLEEP 0
#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */
#define MPI2_HIM_MASK 0xFFFFFFFF /* mask every bit*/
#define MPT2SAS_INVALID_DEVICE_HANDLE 0xFFFF
/*
* reset phases
*/
#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */
#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */
#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */
/*
* logging format
*/
#define MPT2SAS_FMT "%s: "
#define MPT2SAS_DEBUG_FMT KERN_DEBUG MPT2SAS_FMT
#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT
#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT
#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT
#define MPT2SAS_ERR_FMT KERN_ERR MPT2SAS_FMT
/*
* per target private data
*/
#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01
#define MPT_TARGET_FLAGS_VOLUME 0x02
#define MPT_TARGET_FLAGS_DELETED 0x04
/**
* struct MPT2SAS_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 MPT2SAS_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 MPT2SAS_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
*/
struct MPT2SAS_DEVICE {
struct MPT2SAS_TARGET *sas_target;
unsigned int lun;
u32 flags;
u8 configured_lun;
u8 block;
u8 tlr_snoop_check;
};
#define MPT2_CMD_NOT_USED 0x8000 /* free */
#define MPT2_CMD_COMPLETE 0x0001 /* completed */
#define MPT2_CMD_PENDING 0x0002 /* pending */
#define MPT2_CMD_REPLY_VALID 0x0004 /* reply is valid */
#define MPT2_CMD_RESET 0x0008 /* host reset dropped the command */
/**
* struct _internal_cmd - internal commands struct
* @mutex: mutex
* @done: completion
* @reply: reply message pointer
* @status: MPT2_CMD_XXX status
* @smid: system message id
*/
struct _internal_cmd {
struct mutex mutex;
struct completion done;
void *reply;
u16 status;
u16 smid;
};
/*
* SAS Topology Structures
*/
/**
* 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
* @parent_handle: handle to parent device
* @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
* @hidden_raid_component: set to 1 when this is a raid member
* @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;
u16 parent_handle;
u16 enclosure_handle;
u64 enclosure_logical_id;
u16 volume_handle;
u64 volume_wwid;
u32 device_info;
int id;
int channel;
u16 slot;
u8 hidden_raid_component;
u8 responding;
};
/**
* 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
*/
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;
u32 device_info;
u8 num_pds;
u8 responding;
};
/**
* 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
* @handle: device handle for this port
* @sas_address: sas address of this port
* @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;
u16 handle;
u64 sas_address;
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
*/
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;
};
/**
* 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
* @parent_handle: parent handle
* @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;
u16 parent_handle;
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 request_tracker - firmware request tracker
* @smid: system message id
* @scmd: scsi request pointer
* @cb_idx: callback index
* @chain_list: list of chains associated to this IO
* @tracker_list: list of free request (ioc->free_list)
*/
struct request_tracker {
u16 smid;
struct scsi_cmnd *scmd;
u8 cb_idx;
struct list_head tracker_list;
};
typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
/**
* struct MPT2SAS_ADAPTER - per adapter struct
* @list: ioc_list
* @shost: shost object
* @id: unique adapter id
* @pci_irq: irq number
* @name: generic ioc string
* @tmp_string: tmp string used for logging
* @pdev: pci pdev object
* @chip: memory mapped register space
* @chip_phys: physical addrss prior to mapping
* @pio_chip: I/O mapped register space
* @logging_level: see mpt2sas_debug.h
* @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_events_off: flag to turn off fw event handling
* @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
* @ioc_reset_in_progress: 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 managment
* @remove_host: flag for when driver unloads, to avoid sending dev resets
* @wait_for_port_enable_to_complete:
* @msix_enable: flag indicating msix is enabled
* @msix_vector_count: number msix vectors
* @msix_table: virt address to the msix table
* @msix_table_backup: backup msix table
* @scsi_io_cb_idx: shost generated commands
* @tm_cb_idx: task management 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
* @base_cmds:
* @transport_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
* @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
* @config_page_sz: config page size
* @config_page: reserve memory for config page payload
* @config_page_dma:
* @sge_size: sg element size for either 32/64 bit
* @request_depth: hba request 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
* @chain: pool of chains
* @pending_io_count:
* @reset_wq:
* @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_offset_value_for_main_message: location 1st sg in main
* @chain_depth: total chains allocated
* @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_post_free_dma_pool:
* @reply_post_host_index: head index in the pool where FW completes IO
*/
struct MPT2SAS_ADAPTER {
struct list_head list;
struct Scsi_Host *shost;
u8 id;
u32 pci_irq;
char name[MPT_NAME_LENGTH];
char tmp_string[MPT_STRING_LENGTH];
struct pci_dev *pdev;
Mpi2SystemInterfaceRegs_t __iomem *chip;
unsigned long chip_phys;
unsigned long pio_chip;
int logging_level;
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;
u8 fw_events_off;
spinlock_t fw_event_lock;
struct list_head fw_event_list;
/* misc flags */
int aen_event_read_flag;
u8 broadcast_aen_busy;
u8 ioc_reset_in_progress;
u8 shost_recovery;
spinlock_t ioc_reset_in_progress_lock;
u8 ioc_link_reset_in_progress;
u8 ignore_loginfos;
u8 remove_host;
u8 wait_for_port_enable_to_complete;
u8 msix_enable;
u16 msix_vector_count;
u32 *msix_table;
u32 *msix_table_backup;
/* internal commands, callback index */
u8 scsi_io_cb_idx;
u8 tm_cb_idx;
u8 transport_cb_idx;
u8 ctl_cb_idx;
u8 base_cb_idx;
u8 config_cb_idx;
struct _internal_cmd base_cmds;
struct _internal_cmd transport_cmds;
struct _internal_cmd tm_cmds;
struct _internal_cmd ctl_cmds;
struct _internal_cmd config_cmds;
MPT_ADD_SGE base_add_sg_single;
/* 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 */
Mpi2IOCFactsReply_t facts;
Mpi2PortFactsReply_t *pfacts;
Mpi2ManufacturingPage0_t manu_pg0;
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;
/* config page */
u16 config_page_sz;
void *config_page;
dma_addr_t config_page_dma;
/* request */
u16 sge_size;
u16 request_depth;
u16 request_sz;
u8 *request;
dma_addr_t request_dma;
u32 request_dma_sz;
struct request_tracker *scsi_lookup;
spinlock_t scsi_lookup_lock;
struct list_head free_list;
int pending_io_count;
wait_queue_head_t reset_wq;
/* chain */
u8 *chain;
dma_addr_t chain_dma;
u16 max_sges_in_main_message;
u16 max_sges_in_chain_message;
u16 chains_needed_per_io;
u16 chain_offset_value_for_main_message;
u16 chain_depth;
/* 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;
struct dma_pool *reply_dma_pool;
/* reply free queue */
u16 reply_free_queue_depth;
u32 *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;
u32 reply_post_host_index;
/* 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];
};
typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
u32 reply);
/* base shared API */
extern struct list_head ioc_list;
int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc);
void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc);
int mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc);
void mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc);
int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
enum reset_type type);
void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr);
dma_addr_t mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
u16 handle);
void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
u8 vf_id, u16 io_index);
void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
void mpt2sas_base_initialize_callback_handler(void);
u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func);
void mpt2sas_base_release_callback_handler(u8 cb_idx);
void mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr);
u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked);
void mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code);
int mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
Mpi2SasIoUnitControlReply_t *mpi_reply, Mpi2SasIoUnitControlRequest_t
*mpi_request);
int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request);
void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);
/* scsih shared API */
void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
u8 type, u16 smid_task, ulong timeout);
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
u16 handle);
struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
*ioc, u64 sas_address);
struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address(
struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
/* config shared API */
void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys);
int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page);
int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2BiosPage2_t *config_page);
int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2BiosPage3_t *config_page);
int mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage0_t *config_page);
int mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle);
int mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle);
int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz);
int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t config_page);
int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOCPage8_t *config_page);
int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle);
int mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, u16 handle);
int mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle);
int mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number);
int mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number);
int mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u32 handle);
int mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds);
int mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, u32 handle, u16 sz);
int mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
u32 form_specific);
int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
u16 *volume_handle);
int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
u64 *wwid);
/* ctl shared API */
extern struct device_attribute *mpt2sas_host_attrs[];
extern struct device_attribute *mpt2sas_dev_attrs[];
void mpt2sas_ctl_init(void);
void mpt2sas_ctl_exit(void);
void mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventNotificationReply_t *mpi_reply);
/* transport shared API */
void mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc,
u16 handle, u16 parent_handle);
void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
u16 parent_handle);
int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev);
int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev);
void mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle,
u16 attached_handle, u8 phy_number, u8 link_rate);
extern struct sas_function_template mpt2sas_transport_functions;
extern struct scsi_transport_template *mpt2sas_transport_template;
#endif /* MPT2SAS_BASE_H_INCLUDED */
/*
* This module provides common API for accessing firmware configuration pages
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
* Copyright (C) 2007-2008 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/version.h>
#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 "mpt2sas_base.h"
/* local definitions */
/* Timeout for config page request (in seconds) */
#define MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT 15
/* Common sgl flags for READING a config page. */
#define MPT2_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 MPT2_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
* @config_page_sz: size
* @config_page: virt pointer
* @config_page_dma: phys pointer
*
*/
struct config_request{
u16 config_page_sz;
void *config_page;
dma_addr_t config_page_dma;
};
#ifdef CONFIG_SCSI_MPT2SAS_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 helpfull when debugging issues
* in this module.
*/
static void
_config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
{
Mpi2ConfigRequest_t *mpi_request;
char *desc = NULL;
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
return;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) {
case MPI2_CONFIG_PAGETYPE_IO_UNIT:
desc = "io_unit";
break;
case MPI2_CONFIG_PAGETYPE_IOC:
desc = "ioc";
break;
case MPI2_CONFIG_PAGETYPE_BIOS:
desc = "bios";
break;
case MPI2_CONFIG_PAGETYPE_RAID_VOLUME:
desc = "raid_volume";
break;
case MPI2_CONFIG_PAGETYPE_MANUFACTURING:
desc = "manufaucturing";
break;
case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK:
desc = "physdisk";
break;
case MPI2_CONFIG_PAGETYPE_EXTENDED:
switch (mpi_request->ExtPageType) {
case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT:
desc = "sas_io_unit";
break;
case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER:
desc = "sas_expander";
break;
case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE:
desc = "sas_device";
break;
case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY:
desc = "sas_phy";
break;
case MPI2_CONFIG_EXTPAGETYPE_LOG:
desc = "log";
break;
case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE:
desc = "enclosure";
break;
case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG:
desc = "raid_config";
break;
case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING:
desc = "driver_mappping";
break;
}
break;
}
if (!desc)
return;
printk(MPT2SAS_DEBUG_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)
printk(MPT2SAS_DEBUG_FMT
"\tiocstatus(0x%04x), loginfo(0x%08x)\n",
ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo));
}
#endif
/**
* mpt2sas_config_done - config page completion routine
* @ioc: per adapter object
* @smid: system request message index
* @VF_ID: virtual function id
* @reply: reply message frame(lower 32bit addr)
* Context: none.
*
* The callback handler when using _config_request.
*
* Return nothing.
*/
void
mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
if (ioc->config_cmds.status == MPT2_CMD_NOT_USED)
return;
if (ioc->config_cmds.smid != smid)
return;
ioc->config_cmds.status |= MPT2_CMD_COMPLETE;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply) {
ioc->config_cmds.status |= MPT2_CMD_REPLY_VALID;
memcpy(ioc->config_cmds.reply, mpi_reply,
mpi_reply->MsgLength*4);
}
ioc->config_cmds.status &= ~MPT2_CMD_PENDING;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
_config_display_some_debug(ioc, smid, "config_done", mpi_reply);
#endif
complete(&ioc->config_cmds.done);
}
/**
* _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
* Context: sleep, the calling function needs to acquire the config_cmds.mutex
*
* A generic API for config page requests to firmware.
*
* The ioc->config_cmds.status flag should be MPT2_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 MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
*mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout)
{
u16 smid;
u32 ioc_state;
unsigned long timeleft;
Mpi2ConfigRequest_t *config_request;
int r;
u8 retry_count;
u8 issue_reset;
u16 wait_state_count;
if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n",
ioc->name, __func__);
return -EAGAIN;
}
retry_count = 0;
retry_config:
wait_state_count = 0;
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT) {
printk(MPT2SAS_ERR_FMT
"%s: failed due to ioc not operational\n",
ioc->name, __func__);
ioc->config_cmds.status = MPT2_CMD_NOT_USED;
return -EFAULT;
}
ssleep(1);
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
printk(MPT2SAS_INFO_FMT "%s: waiting for "
"operational state(count=%d)\n", ioc->name,
__func__, wait_state_count);
}
if (wait_state_count)
printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
ioc->name, __func__);
smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
ioc->config_cmds.status = MPT2_CMD_NOT_USED;
return -EAGAIN;
}
r = 0;
memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t));
ioc->config_cmds.status = MPT2_CMD_PENDING;
config_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->config_cmds.smid = smid;
memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
_config_display_some_debug(ioc, smid, "config_request", NULL);
#endif
mpt2sas_base_put_smid_default(ioc, smid, config_request->VF_ID);
timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
timeout*HZ);
if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s: timeout\n",
ioc->name, __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2ConfigRequest_t)/4);
if (!(ioc->config_cmds.status & MPT2_CMD_RESET))
issue_reset = 1;
goto issue_host_reset;
}
if (ioc->config_cmds.status & MPT2_CMD_REPLY_VALID)
memcpy(mpi_reply, ioc->config_cmds.reply,
sizeof(Mpi2ConfigReply_t));
if (retry_count)
printk(MPT2SAS_INFO_FMT "%s: retry completed!!\n",
ioc->name, __func__);
ioc->config_cmds.status = MPT2_CMD_NOT_USED;
return r;
issue_host_reset:
if (issue_reset)
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
ioc->config_cmds.status = MPT2_CMD_NOT_USED;
if (!retry_count) {
printk(MPT2SAS_INFO_FMT "%s: attempting retry\n",
ioc->name, __func__);
retry_count++;
goto retry_config;
}
return -EFAULT;
}
/**
* _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 MPT2SAS_ADAPTER *ioc,
struct config_request *mem)
{
int r = 0;
mem->config_page = pci_alloc_consistent(ioc->pdev, mem->config_page_sz,
&mem->config_page_dma);
if (!mem->config_page)
r = -ENOMEM;
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 MPT2SAS_ADAPTER *ioc,
struct config_request *mem)
{
pci_free_consistent(ioc->pdev, mem->config_page_sz, mem->config_page,
mem->config_page_dma);
}
/**
* mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2ManufacturingPage0_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2ManufacturingPage0_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_bios_pg2 - obtain bios page 2
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2BiosPage2_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2BiosPage2_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_bios_pg3 - obtain bios page 3
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2BiosPage3_t *config_page)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2BiosPage3_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2BiosPage3_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_iounit_pg0 - obtain iounit page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2IOUnitPage0_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2IOUnitPage0_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_iounit_pg1 - obtain iounit page 1
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2IOUnitPage1_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2IOUnitPage1_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_set_iounit_pg1 - set iounit page 1
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t config_page)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
memset(mem.config_page, 0, mem.config_page_sz);
memcpy(mem.config_page, &config_page,
sizeof(Mpi2IOUnitPage1_t));
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_ioc_pg8 - obtain ioc page 8
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2IOCPage8_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2IOCPage8_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_HANDLE or HANDLE
* @handle: device handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2SasDevicePage0_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.PageAddress = cpu_to_le32(form | handle);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2SasDevicePage0_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_HANDLE or HANDLE
* @handle: device handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2SasDevicePage1_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.PageAddress = cpu_to_le32(form | handle);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2SasDevicePage1_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_number_hba_phys - obtain number of phys on the host
* @ioc: per adapter object
* @num_phys: pointer returned with the number of phys
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
u16 ioc_status;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasIOUnitPage0_t config_page;
mutex_lock(&ioc->config_cmds.mutex);
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, &mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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.ExtPageLength = mpi_reply.ExtPageLength;
mpi_request.ExtPageType = mpi_reply.ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply.ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, &mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
memcpy(&config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2SasIOUnitPage0_t)));
*num_phys = config_page.NumPhys;
}
}
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @sz: size of buffer passed in config_page
* Context: sleep.
*
* Calling function should call config_get_number_hba_phys prior to
* this function, so enough memory is allocated for config_page.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sz);
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, sz, mem.config_page_sz));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @sz: size of buffer passed in config_page
* Context: sleep.
*
* Calling function should call config_get_number_hba_phys prior to
* this function, so enough memory is allocated for config_page.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sz);
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_SASIOUNITPAGE0_PAGEVERSION;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, sz, mem.config_page_sz));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_expander_pg0 - obtain expander page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_HANDLE or HANDLE
* @handle: expander handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2ExpanderPage0_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.PageAddress = cpu_to_le32(form | handle);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2ExpanderPage0_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_expander_pg1 - obtain expander page 1
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @phy_number: phy number
* @handle: expander handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number,
u16 handle)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2ExpanderPage1_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
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;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2ExpanderPage1_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_HANDLE or HANDLE
* @handle: expander handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2SasEnclosurePage0_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.PageAddress = cpu_to_le32(form | handle);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2SasEnclosurePage0_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_phy_pg0 - obtain phy page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @phy_number: phy number
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2SasPhyPage0_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
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;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2SasPhyPage0_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_phy_pg1 - obtain phy page 1
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @phy_number: phy number
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2SasPhyPage1_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
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;
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.ExtPageLength = mpi_reply->ExtPageLength;
mpi_request.ExtPageType = mpi_reply->ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2SasPhyPage1_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_HANDLE or HANDLE
* @handle: volume handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form,
u32 handle)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(config_page, 0, sizeof(Mpi2RaidVolPage1_t));
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.PageAddress = cpu_to_le32(form | handle);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2RaidVolPage1_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume
* @ioc: per adapter object
* @handle: volume handle
* @num_pds: returns pds count
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle,
u8 *num_pds)
{
Mpi2ConfigRequest_t mpi_request;
Mpi2RaidVolPage0_t *config_page;
Mpi2ConfigReply_t mpi_reply;
int r;
struct config_request mem;
u16 ioc_status;
mutex_lock(&ioc->config_cmds.mutex);
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, &mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
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;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply.Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, &mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r) {
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
MPI2_IOCSTATUS_MASK;
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
config_page = mem.config_page;
*num_pds = config_page->NumPhysDisks;
}
}
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_HANDLE or HANDLE
* @handle: volume handle
* @sz: size of buffer passed in config_page
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form,
u32 handle, u16 sz)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
memset(config_page, 0, sz);
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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.PageAddress = cpu_to_le32(form | handle);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, sz, mem.config_page_sz));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE
* @form_specific: specific to the form
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
u32 form_specific)
{
Mpi2ConfigRequest_t mpi_request;
int r;
struct config_request mem;
mutex_lock(&ioc->config_cmds.mutex);
memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
memset(config_page, 0, sizeof(Mpi2RaidPhysDiskPage0_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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.PageAddress = cpu_to_le32(form | form_specific);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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;
mem.config_page_sz = le16_to_cpu(mpi_reply->Header.PageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (!r)
memcpy(config_page, mem.config_page,
min_t(u16, mem.config_page_sz,
sizeof(Mpi2RaidPhysDiskPage0_t)));
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_volume_handle - returns volume handle for give hidden raid components
* @ioc: per adapter object
* @pd_handle: phys disk handle
* @volume_handle: volume handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
u16 *volume_handle)
{
Mpi2RaidConfigurationPage0_t *config_page;
Mpi2ConfigRequest_t mpi_request;
Mpi2ConfigReply_t mpi_reply;
int r, i;
struct config_request mem;
u16 ioc_status;
mutex_lock(&ioc->config_cmds.mutex);
*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;
mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
r = _config_request(ioc, &mpi_request, &mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
mpi_request.PageAddress =
cpu_to_le32(MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
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.ExtPageLength = mpi_reply.ExtPageLength;
mpi_request.ExtPageType = mpi_reply.ExtPageType;
mem.config_page_sz = le16_to_cpu(mpi_reply.ExtPageLength) * 4;
if (mem.config_page_sz > ioc->config_page_sz) {
r = _config_alloc_config_dma_memory(ioc, &mem);
if (r)
goto out;
} else {
mem.config_page_dma = ioc->config_page_dma;
mem.config_page = ioc->config_page;
}
ioc->base_add_sg_single(&mpi_request.PageBufferSGE,
MPT2_CONFIG_COMMON_SGLFLAGS | mem.config_page_sz,
mem.config_page_dma);
r = _config_request(ioc, &mpi_request, &mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT);
if (r)
goto out;
r = -1;
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
goto done;
config_page = mem.config_page;
for (i = 0; i < config_page->NumElements; i++) {
if ((config_page->ConfigElement[i].ElementFlags &
MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) !=
MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT)
continue;
if (config_page->ConfigElement[i].PhysDiskDevHandle ==
pd_handle) {
*volume_handle = le16_to_cpu(config_page->
ConfigElement[i].VolDevHandle);
r = 0;
goto done;
}
}
done:
if (mem.config_page_sz > ioc->config_page_sz)
_config_free_config_dma_memory(ioc, &mem);
out:
mutex_unlock(&ioc->config_cmds.mutex);
return r;
}
/**
* mpt2sas_config_get_volume_wwid - returns wwid given the volume handle
* @ioc: per adapter object
* @volume_handle: volume handle
* @wwid: volume wwid
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
u64 *wwid)
{
Mpi2ConfigReply_t mpi_reply;
Mpi2RaidVolPage1_t raid_vol_pg1;
*wwid = 0;
if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
&raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE,
volume_handle))) {
*wwid = le64_to_cpu(raid_vol_pg1.WWID);
return 0;
} else
return -1;
}
/*
* Management Module Support for MPT (Message Passing Technology) based
* controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
* Copyright (C) 2007-2008 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/version.h>
#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/smp_lock.h>
#include <linux/compat.h>
#include <linux/poll.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include "mpt2sas_base.h"
#include "mpt2sas_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_MPT2SAS_LOGGING
/**
* _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 helpfull when debugging issues
* in this module.
*/
static void
_ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
{
Mpi2ConfigRequest_t *mpi_request;
char *desc = NULL;
if (!(ioc->logging_level & MPT_DEBUG_IOCTL))
return;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
switch (mpi_request->Function) {
case MPI2_FUNCTION_SCSI_IO_REQUEST:
{
Mpi2SCSIIORequest_t *scsi_request =
(Mpi2SCSIIORequest_t *)mpi_request;
snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
"scsi_io, cmd(0x%02x), cdb_len(%d)",
scsi_request->CDB.CDB32[0],
le16_to_cpu(scsi_request->IoFlags) & 0xF);
desc = ioc->tmp_string;
break;
}
case MPI2_FUNCTION_SCSI_TASK_MGMT:
desc = "task_mgmt";
break;
case MPI2_FUNCTION_IOC_INIT:
desc = "ioc_init";
break;
case MPI2_FUNCTION_IOC_FACTS:
desc = "ioc_facts";
break;
case MPI2_FUNCTION_CONFIG:
{
Mpi2ConfigRequest_t *config_request =
(Mpi2ConfigRequest_t *)mpi_request;
snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
"config, type(0x%02x), ext_type(0x%02x), number(%d)",
(config_request->Header.PageType &
MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType,
config_request->Header.PageNumber);
desc = ioc->tmp_string;
break;
}
case MPI2_FUNCTION_PORT_FACTS:
desc = "port_facts";
break;
case MPI2_FUNCTION_PORT_ENABLE:
desc = "port_enable";
break;
case MPI2_FUNCTION_EVENT_NOTIFICATION:
desc = "event_notification";
break;
case MPI2_FUNCTION_FW_DOWNLOAD:
desc = "fw_download";
break;
case MPI2_FUNCTION_FW_UPLOAD:
desc = "fw_upload";
break;
case MPI2_FUNCTION_RAID_ACTION:
desc = "raid_action";
break;
case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
{
Mpi2SCSIIORequest_t *scsi_request =
(Mpi2SCSIIORequest_t *)mpi_request;
snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
"raid_pass, cmd(0x%02x), cdb_len(%d)",
scsi_request->CDB.CDB32[0],
le16_to_cpu(scsi_request->IoFlags) & 0xF);
desc = ioc->tmp_string;
break;
}
case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
desc = "sas_iounit_cntl";
break;
case MPI2_FUNCTION_SATA_PASSTHROUGH:
desc = "sata_pass";
break;
case MPI2_FUNCTION_DIAG_BUFFER_POST:
desc = "diag_buffer_post";
break;
case MPI2_FUNCTION_DIAG_RELEASE:
desc = "diag_release";
break;
case MPI2_FUNCTION_SMP_PASSTHROUGH:
desc = "smp_passthrough";
break;
}
if (!desc)
return;
printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n",
ioc->name, calling_function_name, desc, smid);
if (!mpi_reply)
return;
if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
printk(MPT2SAS_DEBUG_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;
if (scsi_reply->SCSIState || scsi_reply->SCSIStatus)
printk(MPT2SAS_DEBUG_FMT
"\tscsi_state(0x%02x), scsi_status"
"(0x%02x)\n", ioc->name,
scsi_reply->SCSIState,
scsi_reply->SCSIStatus);
}
}
#endif
/**
* mpt2sas_ctl_done - ctl module completion routine
* @ioc: per adapter object
* @smid: system request message index
* @VF_ID: virtual function id
* @reply: reply message frame(lower 32bit addr)
* Context: none.
*
* The callback handler when using ioc->ctl_cb_idx.
*
* Return nothing.
*/
void
mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)
return;
if (ioc->ctl_cmds.smid != smid)
return;
ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply) {
memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID;
}
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
_ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
#endif
ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->ctl_cmds.done);
}
/**
* _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 MPT2SAS_ADAPTER *ioc, u16 event)
{
u16 i;
u32 desired_event;
if (event >= 128 || !event || !ioc->event_log)
return 0;
desired_event = (1 << (event % 32));
if (!desired_event)
desired_event = 1;
i = event / 32;
return desired_event & ioc->event_type[i];
}
/**
* mpt2sas_ctl_add_to_event_log - add event
* @ioc: per adapter object
* @mpi_reply: reply message frame
*
* Return nothing.
*/
void
mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventNotificationReply_t *mpi_reply)
{
struct MPT2_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 % MPT2SAS_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, MPT2_EVENT_DATA_SIZE);
memset(event_log[i].data, 0, MPT2_EVENT_DATA_SIZE);
memcpy(event_log[i].data, mpi_reply->EventData, sz);
send_aen = 1;
}
/* This aen_event_read_flag flag is set until the
* application has read the event log.
* For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify.
*/
if (event == MPI2_EVENT_LOG_ENTRY_ADDED ||
(send_aen && !ioc->aen_event_read_flag)) {
ioc->aen_event_read_flag = 1;
wake_up_interruptible(&ctl_poll_wait);
if (async_queue)
kill_fasync(&async_queue, SIGIO, POLL_IN);
}
}
/**
* mpt2sas_ctl_event_callback - firmware event handler (called at ISR time)
* @ioc: per adapter object
* @VF_ID: virtual function id
* @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 nothing.
*/
void
mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
{
Mpi2EventNotificationReply_t *mpi_reply;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
}
/**
* _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 MPT2SAS_ADAPTER **iocpp)
{
struct MPT2SAS_ADAPTER *ioc;
list_for_each_entry(ioc, &ioc_list, list) {
if (ioc->id != ioc_number)
continue;
*iocpp = ioc;
return ioc_number;
}
*iocpp = NULL;
return -1;
}
/**
* mpt2sas_ctl_reset_handler - reset callback handler (for ctl)
* @ioc: per adapter object
* @reset_phase: phase
*
* The handler for doing any required cleanup or initialization.
*
* The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
* MPT2_IOC_DONE_RESET
*/
void
mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
{
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
break;
case MPT2_IOC_AFTER_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) {
ioc->ctl_cmds.status |= MPT2_CMD_RESET;
mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid);
complete(&ioc->ctl_cmds.done);
}
break;
case MPT2_IOC_DONE_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
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_release -
* @inode -
* @filep -
*
* Called when application releases the fasyn callback handler.
*/
static int
_ctl_release(struct inode *inode, struct file *filep)
{
return fasync_helper(-1, filep, 0, &async_queue);
}
/**
* _ctl_poll -
* @file -
* @wait -
*
*/
static unsigned int
_ctl_poll(struct file *filep, poll_table *wait)
{
struct MPT2SAS_ADAPTER *ioc;
poll_wait(filep, &ctl_poll_wait, wait);
list_for_each_entry(ioc, &ioc_list, list) {
if (ioc->aen_event_read_flag)
return POLLIN | POLLRDNORM;
}
return 0;
}
/**
* _ctl_do_task_abort - assign an active smid to the abort_task
* @ioc: per adapter object
* @karg - (struct mpt2_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_do_task_abort(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
Mpi2SCSITaskManagementRequest_t *tm_request)
{
u8 found = 0;
u16 i;
u16 handle;
struct scsi_cmnd *scmd;
struct MPT2SAS_DEVICE *priv_data;
unsigned long flags;
Mpi2SCSITaskManagementReply_t *tm_reply;
u32 sz;
u32 lun;
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->request_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, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: "
"DevHandle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
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 = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
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))
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
return 1;
}
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ABORT_TASK: "
"DevHandle(0x%04x), lun(%d), smid(%d)\n", ioc->name,
tm_request->DevHandle, lun, tm_request->TaskMID));
return 0;
}
/**
* _ctl_do_mpt_command - main handler for MPT2COMMAND opcode
* @ioc: per adapter object
* @karg - (struct mpt2_ioctl_command)
* @mf - pointer to mf in user space
* @state - NON_BLOCKING or BLOCKING
*/
static long
_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
struct mpt2_ioctl_command karg, void __user *mf, enum block_state state)
{
MPI2RequestHeader_t *mpi_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 *priv_sense = NULL;
void *data_out = NULL;
dma_addr_t data_out_dma;
size_t data_out_sz = 0;
void *data_in = NULL;
dma_addr_t data_in_dma;
size_t data_in_sz = 0;
u32 sgl_flags;
long ret;
u16 wait_state_count;
issue_reset = 0;
if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
return -EAGAIN;
else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
return -ERESTARTSYS;
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
ioc->name, __func__);
ret = -EAGAIN;
goto out;
}
wait_state_count = 0;
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
printk(MPT2SAS_ERR_FMT
"%s: failed due to ioc not operational\n",
ioc->name, __func__);
ret = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
printk(MPT2SAS_INFO_FMT "%s: waiting for "
"operational state(count=%d)\n", ioc->name,
__func__, wait_state_count);
}
if (wait_state_count)
printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
ioc->name, __func__);
smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
ret = -EAGAIN;
goto out;
}
ret = 0;
ioc->ctl_cmds.status = MPT2_CMD_PENDING;
memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->ctl_cmds.smid = smid;
data_out_sz = karg.data_out_size;
data_in_sz = karg.data_in_size;
/* copy in request message frame from user */
if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__,
__func__);
ret = -EFAULT;
mpt2sas_base_free_smid(ioc, smid);
goto out;
}
if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
if (!mpi_request->FunctionDependent1 ||
mpi_request->FunctionDependent1 >
cpu_to_le16(ioc->facts.MaxDevHandle)) {
ret = -EINVAL;
mpt2sas_base_free_smid(ioc, smid);
goto out;
}
}
/* obtain dma-able memory for data transfer */
if (data_out_sz) /* WRITE */ {
data_out = pci_alloc_consistent(ioc->pdev, data_out_sz,
&data_out_dma);
if (!data_out) {
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
ret = -ENOMEM;
mpt2sas_base_free_smid(ioc, smid);
goto out;
}
if (copy_from_user(data_out, karg.data_out_buf_ptr,
data_out_sz)) {
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
ret = -EFAULT;
mpt2sas_base_free_smid(ioc, smid);
goto out;
}
}
if (data_in_sz) /* READ */ {
data_in = pci_alloc_consistent(ioc->pdev, data_in_sz,
&data_in_dma);
if (!data_in) {
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
ret = -ENOMEM;
mpt2sas_base_free_smid(ioc, smid);
goto out;
}
}
/* add scatter gather elements */
psge = (void *)mpi_request + (karg.data_sge_offset*4);
if (!data_out_sz && !data_in_sz) {
mpt2sas_base_build_zero_len_sge(ioc, psge);
} else 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);
}
/* send command to firmware */
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
_ctl_display_some_debug(ioc, smid, "ctl_request", NULL);
#endif
switch (mpi_request->Function) {
case MPI2_FUNCTION_SCSI_IO_REQUEST:
case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
{
Mpi2SCSIIORequest_t *scsiio_request =
(Mpi2SCSIIORequest_t *)mpi_request;
scsiio_request->SenseBufferLowAddress =
(u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);
priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
mpt2sas_base_put_smid_scsi_io(ioc, smid, 0,
le16_to_cpu(mpi_request->FunctionDependent1));
break;
}
case MPI2_FUNCTION_SCSI_TASK_MGMT:
{
Mpi2SCSITaskManagementRequest_t *tm_request =
(Mpi2SCSITaskManagementRequest_t *)mpi_request;
if (tm_request->TaskType ==
MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
if (_ctl_do_task_abort(ioc, &karg, tm_request))
goto out;
}
mutex_lock(&ioc->tm_cmds.mutex);
mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
tm_request->DevHandle));
mpt2sas_base_put_smid_hi_priority(ioc, smid,
mpi_request->VF_ID);
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
data = data_out;
if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) {
ioc->ioc_link_reset_in_progress = 1;
ioc->ignore_loginfos = 1;
}
mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
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;
}
mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
break;
}
default:
mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
break;
}
if (karg.timeout < MPT2_IOCTL_DEFAULT_TIMEOUT)
timeout = MPT2_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;
mutex_unlock(&ioc->tm_cmds.mutex);
mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(
tm_request->DevHandle));
} 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 & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
__func__);
_debug_dump_mf(mpi_request, karg.data_sge_offset);
if (!(ioc->ctl_cmds.status & MPT2_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_MPT2SAS_LOGGING
if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT &&
(ioc->logging_level & MPT_DEBUG_TM)) {
Mpi2SCSITaskManagementReply_t *tm_reply =
(Mpi2SCSITaskManagementReply_t *)mpi_reply;
printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
"IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
"TerminationCount(0x%08x)\n", ioc->name,
tm_reply->IOCStatus, tm_reply->IOCLogInfo,
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)) {
printk(KERN_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)) {
printk(KERN_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, priv_sense, sz)) {
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
ret = -ENODATA;
goto out;
}
}
issue_host_reset:
if (issue_reset) {
if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
mpi_request->Function ==
MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
printk(MPT2SAS_INFO_FMT "issue target reset: handle "
"= (0x%04x)\n", ioc->name,
mpi_request->FunctionDependent1);
mutex_lock(&ioc->tm_cmds.mutex);
mpt2sas_scsih_issue_tm(ioc,
mpi_request->FunctionDependent1, 0,
MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->tm_cmds.mutex);
} else
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
}
out:
/* free memory associated with sg buffers */
if (data_in)
pci_free_consistent(ioc->pdev, data_in_sz, data_in,
data_in_dma);
if (data_out)
pci_free_consistent(ioc->pdev, data_out_sz, data_out,
data_out_dma);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->ctl_cmds.mutex);
return ret;
}
/**
* _ctl_getiocinfo - main handler for MPT2IOCINFO opcode
* @arg - user space buffer containing ioctl content
*/
static long
_ctl_getiocinfo(void __user *arg)
{
struct mpt2_ioctl_iocinfo karg;
struct MPT2SAS_ADAPTER *ioc;
u8 revision;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
memset(&karg, 0 , sizeof(karg));
karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;
if (ioc->pfacts)
karg.port_number = ioc->pfacts[0].PortNumber;
pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision);
karg.hw_rev = 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;
strncpy(karg.driver_version, MPT2SAS_DRIVER_VERSION,
MPT2_IOCTL_VERSION_LENGTH);
karg.driver_version[MPT2_IOCTL_VERSION_LENGTH - 1] = '\0';
karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
if (copy_to_user(arg, &karg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
return 0;
}
/**
* _ctl_eventquery - main handler for MPT2EVENTQUERY opcode
* @arg - user space buffer containing ioctl content
*/
static long
_ctl_eventquery(void __user *arg)
{
struct mpt2_ioctl_eventquery karg;
struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
karg.event_entries = MPT2SAS_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))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
return 0;
}
/**
* _ctl_eventenable - main handler for MPT2EVENTENABLE opcode
* @arg - user space buffer containing ioctl content
*/
static long
_ctl_eventenable(void __user *arg)
{
struct mpt2_ioctl_eventenable karg;
struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
if (ioc->event_log)
return 0;
memcpy(ioc->event_type, karg.event_types,
MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
mpt2sas_base_validate_event_type(ioc, ioc->event_type);
/* initialize event_log */
ioc->event_context = 0;
ioc->aen_event_read_flag = 0;
ioc->event_log = kcalloc(MPT2SAS_CTL_EVENT_LOG_SIZE,
sizeof(struct MPT2_IOCTL_EVENTS), GFP_KERNEL);
if (!ioc->event_log) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -ENOMEM;
}
return 0;
}
/**
* _ctl_eventreport - main handler for MPT2EVENTREPORT opcode
* @arg - user space buffer containing ioctl content
*/
static long
_ctl_eventreport(void __user *arg)
{
struct mpt2_ioctl_eventreport karg;
struct MPT2SAS_ADAPTER *ioc;
u32 number_bytes, max_events, max;
struct mpt2_ioctl_eventreport __user *uarg = arg;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
number_bytes = karg.hdr.max_data_size -
sizeof(struct mpt2_ioctl_header);
max_events = number_bytes/sizeof(struct MPT2_IOCTL_EVENTS);
max = min_t(u32, MPT2SAS_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 MPT2_IOCTL_EVENTS);
if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) {
printk(KERN_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 MPT2HARDRESET opcode
* @arg - user space buffer containing ioctl content
*/
static long
_ctl_do_reset(void __user *arg)
{
struct mpt2_ioctl_diag_reset karg;
struct MPT2SAS_ADAPTER *ioc;
int retval;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
printk(MPT2SAS_INFO_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 MPT2SAS_ADAPTER *ioc,
struct mpt2_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 MPT2SAS_ADAPTER *ioc,
struct mpt2_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 MPT2BTDHMAPPING opcode
* @arg - user space buffer containing ioctl content
*/
static long
_ctl_btdh_mapping(void __user *arg)
{
struct mpt2_ioctl_btdh_mapping karg;
struct MPT2SAS_ADAPTER *ioc;
int rc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_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))) {
printk(KERN_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 or SNAPSHOT
*
* returns 1 when diag buffer support is enabled in firmware
*/
static u8
_ctl_diag_capability(struct MPT2SAS_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;
}
return rc;
}
/**
* _ctl_diag_register - application register with driver
* @arg - user space buffer containing ioctl content
* @state - NON_BLOCKING or BLOCKING
*
* 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(void __user *arg, enum block_state state)
{
struct mpt2_diag_register karg;
struct MPT2SAS_ADAPTER *ioc;
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;
u8 issue_reset = 0;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.buffer_type;
if (!_ctl_diag_capability(ioc, buffer_type)) {
printk(MPT2SAS_ERR_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] &
MPT2_DIAG_BUFFER_IS_REGISTERED) {
printk(MPT2SAS_ERR_FMT "%s: already has a registered "
"buffer for buffer_type(0x%02x)\n", ioc->name, __func__,
buffer_type);
return -EINVAL;
}
if (karg.requested_buffer_size % 4) {
printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size "
"is not 4 byte aligned\n", ioc->name, __func__);
return -EINVAL;
}
if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
return -EAGAIN;
else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
return -ERESTARTSYS;
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
rc = 0;
ioc->ctl_cmds.status = MPT2_CMD_PENDING;
memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->ctl_cmds.smid = smid;
request_data = ioc->diag_buffer[buffer_type];
request_data_sz = karg.requested_buffer_size;
ioc->unique_id[buffer_type] = karg.unique_id;
ioc->diag_buffer_status[buffer_type] = 0;
memcpy(ioc->product_specific[buffer_type], karg.product_specific,
MPT2_PRODUCT_SPECIFIC_DWORDS);
ioc->diagnostic_flags[buffer_type] = karg.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) {
printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"
" for diag buffers, requested size(%d)\n",
ioc->name, __func__, request_data_sz);
mpt2sas_base_free_smid(ioc, smid);
return -ENOMEM;
}
ioc->diag_buffer[buffer_type] = request_data;
ioc->diag_buffer_sz[buffer_type] = request_data_sz;
ioc->diag_buffer_dma[buffer_type] = request_data_dma;
}
mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
mpi_request->BufferType = karg.buffer_type;
mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags);
mpi_request->BufferAddress = cpu_to_le64(request_data_dma);
mpi_request->BufferLength = cpu_to_le32(request_data_sz);
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
"dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
(unsigned long long)request_data_dma, mpi_request->BufferLength));
for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
mpi_request->ProductSpecific[i] =
cpu_to_le32(ioc->product_specific[buffer_type][i]);
mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
__func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2DiagBufferPostRequest_t)/4);
if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
issue_reset = 1;
goto issue_host_reset;
}
/* process the completed Reply Message Frame */
if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
printk(MPT2SAS_ERR_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] |=
MPT2_DIAG_BUFFER_IS_REGISTERED;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
ioc->name, __func__));
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
ioc_status, mpi_reply->IOCLogInfo);
rc = -EFAULT;
}
issue_host_reset:
if (issue_reset)
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
out:
if (rc && request_data)
pci_free_consistent(ioc->pdev, request_data_sz,
request_data, request_data_dma);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
/**
* _ctl_diag_unregister - application unregister with driver
* @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(void __user *arg)
{
struct mpt2_diag_unregister karg;
struct MPT2SAS_ADAPTER *ioc;
void *request_data;
dma_addr_t request_data_dma;
u32 request_data_sz;
u8 buffer_type;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
if (!_ctl_diag_capability(ioc, buffer_type)) {
printk(MPT2SAS_ERR_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] &
MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
"registered\n", ioc->name, __func__, buffer_type);
return -EINVAL;
}
if ((ioc->diag_buffer_status[buffer_type] &
MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
printk(MPT2SAS_ERR_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]) {
printk(MPT2SAS_ERR_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) {
printk(MPT2SAS_ERR_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
* @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(void __user *arg)
{
struct mpt2_diag_query karg;
struct MPT2SAS_ADAPTER *ioc;
void *request_data;
int i;
u8 buffer_type;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
karg.application_flags = 0;
buffer_type = karg.buffer_type;
if (!_ctl_diag_capability(ioc, buffer_type)) {
printk(MPT2SAS_ERR_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] &
MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
printk(MPT2SAS_ERR_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]) {
printk(MPT2SAS_ERR_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) {
printk(MPT2SAS_ERR_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] & MPT2_DIAG_BUFFER_IS_RELEASED)
karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED |
MPT2_APP_FLAGS_BUFFER_VALID);
else
karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED |
MPT2_APP_FLAGS_BUFFER_VALID |
MPT2_APP_FLAGS_FW_BUFFER_ACCESS);
for (i = 0; i < MPT2_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 mpt2_diag_query))) {
printk(MPT2SAS_ERR_FMT "%s: unable to write mpt2_diag_query "
"data @ %p\n", ioc->name, __func__, arg);
return -EFAULT;
}
return 0;
}
/**
* _ctl_diag_release - request to send Diag Release Message to firmware
* @arg - user space buffer containing ioctl content
* @state - NON_BLOCKING or BLOCKING
*
* 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(void __user *arg, enum block_state state)
{
struct mpt2_diag_release karg;
struct MPT2SAS_ADAPTER *ioc;
void *request_data;
int rc;
Mpi2DiagReleaseRequest_t *mpi_request;
Mpi2DiagReleaseReply_t *mpi_reply;
u8 buffer_type;
unsigned long timeleft;
u16 smid;
u16 ioc_status;
u8 issue_reset = 0;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
if (!_ctl_diag_capability(ioc, buffer_type)) {
printk(MPT2SAS_ERR_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] &
MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
printk(MPT2SAS_ERR_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]) {
printk(MPT2SAS_ERR_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] &
MPT2_DIAG_BUFFER_IS_RELEASED) {
printk(MPT2SAS_ERR_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) {
printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for "
"buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
return -ENOMEM;
}
if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
return -EAGAIN;
else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
return -ERESTARTSYS;
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
rc = 0;
ioc->ctl_cmds.status = MPT2_CMD_PENDING;
memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->ctl_cmds.smid = smid;
mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE;
mpi_request->BufferType = buffer_type;
mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
__func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2DiagReleaseRequest_t)/4);
if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
issue_reset = 1;
goto issue_host_reset;
}
/* process the completed Reply Message Frame */
if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
printk(MPT2SAS_ERR_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] |=
MPT2_DIAG_BUFFER_IS_RELEASED;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
ioc->name, __func__));
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
ioc_status, mpi_reply->IOCLogInfo);
rc = -EFAULT;
}
issue_host_reset:
if (issue_reset)
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
out:
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
/**
* _ctl_diag_read_buffer - request for copy of the diag buffer
* @arg - user space buffer containing ioctl content
* @state - NON_BLOCKING or BLOCKING
*/
static long
_ctl_diag_read_buffer(void __user *arg, enum block_state state)
{
struct mpt2_diag_read_buffer karg;
struct mpt2_diag_read_buffer __user *uarg = arg;
struct MPT2SAS_ADAPTER *ioc;
void *request_data, *diag_data;
Mpi2DiagBufferPostRequest_t *mpi_request;
Mpi2DiagBufferPostReply_t *mpi_reply;
int rc, i;
u8 buffer_type;
unsigned long timeleft;
u16 smid;
u16 ioc_status;
u8 issue_reset = 0;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
if (!_ctl_diag_capability(ioc, buffer_type)) {
printk(MPT2SAS_ERR_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]) {
printk(MPT2SAS_ERR_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) {
printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for "
"buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
return -ENOMEM;
}
if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) {
printk(MPT2SAS_ERR_FMT "%s: either the starting_offset "
"or bytes_to_read are not 4 byte aligned\n", ioc->name,
__func__);
return -EINVAL;
}
diag_data = (void *)(request_data + karg.starting_offset);
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), "
"offset(%d), sz(%d)\n", ioc->name, __func__,
diag_data, karg.starting_offset, karg.bytes_to_read));
if (copy_to_user((void __user *)uarg->diagnostic_data,
diag_data, karg.bytes_to_read)) {
printk(MPT2SAS_ERR_FMT "%s: Unable to write "
"mpt_diag_read_buffer_t data @ %p\n", ioc->name,
__func__, diag_data);
return -EFAULT;
}
if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0)
return 0;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister "
"buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type));
if ((ioc->diag_buffer_status[buffer_type] &
MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
dctlprintk(ioc, printk(MPT2SAS_DEBUG_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 (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex))
return -EAGAIN;
else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
return -ERESTARTSYS;
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
rc = 0;
ioc->ctl_cmds.status = MPT2_CMD_PENDING;
memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->ctl_cmds.smid = smid;
mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
mpi_request->BufferType = buffer_type;
mpi_request->BufferLength =
cpu_to_le32(ioc->diag_buffer_sz[buffer_type]);
mpi_request->BufferAddress =
cpu_to_le64(ioc->diag_buffer_dma[buffer_type]);
for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
mpi_request->ProductSpecific[i] =
cpu_to_le32(ioc->product_specific[buffer_type][i]);
mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
__func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2DiagBufferPostRequest_t)/4);
if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
issue_reset = 1;
goto issue_host_reset;
}
/* process the completed Reply Message Frame */
if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
printk(MPT2SAS_ERR_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] |=
MPT2_DIAG_BUFFER_IS_REGISTERED;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
ioc->name, __func__));
} else {
printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
"log_info(0x%08x)\n", ioc->name, __func__,
ioc_status, mpi_reply->IOCLogInfo);
rc = -EFAULT;
}
issue_host_reset:
if (issue_reset)
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
out:
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->ctl_cmds.mutex);
return rc;
}
/**
* _ctl_ioctl_main - main ioctl entry point
* @file - (struct file)
* @cmd - ioctl opcode
* @arg -
*/
static long
_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
{
enum block_state state;
long ret = -EINVAL;
unsigned long flags;
state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING :
BLOCKING;
switch (cmd) {
case MPT2IOCINFO:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo))
ret = _ctl_getiocinfo(arg);
break;
case MPT2COMMAND:
{
struct mpt2_ioctl_command karg;
struct mpt2_ioctl_command __user *uarg;
struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 ||
!ioc)
return -ENODEV;
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
flags);
return -EAGAIN;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
uarg = arg;
ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
}
break;
}
case MPT2EVENTQUERY:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery))
ret = _ctl_eventquery(arg);
break;
case MPT2EVENTENABLE:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable))
ret = _ctl_eventenable(arg);
break;
case MPT2EVENTREPORT:
ret = _ctl_eventreport(arg);
break;
case MPT2HARDRESET:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset))
ret = _ctl_do_reset(arg);
break;
case MPT2BTDHMAPPING:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping))
ret = _ctl_btdh_mapping(arg);
break;
case MPT2DIAGREGISTER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register))
ret = _ctl_diag_register(arg, state);
break;
case MPT2DIAGUNREGISTER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister))
ret = _ctl_diag_unregister(arg);
break;
case MPT2DIAGQUERY:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query))
ret = _ctl_diag_query(arg);
break;
case MPT2DIAGRELEASE:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release))
ret = _ctl_diag_release(arg, state);
break;
case MPT2DIAGREADBUFFER:
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer))
ret = _ctl_diag_read_buffer(arg, state);
break;
default:
{
struct mpt2_ioctl_command karg;
struct MPT2SAS_ADAPTER *ioc;
if (copy_from_user(&karg, arg, sizeof(karg))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 ||
!ioc)
return -ENODEV;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT
"unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
break;
}
}
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;
lock_kernel();
ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
unlock_kernel();
return ret;
}
#ifdef CONFIG_COMPAT
/**
* _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
* @file - (struct file)
* @cmd - ioctl opcode
* @arg - (struct mpt2_ioctl_command32)
*
* MPT2COMMAND32 - Handle 32bit applications running on 64bit os.
*/
static long
_ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
{
struct mpt2_ioctl_command32 karg32;
struct mpt2_ioctl_command32 __user *uarg;
struct mpt2_ioctl_command karg;
struct MPT2SAS_ADAPTER *ioc;
enum block_state state;
unsigned long flags;
if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
return -EINVAL;
uarg = (struct mpt2_ioctl_command32 __user *) arg;
if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
printk(KERN_ERR "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
return -EFAULT;
}
if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
flags);
return -EAGAIN;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
memset(&karg, 0, sizeof(struct mpt2_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;
memcpy(&karg.reply_frame_buf_ptr, &karg32.reply_frame_buf_ptr,
sizeof(uint32_t));
memcpy(&karg.data_in_buf_ptr, &karg32.data_in_buf_ptr,
sizeof(uint32_t));
memcpy(&karg.data_out_buf_ptr, &karg32.data_out_buf_ptr,
sizeof(uint32_t));
memcpy(&karg.sense_data_ptr, &karg32.sense_data_ptr,
sizeof(uint32_t));
state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state);
}
/**
* _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;
lock_kernel();
if (cmd == MPT2COMMAND32)
ret = _ctl_compat_mpt_command(file, cmd, arg);
else
ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
unlock_kernel();
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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_ADAPTER *ioc = shost_priv(shost);
return snprintf(buf, PAGE_SIZE, "%02xh\n",
le16_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 MPT2SAS_ADAPTER *ioc = shost_priv(shost);
return snprintf(buf, PAGE_SIZE, "%02xh\n",
le16_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_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 MPT2SAS_ADAPTER *ioc = shost_priv(shost);
int val = 0;
if (sscanf(buf, "%x", &val) != 1)
return -EINVAL;
ioc->logging_level = val;
printk(MPT2SAS_INFO_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);
struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_version_fw,
&dev_attr_version_bios,
&dev_attr_version_mpi,
&dev_attr_version_product,
&dev_attr_version_nvdata_persistent,
&dev_attr_version_nvdata_default,
&dev_attr_board_name,
&dev_attr_board_assembly,
&dev_attr_board_tracer,
&dev_attr_io_delay,
&dev_attr_device_delay,
&dev_attr_logging_level,
&dev_attr_fw_queue_depth,
&dev_attr_host_sas_address,
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 MPT2SAS_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 MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
return snprintf(buf, PAGE_SIZE, "0x%04x\n",
sas_device_priv_data->sas_target->handle);
}
static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
struct device_attribute *mpt2sas_dev_attrs[] = {
&dev_attr_sas_address,
&dev_attr_sas_device_handle,
NULL,
};
static const struct file_operations ctl_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = _ctl_ioctl,
.release = _ctl_release,
.poll = _ctl_poll,
.fasync = _ctl_fasync,
#ifdef CONFIG_COMPAT
.compat_ioctl = _ctl_ioctl_compat,
#endif
};
static struct miscdevice ctl_dev = {
.minor = MPT2SAS_MINOR,
.name = MPT2SAS_DEV_NAME,
.fops = &ctl_fops,
};
/**
* mpt2sas_ctl_init - main entry point for ctl.
*
*/
void
mpt2sas_ctl_init(void)
{
async_queue = NULL;
if (misc_register(&ctl_dev) < 0)
printk(KERN_ERR "%s can't register misc device [minor=%d]\n",
MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
init_waitqueue_head(&ctl_poll_wait);
}
/**
* mpt2sas_ctl_exit - exit point for ctl
*
*/
void
mpt2sas_ctl_exit(void)
{
struct MPT2SAS_ADAPTER *ioc;
int i;
list_for_each_entry(ioc, &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;
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);
}
/*
* Management Module Support for MPT (Message Passing Technology) based
* controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
* Copyright (C) 2007-2008 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 MPT2SAS_CTL_H_INCLUDED
#define MPT2SAS_CTL_H_INCLUDED
#ifdef __KERNEL__
#include <linux/miscdevice.h>
#endif
#define MPT2SAS_DEV_NAME "mpt2ctl"
#define MPT2_MAGIC_NUMBER 'm'
#define MPT2_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */
/**
* IOCTL opcodes
*/
#define MPT2IOCINFO _IOWR(MPT2_MAGIC_NUMBER, 17, \
struct mpt2_ioctl_iocinfo)
#define MPT2COMMAND _IOWR(MPT2_MAGIC_NUMBER, 20, \
struct mpt2_ioctl_command)
#ifdef CONFIG_COMPAT
#define MPT2COMMAND32 _IOWR(MPT2_MAGIC_NUMBER, 20, \
struct mpt2_ioctl_command32)
#endif
#define MPT2EVENTQUERY _IOWR(MPT2_MAGIC_NUMBER, 21, \
struct mpt2_ioctl_eventquery)
#define MPT2EVENTENABLE _IOWR(MPT2_MAGIC_NUMBER, 22, \
struct mpt2_ioctl_eventenable)
#define MPT2EVENTREPORT _IOWR(MPT2_MAGIC_NUMBER, 23, \
struct mpt2_ioctl_eventreport)
#define MPT2HARDRESET _IOWR(MPT2_MAGIC_NUMBER, 24, \
struct mpt2_ioctl_diag_reset)
#define MPT2BTDHMAPPING _IOWR(MPT2_MAGIC_NUMBER, 31, \
struct mpt2_ioctl_btdh_mapping)
/* diag buffer support */
#define MPT2DIAGREGISTER _IOWR(MPT2_MAGIC_NUMBER, 26, \
struct mpt2_diag_register)
#define MPT2DIAGRELEASE _IOWR(MPT2_MAGIC_NUMBER, 27, \
struct mpt2_diag_release)
#define MPT2DIAGUNREGISTER _IOWR(MPT2_MAGIC_NUMBER, 28, \
struct mpt2_diag_unregister)
#define MPT2DIAGQUERY _IOWR(MPT2_MAGIC_NUMBER, 29, \
struct mpt2_diag_query)
#define MPT2DIAGREADBUFFER _IOWR(MPT2_MAGIC_NUMBER, 30, \
struct mpt2_diag_read_buffer)
/**
* struct mpt2_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 mpt2_ioctl_header {
uint32_t ioc_number;
uint32_t port_number;
uint32_t max_data_size;
};
/**
* struct mpt2_ioctl_diag_reset - diagnostic reset
* @hdr - generic header
*/
struct mpt2_ioctl_diag_reset {
struct mpt2_ioctl_header hdr;
};
/**
* struct mpt2_ioctl_pci_info - pci device info
* @device - pci device id
* @function - pci function id
* @bus - pci bus id
* @segment_id - pci segment id
*/
struct mpt2_ioctl_pci_info {
union {
struct {
uint32_t device:5;
uint32_t function:3;
uint32_t bus:24;
} bits;
uint32_t word;
} u;
uint32_t segment_id;
};
#define MPT2_IOCTL_INTERFACE_SCSI (0x00)
#define MPT2_IOCTL_INTERFACE_FC (0x01)
#define MPT2_IOCTL_INTERFACE_FC_IP (0x02)
#define MPT2_IOCTL_INTERFACE_SAS (0x03)
#define MPT2_IOCTL_INTERFACE_SAS2 (0x04)
#define MPT2_IOCTL_VERSION_LENGTH (32)
/**
* struct mpt2_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 mpt2_ioctl_iocinfo {
struct mpt2_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 mpt2_ioctl_pci_info pci_information;
};
/* number of event log entries */
#define MPT2SAS_CTL_EVENT_LOG_SIZE (50)
/**
* struct mpt2_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 mpt2_ioctl_eventquery {
struct mpt2_ioctl_header hdr;
uint16_t event_entries;
uint16_t rsvd;
uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
};
/**
* struct mpt2_ioctl_eventenable - enable/disable event capturing
* @hdr - generic header
* @event_types - toggle off/on type of events to be captured
*/
struct mpt2_ioctl_eventenable {
struct mpt2_ioctl_header hdr;
uint32_t event_types[4];
};
#define MPT2_EVENT_DATA_SIZE (192)
/**
* struct MPT2_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 MPT2_IOCTL_EVENTS {
uint32_t event;
uint32_t context;
uint8_t data[MPT2_EVENT_DATA_SIZE];
};
/**
* struct mpt2_ioctl_eventreport - returing event log
* @hdr - generic header
* @event_data - (see struct MPT2_IOCTL_EVENTS)
*/
struct mpt2_ioctl_eventreport {
struct mpt2_ioctl_header hdr;
struct MPT2_IOCTL_EVENTS event_data[1];
};
/**
* struct mpt2_ioctl_command - generic mpt firmware passthru ioclt
* @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 mpt2_ioctl_command {
struct mpt2_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 mpt2_ioctl_command32 {
struct mpt2_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 mpt2_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 mpt2_ioctl_btdh_mapping {
struct mpt2_ioctl_header hdr;
uint32_t id;
uint32_t bus;
uint16_t handle;
uint16_t rsvd;
};
/* status bits for ioc->diag_buffer_status */
#define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01)
#define MPT2_DIAG_BUFFER_IS_RELEASED (0x02)
/* application flags for mpt2_diag_register, mpt2_diag_query */
#define MPT2_APP_FLAGS_APP_OWNED (0x0001)
#define MPT2_APP_FLAGS_BUFFER_VALID (0x0002)
#define MPT2_APP_FLAGS_FW_BUFFER_ACCESS (0x0004)
/* flags for mpt2_diag_read_buffer */
#define MPT2_FLAGS_REREGISTER (0x0001)
#define MPT2_PRODUCT_SPECIFIC_DWORDS 23
/**
* struct mpt2_diag_register - application register with driver
* @hdr - generic header
* @reserved -
* @buffer_type - specifies either TRACE or SNAPSHOT
* @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 mpt2_diag_register {
struct mpt2_ioctl_header hdr;
uint8_t reserved;
uint8_t buffer_type;
uint16_t application_flags;
uint32_t diagnostic_flags;
uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
uint32_t requested_buffer_size;
uint32_t unique_id;
};
/**
* struct mpt2_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 mpt2_diag_unregister {
struct mpt2_ioctl_header hdr;
uint32_t unique_id;
};
/**
* struct mpt2_diag_query - query relevant info associated with diag buffers
* @hdr - generic header
* @reserved -
* @buffer_type - specifies either TRACE or SNAPSHOT
* @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 mpt2_diag_query {
struct mpt2_ioctl_header hdr;
uint8_t reserved;
uint8_t buffer_type;
uint16_t application_flags;
uint32_t diagnostic_flags;
uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
uint32_t total_buffer_size;
uint32_t driver_added_buffer_size;
uint32_t unique_id;
};
/**
* struct mpt2_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 mpt2_diag_release {
struct mpt2_ioctl_header hdr;
uint32_t unique_id;
};
/**
* struct mpt2_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 mpt2_diag_read_buffer {
struct mpt2_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 /* MPT2SAS_CTL_H_INCLUDED */
/*
* Logging Support for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
* Copyright (C) 2007-2008 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 MPT2SAS_DEBUG_H_INCLUDED
#define MPT2SAS_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_CSMISAS 0x00010000
#define MPT_DEBUG_SAS 0x00020000
#define MPT_DEBUG_TRANSPORT 0x00040000
#define MPT_DEBUG_TASK_SET_FULL 0x00080000
#define MPT_DEBUG_TARGET_MODE 0x00100000
/*
* CONFIG_SCSI_MPT2SAS_LOGGING - enabled in Kconfig
*/
#ifdef CONFIG_SCSI_MPT2SAS_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_MPT2SAS_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 dcsmisasprintk(IOC, CMD) \
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS)
#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 dTMprintk(IOC, CMD) \
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TARGET_MODE)
/* inline functions for dumping debug data*/
#ifdef CONFIG_SCSI_MPT2SAS_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;
u32 *mfp = (u32 *)mpi_request;
printk(KERN_INFO "mf:\n\t");
for (i = 0; i < sz; i++) {
if (i && ((i % 8) == 0))
printk("\n\t");
printk("%08x ", le32_to_cpu(mfp[i]));
}
printk("\n");
}
#else
#define _debug_dump_mf(mpi_request, sz)
#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
#endif /* MPT2SAS_DEBUG_H_INCLUDED */
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* SAS Transport Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
* Copyright (C) 2007-2008 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 "mpt2sas_base.h"
/**
* _transport_sas_node_find_by_handle - sas node search
* @ioc: per adapter object
* @handle: expander or hba handle (assigned by firmware)
* 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_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
{
int i;
for (i = 0; i < ioc->sas_hba.num_phys; i++)
if (ioc->sas_hba.phy[i].handle == handle)
return &ioc->sas_hba;
return mpt2sas_scsih_expander_find_by_handle(ioc, handle);
}
/**
* _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 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 MPT2SAS_ADAPTER *ioc, u16 handle,
struct sas_identify *identify)
{
Mpi2SasDevicePage0_t sas_device_pg0;
Mpi2ConfigReply_t mpi_reply;
u32 device_info;
u32 ioc_status;
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
printk(MPT2SAS_ERR_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) {
printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
"\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
__FILE__, __LINE__, __func__);
return -1;
}
memset(identify, 0, sizeof(identify));
device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
/* sas_address */
identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
/* device_type */
switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
identify->device_type = SAS_PHY_UNUSED;
break;
case MPI2_SAS_DEVICE_INFO_END_DEVICE:
identify->device_type = SAS_END_DEVICE;
break;
case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:
identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
break;
case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:
identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
break;
}
/* initiator_port_protocols */
if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)
identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)
identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)
identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)
identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
/* target_port_protocols */
if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)
identify->target_port_protocols |= SAS_PROTOCOL_SSP;
if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
identify->target_port_protocols |= SAS_PROTOCOL_STP;
if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)
identify->target_port_protocols |= SAS_PROTOCOL_SMP;
if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
identify->target_port_protocols |= SAS_PROTOCOL_SATA;
return 0;
}
/**
* mpt2sas_transport_done - internal transport layer callback handler.
* @ioc: per adapter object
* @smid: system request message index
* @VF_ID: virtual function id
* @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 nothing.
*/
void
mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED)
return;
if (ioc->transport_cmds.smid != smid)
return;
ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
if (mpi_reply) {
memcpy(ioc->transport_cmds.reply, mpi_reply,
mpi_reply->MsgLength*4);
ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID;
}
ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->transport_cmds.done);
}
/* 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:1;
u8 reserved1:7;
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 MPT2SAS_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;
u32 sgl_flags;
u8 issue_reset = 0;
unsigned long flags;
void *data_out = NULL;
dma_addr_t data_out_dma;
u32 sz;
u64 *sas_address_le;
u16 wait_state_count;
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->ioc_reset_in_progress) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
mutex_lock(&ioc->transport_cmds.mutex);
if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
ioc->transport_cmds.status = MPT2_CMD_PENDING;
wait_state_count = 0;
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
printk(MPT2SAS_ERR_FMT
"%s: failed due to ioc not operational\n",
ioc->name, __func__);
rc = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
printk(MPT2SAS_INFO_FMT "%s: waiting for "
"operational state(count=%d)\n", ioc->name,
__func__, wait_state_count);
}
if (wait_state_count)
printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
ioc->name, __func__);
smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
rc = 0;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->transport_cmds.smid = smid;
sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
if (!data_out) {
printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
__LINE__, __func__);
rc = -ENOMEM;
mpt2sas_base_free_smid(ioc, smid);
goto out;
}
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;
sas_address_le = (u64 *)&mpi_request->SASAddress;
*sas_address_le = cpu_to_le64(sas_address);
mpi_request->RequestDataLength = sizeof(struct rep_manu_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 rep_manu_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 rep_manu_reply), data_out_dma +
sizeof(struct rep_manu_request));
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
"send to sas_addr(0x%016llx)\n", ioc->name,
(unsigned long long)sas_address));
mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
10*HZ);
if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s: timeout\n",
ioc->name, __func__);
_debug_dump_mf(mpi_request,
sizeof(Mpi2SmpPassthroughRequest_t)/4);
if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
issue_reset = 1;
goto issue_host_reset;
}
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
"complete\n", ioc->name));
if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
u8 *tmp;
mpi_reply = ioc->transport_cmds.reply;
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_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;
if (manufacture_reply->sas_format) {
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, printk(MPT2SAS_DEBUG_FMT
"report_manufacture - no reply\n", ioc->name));
issue_host_reset:
if (issue_reset)
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
out:
ioc->transport_cmds.status = MPT2_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;
}
/**
* mpt2sas_transport_port_add - insert port to the list
* @ioc: per adapter object
* @handle: handle of attached device
* @parent_handle: parent handle(either hba or expander)
* Context: This function will acquire ioc->sas_node_lock.
*
* Adding new port object to the sas_node->sas_port_list.
*
* Returns mpt2sas_port.
*/
struct _sas_port *
mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
u16 parent_handle)
{
struct _sas_phy *mpt2sas_phy, *next;
struct _sas_port *mpt2sas_port;
unsigned long flags;
struct _sas_node *sas_node;
struct sas_rphy *rphy;
int i;
struct sas_port *port;
if (!parent_handle)
return NULL;
mpt2sas_port = kzalloc(sizeof(struct _sas_port),
GFP_KERNEL);
if (!mpt2sas_port) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return NULL;
}
INIT_LIST_HEAD(&mpt2sas_port->port_list);
INIT_LIST_HEAD(&mpt2sas_port->phy_list);
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node) {
printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n",
ioc->name, __func__, parent_handle);
goto out_fail;
}
mpt2sas_port->handle = parent_handle;
mpt2sas_port->sas_address = sas_node->sas_address;
if ((_transport_set_identify(ioc, handle,
&mpt2sas_port->remote_identify))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
goto out_fail;
}
if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
goto out_fail;
}
for (i = 0; i < sas_node->num_phys; i++) {
if (sas_node->phy[i].remote_identify.sas_address !=
mpt2sas_port->remote_identify.sas_address)
continue;
list_add_tail(&sas_node->phy[i].port_siblings,
&mpt2sas_port->phy_list);
mpt2sas_port->num_phys++;
}
if (!mpt2sas_port->num_phys) {
printk(MPT2SAS_ERR_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))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
goto out_fail;
}
list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
port_siblings) {
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)"
", sas_addr(0x%016llx), phy(%d)\n", handle,
(unsigned long long)
mpt2sas_port->remote_identify.sas_address,
mpt2sas_phy->phy_id);
sas_port_add_phy(port, mpt2sas_phy->phy);
}
mpt2sas_port->port = port;
if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE)
rphy = sas_end_device_alloc(port);
else
rphy = sas_expander_alloc(port,
mpt2sas_port->remote_identify.device_type);
rphy->identify = mpt2sas_port->remote_identify;
if ((sas_rphy_add(rphy))) {
printk(MPT2SAS_ERR_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)
mpt2sas_port->remote_identify.sas_address);
mpt2sas_port->rphy = rphy;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
/* fill in report manufacture */
if (mpt2sas_port->remote_identify.device_type ==
MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
mpt2sas_port->remote_identify.device_type ==
MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
transport_expander_report_manufacture(ioc,
mpt2sas_port->remote_identify.sas_address,
rphy_to_expander_device(rphy));
return mpt2sas_port;
out_fail:
list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list,
port_siblings)
list_del(&mpt2sas_phy->port_siblings);
kfree(mpt2sas_port);
return NULL;
}
/**
* mpt2sas_transport_port_remove - remove port from the list
* @ioc: per adapter object
* @sas_address: sas address of attached device
* @parent_handle: handle to the upstream parent(either hba or expander)
* Context: This function will acquire ioc->sas_node_lock.
*
* Removing object and freeing associated memory from the
* ioc->sas_port_list.
*
* Return nothing.
*/
void
mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
u16 parent_handle)
{
int i;
unsigned long flags;
struct _sas_port *mpt2sas_port, *next;
struct _sas_node *sas_node;
u8 found = 0;
struct _sas_phy *mpt2sas_phy, *next_phy;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node)
return;
list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
port_list) {
if (mpt2sas_port->remote_identify.sas_address != sas_address)
continue;
found = 1;
list_del(&mpt2sas_port->port_list);
goto out;
}
out:
if (!found)
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));
}
list_for_each_entry_safe(mpt2sas_phy, next_phy,
&mpt2sas_port->phy_list, port_siblings) {
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
"remove: parent_handle(0x%04x), "
"sas_addr(0x%016llx), phy(%d)\n", parent_handle,
(unsigned long long)
mpt2sas_port->remote_identify.sas_address,
mpt2sas_phy->phy_id);
sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
list_del(&mpt2sas_phy->port_siblings);
}
sas_port_delete(mpt2sas_port->port);
kfree(mpt2sas_port);
}
/**
* mpt2sas_transport_add_host_phy - report sas_host phy to transport
* @ioc: per adapter object
* @mpt2sas_phy: mpt2sas per phy object
* @phy_pg0: sas phy page 0
* @parent_dev: parent device class object
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)
{
struct sas_phy *phy;
int phy_index = mpt2sas_phy->phy_id;
INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
phy = sas_phy_alloc(parent_dev, phy_index);
if (!phy) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -1;
}
if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
&mpt2sas_phy->identify))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -1;
}
phy->identify = mpt2sas_phy->identify;
mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);
if (mpt2sas_phy->attached_handle)
_transport_set_identify(ioc, mpt2sas_phy->attached_handle,
&mpt2sas_phy->remote_identify);
phy->identify.phy_identifier = mpt2sas_phy->phy_id;
phy->negotiated_linkrate = _transport_convert_phy_link_rate(
phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
phy_pg0.HwLinkRate >> 4);
phy->minimum_linkrate = _transport_convert_phy_link_rate(
phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
phy->maximum_linkrate = _transport_convert_phy_link_rate(
phy_pg0.ProgrammedLinkRate >> 4);
if ((sas_phy_add(phy))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
sas_phy_free(phy);
return -1;
}
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &phy->dev,
"add: handle(0x%04x), sas_addr(0x%016llx)\n"
"\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
mpt2sas_phy->handle, (unsigned long long)
mpt2sas_phy->identify.sas_address,
mpt2sas_phy->attached_handle,
(unsigned long long)
mpt2sas_phy->remote_identify.sas_address);
mpt2sas_phy->phy = phy;
return 0;
}
/**
* mpt2sas_transport_add_expander_phy - report expander phy to transport
* @ioc: per adapter object
* @mpt2sas_phy: mpt2sas per phy object
* @expander_pg1: expander page 1
* @parent_dev: parent device class object
*
* Returns 0 for success, non-zero for failure.
*/
int
mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev)
{
struct sas_phy *phy;
int phy_index = mpt2sas_phy->phy_id;
INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
phy = sas_phy_alloc(parent_dev, phy_index);
if (!phy) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -1;
}
if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
&mpt2sas_phy->identify))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -1;
}
phy->identify = mpt2sas_phy->identify;
mpt2sas_phy->attached_handle =
le16_to_cpu(expander_pg1.AttachedDevHandle);
if (mpt2sas_phy->attached_handle)
_transport_set_identify(ioc, mpt2sas_phy->attached_handle,
&mpt2sas_phy->remote_identify);
phy->identify.phy_identifier = mpt2sas_phy->phy_id;
phy->negotiated_linkrate = _transport_convert_phy_link_rate(
expander_pg1.NegotiatedLinkRate &
MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
expander_pg1.HwLinkRate >> 4);
phy->minimum_linkrate = _transport_convert_phy_link_rate(
expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
phy->maximum_linkrate = _transport_convert_phy_link_rate(
expander_pg1.ProgrammedLinkRate >> 4);
if ((sas_phy_add(phy))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
sas_phy_free(phy);
return -1;
}
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &phy->dev,
"add: handle(0x%04x), sas_addr(0x%016llx)\n"
"\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
mpt2sas_phy->handle, (unsigned long long)
mpt2sas_phy->identify.sas_address,
mpt2sas_phy->attached_handle,
(unsigned long long)
mpt2sas_phy->remote_identify.sas_address);
mpt2sas_phy->phy = phy;
return 0;
}
/**
* mpt2sas_transport_update_phy_link_change - refreshing phy link changes and attached devices
* @ioc: per adapter object
* @handle: handle to sas_host or expander
* @attached_handle: attached device handle
* @phy_numberv: phy number
* @link_rate: new link rate
*
* Returns nothing.
*/
void
mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc,
u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate)
{
unsigned long flags;
struct _sas_node *sas_node;
struct _sas_phy *mpt2sas_phy;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_node = _transport_sas_node_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_node)
return;
mpt2sas_phy = &sas_node->phy[phy_number];
mpt2sas_phy->attached_handle = attached_handle;
if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
_transport_set_identify(ioc, mpt2sas_phy->attached_handle,
&mpt2sas_phy->remote_identify);
else
memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
sas_identify));
if (mpt2sas_phy->phy)
mpt2sas_phy->phy->negotiated_linkrate =
_transport_convert_phy_link_rate(link_rate);
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
"refresh: handle(0x%04x), sas_addr(0x%016llx),\n"
"\tlink_rate(0x%02x), phy(%d)\n"
"\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
handle, (unsigned long long)
mpt2sas_phy->identify.sas_address, link_rate,
phy_number, attached_handle,
(unsigned long long)
mpt2sas_phy->remote_identify.sas_address);
}
static inline void *
phy_to_ioc(struct sas_phy *phy)
{
struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
return shost_priv(shost);
}
static inline void *
rphy_to_ioc(struct sas_rphy *rphy)
{
struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
return shost_priv(shost);
}
/**
* transport_get_linkerrors -
* @phy: The sas phy object
*
* Only support sas_host direct attached phys.
* Returns 0 for success, non-zero for failure.
*
*/
static int
transport_get_linkerrors(struct sas_phy *phy)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
struct _sas_phy *mpt2sas_phy;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasPhyPage1_t phy_pg1;
int i;
for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
!mpt2sas_phy; i++) {
if (ioc->sas_hba.phy[i].phy != phy)
continue;
mpt2sas_phy = &ioc->sas_hba.phy[i];
}
if (!mpt2sas_phy) /* this phy not on sas_host */
return -EINVAL;
if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
mpt2sas_phy->phy_id))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -ENXIO;
}
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
"(0x%04x), loginfo(0x%08x)\n", ioc->name,
mpt2sas_phy->phy_id,
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 MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
struct _sas_node *sas_expander;
unsigned long flags;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
rphy->identify.sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
if (!sas_expander)
return -ENXIO;
*identifier = sas_expander->enclosure_logical_id;
return 0;
}
/**
* 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 MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
struct _sas_device *sas_device;
unsigned long flags;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
rphy->identify.sas_address);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!sas_device)
return -ENXIO;
return sas_device->slot;
}
/**
* transport_phy_reset -
* @phy: The sas phy object
* @hard_reset:
*
* Only support sas_host direct attached phys.
* Returns 0 for success, non-zero for failure.
*/
static int
transport_phy_reset(struct sas_phy *phy, int hard_reset)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
struct _sas_phy *mpt2sas_phy;
Mpi2SasIoUnitControlReply_t mpi_reply;
Mpi2SasIoUnitControlRequest_t mpi_request;
int i;
for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
!mpt2sas_phy; i++) {
if (ioc->sas_hba.phy[i].phy != phy)
continue;
mpt2sas_phy = &ioc->sas_hba.phy[i];
}
if (!mpt2sas_phy) /* this phy not on sas_host */
return -EINVAL;
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 = mpt2sas_phy->phy_id;
if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -ENXIO;
}
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
"(0x%04x), loginfo(0x%08x)\n", ioc->name,
mpt2sas_phy->phy_id,
le16_to_cpu(mpi_reply.IOCStatus),
le32_to_cpu(mpi_reply.IOCLogInfo));
return 0;
}
/**
* 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 MPT2SAS_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;
u32 sgl_flags;
u8 issue_reset = 0;
unsigned long flags;
dma_addr_t dma_addr_in = 0;
dma_addr_t dma_addr_out = 0;
u16 wait_state_count;
struct request *rsp = req->next_rq;
if (!rsp) {
printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
"missing\n", ioc->name, __func__);
return -EINVAL;
}
/* do we need to support multiple segments? */
if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
"rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
req->data_len, rsp->bio->bi_vcnt, rsp->data_len);
return -EINVAL;
}
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->ioc_reset_in_progress) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
if (rc)
return rc;
if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name,
__func__);
rc = -EAGAIN;
goto out;
}
ioc->transport_cmds.status = MPT2_CMD_PENDING;
wait_state_count = 0;
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
if (wait_state_count++ == 10) {
printk(MPT2SAS_ERR_FMT
"%s: failed due to ioc not operational\n",
ioc->name, __func__);
rc = -EFAULT;
goto out;
}
ssleep(1);
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
printk(MPT2SAS_INFO_FMT "%s: waiting for "
"operational state(count=%d)\n", ioc->name,
__func__, wait_state_count);
}
if (wait_state_count)
printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
ioc->name, __func__);
smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
}
rc = 0;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->transport_cmds.smid = smid;
memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
mpi_request->PhysicalPort = 0xFF;
*((u64 *)&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(req->data_len - 4);
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;
dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
req->data_len, PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_out) {
mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
goto unmap;
}
ioc->base_add_sg_single(psge, sgl_flags | (req->data_len - 4),
dma_addr_out);
/* 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;
dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
rsp->data_len, PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_in) {
mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
goto unmap;
}
ioc->base_add_sg_single(psge, sgl_flags | (rsp->data_len + 4),
dma_addr_in);
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
"sending smp request\n", ioc->name, __func__));
mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
10*HZ);
if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s : timeout\n",
__func__, ioc->name);
_debug_dump_mf(mpi_request,
sizeof(Mpi2SmpPassthroughRequest_t)/4);
if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
issue_reset = 1;
goto issue_host_reset;
}
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
"complete\n", ioc->name, __func__));
if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
mpi_reply = ioc->transport_cmds.reply;
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_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->data_len = 0;
rsp->data_len -= mpi_reply->ResponseDataLength;
} else {
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
"%s - no reply\n", ioc->name, __func__));
rc = -ENXIO;
}
issue_host_reset:
if (issue_reset) {
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
rc = -ETIMEDOUT;
}
unmap:
if (dma_addr_out)
pci_unmap_single(ioc->pdev, dma_addr_out, req->data_len,
PCI_DMA_BIDIRECTIONAL);
if (dma_addr_in)
pci_unmap_single(ioc->pdev, dma_addr_in, rsp->data_len,
PCI_DMA_BIDIRECTIONAL);
out:
ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->transport_cmds.mutex);
return rc;
}
struct sas_function_template mpt2sas_transport_functions = {
.get_linkerrors = transport_get_linkerrors,
.get_enclosure_identifier = transport_get_enclosure_identifier,
.get_bay_identifier = transport_get_bay_identifier,
.phy_reset = transport_phy_reset,
.smp_handler = transport_smp_handler,
};
struct scsi_transport_template *mpt2sas_transport_template;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment