diff options
author | Paul Mundt <lethal@linux-sh.org> | 2011-01-13 15:06:28 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-01-13 15:06:28 +0900 |
commit | f43dc23d5ea91fca257be02138a255f02d98e806 (patch) | |
tree | b29722f6e965316e90ac97abf79923ced250dc21 /drivers/scsi/mpt2sas | |
parent | f8e53553f452dcbf67cb89c8cba63a1cd6eb4cc0 (diff) | |
parent | 4162cf64973df51fc885825bc9ca4d055891c49f (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6 into common/serial-rework
Conflicts:
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-mxg.c
arch/sh/kernel/cpu/sh2a/setup-sh7201.c
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/setup-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7770.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpu/sh5/setup-sh5.c
drivers/serial/sh-sci.c
drivers/serial/sh-sci.h
include/linux/serial_sci.h
Diffstat (limited to 'drivers/scsi/mpt2sas')
-rw-r--r-- | drivers/scsi/mpt2sas/Kconfig | 3 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2.h | 136 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 686 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_history.txt | 384 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_init.h | 62 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 277 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_raid.h | 18 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_sas.h | 13 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 191 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 1226 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 253 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_config.c | 1047 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 744 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.h | 6 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_debug.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 3386 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 1037 |
17 files changed, 6933 insertions, 2538 deletions
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig index 4a86855c23b..bbb7e4bf30a 100644 --- a/drivers/scsi/mpt2sas/Kconfig +++ b/drivers/scsi/mpt2sas/Kconfig @@ -2,7 +2,7 @@ # Kernel configuration file for the MPT2SAS # # This code is based on drivers/scsi/mpt2sas/Kconfig -# Copyright (C) 2007-2008 LSI Corporation +# Copyright (C) 2007-2010 LSI Corporation # (mailto:DL-MPTFusionLinux@lsi.com) # This program is free software; you can redistribute it and/or @@ -44,6 +44,7 @@ config SCSI_MPT2SAS tristate "LSI MPT Fusion SAS 2.0 Device Driver" depends on PCI && SCSI select SCSI_SAS_ATTRS + select RAID_ATTRS ---help--- This driver supports PCI-Express SAS 6Gb/s Host Adapters. diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 7bb2ece8b2e..8be75e65f76 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2009 LSI Corporation. + * Copyright (c) 2000-2010 LSI Corporation. * * * Name: mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.11 + * mpi2.h Version: 02.00.16 * * Version History * --------------- @@ -45,6 +45,24 @@ * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. * Moved LUN field defines from mpi2_init.h. * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. + * In all request and reply descriptors, replaced VF_ID + * field with MSIxIndex field. + * Removed DevHandle field from + * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those + * bytes reserved. + * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. + * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. + * Added defines for product-specific range of message + * function codes, 0xF0 to 0xFF. + * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. + * Added alternative defines for the SGE Direction bit. * -------------------------------------------------------------------------- */ @@ -70,7 +88,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x0B) +#define MPI2_HEADER_VERSION_UNIT (0x10) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -224,9 +242,12 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS #define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) /* - * Offset for the Reply Descriptor Post Queue + * Defines for the Reply Descriptor Post Queue */ #define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) +#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) +#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) +#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) /* * Defines for the HCBSize and address @@ -257,7 +278,7 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR { U8 RequestFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 0x01 */ U16 SMID; /* 0x02 */ U16 LMID; /* 0x04 */ U16 DescriptorTypeDependent; /* 0x06 */ @@ -271,6 +292,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) #define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) +#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A) #define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) @@ -279,7 +301,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR { U8 RequestFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 0x01 */ U16 SMID; /* 0x02 */ U16 LMID; /* 0x04 */ U16 Reserved1; /* 0x06 */ @@ -293,7 +315,7 @@ typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR { U8 RequestFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 0x01 */ U16 SMID; /* 0x02 */ U16 LMID; /* 0x04 */ U16 DevHandle; /* 0x06 */ @@ -306,7 +328,7 @@ typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR { U8 RequestFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 0x01 */ U16 SMID; /* 0x02 */ U16 LMID; /* 0x04 */ U16 IoIndex; /* 0x06 */ @@ -315,14 +337,29 @@ typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR Mpi2SCSITargetRequestDescriptor_t, MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t; + +/* RAID Accelerator Request Descriptor */ +typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 Reserved; /* 0x06 */ +} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, + Mpi2RAIDAcceleratorRequestDescriptor_t, + MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_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_DEFAULT_REQUEST_DESCRIPTOR Default; + MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; + MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; + MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; + MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; + U64 Words; } MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION, Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t; @@ -333,19 +370,20 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR { U8 ReplyFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 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) +#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) +#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) +#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) +#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05) +#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) /* values for marking a reply descriptor as unused */ #define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) @@ -355,7 +393,7 @@ typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR { U8 ReplyFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 0x01 */ U16 SMID; /* 0x02 */ U32 ReplyFrameAddress; /* 0x04 */ } MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, @@ -368,10 +406,10 @@ typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR { U8 ReplyFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 0x01 */ U16 SMID; /* 0x02 */ U16 TaskTag; /* 0x04 */ - U16 DevHandle; /* 0x06 */ + U16 Reserved1; /* 0x06 */ } MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, Mpi2SCSIIOSuccessReplyDescriptor_t, @@ -382,7 +420,7 @@ typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR { U8 ReplyFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 0x01 */ U16 SMID; /* 0x02 */ U8 SequenceNumber; /* 0x04 */ U8 Reserved1; /* 0x05 */ @@ -397,7 +435,7 @@ typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR { U8 ReplyFlags; /* 0x00 */ - U8 VF_ID; /* 0x01 */ + U8 MSIxIndex; /* 0x01 */ U8 VP_ID; /* 0x02 */ U8 Flags; /* 0x03 */ U16 InitiatorDevHandle; /* 0x04 */ @@ -411,15 +449,28 @@ typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR #define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F) +/* RAID Accelerator Success Reply Descriptor */ +typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U32 Reserved; /* 0x04 */ +} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, + Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; + + /* union of Reply Descriptors */ typedef union _MPI2_REPLY_DESCRIPTORS_UNION { - MPI2_DEFAULT_REPLY_DESCRIPTOR Default; - MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; - MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; - MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; - MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; - U64 Words; + MPI2_DEFAULT_REPLY_DESCRIPTOR Default; + MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; + MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; + MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; + MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; + MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; + U64 Words; } MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; @@ -428,8 +479,6 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION /***************************************************************************** * * Message Functions -* 0x80 -> 0x8F reserved for private message use per product -* * *****************************************************************************/ @@ -458,12 +507,21 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION #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 */ +#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/ +/* Host Based Discovery Action */ +#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) +/* Power Management Control */ +#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) +/* beginning of product-specific range */ +#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) +/* end of product-specific range */ +#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) + /* Doorbell functions */ #define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) -/* #define MPI2_FUNCTION_IO_UNIT_RESET (0x41) */ #define MPI2_FUNCTION_HANDSHAKE (0x42) @@ -555,12 +613,17 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION #define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) +/**************************************************************************** +* RAID Accelerator values +****************************************************************************/ + +#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0) /**************************************************************************** * IOCStatus flag to indicate that log info is available ****************************************************************************/ -#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) +#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) /**************************************************************************** * IOCLogInfo Types @@ -868,6 +931,9 @@ typedef struct _MPI2_MPI_SGE_UNION #define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) #define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) +#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST) +#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC) + /* Address Size */ #define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 2f27cf6d6c6..d76a6584760 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2009 LSI Corporation. + * Copyright (c) 2000-2010 LSI Corporation. * * * Name: mpi2_cnfg.h * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.10 + * mpi2_cnfg.h Version: 02.00.15 * * Version History * --------------- @@ -95,6 +95,36 @@ * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. * Added PortGroups, DmaGroup, and ControlGroup fields to * SAS Device Page 0. + * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO + * Unit Page 6. + * Added expander reduced functionality data to SAS + * Expander Page 0. + * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. + * 02-10-10 02.00.14 Modified the comments for the configuration page + * structures that contain an array of data. The host + * should use the "count" field in the page data (e.g. the + * NumPhys field) to determine the number of valid elements + * in the array. + * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. + * Added PowerManagementCapabilities to IO Unit Page 7. + * Added PortWidthModGroup field to + * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. + * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT + * define. + * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. + * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. * -------------------------------------------------------------------------- */ @@ -177,6 +207,7 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION #define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) +#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) /***************************************************************************** @@ -263,6 +294,14 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION #define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) +/* Ethernet PageAddress format */ +#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) +#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) + +#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) + + + /**************************************************************************** * Configuration messages ****************************************************************************/ @@ -298,7 +337,7 @@ typedef struct _MPI2_CONFIG_REQUEST #define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) #define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) -/* values for SGLFlags field are in the SGL section of mpi2.h */ +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ /* Config Reply Message */ @@ -344,6 +383,20 @@ typedef struct _MPI2_CONFIG_REPLY #define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) #define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) +#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E) + +#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) +#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) +#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) +#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) +#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) +#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) +#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) +#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) +#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) + + + /* Manufacturing Page 0 */ @@ -508,7 +561,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_4 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES #define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) @@ -586,7 +639,7 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX #define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) @@ -682,7 +735,9 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 #define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) /* IO Unit Page 1 Flags defines */ +#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) #define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) +#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9) #define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) #define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) #define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) @@ -698,7 +753,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength at runtime. + * one and check the value returned for GPIOCount at runtime. */ #ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX #define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) @@ -723,6 +778,123 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 #define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001) +/* IO Unit Page 5 */ + +/* + * Upper layer code (drivers, utilities, etc.) should leave this define set to + * one and check the value returned for NumDmaEngines at runtime. + */ +#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES +#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */ + U64 RaidAcceleratorBufferSize; /* 0x0C */ + U64 RaidAcceleratorControlBaseAddress; /* 0x14 */ + U8 RAControlSize; /* 0x1C */ + U8 NumDmaEngines; /* 0x1D */ + U8 RAMinControlSize; /* 0x1E */ + U8 RAMaxControlSize; /* 0x1F */ + U32 Reserved1; /* 0x20 */ + U32 Reserved2; /* 0x24 */ + U32 Reserved3; /* 0x28 */ + U32 DmaEngineCapabilities + [MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */ +} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, + Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t; + +#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00) + +/* defines for IO Unit Page 5 DmaEngineCapabilities field */ +#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFF00) +#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16) + +#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008) +#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004) +#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002) +#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001) + + +/* IO Unit Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 { + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Flags; /* 0x04 */ + U8 RAHostControlSize; /* 0x06 */ + U8 Reserved0; /* 0x07 */ + U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ + U32 Reserved3; /* 0x18 */ +} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, + Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t; + +#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00) + +/* defines for IO Unit Page 6 Flags field */ +#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) + + +/* IO Unit Page 7 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Reserved1; /* 0x04 */ + U8 PCIeWidth; /* 0x06 */ + U8 PCIeSpeed; /* 0x07 */ + U32 ProcessorState; /* 0x08 */ + U32 PowerManagementCapabilities; /* 0x0C */ + U16 IOCTemperature; /* 0x10 */ + U8 IOCTemperatureUnits; /* 0x12 */ + U8 IOCSpeed; /* 0x13 */ + U32 Reserved3; /* 0x14 */ +} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, + Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; + +#define MPI2_IOUNITPAGE7_PAGEVERSION (0x01) + +/* defines for IO Unit Page 7 PCIeWidth field */ +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) + +/* defines for IO Unit Page 7 PCIeSpeed field */ +#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) + +/* defines for IO Unit Page 7 ProcessorState field */ +#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) +#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) + +#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) +#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) + +/* defines for IO Unit Page 7 PowerManagementCapabilities field */ +#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) +#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) +#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) + + +/* defines for IO Unit Page 7 IOCTemperatureUnits field */ +#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) +#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) + +/* defines for IO Unit Page 7 IOCSpeed field */ +#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) +#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) +#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) +#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) + + + /**************************************************************************** * IOC Config Pages ****************************************************************************/ @@ -1053,7 +1225,7 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_3 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES #define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) @@ -1127,7 +1299,7 @@ typedef struct _MPI2_RAIDVOL0_SETTINGS /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength at runtime. + * one and check the value returned for NumPhysDisks at runtime. */ #ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX #define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) @@ -1184,6 +1356,7 @@ typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 #define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) #define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) #define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) +#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080) #define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) #define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) #define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) @@ -1306,11 +1479,15 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 #define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) #define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) #define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) +#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06) #define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) /* PhysDiskAttributes defines */ +#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C) #define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) #define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) + +#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03) #define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) #define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) @@ -1329,7 +1506,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength or NumPhysDiskPaths at runtime. + * one and check the value returned for NumPhysDiskPaths at runtime. */ #ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX #define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) @@ -1382,6 +1559,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 #define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) #define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) #define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) +#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06) #define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) #define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) #define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) @@ -1406,6 +1584,13 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 /* values for PhyInfo fields */ #define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) + +#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) +#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27) +#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) + #define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) #define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) #define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) @@ -1485,7 +1670,7 @@ typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT0_PHY_MAX #define MPI2_SAS_IOUNIT0_PHY_MAX (1) @@ -1556,7 +1741,7 @@ typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT1_PHY_MAX #define MPI2_SAS_IOUNIT1_PHY_MAX (1) @@ -1618,11 +1803,11 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 /* values for SAS IO Unit Page 1 PortFlags */ #define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) -/* values for SAS IO Unit Page 2 PhyFlags */ +/* values for SAS IO Unit Page 1 PhyFlags */ #define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) #define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) -/* values for SAS IO Unit Page 0 MaxMinLinkRate */ +/* values for SAS IO Unit Page 1 MaxMinLinkRate */ #define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) #define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) #define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) @@ -1647,7 +1832,7 @@ typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * four and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT4_PHY_MAX #define MPI2_SAS_IOUNIT4_PHY_MAX (4) @@ -1681,6 +1866,202 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 #define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) +/* SAS IO Unit Page 5 */ + +typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { + U8 ControlFlags; /* 0x00 */ + U8 PortWidthModGroup; /* 0x01 */ + U16 InactivityTimerExponent; /* 0x02 */ + U8 SATAPartialTimeout; /* 0x04 */ + U8 Reserved2; /* 0x05 */ + U8 SATASlumberTimeout; /* 0x06 */ + U8 Reserved3; /* 0x07 */ + U8 SASPartialTimeout; /* 0x08 */ + U8 Reserved4; /* 0x09 */ + U8 SASSlumberTimeout; /* 0x0A */ + U8 Reserved5; /* 0x0B */ +} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, + Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t; + +/* defines for ControlFlags field */ +#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) +#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) +#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) +#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) + +/* defines for PortWidthModeGroup field */ +#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) + +/* defines for InactivityTimerExponent field */ +#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) +#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) +#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) +#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) + +#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) +#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) +#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) +#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) +#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) +#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) +#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) +#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT5_PHY_MAX +#define MPI2_SAS_IOUNIT5_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x08 */ + U8 Reserved1; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings + [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_5, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, + Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; + +#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) + + +/* SAS IO Unit Page 6 */ + +typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { + U8 CurrentStatus; /* 0x00 */ + U8 CurrentModulation; /* 0x01 */ + U8 CurrentUtilization; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 Reserved2; /* 0x04 */ +} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, + Mpi2SasIOUnit6PortWidthModGroupStatus_t, + MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t; + +/* defines for CurrentStatus field */ +#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) +#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) +#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) +#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) +#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) +#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) +#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) +#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) + +/* defines for CurrentModulation field */ +#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) +#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) +#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) +#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumGroups at runtime. + */ +#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX +#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U8 NumGroups; /* 0x10 */ + U8 Reserved3; /* 0x11 */ + U16 Reserved4; /* 0x12 */ + MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS + PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_6, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, + Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t; + +#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) + + +/* SAS IO Unit Page 7 */ + +typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { + U8 Flags; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U8 Threshold75Pct; /* 0x04 */ + U8 Threshold50Pct; /* 0x05 */ + U8 Threshold25Pct; /* 0x06 */ + U8 Reserved3; /* 0x07 */ +} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, + Mpi2SasIOUnit7PortWidthModGroupSettings_t, + MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t; + +/* defines for Flags field */ +#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) + + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumGroups at runtime. + */ +#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX +#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 SamplingInterval; /* 0x08 */ + U8 WindowLength; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U8 NumGroups; /* 0x14 */ + U8 Reserved4; /* 0x15 */ + U16 Reserved5; /* 0x16 */ + MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS + PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_7, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, + Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t; + +#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) + + +/* SAS IO Unit Page 8 */ + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 PowerManagementCapabilities;/* 0x0C */ + U32 Reserved2; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_8, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, + Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t; + +#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) + +/* defines for PowerManagementCapabilities field */ +#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x000001000) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x000000800) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x000000400) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x000000200) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x000000100) +#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x000000010) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x000000008) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x000000004) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x000000002) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x000000001) + + + + /**************************************************************************** * SAS Expander Config Pages ****************************************************************************/ @@ -1709,10 +2090,14 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 U64 ActiveZoneManagerSASAddress;/* 0x2C */ U16 ZoneLockInactivityLimit; /* 0x34 */ U16 Reserved1; /* 0x36 */ + U8 TimeToReducedFunc; /* 0x38 */ + U8 InitialTimeToReducedFunc; /* 0x39 */ + U8 MaxReducedFuncTime; /* 0x3A */ + U8 Reserved2; /* 0x3B */ } MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0, Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t; -#define MPI2_SASEXPANDER0_PAGEVERSION (0x05) +#define MPI2_SASEXPANDER0_PAGEVERSION (0x06) /* values for SAS Expander Page 0 DiscoveryStatus field */ #define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) @@ -1737,6 +2122,7 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 #define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) /* values for SAS Expander Page 0 Flags field */ +#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000) #define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000) #define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) #define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) @@ -1858,6 +2244,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 /* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ /* values for SAS Device Page 0 Flags field */ +#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) +#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) #define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) #define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) #define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) @@ -1944,6 +2332,153 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1 #define MPI2_SASPHY1_PAGEVERSION (0x01) +/* SAS PHY Page 2 */ + +typedef struct _MPI2_SASPHY2_PHY_EVENT { + U8 PhyEventCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 PhyEventInfo; /* 0x04 */ +} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT, + Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t; + +/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ + + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhyEvents at runtime. + */ +#ifndef MPI2_SASPHY2_PHY_EVENT_MAX +#define MPI2_SASPHY2_PHY_EVENT_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhyEvents; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; + /* 0x10 */ +} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, + Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t; + +#define MPI2_SASPHY2_PAGEVERSION (0x00) + + +/* SAS PHY Page 3 */ + +typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { + U8 PhyEventCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U8 CounterType; /* 0x04 */ + U8 ThresholdWindow; /* 0x05 */ + U8 TimeUnits; /* 0x06 */ + U8 Reserved3; /* 0x07 */ + U32 EventThreshold; /* 0x08 */ + U16 ThresholdFlags; /* 0x0C */ + U16 Reserved4; /* 0x0E */ +} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, + Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t; + +/* values for PhyEventCode field */ +#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00) +#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) +#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) +#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) +#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) +#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) +#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06) +#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) +#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) +#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) +#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) +#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) +#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27) +#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28) +#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) +#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A) +#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) +#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) +#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) +#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) +#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) +#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) +#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) +#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) +#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) +#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) +#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) +#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) +#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) +#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) +#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) +#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) +#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) +#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2) + +/* values for the CounterType field */ +#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) +#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01) +#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) + +/* values for the TimeUnits field */ +#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) +#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) +#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) +#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) + +/* values for the ThresholdFlags field */ +#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002) +#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumPhyEvents at runtime. + */ +#ifndef MPI2_SASPHY3_PHY_EVENT_MAX +#define MPI2_SASPHY3_PHY_EVENT_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhyEvents; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig + [MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, + Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t; + +#define MPI2_SASPHY3_PAGEVERSION (0x00) + + +/* SAS PHY Page 4 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 Reserved1; /* 0x08 */ + U8 Reserved2; /* 0x0A */ + U8 Flags; /* 0x0B */ + U8 InitialFrame[28]; /* 0x0C */ +} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, + Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t; + +#define MPI2_SASPHY4_PAGEVERSION (0x00) + +/* values for the Flags field */ +#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) +#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) + + + + /**************************************************************************** * SAS Port Config Pages ****************************************************************************/ @@ -2015,7 +2550,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumLogEntries at runtime. */ #ifndef MPI2_LOG_0_NUM_LOG_ENTRIES #define MPI2_LOG_0_NUM_LOG_ENTRIES (1) @@ -2065,7 +2600,7 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumElements at runtime. */ #ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS #define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) @@ -2147,5 +2682,122 @@ typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 #define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) +/**************************************************************************** +* Ethernet Config Pages +****************************************************************************/ + +/* Ethernet Page 0 */ + +/* IP address (union of IPv4 and IPv6) */ +typedef union _MPI2_ETHERNET_IP_ADDR { + U32 IPv4Addr; + U32 IPv6Addr[4]; +} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR, + Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t; + +#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) + +typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumInterfaces; /* 0x08 */ + U8 Reserved0; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Status; /* 0x0C */ + U8 MediaState; /* 0x10 */ + U8 Reserved2; /* 0x11 */ + U16 Reserved3; /* 0x12 */ + U8 MacAddress[6]; /* 0x14 */ + U8 Reserved4; /* 0x1A */ + U8 Reserved5; /* 0x1B */ + MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */ + MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */ + MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */ + MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */ + MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */ + MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */ + U8 HostName + [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ +} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0, + Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t; + +#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) + +/* values for Ethernet Page 0 Status field */ +#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) +#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) +#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) +#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) +#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) +#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) +#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) +#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) +#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) +#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) +#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) +#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) + +/* values for Ethernet Page 0 MediaState field */ +#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) +#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) +#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) + +#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) +#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) +#define MPI2_ETHPG0_MS_10MBIT (0x01) +#define MPI2_ETHPG0_MS_100MBIT (0x02) +#define MPI2_ETHPG0_MS_1GBIT (0x03) + + +/* Ethernet Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved0; /* 0x08 */ + U32 Flags; /* 0x0C */ + U8 MediaState; /* 0x10 */ + U8 Reserved1; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 MacAddress[6]; /* 0x14 */ + U8 Reserved3; /* 0x1A */ + U8 Reserved4; /* 0x1B */ + MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */ + MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */ + MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */ + MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */ + MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */ + U32 Reserved5; /* 0x6C */ + U32 Reserved6; /* 0x70 */ + U32 Reserved7; /* 0x74 */ + U32 Reserved8; /* 0x78 */ + U8 HostName + [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ +} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1, + Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t; + +#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) + +/* values for Ethernet Page 1 Flags field */ +#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) +#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) +#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) +#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) +#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) +#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) +#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) +#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) +#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) + +/* values for Ethernet Page 1 MediaState field */ +#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) +#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) +#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) + +#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) +#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) +#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) +#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) +#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) + + #endif diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt new file mode 100644 index 00000000000..b1e88f26b74 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt @@ -0,0 +1,384 @@ + ============================== + Fusion-MPT MPI 2.0 Header File Change History + ============================== + + Copyright (c) 2000-2010 LSI Corporation. + + --------------------------------------- + Header Set Release Version: 02.00.14 + Header Set Release Date: 10-28-09 + --------------------------------------- + + Filename Current version Prior version + ---------- --------------- ------------- + mpi2.h 02.00.14 02.00.13 + mpi2_cnfg.h 02.00.13 02.00.12 + mpi2_init.h 02.00.08 02.00.07 + mpi2_ioc.h 02.00.13 02.00.12 + mpi2_raid.h 02.00.04 02.00.04 + mpi2_sas.h 02.00.03 02.00.02 + mpi2_targ.h 02.00.03 02.00.03 + mpi2_tool.h 02.00.04 02.00.04 + mpi2_type.h 02.00.00 02.00.00 + mpi2_ra.h 02.00.00 02.00.00 + mpi2_hbd.h 02.00.00 + mpi2_history.txt 02.00.14 02.00.13 + + + * Date Version Description + * -------- -------- ------------------------------------------------------ + +mpi2.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. + * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved ReplyPostHostIndex register to offset 0x6C of the + * MPI2_SYSTEM_INTERFACE_REGS and modified the define for + * MPI2_REPLY_POST_HOST_INDEX_OFFSET. + * Added union of request descriptors. + * Added union of reply descriptors. + * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_VERSION_02_00. + * Fixed the size of the FunctionDependent5 field in the + * MPI2_DEFAULT_REPLY structure. + * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. + * Removed the MPI-defined Fault Codes and extended the + * product specific codes up to 0xEFFF. + * Added a sixth key value for the WriteSequence register + * and changed the flush value to 0x0. + * Added message function codes for Diagnostic Buffer Post + * and Diagnsotic Release. + * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED + * Moved MPI2_VERSION_UNION from mpi2_ioc.h. + * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. + * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. + * Added #defines for marking a reply descriptor as unused. + * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved LUN field defines from mpi2_init.h. + * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. + * In all request and reply descriptors, replaced VF_ID + * field with MSIxIndex field. + * Removed DevHandle field from + * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those + * bytes reserved. + * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. + * -------------------------------------------------------------------------- + +mpi2_cnfg.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. + * Added Manufacturing Page 11. + * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE + * define. + * 06-26-07 02.00.02 Adding generic structure for product-specific + * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. + * Rework of BIOS Page 2 configuration page. + * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the + * forms. + * Added configuration pages IOC Page 8 and Driver + * Persistent Mapping Page 0. + * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated + * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, + * RAID Physical Disk Pages 0 and 1, RAID Configuration + * Page 0). + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 10-31-07 02.00.04 Added missing SEPDevHandle field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for + * NVDATA. + * Modified IOC Page 7 to use masks and added field for + * SASBroadcastPrimitiveMasks. + * Added MPI2_CONFIG_PAGE_BIOS_4. + * Added MPI2_CONFIG_PAGE_LOG_0. + * 02-29-08 02.00.06 Modified various names to make them 32-character unique. + * Added SAS Device IDs. + * Updated Integrated RAID configuration pages including + * Manufacturing Page 4, IOC Page 6, and RAID Configuration + * Page 0. + * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. + * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. + * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. + * Added missing MaxNumRoutedSasAddresses field to + * MPI2_CONFIG_PAGE_EXPANDER_0. + * Added SAS Port Page 0. + * Modified structure layout for + * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. + * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use + * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. + * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF + * to 0x000000FF. + * Added two new values for the Physical Disk Coercion Size + * bits in the Flags field of Manufacturing Page 4. + * Added product-specific Manufacturing pages 16 to 31. + * Modified Flags bits for controlling write cache on SATA + * drives in IO Unit Page 1. + * Added new bit to AdditionalControlFlags of SAS IO Unit + * Page 1 to control Invalid Topology Correction. + * Added SupportedPhysDisks field to RAID Volume Page 1 and + * added related defines. + * Added additional defines for RAID Volume Page 0 + * VolumeStatusFlags field. + * Modified meaning of RAID Volume Page 0 VolumeSettings + * define for auto-configure of hot-swap drives. + * Added PhysDiskAttributes field (and related defines) to + * RAID Physical Disk Page 0. + * Added MPI2_SAS_PHYINFO_PHY_VACANT define. + * Added three new DiscoveryStatus bits for SAS IO Unit + * Page 0 and SAS Expander Page 0. + * Removed multiplexing information from SAS IO Unit pages. + * Added BootDeviceWaitTime field to SAS IO Unit Page 4. + * Removed Zone Address Resolved bit from PhyInfo and from + * Expander Page 0 Flags field. + * Added two new AccessStatus values to SAS Device Page 0 + * for indicating routing problems. Added 3 reserved words + * to this page. + * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. + * Inserted missing reserved field into structure for IOC + * Page 6. + * Added more pending task bits to RAID Volume Page 0 + * VolumeStatusFlags defines. + * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. + * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 + * and SAS Expander Page 0 to flag a downstream initiator + * when in simplified routing mode. + * Removed SATA Init Failure defines for DiscoveryStatus + * fields of SAS IO Unit Page 0 and SAS Expander Page 0. + * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. + * Added PortGroups, DmaGroup, and ControlGroup fields to + * SAS Device Page 0. + * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO + * Unit Page 6. + * Added expander reduced functionality data to SAS + * Expander Page 0. + * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. + * -------------------------------------------------------------------------- + +mpi2_init.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. + * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. + * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. + * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. + * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. + * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO + * Control field Task Attribute flags. + * Moved LUN field defines to mpi2.h becasue they are + * common to many structures. + * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to + * Query Asynchronous Event. + * Defined two new bits in the SlotStatus field of the SCSI + * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * -------------------------------------------------------------------------- + +mpi2_ioc.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to + * MaxTargets. + * Added TotalImageSize field to FWDownload Request. + * Added reserved words to FWUpload Request. + * 06-26-07 02.00.02 Added IR Configuration Change List Event. + * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit + * request and replaced it with + * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. + * Replaced the MinReplyQueueDepth field of the IOCFacts + * reply with MaxReplyDescriptorPostQueueDepth. + * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum + * depth for the Reply Descriptor Post Queue. + * Added SASAddress field to Initiator Device Table + * Overflow Event data. + * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING + * for SAS Initiator Device Status Change Event data. + * Modified Reason Code defines for SAS Topology Change + * List Event data, including adding a bit for PHY Vacant + * status, and adding a mask for the Reason Code. + * Added define for + * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. + * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. + * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of + * the IOCFacts Reply. + * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Moved MPI2_VERSION_UNION to mpi2.h. + * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks + * instead of enables, and added SASBroadcastPrimitiveMasks + * field. + * Added Log Entry Added Event and related structure. + * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. + * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. + * Added MaxVolumes and MaxPersistentEntries fields to + * IOCFacts reply. + * Added ProtocalFlags and IOCCapabilities fields to + * MPI2_FW_IMAGE_HEADER. + * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. + * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to + * a U16 (from a U32). + * Removed extra 's' from EventMasks name. + * 06-27-08 02.00.08 Fixed an offset in a comment. + * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. + * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and + * renamed MinReplyFrameSize to ReplyFrameSize. + * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. + * Added two new RAIDOperation values for Integrated RAID + * Operations Status Event data. + * Added four new IR Configuration Change List Event data + * ReasonCode values. + * Added two new ReasonCode defines for SAS Device Status + * Change Event data. + * Added three new DiscoveryStatus bits for the SAS + * Discovery event data. + * Added Multiplexing Status Change bit to the PhyStatus + * field of the SAS Topology Change List event data. + * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. + * BootFlags are now product-specific. + * Added defines for the indivdual signature bytes + * for MPI2_INIT_IMAGE_FOOTER. + * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. + * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR + * define. + * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE + * define. + * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. + * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. + * Added two new reason codes for SAS Device Status Change + * Event. + * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). + * -------------------------------------------------------------------------- + +mpi2_raid.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Modifications to RAID Action request and reply, + * including the Actions and ActionData. + * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. + * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that + * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT + * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. + * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. + * -------------------------------------------------------------------------- + +mpi2_sas.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit + * Control Request. + * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control + * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. + * 05-12-10 02.00.04 Modified some comments. + * -------------------------------------------------------------------------- + +mpi2_targ.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to + * BufferPostFlags field of CommandBufferPostBase Request. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 10-02-08 02.00.03 Removed NextCmdBufferOffset from + * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST. + * Target Status Send Request only takes a single SGE for + * response data. + * -------------------------------------------------------------------------- + +mpi2_tool.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release + * structures and defines. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. + * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. + * -------------------------------------------------------------------------- + +mpi2_type.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * -------------------------------------------------------------------------- + +mpi2_ra.h + * 05-06-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + +mpi2_hbd.h + * 10-28-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + + +mpi2_history.txt Parts list history + +Filename 02.00.14 02.00.13 02.00.12 +---------- -------- -------- -------- +mpi2.h 02.00.14 02.00.13 02.00.12 +mpi2_cnfg.h 02.00.13 02.00.12 02.00.11 +mpi2_init.h 02.00.08 02.00.07 02.00.07 +mpi2_ioc.h 02.00.13 02.00.12 02.00.11 +mpi2_raid.h 02.00.04 02.00.04 02.00.03 +mpi2_sas.h 02.00.03 02.00.02 02.00.02 +mpi2_targ.h 02.00.03 02.00.03 02.00.03 +mpi2_tool.h 02.00.04 02.00.04 02.00.03 +mpi2_type.h 02.00.00 02.00.00 02.00.00 +mpi2_ra.h 02.00.00 02.00.00 02.00.00 +mpi2_hbd.h 02.00.00 + +Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 +mpi2_cnfg.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 02.00.06 +mpi2_init.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.04 02.00.03 +mpi2_ioc.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 02.00.06 +mpi2_raid.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.02 02.00.02 +mpi2_sas.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01 +mpi2_targ.h 02.00.03 02.00.03 02.00.02 02.00.02 02.00.02 02.00.02 +mpi2_tool.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 + +Filename 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_cnfg.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_init.h 02.00.02 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_ioc.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_raid.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00 +mpi2_sas.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 +mpi2_targ.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00 +mpi2_tool.h 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index f1115f0f0eb..20e6b886934 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2008 LSI Corporation. + * Copyright (c) 2000-2010 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 + * mpi2_init.h Version: 02.00.10 * * Version History * --------------- @@ -23,6 +23,16 @@ * Control field Task Attribute flags. * Moved LUN field defines to mpi2.h becasue they are * common to many structures. + * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to + * Query Asynchronous Event. + * Defined two new bits in the SlotStatus field of the SCSI + * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. + * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. * -------------------------------------------------------------------------- */ @@ -49,20 +59,6 @@ typedef struct } 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]; @@ -103,7 +99,13 @@ typedef struct _MPI2_SCSI_IO_REQUEST U8 LUN[8]; /* 0x34 */ U32 Control; /* 0x3C */ MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ + +#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */ + MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion; +#endif + MPI2_SGE_IO_UNION SGL; /* 0x60 */ + } MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST, Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t; @@ -250,6 +252,11 @@ typedef struct _MPI2_SCSI_IO_REPLY #define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) #define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) + #define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) @@ -289,7 +296,11 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST #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) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) + +/* obsolete TaskType name */ +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \ + (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT) /* MsgFlags bits */ @@ -319,6 +330,7 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY U16 IOCStatus; /* 0x0E */ U32 IOCLogInfo; /* 0x10 */ U32 TerminationCount; /* 0x14 */ + U32 ResponseInfo; /* 0x18 */ } MPI2_SCSI_TASK_MANAGE_REPLY, MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY, Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t; @@ -331,8 +343,20 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY #define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) #define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) #define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) #define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) + /**************************************************************************** * SCSI Enclosure Processor messages @@ -375,6 +399,8 @@ typedef struct _MPI2_SEP_REQUEST #define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) #define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) #define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) +#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) #define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) #define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) #define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) @@ -410,6 +436,8 @@ typedef struct _MPI2_SEP_REPLY #define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) #define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) #define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) +#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) #define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) #define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) #define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 8c5d81870c0..761cbdb8a03 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2009 LSI Corporation. + * Copyright (c) 2000-2010 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 + * mpi2_ioc.h Version: 02.00.15 * * Version History * --------------- @@ -79,6 +79,30 @@ * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE * define. * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. + * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. + * Added two new reason codes for SAS Device Status Change + * Event. + * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). + * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. + * Added PowerManagementControl Request structures and + * defines. + * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. + * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. * -------------------------------------------------------------------------- */ @@ -111,8 +135,10 @@ typedef struct _MPI2_IOC_INIT_REQUEST U16 MsgVersion; /* 0x0C */ U16 HeaderVersion; /* 0x0E */ U32 Reserved5; /* 0x10 */ - U32 Reserved6; /* 0x14 */ - U16 Reserved7; /* 0x18 */ + U16 Reserved6; /* 0x14 */ + U8 Reserved7; /* 0x16 */ + U8 HostMSIxVectors; /* 0x17 */ + U16 Reserved8; /* 0x18 */ U16 SystemRequestFrameSize; /* 0x1A */ U16 ReplyDescriptorPostQueueDepth; /* 0x1C */ U16 ReplyFreeQueueDepth; /* 0x1E */ @@ -207,7 +233,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY U8 MaxChainDepth; /* 0x14 */ U8 WhoInit; /* 0x15 */ U8 NumberOfPorts; /* 0x16 */ - U8 Reserved2; /* 0x17 */ + U8 MaxMSIxVectors; /* 0x17 */ U16 RequestCredit; /* 0x18 */ U16 ProductID; /* 0x1A */ U32 IOCCapabilities; /* 0x1C */ @@ -225,7 +251,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY U8 MaxVolumes; /* 0x37 */ U16 MaxDevHandle; /* 0x38 */ U16 MaxPersistentEntries; /* 0x3A */ - U32 Reserved4; /* 0x3C */ + U16 MinDevHandle; /* 0x3C */ + U16 Reserved4; /* 0x3E */ } MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY, Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t; @@ -261,12 +288,16 @@ typedef struct _MPI2_IOC_FACTS_REPLY /* ProductID field uses MPI2_FW_HEADER_PID_ */ /* IOCCapabilities */ +#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) +#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) +#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) #define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) #define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000) #define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800) #define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) #define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) #define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) +#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) #define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) #define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) #define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) @@ -427,7 +458,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY #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_TASK_SET_FULL (0x000E) /* obsolete */ #define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) #define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) #define MPI2_EVENT_SAS_DISCOVERY (0x0016) @@ -440,6 +471,10 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY #define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) #define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) #define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) +#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) +#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) +#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) +#define MPI2_EVENT_SAS_QUIESCE (0x0025) /* Log Entry Added Event data */ @@ -461,6 +496,16 @@ typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t; +/* GPIO Interrupt Event data */ + +typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT { + U8 GPIONum; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_EVENT_DATA_GPIO_INTERRUPT, + MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, + Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; + /* Hard Reset Received Event data */ typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED @@ -474,6 +519,7 @@ typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED MPI2_POINTER pMpi2EventDataHardResetReceived_t; /* Task Set Full Event data */ +/* this event is obsolete */ typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL { @@ -502,17 +548,19 @@ typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE 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) +#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) +#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) +#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) +#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F) +#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10) +#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12) /* Integrated RAID Operation Status Event data */ @@ -768,6 +816,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t; /* values for the ExpStatus field */ +#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) #define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) #define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) #define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) @@ -785,6 +834,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST #define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) #define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) #define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) +#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06) #define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) #define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) #define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) @@ -822,6 +872,91 @@ typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE #define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02) +/* SAS PHY Counter Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 PhyEventCode; /* 0x0C */ + U8 PhyNum; /* 0x0D */ + U16 Reserved2; /* 0x0E */ + U32 PhyEventInfo; /* 0x10 */ + U8 CounterType; /* 0x14 */ + U8 ThresholdWindow; /* 0x15 */ + U8 TimeUnits; /* 0x16 */ + U8 Reserved3; /* 0x17 */ + U32 EventThreshold; /* 0x18 */ + U16 ThresholdFlags; /* 0x1C */ + U16 Reserved4; /* 0x1E */ +} MPI2_EVENT_DATA_SAS_PHY_COUNTER, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, + Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t; + +/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the + * PhyEventCode field + * use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the + * CounterType field + * use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the + * TimeUnits field + * use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the + * ThresholdFlags field + * */ + + +/* SAS Quiesce Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE { + U8 ReasonCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_QUIESCE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE, + Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t; + +/* SAS Quiesce Event data ReasonCode values */ +#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) +#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) + + +/* Host Based Discovery Phy Event data */ + +typedef struct _MPI2_EVENT_HBD_PHY_SAS { + U8 Flags; /* 0x00 */ + U8 NegotiatedLinkRate; /* 0x01 */ + U8 PhyNum; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U32 Reserved1; /* 0x04 */ + U8 InitialFrame[28]; /* 0x08 */ +} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS, + Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t; + +/* values for the Flags field */ +#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) +#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) + +/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for + * the NegotiatedLinkRate field */ + +typedef union _MPI2_EVENT_HBD_DESCRIPTOR { + MPI2_EVENT_HBD_PHY_SAS Sas; +} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR, + Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t; + +typedef struct _MPI2_EVENT_DATA_HBD_PHY { + U8 DescriptorType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ + MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */ +} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY, + Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t; + +/* values for the DescriptorType field */ +#define MPI2_EVENT_HBD_DT_SAS (0x01) + + + /**************************************************************************** * EventAck message ****************************************************************************/ @@ -895,6 +1030,7 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) #define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) +#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) /* FWDownload TransactionContext Element */ @@ -1070,12 +1206,16 @@ typedef struct _MPI2_FW_IMAGE_HEADER #define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) #define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) -#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) -#define MPI2_FW_HEADER_PID_PROD_A (0x0000) +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_A (0x0000) +#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) +#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) + #define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) /* SAS */ -#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0010) +#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) +#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) /* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ @@ -1291,5 +1431,100 @@ typedef struct _MPI2_INIT_IMAGE_FOOTER #define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) +/**************************************************************************** +* PowerManagementControl message +****************************************************************************/ + +/* PowerManagementControl Request message */ +typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { + U8 Feature; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 Parameter1; /* 0x0C */ + U8 Parameter2; /* 0x0D */ + U8 Parameter3; /* 0x0E */ + U8 Parameter4; /* 0x0F */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ +} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, + Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t; + +/* defines for the Feature field */ +#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) +#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) +#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) +#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) +#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) +#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ +/* Parameter1 contains a PHY number */ +/* Parameter2 indicates power condition action using these defines */ +#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) +#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) +#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) +/* Parameter3 and Parameter4 are reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION + * Feature */ +/* Parameter1 contains SAS port width modulation group number */ +/* Parameter2 indicates IOC action using these defines */ +#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) +#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) +#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) +/* Parameter3 indicates desired modulation level using these defines */ +#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) +#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) +#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) +#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) +/* Parameter4 is reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ +/* Parameter1 indicates desired PCIe link speed using these defines */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) +#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) +#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) +/* Parameter2 indicates desired PCIe link width using these defines */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) +/* Parameter3 and Parameter4 are reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ +/* Parameter1 indicates desired IOC hardware clock speed using these defines */ +#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) +#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) +#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) +#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) +/* Parameter2, Parameter3, and Parameter4 are reserved */ + + +/* PowerManagementControl Reply message */ +typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY { + U8 Feature; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY, + Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t; + + #endif diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h index 7134816d904..bd61a7b60a2 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2008 LSI Corporation. + * Copyright (c) 2000-2010 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 + * mpi2_raid.h Version: 02.00.05 * * Version History * --------------- @@ -20,6 +20,9 @@ * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. + * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. * -------------------------------------------------------------------------- */ @@ -217,10 +220,14 @@ typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT /* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ /* defines for the VolumeCreationFlags field */ +#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000) +#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) +#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) +#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) +/* The following is an obsolete define. + * It must be shifted left 24 bits in order to set the proper bit. + */ #define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) -#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 */ @@ -254,6 +261,7 @@ typedef struct _MPI2_RAID_VOL_INDICATOR #define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) #define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) #define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) +#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) /* RAID Action Reply ActionData union */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h index 8a42b136cf5..608f6d6e6fc 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2007 LSI Corporation. + * Copyright (c) 2000-2010 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 + * mpi2_sas.h Version: 02.00.04 * * Version History * --------------- @@ -18,6 +18,9 @@ * Control Request. * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. + * 05-12-10 02.00.04 Modified some comments. * -------------------------------------------------------------------------- */ @@ -108,7 +111,7 @@ typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST /* 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 */ +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ /* SMP Passthrough Reply Message */ @@ -160,7 +163,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST U32 Reserved4; /* 0x14 */ U32 DataLength; /* 0x18 */ U8 CommandFIS[20]; /* 0x1C */ - MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ + MPI2_SGE_IO_UNION SGL; /* 0x20 */ } MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; @@ -172,7 +175,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST #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 */ +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ /* SATA Passthrough Reply Message */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 2ff4e936bd3..5c6e3a67bb9 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2008 LSI Corporation. + * Copyright (c) 2000-2010 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 + * mpi2_tool.h Version: 02.00.05 * * Version History * --------------- @@ -17,6 +17,12 @@ * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release * structures and defines. * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. + * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. * -------------------------------------------------------------------------- */ @@ -32,7 +38,11 @@ /* defines for the Tools */ #define MPI2_TOOLBOX_CLEAN_TOOL (0x00) #define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) +#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) +#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) #define MPI2_TOOLBOX_BEACON_TOOL (0x05) +#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) + /**************************************************************************** * Toolbox reply @@ -94,8 +104,7 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST * Toolbox Memory Move request ****************************************************************************/ -typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST -{ +typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST { U8 Tool; /* 0x00 */ U8 Reserved1; /* 0x01 */ U8 ChainOffset; /* 0x02 */ @@ -112,6 +121,115 @@ typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST /**************************************************************************** +* Toolbox Diagnostic Data Upload request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST { + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 SGLFlags; /* 0x0C */ + U8 Reserved5; /* 0x0D */ + U16 Reserved6; /* 0x0E */ + U32 Flags; /* 0x10 */ + U32 DataLength; /* 0x14 */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */ +} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, +MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, +Mpi2ToolboxDiagDataUploadRequest_t, +MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t; + +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + +typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER { + U32 DiagDataLength; /* 00h */ + U8 FormatCode; /* 04h */ + U8 Reserved1; /* 05h */ + U16 Reserved2; /* 06h */ +} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER, +Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t; + + +/**************************************************************************** +* Toolbox ISTWI Read Write Tool +****************************************************************************/ + +/* Toolbox ISTWI Read Write Tool request message */ +typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + U8 DevIndex; /* 0x14 */ + U8 Action; /* 0x15 */ + U8 SGLFlags; /* 0x16 */ + U8 Reserved7; /* 0x17 */ + U16 TxDataLength; /* 0x18 */ + U16 RxDataLength; /* 0x1A */ + U32 Reserved8; /* 0x1C */ + U32 Reserved9; /* 0x20 */ + U32 Reserved10; /* 0x24 */ + U32 Reserved11; /* 0x28 */ + U32 Reserved12; /* 0x2C */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */ +} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + Mpi2ToolboxIstwiReadWriteRequest_t, + MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t; + +/* values for the Action field */ +#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01) +#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02) +#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03) +#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10) +#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) +#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) + +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + +/* Toolbox ISTWI Read Write Tool reply message */ +typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 DevIndex; /* 0x14 */ + U8 Action; /* 0x15 */ + U8 IstwiStatus; /* 0x16 */ + U8 Reserved6; /* 0x17 */ + U16 TxDataCount; /* 0x18 */ + U16 RxDataCount; /* 0x1A */ +} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY, + Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t; + + +/**************************************************************************** * Toolbox Beacon Tool request ****************************************************************************/ @@ -139,6 +257,61 @@ typedef struct _MPI2_TOOLBOX_BEACON_REQUEST #define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01) +/**************************************************************************** +* Toolbox Diagnostic CLI Tool +****************************************************************************/ + +#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C) + +/* Toolbox Diagnostic CLI Tool request message */ +typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST { + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 SGLFlags; /* 0x0C */ + U8 Reserved5; /* 0x0D */ + U16 Reserved6; /* 0x0E */ + U32 DataLength; /* 0x10 */ + U8 DiagnosticCliCommand + [MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x70 */ +} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, + Mpi2ToolboxDiagnosticCliRequest_t, + MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; + +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ + + +/* Toolbox Diagnostic CLI Tool reply message */ +typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY { + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ReturnedDataLength; /* 0x14 */ +} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, + MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, + Mpi2ToolboxDiagnosticCliReply_t, + MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t; + + /***************************************************************************** * * Diagnostic Buffer Messages @@ -152,7 +325,7 @@ typedef struct _MPI2_TOOLBOX_BEACON_REQUEST typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST { - U8 Reserved1; /* 0x00 */ + U8 ExtendedType; /* 0x00 */ U8 BufferType; /* 0x01 */ U8 ChainOffset; /* 0x02 */ U8 Function; /* 0x03 */ @@ -171,11 +344,15 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST } MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST, Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t; +/* values for the ExtendedType field */ +#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) + /* values for the BufferType field */ #define MPI2_DIAG_BUF_TYPE_TRACE (0x00) #define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) +#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) /* count of the number of buffer types */ -#define MPI2_DIAG_BUF_TYPE_COUNT (0x02) +#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) /**************************************************************************** @@ -184,7 +361,7 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST typedef struct _MPI2_DIAG_BUFFER_POST_REPLY { - U8 Reserved1; /* 0x00 */ + U8 ExtendedType; /* 0x00 */ U8 BufferType; /* 0x01 */ U8 MsgLength; /* 0x02 */ U8 Function; /* 0x03 */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index f3da592f7bc..b2a817055b8 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3,7 +3,7 @@ * for access to MPT (Message Passing Technology) firmware. * * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2008 LSI Corporation + * Copyright (C) 2007-2010 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * * This program is free software; you can redistribute it and/or @@ -57,13 +57,14 @@ #include <linux/dma-mapping.h> #include <linux/sort.h> #include <linux/io.h> +#include <linux/time.h> +#include <linux/aer.h> #include "mpt2sas_base.h" static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; #define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ -#define MPT2SAS_MAX_REQUEST_QUEUE 500 /* maximum controller queue depth */ static int max_queue_depth = -1; module_param(max_queue_depth, int, 0); @@ -77,6 +78,51 @@ static int msix_disable = -1; module_param(msix_disable, int, 0); MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); +static int missing_delay[2] = {-1, -1}; +module_param_array(missing_delay, int, NULL, 0); +MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); + +/* diag_buffer_enable is bitwise + * bit 0 set = TRACE + * bit 1 set = SNAPSHOT + * bit 2 set = EXTENDED + * + * Either bit can be set, or both + */ +static int diag_buffer_enable; +module_param(diag_buffer_enable, int, 0); +MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " + "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); + +int mpt2sas_fwfault_debug; +MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " + "and halt firmware - (default=0)"); + +static int disable_discovery = -1; +module_param(disable_discovery, int, 0); +MODULE_PARM_DESC(disable_discovery, " disable discovery "); + +/** + * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. + * + */ +static int +_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) +{ + int ret = param_set_int(val, kp); + struct MPT2SAS_ADAPTER *ioc; + + if (ret) + return ret; + + printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); + list_for_each_entry(ioc, &mpt2sas_ioc_list, list) + ioc->fwfault_debug = mpt2sas_fwfault_debug; + return 0; +} +module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, + param_get_int, &mpt2sas_fwfault_debug, 0644); + /** * _base_fault_reset_work - workq handling ioc fault conditions * @work: input argument, used to derive ioc @@ -94,7 +140,7 @@ _base_fault_reset_work(struct work_struct *work) int rc; spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->ioc_reset_in_progress) + if (ioc->shost_recovery) goto rearm_timer; spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); @@ -119,10 +165,113 @@ _base_fault_reset_work(struct work_struct *work) spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); } +/** + * mpt2sas_base_start_watchdog - start the fault_reset_work_q + * @ioc: per adapter object + * Context: sleep. + * + * Return nothing. + */ +void +mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc) +{ + unsigned long flags; + + if (ioc->fault_reset_work_q) + return; + + /* initialize fault polling */ + INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); + snprintf(ioc->fault_reset_work_q_name, + sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id); + ioc->fault_reset_work_q = + create_singlethread_workqueue(ioc->fault_reset_work_q_name); + if (!ioc->fault_reset_work_q) { + printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n", + ioc->name, __func__, __LINE__); + return; + } + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->fault_reset_work_q) + queue_delayed_work(ioc->fault_reset_work_q, + &ioc->fault_reset_work, + msecs_to_jiffies(FAULT_POLLING_INTERVAL)); + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); +} + +/** + * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q + * @ioc: per adapter object + * Context: sleep. + * + * Return nothing. + */ +void +mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc) +{ + unsigned long flags; + struct workqueue_struct *wq; + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + wq = ioc->fault_reset_work_q; + ioc->fault_reset_work_q = NULL; + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + if (wq) { + if (!cancel_delayed_work(&ioc->fault_reset_work)) + flush_workqueue(wq); + destroy_workqueue(wq); + } +} + +/** + * mpt2sas_base_fault_info - verbose translation of firmware FAULT code + * @ioc: per adapter object + * @fault_code: fault code + * + * Return nothing. + */ +void +mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code) +{ + printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n", + ioc->name, fault_code); +} + +/** + * mpt2sas_halt_firmware - halt's mpt controller firmware + * @ioc: per adapter object + * + * For debugging timeout related issues. Writing 0xCOFFEE00 + * to the doorbell register will halt controller firmware. With + * the purpose to stop both driver and firmware, the enduser can + * obtain a ring buffer from controller UART. + */ +void +mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc) +{ + u32 doorbell; + + if (!ioc->fwfault_debug) + return; + + dump_stack(); + + doorbell = readl(&ioc->chip->Doorbell); + if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) + mpt2sas_base_fault_info(ioc , doorbell); + else { + writel(0xC0FFEE00, &ioc->chip->Doorbell); + printk(MPT2SAS_ERR_FMT "Firmware is halted due to command " + "timeout\n", ioc->name); + } + + panic("panic in %s\n", __func__); +} + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING /** * _base_sas_ioc_info - verbose translation of the ioc status - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware * @request_hdr: request mf * @@ -144,6 +293,9 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) return; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + return; + switch (ioc_status) { /**************************************************************************** @@ -336,7 +488,7 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, /** * _base_display_event_data - verbose translation of firmware asyn events - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware * * Return nothing. @@ -366,9 +518,6 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, case MPI2_EVENT_EVENT_CHANGE: desc = "Event Change"; break; - case MPI2_EVENT_TASK_SET_FULL: - desc = "Task Set Full"; - break; case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: desc = "Device Status Change"; break; @@ -376,8 +525,18 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, desc = "IR Operation Status"; break; case MPI2_EVENT_SAS_DISCOVERY: - desc = "Discovery"; - break; + { + Mpi2EventDataSasDiscovery_t *event_data = + (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; + printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name, + (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? + "start" : "stop"); + if (event_data->DiscoveryStatus) + printk("discovery_status(0x%08x)", + le32_to_cpu(event_data->DiscoveryStatus)); + printk("\n"); + return; + } case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: desc = "SAS Broadcast Primitive"; break; @@ -416,7 +575,7 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, /** * _base_sas_log_info - verbose translation of firmware log info - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @log_info: log info * * Return nothing. @@ -440,6 +599,10 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) if (sas_loginfo.dw.bus_type != 3 /*SAS*/) return; + /* each nexus loss loginfo */ + if (log_info == 0x31170000) + return; + /* eat the loginfos associated with task aborts */ if (ioc->ignore_loginfos && (log_info == 30050000 || log_info == 0x31140000 || log_info == 0x31130000)) @@ -464,30 +627,16 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) } /** - * mpt2sas_base_fault_info - verbose translation of firmware FAULT code - * @ioc: pointer to scsi command object - * @fault_code: fault code - * - * Return nothing. - */ -void -mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code) -{ - printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n", - ioc->name, fault_code); -} - -/** * _base_display_reply_info - - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * * Return nothing. */ static void -_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, +_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) { MPI2DefaultReply_t *mpi_reply; @@ -508,24 +657,26 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, /** * mpt2sas_base_done - base internal command completion routine - * @ioc: pointer to scsi command object + * @ioc: per adapter object * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -void -mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +u8 +mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + u32 reply) { MPI2DefaultReply_t *mpi_reply; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) - return; + return 1; if (ioc->base_cmds.status == MPT2_CMD_NOT_USED) - return; + return 1; ioc->base_cmds.status |= MPT2_CMD_COMPLETE; if (mpi_reply) { @@ -534,18 +685,20 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) } ioc->base_cmds.status &= ~MPT2_CMD_PENDING; complete(&ioc->base_cmds.done); + return 1; } /** * _base_async_event - main callback handler for firmware asyn events - * @ioc: pointer to scsi command object - * @VF_ID: virtual function id + * @ioc: per adapter object + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -static void -_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +static u8 +_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply) { Mpi2EventNotificationReply_t *mpi_reply; Mpi2EventAckRequest_t *ack_request; @@ -553,9 +706,9 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); if (!mpi_reply) - return; + return 1; if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) - return; + return 1; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING _base_display_event_data(ioc, mpi_reply); #endif @@ -573,21 +726,52 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) ack_request->Function = MPI2_FUNCTION_EVENT_ACK; ack_request->Event = mpi_reply->Event; ack_request->EventContext = mpi_reply->EventContext; - ack_request->VF_ID = VF_ID; - mpt2sas_base_put_smid_default(ioc, smid, VF_ID); + ack_request->VF_ID = 0; /* TODO */ + ack_request->VP_ID = 0; + mpt2sas_base_put_smid_default(ioc, smid); out: /* scsih callback handler */ - mpt2sas_scsih_event_callback(ioc, VF_ID, reply); + mpt2sas_scsih_event_callback(ioc, msix_index, reply); /* ctl callback handler */ - mpt2sas_ctl_event_callback(ioc, VF_ID, reply); + mpt2sas_ctl_event_callback(ioc, msix_index, reply); + + return 1; +} + +/** + * _base_get_cb_idx - obtain the callback index + * @ioc: per adapter object + * @smid: system request message index + * + * Return callback index. + */ +static u8 +_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + int i; + u8 cb_idx = 0xFF; + + if (smid >= ioc->hi_priority_smid) { + if (smid < ioc->internal_smid) { + i = smid - ioc->hi_priority_smid; + cb_idx = ioc->hpr_lookup[i].cb_idx; + } else if (smid <= ioc->hba_queue_depth) { + i = smid - ioc->internal_smid; + cb_idx = ioc->internal_lookup[i].cb_idx; + } + } else { + i = smid - 1; + cb_idx = ioc->scsi_lookup[i].cb_idx; + } + return cb_idx; } /** * _base_mask_interrupts - disable interrupts - * @ioc: pointer to scsi command object + * @ioc: per adapter object * * Disabling ResetIRQ, Reply and Doorbell Interrupts * @@ -607,7 +791,7 @@ _base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc) /** * _base_unmask_interrupts - enable interrupts - * @ioc: pointer to scsi command object + * @ioc: per adapter object * * Enabling only Reply Interrupts * @@ -618,13 +802,20 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc) { u32 him_register; - writel(0, &ioc->chip->HostInterruptStatus); him_register = readl(&ioc->chip->HostInterruptMask); him_register &= ~MPI2_HIM_RIM; writel(him_register, &ioc->chip->HostInterruptMask); ioc->mask_interrupts = 0; } +union reply_descriptor { + u64 word; + struct { + u32 low; + u32 high; + } u; +}; + /** * _base_interrupt - MPT adapter (IOC) specific interrupt handler. * @irq: irq number (not used) @@ -636,47 +827,43 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc) static irqreturn_t _base_interrupt(int irq, void *bus_id) { - union reply_descriptor { - u64 word; - struct { - u32 low; - u32 high; - } u; - }; union reply_descriptor rd; - u32 post_index, post_index_next, completed_cmds; + u32 completed_cmds; u8 request_desript_type; u16 smid; u8 cb_idx; u32 reply; - u8 VF_ID; - int i; + u8 msix_index; struct MPT2SAS_ADAPTER *ioc = bus_id; + Mpi2ReplyDescriptorsUnion_t *rpf; + u8 rc; if (ioc->mask_interrupts) return IRQ_NONE; - post_index = ioc->reply_post_host_index; - request_desript_type = ioc->reply_post_free[post_index]. - Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + rpf = &ioc->reply_post_free[ioc->reply_post_host_index]; + request_desript_type = rpf->Default.ReplyFlags + & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) return IRQ_NONE; completed_cmds = 0; + cb_idx = 0xFF; do { - rd.word = ioc->reply_post_free[post_index].Words; + rd.word = rpf->Words; if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) goto out; reply = 0; cb_idx = 0xFF; - smid = le16_to_cpu(ioc->reply_post_free[post_index]. - Default.DescriptorTypeDependent1); - VF_ID = ioc->reply_post_free[post_index]. - Default.VF_ID; + smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); + msix_index = rpf->Default.MSIxIndex; if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { - reply = le32_to_cpu(ioc->reply_post_free[post_index]. - AddressReply.ReplyFrameAddress); + reply = le32_to_cpu + (rpf->AddressReply.ReplyFrameAddress); + if (reply > ioc->reply_dma_max_address || + reply < ioc->reply_dma_min_address) + reply = 0; } else if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER) goto next; @@ -684,16 +871,18 @@ _base_interrupt(int irq, void *bus_id) MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS) goto next; if (smid) - cb_idx = ioc->scsi_lookup[smid - 1].cb_idx; + cb_idx = _base_get_cb_idx(ioc, smid); if (smid && cb_idx != 0xFF) { - mpt_callbacks[cb_idx](ioc, smid, VF_ID, reply); + rc = mpt_callbacks[cb_idx](ioc, smid, msix_index, + reply); if (reply) - _base_display_reply_info(ioc, smid, VF_ID, + _base_display_reply_info(ioc, smid, msix_index, reply); - mpt2sas_base_free_smid(ioc, smid); + if (rc) + mpt2sas_base_free_smid(ioc, smid); } if (!smid) - _base_async_event(ioc, VF_ID, reply); + _base_async_event(ioc, msix_index, reply); /* reply free queue handling */ if (reply) { @@ -703,21 +892,27 @@ _base_interrupt(int irq, void *bus_id) 0 : ioc->reply_free_host_index + 1; ioc->reply_free[ioc->reply_free_host_index] = cpu_to_le32(reply); + wmb(); writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); - wmb(); } next: - post_index_next = (post_index == (ioc->reply_post_queue_depth - - 1)) ? 0 : post_index + 1; + + rpf->Words = ULLONG_MAX; + ioc->reply_post_host_index = (ioc->reply_post_host_index == + (ioc->reply_post_queue_depth - 1)) ? 0 : + ioc->reply_post_host_index + 1; request_desript_type = - ioc->reply_post_free[post_index_next].Default.ReplyFlags - & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + ioc->reply_post_free[ioc->reply_post_host_index].Default. + ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; completed_cmds++; if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) goto out; - post_index = post_index_next; + if (!ioc->reply_post_host_index) + rpf = ioc->reply_post_free; + else + rpf++; } while (1); out: @@ -725,19 +920,8 @@ _base_interrupt(int irq, void *bus_id) if (!completed_cmds) return IRQ_NONE; - /* reply post descriptor handling */ - post_index_next = ioc->reply_post_host_index; - for (i = 0 ; i < completed_cmds; i++) { - post_index = post_index_next; - /* poison the reply post descriptor */ - ioc->reply_post_free[post_index_next].Words = ULLONG_MAX; - post_index_next = (post_index == - (ioc->reply_post_queue_depth - 1)) - ? 0 : post_index + 1; - } - ioc->reply_post_host_index = post_index_next; - writel(post_index_next, &ioc->chip->ReplyPostHostIndex); wmb(); + writel(ioc->reply_post_host_index, &ioc->chip->ReplyPostHostIndex); return IRQ_HANDLED; } @@ -1059,8 +1243,10 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) u32 memap_sz; u32 pio_sz; int i, r = 0; + u64 pio_chip = 0; + u64 chip_phys = 0; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); @@ -1079,6 +1265,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) goto out_fail; } + /* AER (Advanced Error Reporting) hooks */ + pci_enable_pcie_error_reporting(pdev); + pci_set_master(pdev); if (_base_config_dma_addressing(ioc, pdev) != 0) { @@ -1089,27 +1278,30 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) } for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { - if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { + if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { if (pio_sz) continue; - ioc->pio_chip = pci_resource_start(pdev, i); + pio_chip = (u64)pci_resource_start(pdev, i); pio_sz = pci_resource_len(pdev, i); } else { if (memap_sz) continue; - ioc->chip_phys = pci_resource_start(pdev, i); - memap_sz = pci_resource_len(pdev, i); - ioc->chip = ioremap(ioc->chip_phys, memap_sz); - if (ioc->chip == NULL) { - printk(MPT2SAS_ERR_FMT "unable to map adapter " - "memory!\n", ioc->name); - r = -EINVAL; - goto out_fail; + /* verify memory resource is valid before using */ + if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { + ioc->chip_phys = pci_resource_start(pdev, i); + chip_phys = (u64)ioc->chip_phys; + memap_sz = pci_resource_len(pdev, i); + ioc->chip = ioremap(ioc->chip_phys, memap_sz); + if (ioc->chip == NULL) { + printk(MPT2SAS_ERR_FMT "unable to map " + "adapter memory!\n", ioc->name); + r = -EINVAL; + goto out_fail; + } } } } - pci_set_drvdata(pdev, ioc->shost); _base_mask_interrupts(ioc); r = _base_enable_msix(ioc); if (r) @@ -1118,10 +1310,13 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", ioc->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : "IO-APIC enabled"), ioc->pci_irq); - printk(MPT2SAS_INFO_FMT "iomem(0x%lx), mapped(0x%p), size(%d)\n", - ioc->name, ioc->chip_phys, ioc->chip, memap_sz); - printk(MPT2SAS_INFO_FMT "ioport(0x%lx), size(%d)\n", - ioc->name, ioc->pio_chip, pio_sz); + printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", + ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); + printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", + ioc->name, (unsigned long long)pio_chip, pio_sz); + + /* Save PCI configuration state for recovery from PCI AER/EEH errors */ + pci_save_state(pdev); return 0; @@ -1131,25 +1326,12 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) ioc->chip_phys = 0; ioc->pci_irq = -1; pci_release_selected_regions(ioc->pdev, ioc->bars); + pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); return r; } /** - * mpt2sas_base_get_msg_frame_dma - obtain request mf pointer phys addr - * @ioc: per adapter object - * @smid: system request message index(smid zero is invalid) - * - * Returns phys pointer to message frame. - */ -dma_addr_t -mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return ioc->request_dma + (smid * ioc->request_sz); -} - -/** * mpt2sas_base_get_msg_frame - obtain request mf pointer * @ioc: per adapter object * @smid: system request message index(smid zero is invalid) @@ -1180,12 +1362,13 @@ mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) * @ioc: per adapter object * @smid: system request message index * - * Returns phys pointer to sense buffer. + * Returns phys pointer to the low 32bit address of the sense buffer. */ -dma_addr_t +__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) { - return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE); + return cpu_to_le32(ioc->sense_dma + + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); } /** @@ -1204,7 +1387,7 @@ mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr) } /** - * mpt2sas_base_get_smid - obtain a free smid + * mpt2sas_base_get_smid - obtain a free smid from internal queue * @ioc: per adapter object * @cb_idx: callback index * @@ -1218,6 +1401,39 @@ mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) u16 smid; spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + if (list_empty(&ioc->internal_free_list)) { + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + printk(MPT2SAS_ERR_FMT "%s: smid not available\n", + ioc->name, __func__); + return 0; + } + + request = list_entry(ioc->internal_free_list.next, + struct request_tracker, tracker_list); + request->cb_idx = cb_idx; + smid = request->smid; + list_del(&request->tracker_list); + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return smid; +} + +/** + * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue + * @ioc: per adapter object + * @cb_idx: callback index + * @scmd: pointer to scsi command object + * + * Returns smid (zero is invalid) + */ +u16 +mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, + struct scsi_cmnd *scmd) +{ + unsigned long flags; + struct request_tracker *request; + u16 smid; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); if (list_empty(&ioc->free_list)) { spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); printk(MPT2SAS_ERR_FMT "%s: smid not available\n", @@ -1227,6 +1443,36 @@ mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) request = list_entry(ioc->free_list.next, struct request_tracker, tracker_list); + request->scmd = scmd; + request->cb_idx = cb_idx; + smid = request->smid; + list_del(&request->tracker_list); + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return smid; +} + +/** + * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue + * @ioc: per adapter object + * @cb_idx: callback index + * + * Returns smid (zero is invalid) + */ +u16 +mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) +{ + unsigned long flags; + struct request_tracker *request; + u16 smid; + + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + if (list_empty(&ioc->hpr_free_list)) { + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return 0; + } + + request = list_entry(ioc->hpr_free_list.next, + struct request_tracker, tracker_list); request->cb_idx = cb_idx; smid = request->smid; list_del(&request->tracker_list); @@ -1246,10 +1492,41 @@ void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) { unsigned long flags; + int i; + struct chain_tracker *chain_req, *next; spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - ioc->scsi_lookup[smid - 1].cb_idx = 0xFF; - list_add_tail(&ioc->scsi_lookup[smid - 1].tracker_list, + if (smid >= ioc->hi_priority_smid) { + if (smid < ioc->internal_smid) { + /* hi-priority */ + i = smid - ioc->hi_priority_smid; + ioc->hpr_lookup[i].cb_idx = 0xFF; + list_add_tail(&ioc->hpr_lookup[i].tracker_list, + &ioc->hpr_free_list); + } else { + /* internal queue */ + i = smid - ioc->internal_smid; + ioc->internal_lookup[i].cb_idx = 0xFF; + list_add_tail(&ioc->internal_lookup[i].tracker_list, + &ioc->internal_free_list); + } + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return; + } + + /* scsiio queue */ + i = smid - 1; + if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { + list_for_each_entry_safe(chain_req, next, + &ioc->scsi_lookup[i].chain_list, tracker_list) { + list_del_init(&chain_req->tracker_list); + list_add_tail(&chain_req->tracker_list, + &ioc->free_chain_list); + } + } + ioc->scsi_lookup[i].cb_idx = 0xFF; + ioc->scsi_lookup[i].scmd = NULL; + list_add_tail(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -1298,21 +1575,19 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr, * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware * @ioc: per adapter object * @smid: system request message index - * @vf_id: virtual function id * @handle: device handle * * Return nothing. */ void -mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id, - u16 handle) +mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle) { Mpi2RequestDescriptorUnion_t descriptor; u64 *request = (u64 *)&descriptor; descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.SCSIIO.VF_ID = vf_id; + descriptor.SCSIIO.MSIxIndex = 0; /* TODO */ descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -1325,20 +1600,18 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id, * mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware * @ioc: per adapter object * @smid: system request message index - * @vf_id: virtual function id * * Return nothing. */ void -mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 vf_id) +mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid) { Mpi2RequestDescriptorUnion_t descriptor; u64 *request = (u64 *)&descriptor; descriptor.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; - descriptor.HighPriority.VF_ID = vf_id; + descriptor.HighPriority.MSIxIndex = 0; /* TODO */ descriptor.HighPriority.SMID = cpu_to_le16(smid); descriptor.HighPriority.LMID = 0; descriptor.HighPriority.Reserved1 = 0; @@ -1350,18 +1623,17 @@ mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, * mpt2sas_base_put_smid_default - Default, primarily used for config pages * @ioc: per adapter object * @smid: system request message index - * @vf_id: virtual function id * * Return nothing. */ void -mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id) +mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid) { Mpi2RequestDescriptorUnion_t descriptor; u64 *request = (u64 *)&descriptor; descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.Default.VF_ID = vf_id; + descriptor.Default.MSIxIndex = 0; /* TODO */ descriptor.Default.SMID = cpu_to_le16(smid); descriptor.Default.LMID = 0; descriptor.Default.DescriptorTypeDependent = 0; @@ -1373,21 +1645,20 @@ mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id) * mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware * @ioc: per adapter object * @smid: system request message index - * @vf_id: virtual function id * @io_index: value used to track the IO * * Return nothing. */ void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 vf_id, u16 io_index) + u16 io_index) { Mpi2RequestDescriptorUnion_t descriptor; u64 *request = (u64 *)&descriptor; descriptor.SCSITarget.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; - descriptor.SCSITarget.VF_ID = vf_id; + descriptor.SCSITarget.MSIxIndex = 0; /* TODO */ descriptor.SCSITarget.SMID = cpu_to_le16(smid); descriptor.SCSITarget.LMID = 0; descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index); @@ -1482,6 +1753,8 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8, ioc->bios_pg3.BiosVersion & 0x000000FF); + _base_display_dell_branding(ioc); + printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { @@ -1494,8 +1767,6 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) i++; } - _base_display_dell_branding(ioc); - i = 0; printk("), "); printk("Capabilities=("); @@ -1540,6 +1811,12 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) } if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { + printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : ""); + i++; + } + + if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { printk("%sTask Set Full", i ? "," : ""); i++; @@ -1555,6 +1832,97 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) } /** + * _base_update_missing_delay - change the missing delay timers + * @ioc: per adapter object + * @device_missing_delay: amount of time till device is reported missing + * @io_missing_delay: interval IO is returned when there is a missing device + * + * Return nothing. + * + * Passed on the command line, this function will modify the device missing + * delay, as well as the io missing delay. This should be called at driver + * load time. + */ +static void +_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc, + u16 device_missing_delay, u8 io_missing_delay) +{ + u16 dmd, dmd_new, dmd_orignal; + u8 io_missing_delay_original; + u16 sz; + Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2ConfigReply_t mpi_reply; + u8 num_phys = 0; + u16 ioc_status; + + mpt2sas_config_get_number_hba_phys(ioc, &num_phys); + if (!num_phys) + return; + + sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys * + sizeof(Mpi2SasIOUnit1PhyData_t)); + sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg1) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, + sas_iounit_pg1, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + /* device missing delay */ + dmd = sas_iounit_pg1->ReportDeviceMissingDelay; + if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) + dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; + else + dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; + dmd_orignal = dmd; + if (device_missing_delay > 0x7F) { + dmd = (device_missing_delay > 0x7F0) ? 0x7F0 : + device_missing_delay; + dmd = dmd / 16; + dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16; + } else + dmd = device_missing_delay; + sas_iounit_pg1->ReportDeviceMissingDelay = dmd; + + /* io missing delay */ + io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay; + sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay; + + if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, + sz)) { + if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) + dmd_new = (dmd & + MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; + else + dmd_new = + dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; + printk(MPT2SAS_INFO_FMT "device_missing_delay: old(%d), " + "new(%d)\n", ioc->name, dmd_orignal, dmd_new); + printk(MPT2SAS_INFO_FMT "ioc_missing_delay: old(%d), " + "new(%d)\n", ioc->name, io_missing_delay_original, + io_missing_delay); + ioc->device_missing_delay = dmd_new; + ioc->io_missing_delay = io_missing_delay; + } + +out: + kfree(sas_iounit_pg1); +} + +/** * _base_static_config_pages - static start of day config pages * @ioc: per adapter object * @@ -1567,6 +1935,9 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) u32 iounit_pg1_flags; mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); + if (ioc->ir_firmware) + mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply, + &ioc->manu_pg10); mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); @@ -1587,7 +1958,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) iounit_pg1_flags |= MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); - mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, ioc->iounit_pg1); + mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); + } /** @@ -1601,7 +1973,9 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) static void _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) { - dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + int i; + + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); if (ioc->request) { @@ -1659,7 +2033,26 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) ioc->config_page, ioc->config_page_dma); } - kfree(ioc->scsi_lookup); + if (ioc->scsi_lookup) { + free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); + ioc->scsi_lookup = NULL; + } + kfree(ioc->hpr_lookup); + kfree(ioc->internal_lookup); + if (ioc->chain_lookup) { + for (i = 0; i < ioc->chain_depth; i++) { + if (ioc->chain_lookup[i].chain_buffer) + pci_pool_free(ioc->chain_dma_pool, + ioc->chain_lookup[i].chain_buffer, + ioc->chain_lookup[i].chain_buffer_dma); + } + if (ioc->chain_dma_pool) + pci_pool_destroy(ioc->chain_dma_pool); + } + if (ioc->chain_lookup) { + free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); + ioc->chain_lookup = NULL; + } } @@ -1679,11 +2072,11 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) u16 num_of_reply_frames; u16 chains_needed_per_io; u32 sz, total_sz; - u16 i; u32 retry_sz; u16 max_request_credit; + int i; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); retry_sz = 0; @@ -1699,15 +2092,15 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } /* command line tunables for max controller queue depth */ - if (max_queue_depth != -1) { + if (max_queue_depth != -1) max_request_credit = (max_queue_depth < facts->RequestCredit) ? max_queue_depth : facts->RequestCredit; - } else { - max_request_credit = (facts->RequestCredit > - MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE : - facts->RequestCredit; - } - ioc->request_depth = max_request_credit; + else + max_request_credit = facts->RequestCredit; + + ioc->hba_queue_depth = max_request_credit; + ioc->hi_priority_depth = facts->HighPriorityCredit; + ioc->internal_depth = ioc->hi_priority_depth + 5; /* request frame size */ ioc->request_sz = facts->IOCRequestFrameSize * 4; @@ -1745,7 +2138,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) ioc->chains_needed_per_io = chains_needed_per_io; /* reply free queue sizing - taking into account for events */ - num_of_reply_frames = ioc->request_depth + 32; + num_of_reply_frames = ioc->hba_queue_depth + 32; /* number of replies frames can't be a multiple of 16 */ /* decrease number of reply frames by 1 */ @@ -1766,7 +2159,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) * frames */ - queue_size = ioc->request_depth + num_of_reply_frames + 1; + queue_size = ioc->hba_queue_depth + num_of_reply_frames + 1; /* round up to 16 byte boundary */ if (queue_size % 16) queue_size += 16 - (queue_size % 16); @@ -1780,82 +2173,159 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (queue_diff % 16) queue_diff += 16 - (queue_diff % 16); - /* adjust request_depth, reply_free_queue_depth, + /* adjust hba_queue_depth, reply_free_queue_depth, * and queue_size */ - ioc->request_depth -= queue_diff; + ioc->hba_queue_depth -= queue_diff; ioc->reply_free_queue_depth -= queue_diff; queue_size -= queue_diff; } ioc->reply_post_queue_depth = queue_size; - /* max scsi host queue depth */ - ioc->shost->can_queue = ioc->request_depth - INTERNAL_CMDS_COUNT; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host queue: depth" - "(%d)\n", ioc->name, ioc->shost->can_queue)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: " "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message, ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize, ioc->chains_needed_per_io)); + ioc->scsiio_depth = ioc->hba_queue_depth - + ioc->hi_priority_depth - ioc->internal_depth; + + /* set the scsi host can_queue depth + * with some internal commands that could be outstanding + */ + ioc->shost->can_queue = ioc->scsiio_depth - (2); + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: " + "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); + /* contiguous pool for request and chains, 16 byte align, one extra " * "frame for smid=0 */ - ioc->chain_depth = ioc->chains_needed_per_io * ioc->request_depth; - sz = ((ioc->request_depth + 1 + ioc->chain_depth) * ioc->request_sz); + ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; + sz = ((ioc->scsiio_depth + 1) * ioc->request_sz); + + /* hi-priority queue */ + sz += (ioc->hi_priority_depth * ioc->request_sz); + + /* internal queue */ + sz += (ioc->internal_depth * ioc->request_sz); ioc->request_dma_sz = sz; ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma); if (!ioc->request) { printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " - "failed: req_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kB)\n", ioc->name, ioc->request_depth, + "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " + "total(%d kB)\n", ioc->name, ioc->hba_queue_depth, ioc->chains_needed_per_io, ioc->request_sz, sz/1024); - if (ioc->request_depth < MPT2SAS_SAS_QUEUE_DEPTH) + if (ioc->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH) goto out; retry_sz += 64; - ioc->request_depth = max_request_credit - retry_sz; + ioc->hba_queue_depth = max_request_credit - retry_sz; goto retry_allocation; } if (retry_sz) printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " - "succeed: req_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kb)\n", ioc->name, ioc->request_depth, + "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " + "total(%d kb)\n", ioc->name, ioc->hba_queue_depth, ioc->chains_needed_per_io, ioc->request_sz, sz/1024); - ioc->chain = ioc->request + ((ioc->request_depth + 1) * + + /* hi-priority queue */ + ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * + ioc->request_sz); + ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) * + ioc->request_sz); + + /* internal queue */ + ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth * ioc->request_sz); - ioc->chain_dma = ioc->request_dma + ((ioc->request_depth + 1) * + ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * ioc->request_sz); + + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): " "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->request, ioc->request_depth, ioc->request_sz, - ((ioc->request_depth + 1) * ioc->request_sz)/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth" - "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain, - ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * - ioc->request_sz))/1024)); + ioc->request, ioc->hba_queue_depth, ioc->request_sz, + (ioc->hba_queue_depth * ioc->request_sz)/1024)); dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n", ioc->name, (unsigned long long) ioc->request_dma)); total_sz += sz; - ioc->scsi_lookup = kcalloc(ioc->request_depth, - sizeof(struct request_tracker), GFP_KERNEL); + sz = ioc->scsiio_depth * sizeof(struct request_tracker); + ioc->scsi_lookup_pages = get_order(sz); + ioc->scsi_lookup = (struct request_tracker *)__get_free_pages( + GFP_KERNEL, ioc->scsi_lookup_pages); if (!ioc->scsi_lookup) { - printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n", + printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, " + "sz(%d)\n", ioc->name, (int)sz); + goto out; + } + + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): " + "depth(%d)\n", ioc->name, ioc->request, + ioc->scsiio_depth)); + + /* loop till the allocation succeeds */ + do { + sz = ioc->chain_depth * sizeof(struct chain_tracker); + ioc->chain_pages = get_order(sz); + ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( + GFP_KERNEL, ioc->chain_pages); + if (ioc->chain_lookup == NULL) + ioc->chain_depth -= 100; + } while (ioc->chain_lookup == NULL); + ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, + ioc->request_sz, 16, 0); + if (!ioc->chain_dma_pool) { + printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create " + "failed\n", ioc->name); + goto out; + } + for (i = 0; i < ioc->chain_depth; i++) { + ioc->chain_lookup[i].chain_buffer = pci_pool_alloc( + ioc->chain_dma_pool , GFP_KERNEL, + &ioc->chain_lookup[i].chain_buffer_dma); + if (!ioc->chain_lookup[i].chain_buffer) { + ioc->chain_depth = i; + goto chain_done; + } + total_sz += ioc->request_sz; + } +chain_done: + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth" + "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, + ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * + ioc->request_sz))/1024)); + + /* initialize hi-priority queue smid's */ + ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, + sizeof(struct request_tracker), GFP_KERNEL); + if (!ioc->hpr_lookup) { + printk(MPT2SAS_ERR_FMT "hpr_lookup: kcalloc failed\n", ioc->name); goto out; } + ioc->hi_priority_smid = ioc->scsiio_depth + 1; + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hi_priority(0x%p): " + "depth(%d), start smid(%d)\n", ioc->name, ioc->hi_priority, + ioc->hi_priority_depth, ioc->hi_priority_smid)); - /* initialize some bits */ - for (i = 0; i < ioc->request_depth; i++) - ioc->scsi_lookup[i].smid = i + 1; + /* initialize internal queue smid's */ + ioc->internal_lookup = kcalloc(ioc->internal_depth, + sizeof(struct request_tracker), GFP_KERNEL); + if (!ioc->internal_lookup) { + printk(MPT2SAS_ERR_FMT "internal_lookup: kcalloc failed\n", + ioc->name); + goto out; + } + ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "internal(0x%p): " + "depth(%d), start smid(%d)\n", ioc->name, ioc->internal, + ioc->internal_depth, ioc->internal_smid)); /* sense buffers, 4 byte align */ - sz = ioc->request_depth * SCSI_SENSE_BUFFERSIZE; + sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE; ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4, 0); if (!ioc->sense_dma_pool) { @@ -1872,7 +2342,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense pool(0x%p): depth(%d), element_size(%d), pool_size" - "(%d kB)\n", ioc->name, ioc->sense, ioc->request_depth, + "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth, SCSI_SENSE_BUFFERSIZE, sz/1024)); dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n", ioc->name, (unsigned long long)ioc->sense_dma)); @@ -1894,6 +2364,8 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) ioc->name); goto out; } + ioc->reply_dma_min_address = (u32)(ioc->reply_dma); + ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz; dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth" "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply, ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024)); @@ -1975,7 +2447,6 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) return 0; out: - _base_release_memory_pools(ioc); return -ENOMEM; } @@ -2054,7 +2525,7 @@ _base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout, do { int_status = readl(&ioc->chip->HostInterruptStatus); if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "successfull count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; @@ -2095,7 +2566,7 @@ _base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout, do { int_status = readl(&ioc->chip->HostInterruptStatus); if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "successfull count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; @@ -2143,7 +2614,7 @@ _base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout, do { doorbell_reg = readl(&ioc->chip->Doorbell); if (!(doorbell_reg & MPI2_DOORBELL_USED)) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "successfull count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; @@ -2247,7 +2718,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)), &ioc->chip->Doorbell); - if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { + if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) { printk(MPT2SAS_ERR_FMT "doorbell handshake " "int failed (line=%d)\n", ioc->name, __LINE__); return -EFAULT; @@ -2317,9 +2788,9 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, if (ioc->logging_level & MPT_DEBUG_INIT) { mfp = (u32 *)reply; - printk(KERN_DEBUG "\toffset:data\n"); + printk(KERN_INFO "\toffset:data\n"); for (i = 0; i < reply_bytes/4; i++) - printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4, + printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, le32_to_cpu(mfp[i])); } return 0; @@ -2352,7 +2823,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, void *request; u16 wait_state_count; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mutex_lock(&ioc->base_cmds.mutex); @@ -2397,7 +2868,8 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) ioc->ioc_link_reset_in_progress = 1; - mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->base_cmds.done); timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, msecs_to_jiffies(10000)); if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || @@ -2456,7 +2928,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, void *request; u16 wait_state_count; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mutex_lock(&ioc->base_cmds.mutex); @@ -2498,7 +2970,8 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, request = mpt2sas_base_get_msg_frame(ioc, smid); ioc->base_cmds.smid = smid; memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); - mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->base_cmds.done); timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, msecs_to_jiffies(10000)); if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { @@ -2543,7 +3016,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) Mpi2PortFactsReply_t mpi_reply, *pfacts; int mpi_reply_sz, mpi_request_sz, r; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); @@ -2585,7 +3058,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) Mpi2IOCFactsReply_t mpi_reply, *facts; int mpi_reply_sz, mpi_request_sz, r; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); @@ -2644,25 +3117,27 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) /** * _base_send_ioc_init - send ioc_init to firmware * @ioc: per adapter object - * @VF_ID: virtual function id * @sleep_flag: CAN_SLEEP or NO_SLEEP * * Returns 0 for success, non-zero for failure. */ static int -_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { Mpi2IOCInitRequest_t mpi_request; Mpi2IOCInitReply_t mpi_reply; int r; + struct timeval current_time; + u16 ioc_status; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); mpi_request.Function = MPI2_FUNCTION_IOC_INIT; mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; - mpi_request.VF_ID = VF_ID; + mpi_request.VF_ID = 0; /* TODO */ + mpi_request.VP_ID = 0; mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); @@ -2704,14 +3179,21 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) cpu_to_le32(ioc->reply_post_free_dma); #endif + /* This time stamp specifies number of milliseconds + * since epoch ~ midnight January 1, 1970. + */ + do_gettimeofday(¤t_time); + mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 + + (current_time.tv_usec / 1000)); + if (ioc->logging_level & MPT_DEBUG_INIT) { u32 *mfp; int i; mfp = (u32 *)&mpi_request; - printk(KERN_DEBUG "\toffset:data\n"); + printk(KERN_INFO "\toffset:data\n"); for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) - printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4, + printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, le32_to_cpu(mfp[i])); } @@ -2726,7 +3208,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) return r; } - if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS || + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS || mpi_reply.IOCLogInfo) { printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__); r = -EIO; @@ -2738,13 +3221,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) /** * _base_send_port_enable - send port_enable(discovery stuff) to firmware * @ioc: per adapter object - * @VF_ID: virtual function id * @sleep_flag: CAN_SLEEP or NO_SLEEP * * Returns 0 for success, non-zero for failure. */ static int -_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { Mpi2PortEnableRequest_t *mpi_request; u32 ioc_state; @@ -2772,9 +3254,11 @@ _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) ioc->base_cmds.smid = smid; memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - mpi_request->VF_ID = VF_ID; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; - mpt2sas_base_put_smid_default(ioc, smid, VF_ID); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->base_cmds.done); timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 300*HZ); if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { @@ -2788,7 +3272,7 @@ _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) r = -ETIME; goto out; } else - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n", + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", ioc->name, __func__)); ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL, @@ -2835,13 +3319,12 @@ _base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event) /** * _base_event_notification - send event notification * @ioc: per adapter object - * @VF_ID: virtual function id * @sleep_flag: CAN_SLEEP or NO_SLEEP * * Returns 0 for success, non-zero for failure. */ static int -_base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { Mpi2EventNotificationRequest_t *mpi_request; unsigned long timeleft; @@ -2849,7 +3332,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) int r = 0; int i; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); if (ioc->base_cmds.status & MPT2_CMD_PENDING) { @@ -2869,11 +3352,13 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) ioc->base_cmds.smid = smid; memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t)); mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; - mpi_request->VF_ID = VF_ID; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) mpi_request->EventMasks[i] = - le32_to_cpu(ioc->event_masks[i]); - mpt2sas_base_put_smid_default(ioc, smid, VF_ID); + cpu_to_le32(ioc->event_masks[i]); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->base_cmds.done); timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { printk(MPT2SAS_ERR_FMT "%s: timeout\n", @@ -2885,7 +3370,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) else r = -ETIME; } else - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n", + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", ioc->name, __func__)); ioc->base_cmds.status = MPT2_CMD_NOT_USED; return r; @@ -2924,7 +3409,7 @@ mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type) return; mutex_lock(&ioc->base_cmds.mutex); - _base_event_notification(ioc, 0, CAN_SLEEP); + _base_event_notification(ioc, CAN_SLEEP); mutex_unlock(&ioc->base_cmds.mutex); } @@ -2947,16 +3432,15 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) _base_save_msix_table(ioc); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n", + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n", ioc->name)); - writel(0, &ioc->chip->HostInterruptStatus); count = 0; do { /* Write magic sequence to WriteSequence register * Loop until in diagnostic mode */ - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic " "sequence\n", ioc->name)); writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); @@ -2976,7 +3460,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) goto out; host_diagnostic = readl(&ioc->chip->HostDiagnostic); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic " "sequence: count(%d), host_diagnostic(0x%08x)\n", ioc->name, count, host_diagnostic)); @@ -2984,7 +3468,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) hcb_size = readl(&ioc->chip->HCBSize); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n", + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n", ioc->name)); writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, &ioc->chip->HostDiagnostic); @@ -3011,29 +3495,29 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (host_diagnostic & MPI2_DIAG_HCB_MODE) { - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter " "assuming the HCB Address points to good F/W\n", ioc->name)); host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; writel(host_diagnostic, &ioc->chip->HostDiagnostic); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "re-enable the HCDW\n", ioc->name)); writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, &ioc->chip->HCBSize); } - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter\n", + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n", ioc->name)); writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, &ioc->chip->HostDiagnostic); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "disable writes to the " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the " "diagnostic register\n", ioc->name)); writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "Wait for FW to go to the " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the " "READY state\n", ioc->name)); ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20, sleep_flag); @@ -3065,19 +3549,23 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, enum reset_type type) { u32 ioc_state; + int rc; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); + if (ioc->pci_error_recovery) + return 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n", + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n", ioc->name, __func__, ioc_state)); if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) return 0; if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " "active!\n", ioc->name)); goto issue_diag_reset; } @@ -3093,40 +3581,88 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) if (!(_base_send_ioc_reset(ioc, - MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) + MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) { + ioc->ioc_reset_count++; return 0; + } issue_diag_reset: - return _base_diag_reset(ioc, CAN_SLEEP); + rc = _base_diag_reset(ioc, CAN_SLEEP); + ioc->ioc_reset_count++; + return rc; } /** * _base_make_ioc_operational - put controller in OPERATIONAL state * @ioc: per adapter object - * @VF_ID: virtual function id * @sleep_flag: CAN_SLEEP or NO_SLEEP * * Returns 0 for success, non-zero for failure. */ static int -_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - int sleep_flag) +_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { int r, i; unsigned long flags; u32 reply_address; + u16 smid; + struct _tr_list *delayed_tr, *delayed_tr_next; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); + /* clean the delayed target reset list */ + list_for_each_entry_safe(delayed_tr, delayed_tr_next, + &ioc->delayed_tr_list, list) { + list_del(&delayed_tr->list); + kfree(delayed_tr); + } + + list_for_each_entry_safe(delayed_tr, delayed_tr_next, + &ioc->delayed_tr_volume_list, list) { + list_del(&delayed_tr->list); + kfree(delayed_tr); + } + /* initialize the scsi lookup free list */ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); INIT_LIST_HEAD(&ioc->free_list); - for (i = 0; i < ioc->request_depth; i++) { + smid = 1; + for (i = 0; i < ioc->scsiio_depth; i++, smid++) { + INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); ioc->scsi_lookup[i].cb_idx = 0xFF; + ioc->scsi_lookup[i].smid = smid; + ioc->scsi_lookup[i].scmd = NULL; list_add_tail(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); } + + /* hi-priority queue */ + INIT_LIST_HEAD(&ioc->hpr_free_list); + smid = ioc->hi_priority_smid; + for (i = 0; i < ioc->hi_priority_depth; i++, smid++) { + ioc->hpr_lookup[i].cb_idx = 0xFF; + ioc->hpr_lookup[i].smid = smid; + list_add_tail(&ioc->hpr_lookup[i].tracker_list, + &ioc->hpr_free_list); + } + + /* internal queue */ + INIT_LIST_HEAD(&ioc->internal_free_list); + smid = ioc->internal_smid; + for (i = 0; i < ioc->internal_depth; i++, smid++) { + ioc->internal_lookup[i].cb_idx = 0xFF; + ioc->internal_lookup[i].smid = smid; + list_add_tail(&ioc->internal_lookup[i].tracker_list, + &ioc->internal_free_list); + } + + /* chain pool */ + INIT_LIST_HEAD(&ioc->free_chain_list); + for (i = 0; i < ioc->chain_depth; i++) + list_add_tail(&ioc->chain_lookup[i].tracker_list, + &ioc->free_chain_list); + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); /* initialize Reply Free Queue */ @@ -3139,7 +3675,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, for (i = 0; i < ioc->reply_post_queue_depth; i++) ioc->reply_post_free[i].Words = ULLONG_MAX; - r = _base_send_ioc_init(ioc, VF_ID, sleep_flag); + r = _base_send_ioc_init(ioc, sleep_flag); if (r) return r; @@ -3150,14 +3686,21 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, writel(0, &ioc->chip->ReplyPostHostIndex); _base_unmask_interrupts(ioc); - r = _base_event_notification(ioc, VF_ID, sleep_flag); + r = _base_event_notification(ioc, sleep_flag); if (r) return r; if (sleep_flag == CAN_SLEEP) _base_static_config_pages(ioc); - r = _base_send_port_enable(ioc, VF_ID, sleep_flag); + if (ioc->wait_for_port_enable_to_complete) { + if (diag_buffer_enable != 0) + mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); + if (disable_discovery > 0) + return r; + } + + r = _base_send_port_enable(ioc, sleep_flag); if (r) return r; @@ -3175,11 +3718,13 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) { struct pci_dev *pdev = ioc->pdev; - dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); _base_mask_interrupts(ioc); + ioc->shost_recovery = 1; _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); + ioc->shost_recovery = 0; if (ioc->pci_irq) { synchronize_irq(pdev->irq); free_irq(ioc->pci_irq, ioc); @@ -3190,8 +3735,8 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) ioc->pci_irq = -1; ioc->chip_phys = 0; pci_release_selected_regions(ioc->pdev, ioc->bars); + pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); return; } @@ -3205,32 +3750,57 @@ int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) { int r, i; - unsigned long flags; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); r = mpt2sas_base_map_resources(ioc); if (r) return r; - r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); + pci_set_drvdata(ioc->pdev, ioc->shost); + r = _base_get_ioc_facts(ioc, CAN_SLEEP); if (r) goto out_free_resources; - r = _base_get_ioc_facts(ioc, CAN_SLEEP); + r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); if (r) goto out_free_resources; + ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, + sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); + if (!ioc->pfacts) { + r = -ENOMEM; + goto out_free_resources; + } + + for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { + r = _base_get_port_facts(ioc, i, CAN_SLEEP); + if (r) + goto out_free_resources; + } + r = _base_allocate_memory_pools(ioc, CAN_SLEEP); if (r) goto out_free_resources; init_waitqueue_head(&ioc->reset_wq); + /* allocate memory pd handle bitmask list */ + ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); + if (ioc->facts.MaxDevHandle % 8) + ioc->pd_handles_sz++; + ioc->pd_handles = kzalloc(ioc->pd_handles_sz, + GFP_KERNEL); + if (!ioc->pd_handles) { + r = -ENOMEM; + goto out_free_resources; + } + + ioc->fwfault_debug = mpt2sas_fwfault_debug; + /* base internal command bits */ mutex_init(&ioc->base_cmds.mutex); - init_completion(&ioc->base_cmds.done); ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); ioc->base_cmds.status = MPT2_CMD_NOT_USED; @@ -3238,25 +3808,44 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); ioc->transport_cmds.status = MPT2_CMD_NOT_USED; mutex_init(&ioc->transport_cmds.mutex); - init_completion(&ioc->transport_cmds.done); + + /* scsih internal command bits */ + ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; + mutex_init(&ioc->scsih_cmds.mutex); /* task management internal command bits */ ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; mutex_init(&ioc->tm_cmds.mutex); - init_completion(&ioc->tm_cmds.done); /* config page internal command bits */ ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); ioc->config_cmds.status = MPT2_CMD_NOT_USED; mutex_init(&ioc->config_cmds.mutex); - init_completion(&ioc->config_cmds.done); /* ctl module internal command bits */ ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; mutex_init(&ioc->ctl_cmds.mutex); - init_completion(&ioc->ctl_cmds.done); + + if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || + !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || + !ioc->config_cmds.reply || !ioc->ctl_cmds.reply || + !ioc->ctl_cmds.sense) { + r = -ENOMEM; + goto out_free_resources; + } + + if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || + !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || + !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { + r = -ENOMEM; + goto out_free_resources; + } + + init_completion(&ioc->shost_recovery_done); for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) ioc->event_masks[i] = -1; @@ -3271,40 +3860,16 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME); _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); - _base_unmask_events(ioc, MPI2_EVENT_TASK_SET_FULL); _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); - - ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, - sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); - if (!ioc->pfacts) - goto out_free_resources; - - for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { - r = _base_get_port_facts(ioc, i, CAN_SLEEP); - if (r) - goto out_free_resources; - } - r = _base_make_ioc_operational(ioc, 0, CAN_SLEEP); + r = _base_make_ioc_operational(ioc, CAN_SLEEP); if (r) goto out_free_resources; - /* initialize fault polling */ - INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); - snprintf(ioc->fault_reset_work_q_name, - sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id); - ioc->fault_reset_work_q = - create_singlethread_workqueue(ioc->fault_reset_work_q_name); - if (!ioc->fault_reset_work_q) { - printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n", - ioc->name, __func__, __LINE__); - goto out_free_resources; - } - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->fault_reset_work_q) - queue_delayed_work(ioc->fault_reset_work_q, - &ioc->fault_reset_work, - msecs_to_jiffies(FAULT_POLLING_INTERVAL)); - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + if (missing_delay[0] != -1 && missing_delay[1] != -1) + _base_update_missing_delay(ioc, missing_delay[0], + missing_delay[1]); + + mpt2sas_base_start_watchdog(ioc); return 0; out_free_resources: @@ -3312,15 +3877,20 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) ioc->remove_host = 1; mpt2sas_base_free_resources(ioc); _base_release_memory_pools(ioc); + pci_set_drvdata(ioc->pdev, NULL); + kfree(ioc->pd_handles); kfree(ioc->tm_cmds.reply); kfree(ioc->transport_cmds.reply); + kfree(ioc->scsih_cmds.reply); kfree(ioc->config_cmds.reply); kfree(ioc->base_cmds.reply); kfree(ioc->ctl_cmds.reply); + kfree(ioc->ctl_cmds.sense); kfree(ioc->pfacts); ioc->ctl_cmds.reply = NULL; ioc->base_cmds.reply = NULL; ioc->tm_cmds.reply = NULL; + ioc->scsih_cmds.reply = NULL; ioc->transport_cmds.reply = NULL; ioc->config_cmds.reply = NULL; ioc->pfacts = NULL; @@ -3337,27 +3907,22 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) { - unsigned long flags; - struct workqueue_struct *wq; - dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - wq = ioc->fault_reset_work_q; - ioc->fault_reset_work_q = NULL; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - if (!cancel_delayed_work(&ioc->fault_reset_work)) - flush_workqueue(wq); - destroy_workqueue(wq); - + mpt2sas_base_stop_watchdog(ioc); mpt2sas_base_free_resources(ioc); _base_release_memory_pools(ioc); + pci_set_drvdata(ioc->pdev, NULL); + kfree(ioc->pd_handles); kfree(ioc->pfacts); kfree(ioc->ctl_cmds.reply); + kfree(ioc->ctl_cmds.sense); kfree(ioc->base_cmds.reply); kfree(ioc->tm_cmds.reply); kfree(ioc->transport_cmds.reply); + kfree(ioc->scsih_cmds.reply); kfree(ioc->config_cmds.reply); } @@ -3378,11 +3943,11 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) { switch (reset_phase) { case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); break; case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); if (ioc->transport_cmds.status & MPT2_CMD_PENDING) { ioc->transport_cmds.status |= MPT2_CMD_RESET; @@ -3397,11 +3962,12 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) if (ioc->config_cmds.status & MPT2_CMD_PENDING) { ioc->config_cmds.status |= MPT2_CMD_RESET; mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); + ioc->config_cmds.smid = USHRT_MAX; complete(&ioc->config_cmds.done); } break; case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); break; } @@ -3434,7 +4000,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) /* pending command count */ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - for (i = 0; i < ioc->request_depth; i++) + for (i = 0; i < ioc->scsiio_depth; i++) if (ioc->scsi_lookup[i].cb_idx != 0xFF) ioc->pending_io_count++; spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -3443,7 +4009,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) return; /* wait for pending commands to complete */ - wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 3 * HZ); + wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ); } /** @@ -3458,27 +4024,41 @@ int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, enum reset_type type) { - int r, i; + int r; unsigned long flags; - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); - 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_ERR_FMT "%s: busy\n", + if (ioc->pci_error_recovery) { + printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n", ioc->name, __func__); - return -EBUSY; + r = 0; + goto out; } - ioc->ioc_reset_in_progress = 1; - ioc->shost_recovery = 1; - if (ioc->shost->shost_state == SHOST_RUNNING) { - /* set back to SHOST_RUNNING in mpt2sas_scsih.c */ - scsi_host_set_state(ioc->shost, SHOST_RECOVERY); - printk(MPT2SAS_INFO_FMT "putting controller into " - "SHOST_RECOVERY\n", ioc->name); + + if (mpt2sas_fwfault_debug) + mpt2sas_halt_firmware(ioc); + + /* TODO - What we really should be doing is pulling + * out all the code associated with NO_SLEEP; its never used. + * That is legacy code from mpt fusion driver, ported over. + * I will leave this BUG_ON here for now till its been resolved. + */ + BUG_ON(sleep_flag == NO_SLEEP); + + /* wait for an active reset in progress to complete */ + if (!mutex_trylock(&ioc->reset_in_progress_mutex)) { + do { + ssleep(1); + } while (ioc->shost_recovery == 1); + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, + __func__)); + return ioc->ioc_reset_in_progress_status; } + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + ioc->shost_recovery = 1; spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); _base_reset_handler(ioc, MPT2_IOC_PRE_RESET); @@ -3488,17 +4068,21 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, if (r) goto out; _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET); - for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) - r = _base_make_ioc_operational(ioc, ioc->pfacts[i].VF_ID, - sleep_flag); + r = _base_make_ioc_operational(ioc, sleep_flag); if (!r) _base_reset_handler(ioc, MPT2_IOC_DONE_RESET); out: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: %s\n", + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n", ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->ioc_reset_in_progress = 0; + ioc->ioc_reset_in_progress_status = r; + ioc->shost_recovery = 0; + complete(&ioc->shost_recovery_done); spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + mutex_unlock(&ioc->reset_in_progress_mutex); + + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, + __func__)); return r; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 286c185fa9e..283568c6fb0 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -3,7 +3,7 @@ * 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 + * Copyright (C) 2007-2010 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * * This program is free software; you can redistribute it and/or @@ -69,10 +69,10 @@ #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 "01.100.03.00" -#define MPT2SAS_MAJOR_VERSION 01 +#define MPT2SAS_DRIVER_VERSION "07.100.00.00" +#define MPT2SAS_MAJOR_VERSION 07 #define MPT2SAS_MINOR_VERSION 100 -#define MPT2SAS_BUILD_VERSION 03 +#define MPT2SAS_BUILD_VERSION 00 #define MPT2SAS_RELEASE_VERSION 00 /* @@ -124,7 +124,6 @@ * 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 @@ -196,6 +195,38 @@ struct MPT2SAS_TARGET { * @block: device is in SDEV_BLOCK state * @tlr_snoop_check: flag used in determining whether to disable TLR */ + +/* OEM Identifiers */ +#define MFG10_OEM_ID_INVALID (0x00000000) +#define MFG10_OEM_ID_DELL (0x00000001) +#define MFG10_OEM_ID_FSC (0x00000002) +#define MFG10_OEM_ID_SUN (0x00000003) +#define MFG10_OEM_ID_IBM (0x00000004) + +/* GENERIC Flags 0*/ +#define MFG10_GF0_OCE_DISABLED (0x00000001) +#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002) +#define MFG10_GF0_R10_DISPLAY (0x00000004) +#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008) +#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010) + +/* OEM Specific Flags will come from OEM specific header files */ +typedef struct _MPI2_CONFIG_PAGE_MAN_10 { + MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ + U8 OEMIdentifier; /* 04h */ + U8 Reserved1; /* 05h */ + U16 Reserved2; /* 08h */ + U32 Reserved3; /* 0Ch */ + U32 GenericFlags0; /* 10h */ + U32 GenericFlags1; /* 14h */ + U32 Reserved4; /* 18h */ + U32 OEMSpecificFlags0; /* 1Ch */ + U32 OEMSpecificFlags1; /* 20h */ + U32 Reserved5[18]; /* 24h-60h*/ +} MPI2_CONFIG_PAGE_MAN_10, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10, + Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t; + struct MPT2SAS_DEVICE { struct MPT2SAS_TARGET *sas_target; unsigned int lun; @@ -216,6 +247,7 @@ struct MPT2SAS_DEVICE { * @mutex: mutex * @done: completion * @reply: reply message pointer + * @sense: sense data * @status: MPT2_CMD_XXX status * @smid: system message id */ @@ -223,13 +255,11 @@ struct _internal_cmd { struct mutex mutex; struct completion done; void *reply; + void *sense; u16 status; u16 smid; }; -/* - * SAS Topology Structures - */ /** * struct _sas_device - attached device information @@ -238,7 +268,7 @@ struct _internal_cmd { * @sas_address: device sas address * @device_name: retrieved from the SAS IDENTIFY frame. * @handle: device handle - * @parent_handle: handle to parent device + * @sas_address_parent: sas address of parent expander or sas host * @enclosure_handle: enclosure handle * @enclosure_logical_id: enclosure logical identifier * @volume_handle: volume handle (valid when hidden raid member) @@ -247,7 +277,7 @@ struct _internal_cmd { * @id: target id * @channel: target channel * @slot: number number - * @hidden_raid_component: set to 1 when this is a raid member + * @phy: phy identifier provided in sas device page 0 * @responding: used in _scsih_sas_device_mark_responding */ struct _sas_device { @@ -256,7 +286,7 @@ struct _sas_device { u64 sas_address; u64 device_name; u16 handle; - u16 parent_handle; + u64 sas_address_parent; u16 enclosure_handle; u64 enclosure_logical_id; u16 volume_handle; @@ -265,7 +295,7 @@ struct _sas_device { int id; int channel; u16 slot; - u8 hidden_raid_component; + u8 phy; u8 responding; }; @@ -282,6 +312,7 @@ struct _sas_device { * @device_info: bitfield provides detailed info about the hidden components * @num_pds: number of hidden raid components * @responding: used in _scsih_raid_device_mark_responding + * @percent_complete: resync percent complete */ struct _raid_device { struct list_head list; @@ -295,6 +326,7 @@ struct _raid_device { u32 device_info; u8 num_pds; u8 responding; + u8 percent_complete; }; /** @@ -311,8 +343,6 @@ struct _boot_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 @@ -321,8 +351,6 @@ struct _boot_device { */ 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; @@ -339,6 +367,7 @@ struct _sas_port { * @phy_id: unique phy id * @handle: device handle for this phy * @attached_handle: device handle for attached device + * @phy_belongs_to_port: port has been created for this phy */ struct _sas_phy { struct list_head port_siblings; @@ -348,6 +377,7 @@ struct _sas_phy { u8 phy_id; u16 handle; u16 attached_handle; + u8 phy_belongs_to_port; }; /** @@ -357,7 +387,7 @@ struct _sas_phy { * @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 + * @sas_address_parent: sas address of parent expander or sas host * @enclosure_handle: handle for this a member of an enclosure * @device_info: bitwise defining capabilities of this sas_host/expander * @responding: used in _scsih_expander_device_mark_responding @@ -370,7 +400,7 @@ struct _sas_node { u8 num_phys; u64 sas_address; u16 handle; - u16 parent_handle; + u64 sas_address_parent; u16 enclosure_handle; u64 enclosure_logical_id; u8 responding; @@ -389,6 +419,18 @@ enum reset_type { }; /** + * struct chain_tracker - firmware chain tracker + * @chain_buffer: chain buffer + * @chain_buffer_dma: physical address + * @tracker_list: list of free request (ioc->free_chain_list) + */ +struct chain_tracker { + void *chain_buffer; + dma_addr_t chain_buffer_dma; + struct list_head tracker_list; +}; + +/** * struct request_tracker - firmware request tracker * @smid: system message id * @scmd: scsi request pointer @@ -400,9 +442,21 @@ struct request_tracker { u16 smid; struct scsi_cmnd *scmd; u8 cb_idx; + struct list_head chain_list; struct list_head tracker_list; }; +/** + * struct _tr_list - target reset list + * @handle: device handle + * @state: state machine + */ +struct _tr_list { + struct list_head list; + u16 handle; + u16 state; +}; + typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); /** @@ -416,8 +470,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @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 + * @fwfault_debug: debuging FW timeouts * @ir_firmware: IR firmware present * @bars: bitmask of BAR's that must be configured * @mask_interrupts: ignore interrupt @@ -431,11 +485,12 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @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 + * @shost_recovery: host reset in progress * @ioc_reset_in_progress_lock: * @ioc_link_reset_in_progress: phy/hard reset in progress - * @ignore_loginfos: ignore loginfos during task managment + * @ignore_loginfos: ignore loginfos during task management * @remove_host: flag for when driver unloads, to avoid sending dev resets + * @pci_error_recovery: flag to prevent ioc access until slot reset completes * @wait_for_port_enable_to_complete: * @msix_enable: flag indicating msix is enabled * @msix_vector_count: number msix vectors @@ -443,12 +498,16 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @msix_table_backup: backup msix table * @scsi_io_cb_idx: shost generated commands * @tm_cb_idx: task management commands + * @scsih_cb_idx: scsih internal commands * @transport_cb_idx: transport internal commands * @ctl_cb_idx: clt internal commands * @base_cb_idx: base internal commands * @config_cb_idx: base internal commands + * @tm_tr_cb_idx : device removal target reset handshake + * @tm_tr_volume_cb_idx : volume removal target reset * @base_cmds: * @transport_cmds: + * @scsih_cmds: * @tm_cmds: * @ctl_cmds: * @config_cmds: @@ -460,6 +519,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @facts: static facts data * @pfacts: static port facts data * @manu_pg0: static manufacturing page 0 + * @manu_pg10: static manufacturing page 10 * @bios_pg2: static bios page 2 * @bios_pg3: static bios page 3 * @ioc_pg8: static ioc page 8 @@ -473,11 +533,15 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @sas_device_lock: * @io_missing_delay: time for IO completed by fw when PDR enabled * @device_missing_delay: time for device missing by fw when PDR enabled + * @sas_id : used for setting volume target IDs + * @pd_handles : bitmask for PD handles + * @pd_handles_sz : size of pd_handle bitmask * @config_page_sz: config page size * @config_page: reserve memory for config page payload * @config_page_dma: + * @hba_queue_depth: hba request queue depth * @sge_size: sg element size for either 32/64 bit - * @request_depth: hba request queue depth + * @scsiio_depth: SCSI_IO queue depth * @request_sz: per request frame size * @request: pool of request frames * @request_dma: @@ -494,6 +558,18 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @chains_needed_per_io: max chains per io * @chain_offset_value_for_main_message: location 1st sg in main * @chain_depth: total chains allocated + * @hi_priority_smid: + * @hi_priority: + * @hi_priority_dma: + * @hi_priority_depth: + * @hpr_lookup: + * @hpr_free_list: + * @internal_smid: + * @internal: + * @internal_dma: + * @internal_depth: + * @internal_lookup: + * @internal_free_list: * @sense: pool of sense * @sense_dma: * @sense_dma_pool: @@ -512,6 +588,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @reply_post_free_dma: * @reply_post_free_dma_pool: * @reply_post_host_index: head index in the pool where FW completes IO + * @delayed_tr_list: target reset link list + * @delayed_tr_volume_list: volume target reset link list */ struct MPT2SAS_ADAPTER { struct list_head list; @@ -522,9 +600,9 @@ struct MPT2SAS_ADAPTER { char tmp_string[MPT_STRING_LENGTH]; struct pci_dev *pdev; Mpi2SystemInterfaceRegs_t __iomem *chip; - unsigned long chip_phys; - unsigned long pio_chip; + resource_size_t chip_phys; int logging_level; + int fwfault_debug; u8 ir_firmware; int bars; u8 mask_interrupts; @@ -537,35 +615,45 @@ struct MPT2SAS_ADAPTER { /* 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; + + struct mutex reset_in_progress_mutex; + struct completion shost_recovery_done; spinlock_t ioc_reset_in_progress_lock; u8 ioc_link_reset_in_progress; + int ioc_reset_in_progress_status; + u8 ignore_loginfos; u8 remove_host; + u8 pci_error_recovery; u8 wait_for_port_enable_to_complete; u8 msix_enable; u16 msix_vector_count; u32 *msix_table; u32 *msix_table_backup; + u32 ioc_reset_count; /* internal commands, callback index */ u8 scsi_io_cb_idx; u8 tm_cb_idx; u8 transport_cb_idx; + u8 scsih_cb_idx; u8 ctl_cb_idx; u8 base_cb_idx; u8 config_cb_idx; + u8 tm_tr_cb_idx; + u8 tm_tr_volume_cb_idx; + u8 tm_sas_control_cb_idx; struct _internal_cmd base_cmds; struct _internal_cmd transport_cmds; + struct _internal_cmd scsih_cmds; struct _internal_cmd tm_cmds; struct _internal_cmd ctl_cmds; struct _internal_cmd config_cmds; @@ -605,32 +693,55 @@ struct MPT2SAS_ADAPTER { u16 device_missing_delay; int sas_id; + void *pd_handles; + u16 pd_handles_sz; + /* config page */ u16 config_page_sz; void *config_page; dma_addr_t config_page_dma; - /* request */ + /* scsiio request */ + u16 hba_queue_depth; u16 sge_size; - u16 request_depth; + u16 scsiio_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; + ulong scsi_lookup_pages; + spinlock_t scsi_lookup_lock; struct list_head free_list; int pending_io_count; wait_queue_head_t reset_wq; /* chain */ - u8 *chain; - dma_addr_t chain_dma; + struct chain_tracker *chain_lookup; + struct list_head free_chain_list; + struct dma_pool *chain_dma_pool; + ulong chain_pages; u16 max_sges_in_main_message; u16 max_sges_in_chain_message; u16 chains_needed_per_io; u16 chain_offset_value_for_main_message; - u16 chain_depth; + u32 chain_depth; + + /* hi-priority queue */ + u16 hi_priority_smid; + u8 *hi_priority; + dma_addr_t hi_priority_dma; + u16 hi_priority_depth; + struct request_tracker *hpr_lookup; + struct list_head hpr_free_list; + + /* internal queue */ + u16 internal_smid; + u8 *internal; + dma_addr_t internal_dma; + u16 internal_depth; + struct request_tracker *internal_lookup; + struct list_head internal_free_list; /* sense */ u8 *sense; @@ -641,6 +752,8 @@ struct MPT2SAS_ADAPTER { u16 reply_sz; u8 *reply; dma_addr_t reply_dma; + u32 reply_dma_max_address; + u32 reply_dma_min_address; struct dma_pool *reply_dma_pool; /* reply free queue */ @@ -657,22 +770,30 @@ struct MPT2SAS_ADAPTER { struct dma_pool *reply_post_free_dma_pool; u32 reply_post_host_index; + struct list_head delayed_tr_list; + struct list_head delayed_tr_volume_list; + /* diag buffer support */ u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT]; dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT]; u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT]; u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT]; + Mpi2ManufacturingPage10_t manu_pg10; u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; + u32 ring_buffer_offset; + u32 ring_buffer_sz; }; -typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, +typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); /* base shared API */ extern struct list_head mpt2sas_ioc_list; +void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc); +void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc); int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc); void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc); @@ -684,22 +805,28 @@ int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, 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); +__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, + u16 smid); + +/* hi-priority queue */ +u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); +u16 mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, + struct scsi_cmnd *scmd); 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, +void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle); -void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id); +void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid); 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); + u16 io_index); +void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid); void mpt2sas_base_initialize_callback_handler(void); u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func); void mpt2sas_base_release_callback_handler(u8 cb_idx); -void mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + 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); @@ -712,11 +839,18 @@ 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); +void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); + /* scsih shared API */ -void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, - u8 type, u16 smid_task, ulong timeout); +u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, + u32 reply); +int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, + uint channel, uint id, uint lun, u8 type, u16 smid_task, + ulong timeout, struct scsi_cmnd *scmd); void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); +void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); +void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); 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 @@ -724,14 +858,16 @@ struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAP 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); +u8 mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + 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_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_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 @@ -747,9 +883,11 @@ int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRep 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); + *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_set_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 @@ -774,31 +912,40 @@ 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); +u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + 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); +u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, + u32 reply); void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, Mpi2EventNotificationReply_t *mpi_reply); +void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, + u8 bits_to_regsiter); + /* transport shared API */ -void mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + u32 reply); struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, - u16 handle, u16 parent_handle); + u16 handle, u64 sas_address); void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 parent_handle); + u64 sas_address_parent); 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); +void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); extern struct sas_function_template mpt2sas_transport_functions; extern struct scsi_transport_template *mpt2sas_transport_template; +extern int scsi_internal_device_block(struct scsi_device *sdev); +extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc, + u8 msix_index, u32 reply); +extern int scsi_internal_device_unblock(struct scsi_device *sdev); #endif /* MPT2SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index 58cfb97846f..6afd67b324f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -2,7 +2,7 @@ * 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 + * Copyright (C) 2007-2010 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * * This program is free software; you can redistribute it and/or @@ -51,6 +51,7 @@ #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/pci.h> +#include <linux/slab.h> #include "mpt2sas_base.h" @@ -72,15 +73,15 @@ /** * struct config_request - obtain dma memory via routine - * @config_page_sz: size - * @config_page: virt pointer - * @config_page_dma: phys pointer + * @sz: size + * @page: virt pointer + * @page_dma: phys pointer * */ struct config_request{ - u16 config_page_sz; - void *config_page; - dma_addr_t config_page_dma; + u16 sz; + void *page; + dma_addr_t page_dma; }; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -158,7 +159,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, if (!desc) return; - printk(MPT2SAS_DEBUG_FMT "%s: %s(%d), action(%d), form(0x%08x), " + printk(MPT2SAS_INFO_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); @@ -167,7 +168,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, return; if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_DEBUG_FMT + printk(MPT2SAS_INFO_FMT "\tiocstatus(0x%04x), loginfo(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo)); @@ -175,26 +176,77 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, #endif /** + * _config_alloc_config_dma_memory - obtain physical memory + * @ioc: per adapter object + * @mem: struct config_request + * + * A wrapper for obtaining dma-able memory for config page request. + * + * Returns 0 for success, non-zero for failure. + */ +static int +_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, + struct config_request *mem) +{ + int r = 0; + + if (mem->sz > ioc->config_page_sz) { + mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz, + &mem->page_dma, GFP_KERNEL); + if (!mem->page) { + printk(MPT2SAS_ERR_FMT "%s: dma_alloc_coherent" + " failed asking for (%d) bytes!!\n", + ioc->name, __func__, mem->sz); + r = -ENOMEM; + } + } else { /* use tmp buffer if less than 512 bytes */ + mem->page = ioc->config_page; + mem->page_dma = ioc->config_page_dma; + } + return r; +} + +/** + * _config_free_config_dma_memory - wrapper to free the memory + * @ioc: per adapter object + * @mem: struct config_request + * + * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory. + * + * Returns 0 for success, non-zero for failure. + */ +static void +_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, + struct config_request *mem) +{ + if (mem->sz > ioc->config_page_sz) + dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page, + mem->page_dma); +} + +/** * mpt2sas_config_done - config page completion routine * @ioc: per adapter object * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * Context: none. * * The callback handler when using _config_request. * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -void -mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +u8 +mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + u32 reply) { MPI2DefaultReply_t *mpi_reply; if (ioc->config_cmds.status == MPT2_CMD_NOT_USED) - return; + return 1; if (ioc->config_cmds.smid != smid) - return; + return 1; ioc->config_cmds.status |= MPT2_CMD_COMPLETE; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); if (mpi_reply) { @@ -206,7 +258,9 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) #ifdef CONFIG_SCSI_MPT2SAS_LOGGING _config_display_some_debug(ioc, smid, "config_done", mpi_reply); #endif + ioc->config_cmds.smid = USHRT_MAX; complete(&ioc->config_cmds.done); + return 1; } /** @@ -215,7 +269,9 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) * @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 + * @config_page: contents of the config page + * @config_page_sz: size of config page + * Context: sleep * * A generic API for config page requests to firmware. * @@ -228,25 +284,71 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) */ static int _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t - *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout) + *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout, + void *config_page, u16 config_page_sz) { u16 smid; u32 ioc_state; unsigned long timeleft; Mpi2ConfigRequest_t *config_request; int r; - u8 retry_count; - u8 issue_reset; + u8 retry_count, issue_host_reset = 0; u16 wait_state_count; + struct config_request mem; + mutex_lock(&ioc->config_cmds.mutex); if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) { printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n", ioc->name, __func__); + mutex_unlock(&ioc->config_cmds.mutex); return -EAGAIN; } + retry_count = 0; + memset(&mem, 0, sizeof(struct config_request)); + + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; + + if (config_page) { + mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion; + mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber; + mpi_request->Header.PageType = mpi_reply->Header.PageType; + mpi_request->Header.PageLength = mpi_reply->Header.PageLength; + mpi_request->ExtPageLength = mpi_reply->ExtPageLength; + mpi_request->ExtPageType = mpi_reply->ExtPageType; + if (mpi_request->Header.PageLength) + mem.sz = mpi_request->Header.PageLength * 4; + else + mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; + r = _config_alloc_config_dma_memory(ioc, &mem); + if (r != 0) + goto out; + if (mpi_request->Action == + MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT || + mpi_request->Action == + MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) { + ioc->base_add_sg_single(&mpi_request->PageBufferSGE, + MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, + mem.page_dma); + memcpy(mem.page, config_page, min_t(u16, mem.sz, + config_page_sz)); + } else { + memset(config_page, 0, config_page_sz); + ioc->base_add_sg_single(&mpi_request->PageBufferSGE, + MPT2_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma); + } + } retry_config: + if (retry_count) { + if (retry_count > 2) { /* attempt only 2 retries */ + r = -EFAULT; + goto free_mem; + } + printk(MPT2SAS_INFO_FMT "%s: attempting retry (%d)\n", + ioc->name, __func__, retry_count); + } wait_state_count = 0; ioc_state = mpt2sas_base_get_iocstate(ioc, 1); while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { @@ -255,7 +357,8 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t "%s: failed due to ioc not operational\n", ioc->name, __func__); ioc->config_cmds.status = MPT2_CMD_NOT_USED; - return -EFAULT; + r = -EFAULT; + goto free_mem; } ssleep(1); ioc_state = mpt2sas_base_get_iocstate(ioc, 1); @@ -272,7 +375,8 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", ioc->name, __func__); ioc->config_cmds.status = MPT2_CMD_NOT_USED; - return -EAGAIN; + r = -EAGAIN; + goto free_mem; } r = 0; @@ -284,7 +388,8 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, 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); + init_completion(&ioc->config_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ); if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) { @@ -292,74 +397,78 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t 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; + retry_count++; + if (ioc->config_cmds.smid == smid) + mpt2sas_base_free_smid(ioc, smid); + if ((ioc->shost_recovery) || (ioc->config_cmds.status & + MPT2_CMD_RESET) || ioc->pci_error_recovery) + goto retry_config; + issue_host_reset = 1; + r = -EFAULT; + goto free_mem; } + 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__); + printk(MPT2SAS_INFO_FMT "%s: retry (%d) completed!!\n", + ioc->name, __func__, retry_count); + if (config_page && mpi_request->Action == + MPI2_CONFIG_ACTION_PAGE_READ_CURRENT) + memcpy(config_page, mem.page, min_t(u16, mem.sz, + config_page_sz)); + free_mem: + if (config_page) + _config_free_config_dma_memory(ioc, &mem); + out: ioc->config_cmds.status = MPT2_CMD_NOT_USED; - return r; + mutex_unlock(&ioc->config_cmds.mutex); - issue_host_reset: - if (issue_reset) + if (issue_host_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; + return r; } /** - * _config_alloc_config_dma_memory - obtain physical memory + * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0 * @ioc: per adapter object - * @mem: struct config_request - * - * A wrapper for obtaining dma-able memory for config page request. + * @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. */ -static int -_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, - struct config_request *mem) +int +mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page) { - int r = 0; + Mpi2ConfigRequest_t mpi_request; + int r; - mem->config_page = pci_alloc_consistent(ioc->pdev, mem->config_page_sz, - &mem->config_page_dma); - if (!mem->config_page) - r = -ENOMEM; - return r; -} + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; + mpi_request.Header.PageNumber = 0; + mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; -/** - * _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); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; } /** - * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0 + * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware * @config_page: contents of the config page @@ -368,56 +477,29 @@ _config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, * 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) +mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_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.PageNumber = 10; 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -436,10 +518,7 @@ mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, { 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; @@ -448,39 +527,15 @@ mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -499,10 +554,7 @@ mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -511,39 +563,15 @@ mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -562,10 +590,7 @@ mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, { 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; @@ -574,39 +599,15 @@ mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -625,10 +626,7 @@ mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, { 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; @@ -637,39 +635,15 @@ mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -684,13 +658,11 @@ mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, */ int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t config_page) + 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; @@ -699,40 +671,15 @@ mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -751,10 +698,7 @@ mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, { 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; @@ -763,39 +707,15 @@ mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -816,10 +736,7 @@ mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -829,41 +746,16 @@ mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -884,10 +776,7 @@ mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -897,41 +786,16 @@ mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -948,12 +812,11 @@ 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); + *num_phys = 0; memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); mpi_request.Function = MPI2_FUNCTION_CONFIG; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; @@ -963,46 +826,21 @@ mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys) 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, + sizeof(Mpi2SasIOUnitPage0_t)); if (!r) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - memcpy(&config_page, mem.config_page, - min_t(u16, mem.config_page_sz, - sizeof(Mpi2SasIOUnitPage0_t))); + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) *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; } @@ -1025,10 +863,7 @@ mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -1038,44 +873,19 @@ mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } /** - * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 0 + * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1 * @ioc: per adapter object * @mpi_reply: reply mf payload returned from firmware * @config_page: contents of the config page @@ -1093,52 +903,67 @@ mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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)); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + out: + return r; +} - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); +/** + * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Calling function should call config_get_number_hba_phys prior to + * this function, so enough memory is allocated for config_page. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; + mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1159,10 +984,7 @@ mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -1172,41 +994,16 @@ mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1228,10 +1025,7 @@ mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -1241,7 +1035,7 @@ mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; @@ -1249,35 +1043,10 @@ mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1298,10 +1067,7 @@ mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -1311,41 +1077,16 @@ mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1365,10 +1106,7 @@ mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -1378,42 +1116,17 @@ mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1433,10 +1146,7 @@ mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -1446,42 +1156,17 @@ mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1503,10 +1188,7 @@ mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, { 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; @@ -1515,40 +1197,16 @@ mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1566,13 +1224,11 @@ mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds) { Mpi2ConfigRequest_t mpi_request; - Mpi2RaidVolPage0_t *config_page; + 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; @@ -1582,45 +1238,24 @@ mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, + sizeof(Mpi2RaidVolPage0_t)); if (!r) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - config_page = mem.config_page; - *num_pds = config_page->NumPhysDisks; - } + if (ioc_status == MPI2_IOCSTATUS_SUCCESS) + *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; } @@ -1643,11 +1278,8 @@ mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, { 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; @@ -1655,39 +1287,15 @@ mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | handle); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1709,11 +1317,8 @@ mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t { 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; @@ -1721,40 +1326,16 @@ mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); if (r) goto out; mpi_request.PageAddress = cpu_to_le32(form | form_specific); mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - 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); - + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); out: - mutex_unlock(&ioc->config_cmds.mutex); return r; } @@ -1771,14 +1352,12 @@ int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, u16 *volume_handle) { - Mpi2RaidConfigurationPage0_t *config_page; + Mpi2RaidConfigurationPage0_t *config_page = NULL; Mpi2ConfigRequest_t mpi_request; Mpi2ConfigReply_t mpi_reply; - int r, i; - struct config_request mem; + int r, i, config_page_sz; 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; @@ -1789,60 +1368,42 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, 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); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); 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); + config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); + config_page = kmalloc(config_page_sz, GFP_KERNEL); + if (!config_page) + goto out; r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT); + MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + config_page_sz); if (r) goto out; r = -1; ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto done; - config_page = mem.config_page; + goto out; for (i = 0; i < config_page->NumElements; i++) { - if ((config_page->ConfigElement[i].ElementFlags & + if ((le16_to_cpu(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) { + if (le16_to_cpu(config_page->ConfigElement[i]. + PhysDiskDevHandle) == pd_handle) { *volume_handle = le16_to_cpu(config_page-> ConfigElement[i].VolDevHandle); r = 0; - goto done; + goto out; } } - - done: - if (mem.config_page_sz > ioc->config_page_sz) - _config_free_config_dma_memory(ioc, &mem); - out: - mutex_unlock(&ioc->config_cmds.mutex); + kfree(config_page); return r; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 14e473d1fa7..e92b77af548 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -3,7 +3,7 @@ * controllers * * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c - * Copyright (C) 2007-2008 LSI Corporation + * Copyright (C) 2007-2010 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * * This program is free software; you can redistribute it and/or @@ -51,7 +51,7 @@ #include <linux/types.h> #include <linux/pci.h> #include <linux/delay.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compat.h> #include <linux/poll.h> @@ -61,6 +61,7 @@ #include "mpt2sas_base.h" #include "mpt2sas_ctl.h" +static DEFINE_MUTEX(_ctl_mutex); static struct fasync_struct *async_queue; static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); @@ -82,6 +83,32 @@ enum block_state { #ifdef CONFIG_SCSI_MPT2SAS_LOGGING /** + * _ctl_sas_device_find_by_handle - sas device search + * @ioc: per adapter object + * @handle: sas device handle (assigned by firmware) + * Context: Calling function should acquire ioc->sas_device_lock + * + * This searches for sas_device based on sas_address, then return sas_device + * object. + */ +static struct _sas_device * +_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_device *sas_device, *r; + + r = NULL; + list_for_each_entry(sas_device, &ioc->sas_device_list, list) { + if (sas_device->handle != handle) + continue; + r = sas_device; + goto out; + } + + out: + return r; +} + +/** * _ctl_display_some_debug - debug routine * @ioc: per adapter object * @smid: system request message index @@ -188,14 +215,14 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, if (!desc) return; - printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n", + printk(MPT2SAS_INFO_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 + printk(MPT2SAS_INFO_FMT "\tiocstatus(0x%04x), loginfo(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo)); @@ -205,8 +232,24 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { Mpi2SCSIIOReply_t *scsi_reply = (Mpi2SCSIIOReply_t *)mpi_reply; + struct _sas_device *sas_device = NULL; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _ctl_sas_device_find_by_handle(ioc, + le16_to_cpu(scsi_reply->DevHandle)); + if (sas_device) { + printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " + "phy(%d)\n", ioc->name, (unsigned long long) + sas_device->sas_address, sas_device->phy); + printk(MPT2SAS_WARN_FMT + "\tenclosure_logical_id(0x%016llx), slot(%d)\n", + ioc->name, sas_device->enclosure_logical_id, + sas_device->slot); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) - printk(MPT2SAS_DEBUG_FMT + printk(MPT2SAS_INFO_FMT "\tscsi_state(0x%02x), scsi_status" "(0x%02x)\n", ioc->name, scsi_reply->SCSIState, @@ -219,34 +262,54 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, * mpt2sas_ctl_done - ctl module completion routine * @ioc: per adapter object * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * Context: none. * * The callback handler when using ioc->ctl_cb_idx. * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -void -mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +u8 +mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + u32 reply) { MPI2DefaultReply_t *mpi_reply; + Mpi2SCSIIOReply_t *scsiio_reply; + const void *sense_data; + u32 sz; if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED) - return; + return 1; if (ioc->ctl_cmds.smid != smid) - return; + return 1; 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; + /* get sense data */ + if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || + mpi_reply->Function == + MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { + scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; + if (scsiio_reply->SCSIState & + MPI2_SCSI_STATE_AUTOSENSE_VALID) { + sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, + le32_to_cpu(scsiio_reply->SenseCount)); + sense_data = mpt2sas_base_get_sense_buffer(ioc, + smid); + memcpy(ioc->ctl_cmds.sense, sense_data, sz); + } + } } #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); + return 1; } /** @@ -328,22 +391,25 @@ mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, /** * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time) * @ioc: per adapter object - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * Context: interrupt. * * This function merely adds a new work task into ioc->firmware_event_thread. * The tasks are worked from _firmware_event_work in user context. * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -void -mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +u8 +mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, + 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); + return 1; } /** @@ -386,7 +452,7 @@ 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: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { if (!(ioc->diag_buffer_status[i] & @@ -399,7 +465,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) } break; case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_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; @@ -408,7 +474,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) } break; case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { @@ -507,7 +573,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, handle = le16_to_cpu(tm_request->DevHandle); spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - for (i = ioc->request_depth; i && !found; i--) { + for (i = ioc->scsiio_depth; i && !found; i--) { scmd = ioc->scsi_lookup[i - 1].scmd; if (scmd == NULL || scmd->device == NULL || scmd->device->hostdata == NULL) @@ -525,9 +591,9 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); if (!found) { - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, - desc, tm_request->DevHandle, lun)); + desc, le16_to_cpu(tm_request->DevHandle), lun)); tm_reply = ioc->ctl_cmds.reply; tm_reply->DevHandle = tm_request->DevHandle; tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; @@ -543,9 +609,10 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, return 1; } - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, - desc, tm_request->DevHandle, lun, tm_request->TaskMID)); + desc, le16_to_cpu(tm_request->DevHandle), lun, + le16_to_cpu(tm_request->TaskMID))); return 0; } @@ -560,7 +627,7 @@ 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; + MPI2RequestHeader_t *mpi_request = NULL, *request; MPI2DefaultReply_t *mpi_reply; u32 ioc_state; u16 ioc_status; @@ -569,7 +636,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, 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; @@ -614,36 +680,55 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, 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; + mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); + if (!mpi_request) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for " + "mpi_request\n", ioc->name, __func__); + ret = -ENOMEM; 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_TASK_MGMT) { + smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + ret = -EAGAIN; + goto out; + } + } else { + + smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); + if (!smid) { + 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); + request = mpt2sas_base_get_msg_frame(ioc, smid); + memcpy(request, mpi_request, karg.data_sge_offset*4); + ioc->ctl_cmds.smid = smid; + data_out_sz = karg.data_out_size; + data_in_sz = karg.data_in_size; + if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - if (!mpi_request->FunctionDependent1 || - mpi_request->FunctionDependent1 > - cpu_to_le16(ioc->facts.MaxDevHandle)) { + if (!le16_to_cpu(mpi_request->FunctionDependent1) || + le16_to_cpu(mpi_request->FunctionDependent1) > + ioc->facts.MaxDevHandle) { ret = -EINVAL; mpt2sas_base_free_smid(ioc, smid); goto out; @@ -684,7 +769,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, } /* add scatter gather elements */ - psge = (void *)mpi_request + (karg.data_sge_offset*4); + psge = (void *)request + (karg.data_sge_offset*4); if (!data_out_sz && !data_in_sz) { mpt2sas_base_build_zero_len_sge(ioc, psge); @@ -732,19 +817,26 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: { Mpi2SCSIIORequest_t *scsiio_request = - (Mpi2SCSIIORequest_t *)mpi_request; + (Mpi2SCSIIORequest_t *)request; + scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; 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)); + mpt2sas_base_get_sense_buffer_dma(ioc, smid); + memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); + if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) + mpt2sas_base_put_smid_scsi_io(ioc, smid, + le16_to_cpu(mpi_request->FunctionDependent1)); + else + mpt2sas_base_put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SCSI_TASK_MGMT: { Mpi2SCSITaskManagementRequest_t *tm_request = - (Mpi2SCSITaskManagementRequest_t *)mpi_request; + (Mpi2SCSITaskManagementRequest_t *)request; + + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: " + "handle(0x%04x), task_type(0x%02x)\n", ioc->name, + le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || @@ -756,11 +848,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, } } - 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); + mpt2sas_base_put_smid_hi_priority(ioc, smid); break; } case MPI2_FUNCTION_SMP_PASSTHROUGH: @@ -781,7 +871,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, ioc->ioc_link_reset_in_progress = 1; ioc->ignore_loginfos = 1; } - mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + mpt2sas_base_put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: @@ -795,11 +885,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, ioc->ioc_link_reset_in_progress = 1; ioc->ignore_loginfos = 1; } - mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + mpt2sas_base_put_smid_default(ioc, smid); break; } default: - mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + mpt2sas_base_put_smid_default(ioc, smid); break; } @@ -807,12 +897,12 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, timeout = MPT2_IOCTL_DEFAULT_TIMEOUT; else timeout = karg.timeout; + init_completion(&ioc->ctl_cmds.done); 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 || @@ -839,11 +929,12 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, Mpi2SCSITaskManagementReply_t *tm_reply = (Mpi2SCSITaskManagementReply_t *)mpi_reply; - printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " + printk(MPT2SAS_INFO_FMT "TASK_MGMT: " "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " "TerminationCount(0x%08x)\n", ioc->name, - tm_reply->IOCStatus, tm_reply->IOCLogInfo, - tm_reply->TerminationCount); + le16_to_cpu(tm_reply->IOCStatus), + le32_to_cpu(tm_reply->IOCLogInfo), + le32_to_cpu(tm_reply->TerminationCount)); } #endif /* copy out xdata to user */ @@ -874,7 +965,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, 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)) { + if (copy_to_user(karg.sense_data_ptr, + ioc->ctl_cmds.sense, sz)) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); ret = -ENODATA; @@ -884,18 +976,19 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, issue_host_reset: if (issue_reset) { + ret = -ENODATA; if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { printk(MPT2SAS_INFO_FMT "issue target reset: handle " "= (0x%04x)\n", ioc->name, - mpi_request->FunctionDependent1); - mutex_lock(&ioc->tm_cmds.mutex); + le16_to_cpu(mpi_request->FunctionDependent1)); + mpt2sas_halt_firmware(ioc); mpt2sas_scsih_issue_tm(ioc, - mpi_request->FunctionDependent1, 0, - MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); + le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, + 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, + NULL); 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); @@ -912,6 +1005,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, pci_free_consistent(ioc->pdev, data_out_sz, data_out, data_out_dma); + kfree(mpi_request); ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; mutex_unlock(&ioc->ctl_cmds.mutex); return ret; @@ -936,7 +1030,7 @@ _ctl_getiocinfo(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); memset(&karg, 0 , sizeof(karg)); @@ -984,7 +1078,7 @@ _ctl_eventquery(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE; @@ -1017,7 +1111,7 @@ _ctl_eventenable(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); if (ioc->event_log) @@ -1059,7 +1153,7 @@ _ctl_eventreport(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); number_bytes = karg.hdr.max_data_size - @@ -1104,7 +1198,7 @@ _ctl_do_reset(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, @@ -1205,7 +1299,7 @@ _ctl_btdh_mapping(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); rc = _ctl_btdh_search_sas_device(ioc, &karg); @@ -1223,7 +1317,7 @@ _ctl_btdh_mapping(void __user *arg) /** * _ctl_diag_capability - return diag buffer capability * @ioc: per adapter object - * @buffer_type: specifies either TRACE or SNAPSHOT + * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED * * returns 1 when diag buffer support is enabled in firmware */ @@ -1243,24 +1337,25 @@ _ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type) MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) rc = 1; break; + case MPI2_DIAG_BUF_TYPE_EXTENDED: + if (ioc->facts.IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) + rc = 1; } return rc; } /** - * _ctl_diag_register - application register with driver - * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING + * _ctl_diag_register_2 - wrapper for registering diag buffer support + * @ioc: per adapter object + * @diag_register: the diag_register struct passed in from user space * - * 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) +_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, + struct mpt2_diag_register *diag_register) { - struct mpt2_diag_register karg; - struct MPT2SAS_ADAPTER *ioc; int rc, i; void *request_data = NULL; dma_addr_t request_data_dma; @@ -1273,18 +1368,17 @@ _ctl_diag_register(void __user *arg, enum block_state state) 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, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); - buffer_type = karg.buffer_type; + 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; + } + + buffer_type = diag_register->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); @@ -1299,24 +1393,12 @@ _ctl_diag_register(void __user *arg, enum block_state state) return -EINVAL; } - if (karg.requested_buffer_size % 4) { + if (diag_register->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", @@ -1332,12 +1414,12 @@ _ctl_diag_register(void __user *arg, enum block_state state) 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; + request_data_sz = diag_register->requested_buffer_size; + ioc->unique_id[buffer_type] = diag_register->unique_id; ioc->diag_buffer_status[buffer_type] = 0; - memcpy(ioc->product_specific[buffer_type], karg.product_specific, - MPT2_PRODUCT_SPECIFIC_DWORDS); - ioc->diagnostic_flags[buffer_type] = karg.diagnostic_flags; + memcpy(ioc->product_specific[buffer_type], + diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS); + ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags; if (request_data) { request_data_dma = ioc->diag_buffer_dma[buffer_type]; @@ -1367,20 +1449,24 @@ _ctl_diag_register(void __user *arg, enum block_state state) } 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->BufferType = diag_register->buffer_type; + mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags); mpi_request->BufferAddress = cpu_to_le64(request_data_dma); mpi_request->BufferLength = cpu_to_le32(request_data_sz); + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), " + dctlprintk(ioc, printk(MPT2SAS_INFO_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)); + (unsigned long long)request_data_dma, + le32_to_cpu(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); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->ctl_cmds.done); timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1408,12 +1494,12 @@ _ctl_diag_register(void __user *arg, enum block_state state) 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", + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", ioc->name, __func__)); } else { - printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, mpi_reply->IOCLogInfo); + ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -1429,6 +1515,83 @@ _ctl_diag_register(void __user *arg, enum block_state state) request_data, request_data_dma); ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; + return rc; +} + +/** + * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time + * @ioc: per adapter object + * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1 + * + * This is called when command line option diag_buffer_enable is enabled + * at driver load time. + */ +void +mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register) +{ + struct mpt2_diag_register diag_register; + + memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); + + if (bits_to_register & 1) { + printk(MPT2SAS_INFO_FMT "registering trace buffer support\n", + ioc->name); + diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; + /* register for 1MB buffers */ + diag_register.requested_buffer_size = (1024 * 1024); + diag_register.unique_id = 0x7075900; + _ctl_diag_register_2(ioc, &diag_register); + } + + if (bits_to_register & 2) { + printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n", + ioc->name); + diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; + /* register for 2MB buffers */ + diag_register.requested_buffer_size = 2 * (1024 * 1024); + diag_register.unique_id = 0x7075901; + _ctl_diag_register_2(ioc, &diag_register); + } + + if (bits_to_register & 4) { + printk(MPT2SAS_INFO_FMT "registering extended buffer support\n", + ioc->name); + diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; + /* register for 2MB buffers */ + diag_register.requested_buffer_size = 2 * (1024 * 1024); + diag_register.unique_id = 0x7075901; + _ctl_diag_register_2(ioc, &diag_register); + } +} + +/** + * _ctl_diag_register - application register with driver + * @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; + long 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; + + if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) + return -EAGAIN; + else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) + return -ERESTARTSYS; + rc = _ctl_diag_register_2(ioc, &karg); mutex_unlock(&ioc->ctl_cmds.mutex); return rc; } @@ -1458,7 +1621,7 @@ _ctl_diag_unregister(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); buffer_type = karg.unique_id & 0x000000ff; @@ -1528,7 +1691,7 @@ _ctl_diag_query(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); karg.application_flags = 0; @@ -1591,7 +1754,7 @@ _ctl_diag_query(void __user *arg) /** * _ctl_send_release - Diag Release Message * @ioc: per adapter object - * @buffer_type - specifies either TRACE or SNAPSHOT + * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED * @issue_reset - specifies whether host reset is required. * */ @@ -1606,7 +1769,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) int rc; unsigned long timeleft; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); rc = 0; @@ -1614,7 +1777,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) ioc_state = mpt2sas_base_get_iocstate(ioc, 1); if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "skipping due to FAULT state\n", ioc->name, __func__)); rc = -EAGAIN; @@ -1643,8 +1806,11 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE; mpi_request->BufferType = buffer_type; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; - mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->ctl_cmds.done); timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1673,12 +1839,12 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) 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", + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", ioc->name, __func__)); } else { - printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, mpi_reply->IOCLogInfo); + ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -1714,7 +1880,7 @@ _ctl_diag_release(void __user *arg, enum block_state state) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); buffer_type = karg.unique_id & 0x000000ff; @@ -1810,7 +1976,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); buffer_type = karg.unique_id & 0x000000ff; @@ -1841,7 +2007,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) } diag_data = (void *)(request_data + karg.starting_offset); - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " "offset(%d), sz(%d)\n", ioc->name, __func__, diag_data, karg.starting_offset, karg.bytes_to_read)); @@ -1856,11 +2022,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0) return 0; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister " + dctlprintk(ioc, printk(MPT2SAS_INFO_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: " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "buffer_type(0x%02x) is still registered\n", ioc->name, __func__, buffer_type)); return 0; @@ -1902,8 +2068,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) mpi_request->ProductSpecific[i] = cpu_to_le32(ioc->product_specific[buffer_type][i]); + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; - mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->ctl_cmds.done); timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1931,12 +2100,12 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) 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", + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", ioc->name, __func__)); } else { - printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, mpi_reply->IOCLogInfo); + ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; } @@ -1963,7 +2132,6 @@ _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; @@ -1989,13 +2157,8 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) !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); + if (ioc->shost_recovery || ioc->pci_error_recovery) return -EAGAIN; - } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { uarg = arg; @@ -2057,7 +2220,7 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); break; } @@ -2075,9 +2238,10 @@ static long _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + + mutex_lock(&_ctl_mutex); ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); - unlock_kernel(); + mutex_unlock(&_ctl_mutex); return ret; } @@ -2098,7 +2262,6 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) 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; @@ -2113,13 +2276,8 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) 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); + if (ioc->shost_recovery || ioc->pci_error_recovery) 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; @@ -2131,14 +2289,10 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) 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)); + karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); + karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); + karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); + karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); } @@ -2155,12 +2309,13 @@ static long _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) { long ret; - lock_kernel(); + + mutex_lock(&_ctl_mutex); if (cmd == MPT2COMMAND32) ret = _ctl_compat_mpt_command(file, cmd, arg); else ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); - unlock_kernel(); + mutex_unlock(&_ctl_mutex); return ret; } #endif @@ -2265,8 +2420,8 @@ _ctl_version_nvdata_persistent_show(struct device *cdev, 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)); + return snprintf(buf, PAGE_SIZE, "%08xh\n", + le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); } static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, _ctl_version_nvdata_persistent_show, NULL); @@ -2285,8 +2440,8 @@ _ctl_version_nvdata_default_show(struct device *cdev, 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)); + return snprintf(buf, PAGE_SIZE, "%08xh\n", + le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); } static DEVICE_ATTR(version_nvdata_default, S_IRUGO, _ctl_version_nvdata_default_show, NULL); @@ -2469,6 +2624,255 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, _ctl_logging_level_store); +/* device attributes */ +/* + * _ctl_fwfault_debug_show - show/store fwfault_debug + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * mpt2sas_fwfault_debug is command line option + * A sysfs 'read/write' shost attribute. + */ +static ssize_t +_ctl_fwfault_debug_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); +} +static ssize_t +_ctl_fwfault_debug_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + int val = 0; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + ioc->fwfault_debug = val; + printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name, + ioc->fwfault_debug); + return strlen(buf); +} +static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, + _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); + + +/** + * _ctl_ioc_reset_count_show - ioc reset count + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is firmware queue depth limit + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count); +} +static DEVICE_ATTR(ioc_reset_count, S_IRUGO, + _ctl_ioc_reset_count_show, NULL); + +struct DIAG_BUFFER_START { + u32 Size; + u32 DiagVersion; + u8 BufferType; + u8 Reserved[3]; + u32 Reserved1; + u32 Reserved2; + u32 Reserved3; +}; +/** + * _ctl_host_trace_buffer_size_show - host buffer size (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_host_trace_buffer_size_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + u32 size = 0; + struct DIAG_BUFFER_START *request_data; + + if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { + printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " + "registered\n", ioc->name, __func__); + return 0; + } + + if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " + "registered\n", ioc->name, __func__); + return 0; + } + + request_data = (struct DIAG_BUFFER_START *) + ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; + if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || + le32_to_cpu(request_data->DiagVersion) == 0x01000000) && + le32_to_cpu(request_data->Reserved3) == 0x4742444c) + size = le32_to_cpu(request_data->Size); + + ioc->ring_buffer_sz = size; + return snprintf(buf, PAGE_SIZE, "%d\n", size); +} +static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, + _ctl_host_trace_buffer_size_show, NULL); + +/** + * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read/write' shost attribute. + * + * You will only be able to read 4k bytes of ring buffer at a time. + * In order to read beyond 4k bytes, you will have to write out the + * offset to the same attribute, it will move the pointer. + */ +static ssize_t +_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + void *request_data; + u32 size; + + if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { + printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " + "registered\n", ioc->name, __func__); + return 0; + } + + if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " + "registered\n", ioc->name, __func__); + return 0; + } + + if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) + return 0; + + size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; + size = (size > PAGE_SIZE) ? PAGE_SIZE : size; + request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; + memcpy(buf, request_data, size); + return size; +} + +static ssize_t +_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + int val = 0; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + ioc->ring_buffer_offset = val; + return strlen(buf); +} +static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, + _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); + +/*****************************************/ + +/** + * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read/write' shost attribute. + * + * This is a mechnism to post/release host_trace_buffers + */ +static ssize_t +_ctl_host_trace_buffer_enable_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || + ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)) + return snprintf(buf, PAGE_SIZE, "off\n"); + else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_RELEASED)) + return snprintf(buf, PAGE_SIZE, "release\n"); + else + return snprintf(buf, PAGE_SIZE, "post\n"); +} + +static ssize_t +_ctl_host_trace_buffer_enable_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + char str[10] = ""; + struct mpt2_diag_register diag_register; + u8 issue_reset = 0; + + if (sscanf(buf, "%s", str) != 1) + return -EINVAL; + + if (!strcmp(str, "post")) { + /* exit out if host buffers are already posted */ + if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && + (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) && + ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_RELEASED) == 0)) + goto out; + memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); + printk(MPT2SAS_INFO_FMT "posting host trace buffers\n", + ioc->name); + diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; + diag_register.requested_buffer_size = (1024 * 1024); + diag_register.unique_id = 0x7075900; + ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; + _ctl_diag_register_2(ioc, &diag_register); + } else if (!strcmp(str, "release")) { + /* exit out if host buffers are already released */ + if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) + goto out; + if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) + goto out; + if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_RELEASED)) + goto out; + printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n", + ioc->name); + _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); + } + + out: + return strlen(buf); +} +static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, + _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store); + struct device_attribute *mpt2sas_host_attrs[] = { &dev_attr_version_fw, &dev_attr_version_bios, @@ -2482,13 +2886,16 @@ struct device_attribute *mpt2sas_host_attrs[] = { &dev_attr_io_delay, &dev_attr_device_delay, &dev_attr_logging_level, + &dev_attr_fwfault_debug, &dev_attr_fw_queue_depth, &dev_attr_host_sas_address, + &dev_attr_ioc_reset_count, + &dev_attr_host_trace_buffer_size, + &dev_attr_host_trace_buffer, + &dev_attr_host_trace_buffer_enable, NULL, }; -/* device attributes */ - /** * _ctl_device_sas_address_show - sas address * @cdev - pointer to embedded class device @@ -2546,6 +2953,7 @@ static const struct file_operations ctl_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = _ctl_ioctl_compat, #endif + .llseek = noop_llseek, }; static struct miscdevice ctl_dev = { diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 4da11435533..69916e46e04 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -3,7 +3,7 @@ * controllers * * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h - * Copyright (C) 2007-2008 LSI Corporation + * Copyright (C) 2007-2010 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * * This program is free software; you can redistribute it and/or @@ -313,7 +313,7 @@ struct mpt2_ioctl_btdh_mapping { * struct mpt2_diag_register - application register with driver * @hdr - generic header * @reserved - - * @buffer_type - specifies either TRACE or SNAPSHOT + * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED * @application_flags - misc flags * @diagnostic_flags - specifies flags affecting command processing * @product_specific - product specific information @@ -352,7 +352,7 @@ struct mpt2_diag_unregister { * struct mpt2_diag_query - query relevant info associated with diag buffers * @hdr - generic header * @reserved - - * @buffer_type - specifies either TRACE or SNAPSHOT + * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED * @application_flags - misc flags * @diagnostic_flags - specifies flags affecting command processing * @product_specific - product specific information diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h index ad325096e84..3dcddfeb6f4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h @@ -2,7 +2,7 @@ * 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 + * Copyright (C) 2007-2010 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 2a01a5f2a84..eda347c5797 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2,7 +2,7 @@ * Scsi Host Layer for MPT (Message Passing Technology) based controllers * * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c - * Copyright (C) 2007-2008 LSI Corporation + * Copyright (C) 2007-2010 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * * This program is free software; you can redistribute it and/or @@ -52,6 +52,9 @@ #include <linux/delay.h> #include <linux/pci.h> #include <linux/interrupt.h> +#include <linux/aer.h> +#include <linux/raid_class.h> +#include <linux/slab.h> #include "mpt2sas_base.h" @@ -67,6 +70,8 @@ static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_expander); static void _firmware_event_work(struct work_struct *work); +static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid); + /* global parameters */ LIST_HEAD(mpt2sas_ioc_list); @@ -76,9 +81,14 @@ static u8 tm_cb_idx = -1; static u8 ctl_cb_idx = -1; static u8 base_cb_idx = -1; static u8 transport_cb_idx = -1; +static u8 scsih_cb_idx = -1; static u8 config_cb_idx = -1; static int mpt_ids; +static u8 tm_tr_cb_idx = -1 ; +static u8 tm_tr_volume_cb_idx = -1 ; +static u8 tm_sas_control_cb_idx = -1; + /* command line options */ static u32 logging_level; MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " @@ -104,13 +114,15 @@ struct sense_info { #define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF) + /** * struct fw_event_work - firmware event struct * @list: link list framework * @work: work object (ioc->fault_reset_work_q) + * @cancel_pending_work: flag set during reset handling * @ioc: per adapter object * @VF_ID: virtual function id - * @host_reset_handling: handling events during host reset + * @VP_ID: virtual port id * @ignore: flag meaning this event has been marked to ignore * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h * @event_data: reply event data payload follows @@ -119,15 +131,19 @@ struct sense_info { */ struct fw_event_work { struct list_head list; - struct work_struct work; + u8 cancel_pending_work; + struct delayed_work delayed_work; struct MPT2SAS_ADAPTER *ioc; u8 VF_ID; - u8 host_reset_handling; + u8 VP_ID; u8 ignore; u16 event; void *event_data; }; +/* raid transport support */ +static struct raid_template *mpt2sas_raid_template; + /** * struct _scsi_io_transfer - scsi io transfer * @handle: sas device handle (assigned by firmware) @@ -139,8 +155,10 @@ struct fw_event_work { * @lun: lun number * @cdb_length: cdb length * @cdb: cdb contents - * @valid_reply: flag set for reply message * @timeout: timeout for this command + * @VF_ID: virtual function id + * @VP_ID: virtual port id + * @valid_reply: flag set for reply message * @sense_length: sense length * @ioc_status: ioc status * @scsi_state: scsi state @@ -162,6 +180,8 @@ struct _scsi_io_transfer { u8 cdb_length; u8 cdb[32]; u8 timeout; + u8 VF_ID; + u8 VP_ID; u8 valid_reply; /* the following bits are only valid when 'valid_reply = 1' */ u32 sense_length; @@ -188,10 +208,31 @@ static struct pci_device_id scsih_pci_table[] = { PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, PCI_ANY_ID, PCI_ANY_ID }, + /* Meteor ~ 2116 */ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, PCI_ANY_ID, PCI_ANY_ID }, + /* Thunderbolt ~ 2208 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, + PCI_ANY_ID, PCI_ANY_ID }, + /* Mustang ~ 2308 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, + PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, scsih_pci_table); @@ -309,6 +350,47 @@ _scsih_is_boot_device(u64 sas_address, u64 device_name, } /** + * _scsih_get_sas_address - set the sas_address for given device handle + * @handle: device handle + * @sas_address: sas address + * + * Returns 0 success, non-zero when failure + */ +static int +_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle, + u64 *sas_address) +{ + Mpi2SasDevicePage0_t sas_device_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 ioc_status; + + if (handle <= ioc->sas_hba.num_phys) { + *sas_address = ioc->sas_hba.sas_address; + return 0; + } else + *sas_address = 0; + + 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 -ENXIO; + } + + 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 -EIO; + } + + *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + return 0; +} + +/** * _scsih_determine_boot_device - determine boot device. * @ioc: per adapter object * @device: either sas_device or raid_device object @@ -356,7 +438,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, (ioc->bios_pg2.ReqBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.RequestedBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: req_boot_device(0x%016llx)\n", ioc->name, __func__, (unsigned long long)sas_address)); @@ -371,7 +453,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, (ioc->bios_pg2.ReqAltBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.RequestedAltBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: req_alt_boot_device(0x%016llx)\n", ioc->name, __func__, (unsigned long long)sas_address)); @@ -386,7 +468,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, (ioc->bios_pg2.CurrentBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.CurrentBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: current_boot_device(0x%016llx)\n", ioc->name, __func__, (unsigned long long)sas_address)); @@ -409,27 +491,17 @@ struct _sas_device * mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) { - struct _sas_device *sas_device, *r; + struct _sas_device *sas_device; - r = NULL; - /* check the sas_device_init_list */ - list_for_each_entry(sas_device, &ioc->sas_device_init_list, - list) { - if (sas_device->sas_address != sas_address) - continue; - r = sas_device; - goto out; - } + list_for_each_entry(sas_device, &ioc->sas_device_list, list) + if (sas_device->sas_address == sas_address) + return sas_device; - /* then check the sas_device_list */ - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->sas_address != sas_address) - continue; - r = sas_device; - goto out; - } - out: - return r; + list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) + if (sas_device->sas_address == sas_address) + return sas_device; + + return NULL; } /** @@ -444,28 +516,17 @@ mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, static struct _sas_device * _scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) { - struct _sas_device *sas_device, *r; + struct _sas_device *sas_device; - r = NULL; - if (ioc->wait_for_port_enable_to_complete) { - list_for_each_entry(sas_device, &ioc->sas_device_init_list, - list) { - if (sas_device->handle != handle) - continue; - r = sas_device; - goto out; - } - } else { - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->handle != handle) - continue; - r = sas_device; - goto out; - } - } + list_for_each_entry(sas_device, &ioc->sas_device_list, list) + if (sas_device->handle == handle) + return sas_device; - out: - return r; + list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) + if (sas_device->handle == handle) + return sas_device; + + return NULL; } /** @@ -482,10 +543,15 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, { unsigned long flags; + if (!sas_device) + return; + spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_del(&sas_device->list); - memset(sas_device, 0, sizeof(struct _sas_device)); - kfree(sas_device); + if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device->sas_address)) { + list_del(&sas_device->list); + kfree(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -502,10 +568,8 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, struct _sas_device *sas_device) { unsigned long flags; - u16 handle, parent_handle; - u64 sas_address; - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, sas_device->handle, (unsigned long long)sas_device->sas_address)); @@ -513,10 +577,8 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, list_add_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - handle = sas_device->handle; - parent_handle = sas_device->parent_handle; - sas_address = sas_device->sas_address; - if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, + sas_device->sas_address_parent)) _scsih_sas_device_remove(ioc, sas_device); } @@ -534,7 +596,7 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, sas_device->handle, (unsigned long long)sas_device->sas_address)); @@ -545,31 +607,6 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, } /** - * mpt2sas_scsih_expander_find_by_handle - expander device search - * @ioc: per adapter object - * @handle: expander handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for expander device based on handle, then returns the - * sas_node object. - */ -struct _sas_node * -mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_node *sas_expander, *r; - - r = NULL; - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->handle != handle) - continue; - r = sas_expander; - goto out; - } - out: - return r; -} - -/** * _scsih_raid_device_find_by_id - raid device search * @ioc: per adapter object * @id: sas device target id @@ -661,7 +698,7 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, raid_device->handle, (unsigned long long)raid_device->wwid)); @@ -691,6 +728,31 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc, } /** + * mpt2sas_scsih_expander_find_by_handle - expander device search + * @ioc: per adapter object + * @handle: expander handle (assigned by firmware) + * Context: Calling function should acquire ioc->sas_device_lock + * + * This searches for expander device based on handle, then returns the + * sas_node object. + */ +struct _sas_node * +mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_node *sas_expander, *r; + + r = NULL; + list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { + if (sas_expander->handle != handle) + continue; + r = sas_expander; + goto out; + } + out: + return r; +} + +/** * mpt2sas_scsih_expander_find_by_sas_address - expander device search * @ioc: per adapter object * @sas_address: sas address @@ -757,66 +819,16 @@ _scsih_is_end_device(u32 device_info) } /** - * _scsih_scsi_lookup_get - returns scmd entry + * mptscsih_get_scsi_lookup - returns scmd entry * @ioc: per adapter object * @smid: system request message index - * Context: This function will acquire ioc->scsi_lookup_lock. * * Returns the smid stored scmd pointer. */ static struct scsi_cmnd * _scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) { - unsigned long flags; - struct scsi_cmnd *scmd; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - scmd = ioc->scsi_lookup[smid - 1].scmd; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return scmd; -} - -/** - * mptscsih_getclear_scsi_lookup - returns scmd entry - * @ioc: per adapter object - * @smid: system request message index - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * Returns the smid stored scmd pointer, as well as clearing the scmd pointer. - */ -static struct scsi_cmnd * -_scsih_scsi_lookup_getclear(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - unsigned long flags; - struct scsi_cmnd *scmd; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - scmd = ioc->scsi_lookup[smid - 1].scmd; - ioc->scsi_lookup[smid - 1].scmd = NULL; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return scmd; -} - -/** - * _scsih_scsi_lookup_set - updates scmd entry in lookup - * @ioc: per adapter object - * @smid: system request message index - * @scmd: pointer to scsi command object - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will save scmd pointer in the scsi_lookup array. - * - * Return nothing. - */ -static void -_scsih_scsi_lookup_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, - struct scsi_cmnd *scmd) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - ioc->scsi_lookup[smid - 1].scmd = scmd; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return ioc->scsi_lookup[smid - 1].scmd; } /** @@ -839,9 +851,9 @@ _scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); smid = 0; - for (i = 0; i < ioc->request_depth; i++) { + for (i = 0; i < ioc->scsiio_depth; i++) { if (ioc->scsi_lookup[i].scmd == scmd) { - smid = i + 1; + smid = ioc->scsi_lookup[i].smid; goto out; } } @@ -870,7 +882,7 @@ _scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id, spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); found = 0; - for (i = 0 ; i < ioc->request_depth; i++) { + for (i = 0 ; i < ioc->scsiio_depth; i++) { if (ioc->scsi_lookup[i].scmd && (ioc->scsi_lookup[i].scmd->device->id == id && ioc->scsi_lookup[i].scmd->device->channel == channel)) { @@ -904,7 +916,7 @@ _scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id, spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); found = 0; - for (i = 0 ; i < ioc->request_depth; i++) { + for (i = 0 ; i < ioc->scsiio_depth; i++) { if (ioc->scsi_lookup[i].scmd && (ioc->scsi_lookup[i].scmd->device->id == id && ioc->scsi_lookup[i].scmd->device->channel == channel && @@ -919,31 +931,32 @@ _scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id, } /** - * _scsih_get_chain_buffer_dma - obtain block of chains (dma address) + * _scsih_get_chain_buffer_tracker - obtain chain tracker * @ioc: per adapter object - * @smid: system request message index + * @smid: smid associated to an IO request * - * Returns phys pointer to chain buffer. + * Returns chain tracker(from ioc->free_chain_list) */ -static dma_addr_t -_scsih_get_chain_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) +static struct chain_tracker * +_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid) { - return ioc->chain_dma + ((smid - 1) * (ioc->request_sz * - ioc->chains_needed_per_io)); -} + struct chain_tracker *chain_req; + unsigned long flags; -/** - * _scsih_get_chain_buffer - obtain block of chains assigned to a mf request - * @ioc: per adapter object - * @smid: system request message index - * - * Returns virt pointer to chain buffer. - */ -static void * -_scsih_get_chain_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return (void *)(ioc->chain + ((smid - 1) * (ioc->request_sz * - ioc->chains_needed_per_io))); + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + if (list_empty(&ioc->free_chain_list)) { + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + printk(MPT2SAS_WARN_FMT "chain buffers not available\n", + ioc->name); + return NULL; + } + chain_req = list_entry(ioc->free_chain_list.next, + struct chain_tracker, tracker_list); + list_del_init(&chain_req->tracker_list); + list_add_tail(&chain_req->tracker_list, + &ioc->scsi_lookup[smid - 1].chain_list); + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + return chain_req; } /** @@ -969,11 +982,12 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, u32 chain_offset; u32 chain_length; u32 chain_flags; - u32 sges_left; + int sges_left; u32 sges_in_segment; u32 sgl_flags; u32 sgl_flags_last_element; u32 sgl_flags_end_buffer; + struct chain_tracker *chain_req; mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); @@ -990,7 +1004,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, sg_scmd = scsi_sglist(scmd); sges_left = scsi_dma_map(scmd); - if (!sges_left) { + if (sges_left < 0) { sdev_printk(KERN_ERR, scmd->device, "pci_map_sg" " failed: request for %d bytes!\n", scsi_bufflen(scmd)); return -ENOMEM; @@ -1021,8 +1035,11 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, /* initializing the chain flags and pointers */ chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; - chain = _scsih_get_chain_buffer(ioc, smid); - chain_dma = _scsih_get_chain_buffer_dma(ioc, smid); + chain_req = _scsih_get_chain_buffer_tracker(ioc, smid); + if (!chain_req) + return -1; + chain = chain_req->chain_buffer; + chain_dma = chain_req->chain_buffer_dma; do { sges_in_segment = (sges_left <= ioc->max_sges_in_chain_message) ? sges_left : @@ -1058,8 +1075,11 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, sges_in_segment--; } - chain_dma += ioc->request_sz; - chain += ioc->request_sz; + chain_req = _scsih_get_chain_buffer_tracker(ioc, smid); + if (!chain_req) + return -1; + chain = chain_req->chain_buffer; + chain_dma = chain_req->chain_buffer_dma; } while (1); @@ -1082,26 +1102,70 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, } /** - * _scsih_change_queue_depth - setting device queue depth + * _scsih_adjust_queue_depth - setting device queue depth * @sdev: scsi device struct * @qdepth: requested queue depth * - * Returns queue depth. + * + * Returns nothing */ -static int -_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) +static void +_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) { struct Scsi_Host *shost = sdev->host; int max_depth; - int tag_type; + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + struct MPT2SAS_DEVICE *sas_device_priv_data; + struct MPT2SAS_TARGET *sas_target_priv_data; + struct _sas_device *sas_device; + unsigned long flags; max_depth = shost->can_queue; + + /* limit max device queue for SATA to 32 */ + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + goto not_sata; + sas_target_priv_data = sas_device_priv_data->sas_target; + if (!sas_target_priv_data) + goto not_sata; + if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) + goto not_sata; + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device_priv_data->sas_target->sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device && sas_device->device_info & + MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + max_depth = MPT2SAS_SATA_QUEUE_DEPTH; + + not_sata: + if (!sdev->tagged_supported) max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; - tag_type = (qdepth == 1) ? 0 : MSG_SIMPLE_TAG; - scsi_adjust_queue_depth(sdev, tag_type, qdepth); + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); +} + +/** + * _scsih_change_queue_depth - setting device queue depth + * @sdev: scsi device struct + * @qdepth: requested queue depth + * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP + * (see include/scsi/scsi_host.h for definition) + * + * Returns queue depth. + */ +static int +_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) +{ + if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) + _scsih_adjust_queue_depth(sdev, qdepth); + else if (reason == SCSI_QDEPTH_QFULL) + scsi_track_queue_full(sdev, qdepth); + else + return -EOPNOTSUPP; if (sdev->inquiry_len > 7) sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), " @@ -1114,7 +1178,7 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) } /** - * _scsih_change_queue_depth - changing device queue tag type + * _scsih_change_queue_type - changing device queue tag type * @sdev: scsi device struct * @tag_type: requested tag type * @@ -1188,7 +1252,7 @@ _scsih_target_alloc(struct scsi_target *starget) sas_device->starget = starget; sas_device->id = starget->id; sas_device->channel = starget->channel; - if (sas_device->hidden_raid_component) + if (test_bit(sas_device->handle, ioc->pd_handles)) sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; } @@ -1262,7 +1326,6 @@ _scsih_slave_alloc(struct scsi_device *sdev) struct MPT2SAS_DEVICE *sas_device_priv_data; struct scsi_target *starget; struct _raid_device *raid_device; - struct _sas_device *sas_device; unsigned long flags; sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL); @@ -1289,21 +1352,8 @@ _scsih_slave_alloc(struct scsi_device *sdev) if (raid_device) raid_device->sdev = sdev; /* raid is single lun */ spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } else { - /* set TLR bit for SSP devices */ - if (!(ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_TLR)) - goto out; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device && sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SSP_TARGET) - sas_device_priv_data->flags |= MPT_DEVICE_TLR_ON; } - out: return 0; } @@ -1361,7 +1411,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, } flags = le16_to_cpu(sas_device_pg0.Flags); - device_info = le16_to_cpu(sas_device_pg0.DeviceInfo); + device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); sdev_printk(KERN_INFO, sdev, "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " @@ -1376,6 +1426,140 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, } /** + * _scsih_is_raid - return boolean indicating device is raid volume + * @dev the device struct object + */ +static int +_scsih_is_raid(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return (sdev->channel == RAID_CHANNEL) ? 1 : 0; +} + +/** + * _scsih_get_resync - get raid volume resync percent complete + * @dev the device struct object + */ +static void +_scsih_get_resync(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); + static struct _raid_device *raid_device; + unsigned long flags; + Mpi2RaidVolPage0_t vol_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 volume_status_flags; + u8 percent_complete = 0; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, + sdev->channel); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + goto out; + + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, + sizeof(Mpi2RaidVolPage0_t))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); + if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) + percent_complete = raid_device->percent_complete; + out: + raid_set_resync(mpt2sas_raid_template, dev, percent_complete); +} + +/** + * _scsih_get_state - get raid volume level + * @dev the device struct object + */ +static void +_scsih_get_state(struct device *dev) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); + static struct _raid_device *raid_device; + unsigned long flags; + Mpi2RaidVolPage0_t vol_pg0; + Mpi2ConfigReply_t mpi_reply; + u32 volstate; + enum raid_state state = RAID_STATE_UNKNOWN; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, + sdev->channel); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + goto out; + + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, + sizeof(Mpi2RaidVolPage0_t))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + goto out; + } + + volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags); + if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { + state = RAID_STATE_RESYNCING; + goto out; + } + + switch (vol_pg0.VolumeState) { + case MPI2_RAID_VOL_STATE_OPTIMAL: + case MPI2_RAID_VOL_STATE_ONLINE: + state = RAID_STATE_ACTIVE; + break; + case MPI2_RAID_VOL_STATE_DEGRADED: + state = RAID_STATE_DEGRADED; + break; + case MPI2_RAID_VOL_STATE_FAILED: + case MPI2_RAID_VOL_STATE_MISSING: + state = RAID_STATE_OFFLINE; + break; + } + out: + raid_set_state(mpt2sas_raid_template, dev, state); +} + +/** + * _scsih_set_level - set raid level + * @sdev: scsi device struct + * @raid_device: raid_device object + */ +static void +_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device) +{ + enum raid_level level = RAID_LEVEL_UNKNOWN; + + switch (raid_device->volume_type) { + case MPI2_RAID_VOL_TYPE_RAID0: + level = RAID_LEVEL_0; + break; + case MPI2_RAID_VOL_TYPE_RAID10: + level = RAID_LEVEL_10; + break; + case MPI2_RAID_VOL_TYPE_RAID1E: + level = RAID_LEVEL_1E; + break; + case MPI2_RAID_VOL_TYPE_RAID1: + level = RAID_LEVEL_1; + break; + } + + raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level); +} + +/** * _scsih_get_volume_capabilities - volume capabilities * @ioc: per adapter object * @sas_device: the raid_device object @@ -1436,6 +1620,32 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, } /** + * _scsih_enable_tlr - setting TLR flags + * @ioc: per adapter object + * @sdev: scsi device struct + * + * Enabling Transaction Layer Retries for tape devices when + * vpd page 0x90 is present + * + */ +static void +_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev) +{ + /* only for TAPE */ + if (sdev->type != TYPE_TAPE) + return; + + if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)) + return; + + sas_enable_tlr(sdev); + sdev_printk(KERN_INFO, sdev, "TLR %s\n", + sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled"); + return; + +} + +/** * _scsih_slave_configure - device configure routine. * @sdev: scsi device struct * @@ -1502,7 +1712,13 @@ _scsih_slave_configure(struct scsi_device *sdev) break; case MPI2_RAID_VOL_TYPE_RAID1E: qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - r_level = "RAID1E"; + if (ioc->manu_pg10.OEMIdentifier && + (ioc->manu_pg10.GenericFlags0 & + MFG10_GF0_R10_DISPLAY) && + !(raid_device->num_pds % 2)) + r_level = "RAID10"; + else + r_level = "RAID1E"; break; case MPI2_RAID_VOL_TYPE_RAID1: qdepth = MPT2SAS_RAID_QUEUE_DEPTH; @@ -1524,7 +1740,9 @@ _scsih_slave_configure(struct scsi_device *sdev) r_level, raid_device->handle, (unsigned long long)raid_device->wwid, raid_device->num_pds, ds); - _scsih_change_queue_depth(sdev, qdepth); + _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); + /* raid transport support */ + _scsih_set_level(sdev, raid_device); return 0; } @@ -1557,9 +1775,10 @@ _scsih_slave_configure(struct scsi_device *sdev) } sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " - "sas_addr(0x%016llx), device_name(0x%016llx)\n", + "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", ds, sas_device->handle, (unsigned long long)sas_device->sas_address, + sas_device->phy, (unsigned long long)sas_device->device_name); sdev_printk(KERN_INFO, sdev, "%s: " "enclosure_logical_id(0x%016llx), slot(%d)\n", ds, @@ -1570,10 +1789,12 @@ _scsih_slave_configure(struct scsi_device *sdev) _scsih_display_sata_capabilities(ioc, sas_device, sdev); } - _scsih_change_queue_depth(sdev, qdepth); + _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); - if (ssp_target) + if (ssp_target) { sas_read_port_mode_page(sdev); + _scsih_enable_tlr(ioc, sdev); + } return 0; } @@ -1674,23 +1895,24 @@ _scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code) * _scsih_tm_done - tm completion routine * @ioc: per adapter object * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * Context: none. * * The callback handler when using scsih_issue_tm. * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -static void -_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +static u8 +_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) { MPI2DefaultReply_t *mpi_reply; if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED) - return; + return 1; if (ioc->tm_cmds.smid != smid) - return; + return 1; ioc->tm_cmds.status |= MPT2_CMD_COMPLETE; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); if (mpi_reply) { @@ -1699,6 +1921,7 @@ _scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) } ioc->tm_cmds.status &= ~MPT2_CMD_PENDING; complete(&ioc->tm_cmds.done); + return 1; } /** @@ -1757,69 +1980,84 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) } } + /** * mpt2sas_scsih_issue_tm - main routine for sending tm requests * @ioc: per adapter struct * @device_handle: device handle + * @channel: the channel assigned by the OS + * @id: the id assigned by the OS * @lun: lun number * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) * @smid_task: smid assigned to the task * @timeout: timeout in seconds - * Context: The calling function needs to acquire the tm_cmds.mutex + * Context: user * * A generic API for sending task management requests to firmware. * - * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling - * this API. - * * The callback index is set inside `ioc->tm_cb_idx`. * - * Return nothing. + * Return SUCCESS or FAILED. */ -void -mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, - u8 type, u16 smid_task, ulong timeout) +int +mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, + uint id, uint lun, u8 type, u16 smid_task, ulong timeout, + struct scsi_cmnd *scmd) { Mpi2SCSITaskManagementRequest_t *mpi_request; Mpi2SCSITaskManagementReply_t *mpi_reply; u16 smid = 0; u32 ioc_state; unsigned long timeleft; - u8 VF_ID = 0; - unsigned long flags; + struct scsi_cmnd *scmd_lookup; + int rc; + + mutex_lock(&ioc->tm_cmds.mutex); + if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", + __func__, ioc->name); + rc = FAILED; + goto err_out; + } - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED || - ioc->shost_recovery) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); - return; + rc = FAILED; + goto err_out; } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); ioc_state = mpt2sas_base_get_iocstate(ioc, 0); if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " "active!\n", ioc->name)); - goto issue_host_reset; + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + rc = SUCCESS; + goto err_out; } if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { mpt2sas_base_fault_info(ioc, ioc_state & MPI2_DOORBELL_DATA_MASK); - goto issue_host_reset; + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + rc = SUCCESS; + goto err_out; } - smid = mpt2sas_base_get_smid(ioc, ioc->tm_cb_idx); + smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); if (!smid) { printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", ioc->name, __func__); - return; + rc = FAILED; + goto err_out; } dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," - " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid)); + " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, + smid_task)); ioc->tm_cmds.status = MPT2_CMD_PENDING; mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); ioc->tm_cmds.smid = smid; @@ -1830,16 +2068,22 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, mpi_request->TaskMID = cpu_to_le16(smid_task); int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); mpt2sas_scsih_set_tm_flag(ioc, handle); - mpt2sas_base_put_smid_hi_priority(ioc, smid, VF_ID); + init_completion(&ioc->tm_cmds.done); + mpt2sas_base_put_smid_hi_priority(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); - mpt2sas_scsih_clear_tm_flag(ioc, handle); if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) { printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, __func__); _debug_dump_mf(mpi_request, sizeof(Mpi2SCSITaskManagementRequest_t)/4); - if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) - goto issue_host_reset; + if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + rc = SUCCESS; + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mpt2sas_scsih_clear_tm_flag(ioc, handle); + goto err_out; + } } if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) { @@ -1849,17 +2093,113 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun, ioc->name, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo), le32_to_cpu(mpi_reply->TerminationCount))); - if (ioc->logging_level & MPT_DEBUG_TM) + if (ioc->logging_level & MPT_DEBUG_TM) { _scsih_response_code(ioc, mpi_reply->ResponseCode); + if (mpi_reply->IOCStatus) + _debug_dump_mf(mpi_request, + sizeof(Mpi2SCSITaskManagementRequest_t)/4); + } + } + + /* sanity check: + * Check to see the commands were terminated. + * This is only needed for eh callbacks, hence the scmd check. + */ + rc = FAILED; + if (scmd == NULL) + goto bypass_sanity_checks; + switch (type) { + case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: + scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task); + if (scmd_lookup && (scmd_lookup->serial_number == + scmd->serial_number)) + rc = FAILED; + else + rc = SUCCESS; + break; + + case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: + if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) + rc = FAILED; + else + rc = SUCCESS; + break; + + case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: + if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) + rc = FAILED; + else + rc = SUCCESS; + break; + } + + bypass_sanity_checks: + + mpt2sas_scsih_clear_tm_flag(ioc, handle); + ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->tm_cmds.mutex); + + return rc; + + err_out: + mutex_unlock(&ioc->tm_cmds.mutex); + return rc; +} + +/** + * _scsih_tm_display_info - displays info about the device + * @ioc: per adapter struct + * @scmd: pointer to scsi command object + * + * Called by task management callback handlers. + */ +static void +_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) +{ + struct scsi_target *starget = scmd->device->sdev_target; + struct MPT2SAS_TARGET *priv_target = starget->hostdata; + struct _sas_device *sas_device = NULL; + unsigned long flags; + + if (!priv_target) + return; + + scsi_print_command(scmd); + if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { + starget_printk(KERN_INFO, starget, "volume handle(0x%04x), " + "volume wwid(0x%016llx)\n", + priv_target->handle, + (unsigned long long)priv_target->sas_address); + } else { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + priv_target->sas_address); + if (sas_device) { + if (priv_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT) { + starget_printk(KERN_INFO, starget, + "volume handle(0x%04x), " + "volume wwid(0x%016llx)\n", + sas_device->volume_handle, + (unsigned long long)sas_device->volume_wwid); + } + starget_printk(KERN_INFO, starget, + "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n", + sas_device->handle, + (unsigned long long)sas_device->sas_address, + sas_device->phy); + starget_printk(KERN_INFO, starget, + "enclosure_logical_id(0x%016llx), slot(%d)\n", + (unsigned long long)sas_device->enclosure_logical_id, + sas_device->slot); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } - return; - issue_host_reset: - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); } /** * _scsih_abort - eh threads main abort routine - * @sdev: scsi device struct + * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ @@ -1871,16 +2211,15 @@ _scsih_abort(struct scsi_cmnd *scmd) u16 smid; u16 handle; int r; - struct scsi_cmnd *scmd_lookup; - printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n", - ioc->name, scmd); - scsi_print_command(scmd); + sdev_printk(KERN_INFO, scmd->device, "attempting task abort! " + "scmd(%p)\n", scmd); + _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n", - ioc->name, scmd); + sdev_printk(KERN_INFO, scmd->device, "device been deleted! " + "scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); r = SUCCESS; @@ -1904,29 +2243,22 @@ _scsih_abort(struct scsi_cmnd *scmd) goto out; } - mutex_lock(&ioc->tm_cmds.mutex); - handle = sas_device_priv_data->sas_target->handle; - mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun, - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30); + mpt2sas_halt_firmware(ioc); - /* sanity check - see whether command actually completed */ - scmd_lookup = _scsih_scsi_lookup_get(ioc, smid); - if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number)) - r = FAILED; - else - r = SUCCESS; - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->tm_cmds.mutex); + handle = sas_device_priv_data->sas_target->handle; + r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, + scmd->device->id, scmd->device->lun, + MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd); out: - printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", + ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return r; } /** * _scsih_dev_reset - eh threads main device reset routine - * @sdev: scsi device struct + * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ @@ -1940,14 +2272,16 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) u16 handle; int r; - printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n", - ioc->name, scmd); - scsi_print_command(scmd); + struct scsi_target *starget = scmd->device->sdev_target; + + starget_printk(KERN_INFO, starget, "attempting device reset! " + "scmd(%p)\n", scmd); + _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n", - ioc->name, scmd); + starget_printk(KERN_INFO, starget, "device been deleted! " + "scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); r = SUCCESS; @@ -1973,32 +2307,19 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) goto out; } - mutex_lock(&ioc->tm_cmds.mutex); - mpt2sas_scsih_issue_tm(ioc, handle, 0, - MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun, - 30); - - /* - * sanity check see whether all commands to this device been - * completed - */ - if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id, - scmd->device->lun, scmd->device->channel)) - r = FAILED; - else - r = SUCCESS; - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->tm_cmds.mutex); + r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, + scmd->device->id, scmd->device->lun, + MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd); out: - printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", + ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return r; } /** * _scsih_target_reset - eh threads main target reset routine - * @sdev: scsi device struct + * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ @@ -2011,15 +2332,16 @@ _scsih_target_reset(struct scsi_cmnd *scmd) unsigned long flags; u16 handle; int r; + struct scsi_target *starget = scmd->device->sdev_target; - printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n", - ioc->name, scmd); - scsi_print_command(scmd); + starget_printk(KERN_INFO, starget, "attempting target reset! " + "scmd(%p)\n", scmd); + _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n", - ioc->name, scmd); + starget_printk(KERN_INFO, starget, "target been deleted! " + "scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); r = SUCCESS; @@ -2045,31 +2367,19 @@ _scsih_target_reset(struct scsi_cmnd *scmd) goto out; } - mutex_lock(&ioc->tm_cmds.mutex); - mpt2sas_scsih_issue_tm(ioc, handle, 0, - MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30); - - /* - * sanity check see whether all commands to this target been - * completed - */ - if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id, - scmd->device->channel)) - r = FAILED; - else - r = SUCCESS; - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->tm_cmds.mutex); + r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, + scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, + 30, scmd); out: - printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", + ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return r; } /** - * _scsih_abort - eh threads main host reset routine - * @sdev: scsi device struct + * _scsih_host_reset - eh threads main host reset routine + * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ @@ -2113,8 +2423,9 @@ _scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) spin_lock_irqsave(&ioc->fw_event_lock, flags); list_add_tail(&fw_event->list, &ioc->fw_event_list); - INIT_WORK(&fw_event->work, _firmware_event_work); - queue_work(ioc->firmware_event_thread, &fw_event->work); + INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work); + queue_delayed_work(ioc->firmware_event_thread, + &fw_event->delayed_work, 0); spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } @@ -2141,61 +2452,53 @@ _scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } + /** - * _scsih_fw_event_add - requeue an event + * _scsih_queue_rescan - queue a topology rescan from user context * @ioc: per adapter object - * @fw_event: object describing the event - * Context: This function will acquire ioc->fw_event_lock. * * Return nothing. */ static void -_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work - *fw_event, unsigned long delay) +_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc) { - unsigned long flags; - if (ioc->firmware_event_thread == NULL) - return; + struct fw_event_work *fw_event; - spin_lock_irqsave(&ioc->fw_event_lock, flags); - queue_work(ioc->firmware_event_thread, &fw_event->work); - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + if (ioc->wait_for_port_enable_to_complete) + return; + fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + if (!fw_event) + return; + fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET; + fw_event->ioc = ioc; + _scsih_fw_event_add(ioc, fw_event); } /** - * _scsih_fw_event_off - turn flag off preventing event handling + * _scsih_fw_event_cleanup_queue - cleanup event queue * @ioc: per adapter object * - * Used to prevent handling of firmware events during adapter reset - * driver unload. + * Walk the firmware event queue, either killing timers, or waiting + * for outstanding events to complete * * Return nothing. */ static void -_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc) +_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc) { - unsigned long flags; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - ioc->fw_events_off = 1; - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - -} + struct fw_event_work *fw_event, *next; -/** - * _scsih_fw_event_on - turn flag on allowing firmware event handling - * @ioc: per adapter object - * - * Returns nothing. - */ -static void -_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; + if (list_empty(&ioc->fw_event_list) || + !ioc->firmware_event_thread || in_interrupt()) + return; - spin_lock_irqsave(&ioc->fw_event_lock, flags); - ioc->fw_events_off = 0; - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { + if (cancel_delayed_work(&fw_event->delayed_work)) { + _scsih_fw_event_free(ioc, fw_event); + continue; + } + fw_event->cancel_pending_work = 1; + } } /** @@ -2222,7 +2525,7 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) MPT2SAS_INFO_FMT "SDEV_RUNNING: " "handle(0x%04x)\n", ioc->name, handle)); sas_device_priv_data->block = 0; - scsi_device_set_state(sdev, SDEV_RUNNING); + scsi_internal_device_unblock(sdev); } } } @@ -2251,7 +2554,7 @@ _scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) MPT2SAS_INFO_FMT "SDEV_BLOCK: " "handle(0x%04x)\n", ioc->name, handle)); sas_device_priv_data->block = 1; - scsi_device_set_state(sdev, SDEV_BLOCK); + scsi_internal_device_block(sdev); } } } @@ -2296,9 +2599,9 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc, &sas_expander->sas_port_list, port_list) { if (mpt2sas_port->remote_identify.device_type == - MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || + SAS_EDGE_EXPANDER_DEVICE || mpt2sas_port->remote_identify.device_type == - MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) { + SAS_FANOUT_EXPANDER_DEVICE) { spin_lock_irqsave(&ioc->sas_node_lock, flags); expander_sibling = @@ -2341,6 +2644,318 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, } /** + * _scsih_tm_tr_send - send task management request + * @ioc: per adapter object + * @handle: device handle + * Context: interrupt time. + * + * This code is to initiate the device removal handshake protocal + * with controller firmware. This function will issue target reset + * using high priority request queue. It will send a sas iounit + * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. + * + * This is designed to send muliple task management request at the same + * time to the fifo. If the fifo is full, we will append the request, + * and process it in a future completion. + */ +static void +_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + Mpi2SCSITaskManagementRequest_t *mpi_request; + u16 smid; + struct _sas_device *sas_device; + struct MPT2SAS_TARGET *sas_target_priv_data; + unsigned long flags; + struct _tr_list *delayed_tr; + + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " + "progress!\n", __func__, ioc->name)); + return; + } + + /* if PD, then return */ + if (test_bit(handle, ioc->pd_handles)) + return; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (sas_device && sas_device->starget && + sas_device->starget->hostdata) { + sas_target_priv_data = sas_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "setting delete flag: handle(0x%04x), " + "sas_addr(0x%016llx)\n", ioc->name, handle, + (unsigned long long) sas_device->sas_address)); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); + if (!smid) { + delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); + if (!delayed_tr) + return; + INIT_LIST_HEAD(&delayed_tr->list); + delayed_tr->handle = handle; + list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "DELAYED:tr:handle(0x%04x), (open)\n", + ioc->name, handle)); + return; + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " + "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, + ioc->tm_tr_cb_idx)); + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + mpi_request->DevHandle = cpu_to_le16(handle); + mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + mpt2sas_base_put_smid_hi_priority(ioc, smid); +} + + + +/** + * _scsih_sas_control_complete - completion routine + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * Context: interrupt time. + * + * This is the sas iounit controll completion routine. + * This code is part of the code to initiate the device removal + * handshake protocal with controller firmware. + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +static u8 +_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, + u8 msix_index, u32 reply) +{ +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + Mpi2SasIoUnitControlReply_t *mpi_reply = + mpt2sas_base_get_reply_virt_addr(ioc, reply); +#endif + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "sc_complete:handle(0x%04x), (open) " + "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, + le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo))); + return 1; +} + +/** + * _scsih_tm_tr_volume_send - send target reset request for volumes + * @ioc: per adapter object + * @handle: device handle + * Context: interrupt time. + * + * This is designed to send muliple task management request at the same + * time to the fifo. If the fifo is full, we will append the request, + * and process it in a future completion. + */ +static void +_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + Mpi2SCSITaskManagementRequest_t *mpi_request; + u16 smid; + struct _tr_list *delayed_tr; + + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " + "progress!\n", __func__, ioc->name)); + return; + } + + smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx); + if (!smid) { + delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); + if (!delayed_tr) + return; + INIT_LIST_HEAD(&delayed_tr->list); + delayed_tr->handle = handle; + list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "DELAYED:tr:handle(0x%04x), (open)\n", + ioc->name, handle)); + return; + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " + "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, + ioc->tm_tr_volume_cb_idx)); + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + mpi_request->DevHandle = cpu_to_le16(handle); + mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + mpt2sas_base_put_smid_hi_priority(ioc, smid); +} + +/** + * _scsih_tm_volume_tr_complete - target reset completion + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * Context: interrupt time. + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +static u8 +_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, + u8 msix_index, u32 reply) +{ + u16 handle; + Mpi2SCSITaskManagementRequest_t *mpi_request_tm; + Mpi2SCSITaskManagementReply_t *mpi_reply = + mpt2sas_base_get_reply_virt_addr(ioc, reply); + + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " + "progress!\n", __func__, ioc->name)); + return 1; + } + + mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); + handle = le16_to_cpu(mpi_request_tm->DevHandle); + if (handle != le16_to_cpu(mpi_reply->DevHandle)) { + dewtprintk(ioc, printk("spurious interrupt: " + "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle, + le16_to_cpu(mpi_reply->DevHandle), smid)); + return 0; + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " + "loginfo(0x%08x), completed(%d)\n", ioc->name, + handle, smid, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo), + le32_to_cpu(mpi_reply->TerminationCount))); + + return _scsih_check_for_pending_tm(ioc, smid); +} + +/** + * _scsih_tm_tr_complete - + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * Context: interrupt time. + * + * This is the target reset completion routine. + * This code is part of the code to initiate the device removal + * handshake protocal with controller firmware. + * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE) + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +static u8 +_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, + u32 reply) +{ + u16 handle; + Mpi2SCSITaskManagementRequest_t *mpi_request_tm; + Mpi2SCSITaskManagementReply_t *mpi_reply = + mpt2sas_base_get_reply_virt_addr(ioc, reply); + Mpi2SasIoUnitControlRequest_t *mpi_request; + u16 smid_sas_ctrl; + + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " + "progress!\n", __func__, ioc->name)); + return 1; + } + + mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); + handle = le16_to_cpu(mpi_request_tm->DevHandle); + if (handle != le16_to_cpu(mpi_reply->DevHandle)) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: " + "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle, + le16_to_cpu(mpi_reply->DevHandle), smid)); + return 0; + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " + "loginfo(0x%08x), completed(%d)\n", ioc->name, + handle, smid, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo), + le32_to_cpu(mpi_reply->TerminationCount))); + + smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); + if (!smid_sas_ctrl) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + return 1; + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), " + "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl, + ioc->tm_sas_control_cb_idx)); + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); + memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; + mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; + mpi_request->DevHandle = mpi_request_tm->DevHandle; + mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); + + return _scsih_check_for_pending_tm(ioc, smid); +} + +/** + * _scsih_check_for_pending_tm - check for pending task management + * @ioc: per adapter object + * @smid: system request message index + * + * This will check delayed target reset list, and feed the + * next reqeust. + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +static u8 +_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + struct _tr_list *delayed_tr; + + if (!list_empty(&ioc->delayed_tr_volume_list)) { + delayed_tr = list_entry(ioc->delayed_tr_volume_list.next, + struct _tr_list, list); + mpt2sas_base_free_smid(ioc, smid); + _scsih_tm_tr_volume_send(ioc, delayed_tr->handle); + list_del(&delayed_tr->list); + kfree(delayed_tr); + return 0; + } + + if (!list_empty(&ioc->delayed_tr_list)) { + delayed_tr = list_entry(ioc->delayed_tr_list.next, + struct _tr_list, list); + mpt2sas_base_free_smid(ioc, smid); + _scsih_tm_tr_send(ioc, delayed_tr->handle); + list_del(&delayed_tr->list); + kfree(delayed_tr); + return 0; + } + + return 1; +} + +/** * _scsih_check_topo_delete_events - sanity check on topo events * @ioc: per adapter object * @event_data: the event data payload @@ -2362,6 +2977,21 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, u16 expander_handle; struct _sas_node *sas_expander; unsigned long flags; + int i, reason_code; + u16 handle; + + for (i = 0 ; i < event_data->NumEntries; i++) { + if (event_data->PHY[i].PhyStatus & + MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) + continue; + handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); + if (!handle) + continue; + reason_code = event_data->PHY[i].PhyStatus & + MPI2_EVENT_SAS_TOPO_RC_MASK; + if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING) + _scsih_tm_tr_send(ioc, handle); + } expander_handle = le16_to_cpu(event_data->ExpanderDevHandle); if (expander_handle < ioc->sas_hba.num_phys) { @@ -2395,7 +3025,7 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { if (le16_to_cpu(local_event_data->ExpanderDevHandle) == expander_handle) { - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting ignoring flag\n", ioc->name)); fw_event->ignore = 1; } @@ -2405,24 +3035,162 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, } /** - * _scsih_queue_rescan - queue a topology rescan from user context + * _scsih_set_volume_delete_flag - setting volume delete flag * @ioc: per adapter object + * @handle: device handle * + * This * Return nothing. */ static void -_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc) +_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) { - struct fw_event_work *fw_event; + struct _raid_device *raid_device; + struct MPT2SAS_TARGET *sas_target_priv_data; + unsigned long flags; - if (ioc->wait_for_port_enable_to_complete) + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + if (raid_device && raid_device->starget && + raid_device->starget->hostdata) { + sas_target_priv_data = + raid_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "setting delete flag: handle(0x%04x), " + "wwid(0x%016llx)\n", ioc->name, handle, + (unsigned long long) raid_device->wwid)); + } + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +} + +/** + * _scsih_set_volume_handle_for_tr - set handle for target reset to volume + * @handle: input handle + * @a: handle for volume a + * @b: handle for volume b + * + * IR firmware only supports two raid volumes. The purpose of this + * routine is to set the volume handle in either a or b. When the given + * input handle is non-zero, or when a and b have not been set before. + */ +static void +_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b) +{ + if (!handle || handle == *a || handle == *b) return; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); - if (!fw_event) + if (!*a) + *a = handle; + else if (!*b) + *b = handle; +} + +/** + * _scsih_check_ir_config_unhide_events - check for UNHIDE events + * @ioc: per adapter object + * @event_data: the event data payload + * Context: interrupt time. + * + * This routine will send target reset to volume, followed by target + * resets to the PDs. This is called when a PD has been removed, or + * volume has been deleted or removed. When the target reset is sent + * to volume, the PD target resets need to be queued to start upon + * completion of the volume target reset. + * + * Return nothing. + */ +static void +_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataIrConfigChangeList_t *event_data) +{ + Mpi2EventIrConfigElement_t *element; + int i; + u16 handle, volume_handle, a, b; + struct _tr_list *delayed_tr; + + a = 0; + b = 0; + + /* Volume Resets for Deleted or Removed */ + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + if (element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED || + element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_REMOVED) { + volume_handle = le16_to_cpu(element->VolDevHandle); + _scsih_set_volume_delete_flag(ioc, volume_handle); + _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); + } + } + + /* Volume Resets for UNHIDE events */ + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + if (le32_to_cpu(event_data->Flags) & + MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) + continue; + if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) { + volume_handle = le16_to_cpu(element->VolDevHandle); + _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); + } + } + + if (a) + _scsih_tm_tr_volume_send(ioc, a); + if (b) + _scsih_tm_tr_volume_send(ioc, b); + + /* PD target resets */ + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) + continue; + handle = le16_to_cpu(element->PhysDiskDevHandle); + volume_handle = le16_to_cpu(element->VolDevHandle); + clear_bit(handle, ioc->pd_handles); + if (!volume_handle) + _scsih_tm_tr_send(ioc, handle); + else if (volume_handle == a || volume_handle == b) { + delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); + BUG_ON(!delayed_tr); + INIT_LIST_HEAD(&delayed_tr->list); + delayed_tr->handle = handle; + list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, + handle)); + } else + _scsih_tm_tr_send(ioc, handle); + } +} + + +/** + * _scsih_check_volume_delete_events - set delete flag for volumes + * @ioc: per adapter object + * @event_data: the event data payload + * Context: interrupt time. + * + * This will handle the case when the cable connected to entire volume is + * pulled. We will take care of setting the deleted flag so normal IO will + * not be sent. + * + * Return nothing. + */ +static void +_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataIrVolume_t *event_data) +{ + u32 state; + + if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) return; - fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); + state = le32_to_cpu(event_data->NewValue); + if (state == MPI2_RAID_VOL_STATE_MISSING || state == + MPI2_RAID_VOL_STATE_FAILED) + _scsih_set_volume_delete_flag(ioc, + le16_to_cpu(event_data->VolDevHandle)); } /** @@ -2441,14 +3209,17 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc) u16 smid; u16 count = 0; - for (smid = 1; smid <= ioc->request_depth; smid++) { - scmd = _scsih_scsi_lookup_getclear(ioc, smid); + for (smid = 1; smid <= ioc->scsiio_depth; smid++) { + scmd = _scsih_scsi_lookup_get(ioc, smid); if (!scmd) continue; count++; mpt2sas_base_free_smid(ioc, smid); scsi_dma_unmap(scmd); - scmd->result = DID_RESET << 16; + if (ioc->pci_error_recovery) + scmd->result = DID_NO_CONNECT << 16; + else + scmd->result = DID_RESET << 16; scmd->scsi_done(scmd); } dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n", @@ -2456,46 +3227,6 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc) } /** - * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) - * @ioc: per adapter object - * @reset_phase: phase - * - * The handler for doing any required cleanup or initialization. - * - * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, - * MPT2_IOC_DONE_RESET - * - * Return nothing. - */ -void -mpt2sas_scsih_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__)); - _scsih_fw_event_off(ioc); - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { - ioc->tm_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); - complete(&ioc->tm_cmds.done); - } - _scsih_fw_event_on(ioc); - _scsih_flush_running_cmds(ioc); - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - _scsih_queue_rescan(ioc); - break; - } -} - -/** * _scsih_setup_eedp - setup MPI request for EEDP transfer * @scmd: pointer to scsi command object * @mpi_request: pointer to the SCSI_IO reqest message frame @@ -2511,9 +3242,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) unsigned char prot_op = scsi_get_prot_op(scmd); unsigned char prot_type = scsi_get_prot_type(scmd); - if (prot_type == SCSI_PROT_DIF_TYPE0 || - prot_type == SCSI_PROT_DIF_TYPE2 || - prot_op == SCSI_PROT_NORMAL) + if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL) return; if (prot_op == SCSI_PROT_READ_STRIP) @@ -2523,8 +3252,6 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) else return; - mpi_request->EEDPBlockSize = scmd->device->sector_size; - switch (prot_type) { case SCSI_PROT_DIF_TYPE1: @@ -2532,13 +3259,18 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) * enable ref/guard checking * auto increment ref tag */ - mpi_request->EEDPFlags = eedp_flags | - MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; mpi_request->CDB.EEDP32.PrimaryReferenceTag = cpu_to_be32(scsi_get_lba(scmd)); + break; + + case SCSI_PROT_DIF_TYPE2: + eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; break; case SCSI_PROT_DIF_TYPE3: @@ -2546,11 +3278,11 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) /* * enable guard checking */ - mpi_request->EEDPFlags = eedp_flags | - MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - + eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; break; } + mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size); + mpi_request->EEDPFlags = cpu_to_le16(eedp_flags); } /** @@ -2607,7 +3339,7 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full */ static int -_scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) +_scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) { struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT2SAS_DEVICE *sas_device_priv_data; @@ -2615,32 +3347,41 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) Mpi2SCSIIORequest_t *mpi_request; u32 mpi_control; u16 smid; - unsigned long flags; scmd->scsi_done = done; sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data) { + if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + return 0; + } + + if (ioc->pci_error_recovery) { scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); return 0; } sas_target_priv_data = sas_device_priv_data->sas_target; - if (!sas_target_priv_data || sas_target_priv_data->handle == - MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) { + /* invalid device handle */ + if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) { scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); return 0; } - /* see if we are busy with task managment stuff */ - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (sas_target_priv_data->tm_busy || - ioc->shost_recovery || ioc->ioc_link_reset_in_progress) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + /* host recovery or link resets sent via IOCTLs */ + if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) return SCSI_MLQUEUE_HOST_BUSY; + /* device busy with task management */ + else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) + return SCSI_MLQUEUE_DEVICE_BUSY; + /* device has been deleted */ + else if (sas_target_priv_data->deleted) { + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + return 0; } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); if (scmd->sc_data_direction == DMA_FROM_DEVICE) mpi_control = MPI2_SCSIIO_CONTROL_READ; @@ -2664,11 +3405,12 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } else mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - - if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON)) + /* Make sure Device is not raid volume */ + if (!_scsih_is_raid(&scmd->device->sdev_gendev) && + sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; - smid = mpt2sas_base_get_smid(ioc, ioc->scsi_io_cb_idx); + smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); if (!smid) { printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", ioc->name, __func__); @@ -2677,6 +3419,8 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); _scsih_setup_eedp(scmd, mpi_request); + if (scmd->cmd_len == 32) + mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; if (sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) @@ -2691,11 +3435,12 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; mpi_request->SenseBufferLowAddress = - (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid); + mpt2sas_base_get_sense_buffer_dma(ioc, smid); mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI + MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR); - + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *) mpi_request->LUN); memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); @@ -2709,15 +3454,19 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) } } - _scsih_scsi_lookup_set(ioc, smid, scmd); - mpt2sas_base_put_smid_scsi_io(ioc, smid, 0, - sas_device_priv_data->sas_target->handle); + if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) + mpt2sas_base_put_smid_scsi_io(ioc, smid, + sas_device_priv_data->sas_target->handle); + else + mpt2sas_base_put_smid_default(ioc, smid); return 0; out: return SCSI_MLQUEUE_HOST_BUSY; } +static DEF_SCSI_QCMD(_scsih_qcmd) + /** * _scsih_normalize_sense - normalize descriptor and fixed format sense data * @sense_buffer: sense data returned by target @@ -2743,7 +3492,7 @@ _scsih_normalize_sense(char *sense_buffer, struct sense_info *data) #ifdef CONFIG_SCSI_MPT2SAS_LOGGING /** - * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request + * _scsih_scsi_ioc_info - translated non-successfull SCSI_IO request * @ioc: per adapter object * @scmd: pointer to scsi command object * @mpi_reply: reply mf payload returned from firmware @@ -2767,6 +3516,17 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, char *desc_ioc_state = NULL; char *desc_scsi_status = NULL; char *desc_scsi_state = ioc->tmp_string; + u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); + struct _sas_device *sas_device = NULL; + unsigned long flags; + struct scsi_target *starget = scmd->device->sdev_target; + struct MPT2SAS_TARGET *priv_target = starget->hostdata; + + if (!priv_target) + return; + + if (log_info == 0x31170000) + return; switch (ioc_status) { case MPI2_IOCSTATUS_SUCCESS: @@ -2879,10 +3639,29 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, strcat(desc_scsi_state, "autosense valid "); scsi_print_command(scmd); - printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), " - "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name, - le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state, - ioc_status, smid); + + if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { + printk(MPT2SAS_WARN_FMT "\tvolume wwid(0x%016llx)\n", ioc->name, + (unsigned long long)priv_target->sas_address); + } else { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + priv_target->sas_address); + if (sas_device) { + printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " + "phy(%d)\n", ioc->name, sas_device->sas_address, + sas_device->phy); + printk(MPT2SAS_WARN_FMT + "\tenclosure_logical_id(0x%016llx), slot(%d)\n", + ioc->name, sas_device->enclosure_logical_id, + sas_device->slot); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } + + printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), " + "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle), + desc_ioc_state, ioc_status, smid); printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), " "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow, scsi_get_resid(scmd)); @@ -2897,14 +3676,14 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, struct sense_info data; _scsih_normalize_sense(scmd->sense_buffer, &data); printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: " - "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey, - data.asc, data.ascq); + "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey, + data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); } if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { response_info = le32_to_cpu(mpi_reply->ResponseInfo); response_bytes = (u8 *)&response_info; - _scsih_response_code(ioc, response_bytes[3]); + _scsih_response_code(ioc, response_bytes[0]); } } #endif @@ -2952,7 +3731,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; mpi_request.SlotStatus = - MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT; + cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); mpi_request.DevHandle = cpu_to_le16(handle); mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, @@ -3002,15 +3781,16 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) * _scsih_io_done - scsi request callback * @ioc: per adapter object * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * - * Callback handler when using scsih_qcmd. + * Callback handler when using _scsih_qcmd. * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -static void -_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +static u8 +_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) { Mpi2SCSIIORequest_t *mpi_request; Mpi2SCSIIOReply_t *mpi_reply; @@ -3021,12 +3801,12 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) u8 scsi_status; u32 log_info; struct MPT2SAS_DEVICE *sas_device_priv_data; - u32 response_code; + u32 response_code = 0; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - scmd = _scsih_scsi_lookup_getclear(ioc, smid); + scmd = _scsih_scsi_lookup_get(ioc, smid); if (scmd == NULL) - return; + return 1; mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); @@ -3043,15 +3823,17 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) } /* turning off TLR */ + scsi_state = mpi_reply->SCSIState; + if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) + response_code = + le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; if (!sas_device_priv_data->tlr_snoop_check) { sas_device_priv_data->tlr_snoop_check++; - if (sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) { - response_code = (le32_to_cpu(mpi_reply->ResponseInfo) - >> 24); - if (response_code == - MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) - sas_device_priv_data->flags &= - ~MPT_DEVICE_TLR_ON; + if (!_scsih_is_raid(&scmd->device->sdev_gendev) && + sas_is_tlr_enabled(scmd->device) && + response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { + sas_disable_tlr(scmd->device); + sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); } } @@ -3063,7 +3845,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) else log_info = 0; ioc_status &= MPI2_IOCSTATUS_MASK; - scsi_state = mpi_reply->SCSIState; scsi_status = mpi_reply->SCSIStatus; if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && @@ -3099,10 +3880,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: if (sas_device_priv_data->block) { - scmd->result = (DID_BUS_BUSY << 16); - break; + scmd->result = DID_TRANSPORT_DISRUPTED << 16; + goto out; } - case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: scmd->result = DID_RESET << 16; @@ -3148,8 +3928,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: case MPI2_IOCSTATUS_SUCCESS: scmd->result = (DID_OK << 16) | scsi_status; - if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | - MPI2_SCSI_STATE_NO_SCSI_STATUS)) + if (response_code == + MPI2_SCSITASKMGMT_RSP_INVALID_FRAME || + (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | + MPI2_SCSI_STATE_NO_SCSI_STATUS))) scmd->result = DID_SOFT_ERROR << 16; else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) scmd->result = DID_RESET << 16; @@ -3182,31 +3964,12 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) out: scsi_dma_unmap(scmd); scmd->scsi_done(scmd); -} - -/** - * _scsih_link_change - process phy link changes - * @ioc: per adapter object - * @handle: phy handle - * @attached_handle: valid for devices attached to link - * @phy_number: phy number - * @link_rate: new link rate - * Context: user. - * - * Return nothing. - */ -static void -_scsih_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle, - u8 phy_number, u8 link_rate) -{ - mpt2sas_transport_update_phy_link_change(ioc, handle, attached_handle, - phy_number, link_rate); + return 1; } /** * _scsih_sas_host_refresh - refreshing sas host object contents * @ioc: per adapter object - * @update: update link information * Context: user * * During port enable, fw will send topology events for every device. Its @@ -3216,13 +3979,15 @@ _scsih_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle, * Return nothing. */ static void -_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update) +_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc) { u16 sz; u16 ioc_status; int i; Mpi2ConfigReply_t mpi_reply; Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; + u16 attached_handle; + u8 link_rate; dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "updating handles for sas_host(0x%016llx)\n", @@ -3236,26 +4001,26 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update) ioc->name, __FILE__, __LINE__, __func__); return; } - if (!(mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, - sas_iounit_pg0, sz))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto out; - for (i = 0; i < ioc->sas_hba.num_phys ; i++) { - ioc->sas_hba.phy[i].handle = - le16_to_cpu(sas_iounit_pg0->PhyData[i]. - ControllerDevHandle); - if (update) - _scsih_link_change(ioc, - ioc->sas_hba.phy[i].handle, - le16_to_cpu(sas_iounit_pg0->PhyData[i]. - AttachedDevHandle), i, - sas_iounit_pg0->PhyData[i]. - NegotiatedLinkRate >> 4); - } - } + if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, + sas_iounit_pg0, sz)) != 0) + goto out; + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + goto out; + for (i = 0; i < ioc->sas_hba.num_phys ; i++) { + link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4; + if (i == 0) + ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> + PhyData[0].ControllerDevHandle); + ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; + attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. + AttachedDevHandle); + if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) + link_rate = MPI2_SAS_NEG_LINK_RATE_1_5; + mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, + attached_handle, i, link_rate); + } out: kfree(sas_iounit_pg0); } @@ -3368,19 +4133,21 @@ _scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc) ioc->name, __FILE__, __LINE__, __func__); goto out; } - ioc->sas_hba.phy[i].handle = - le16_to_cpu(sas_iounit_pg0->PhyData[i].ControllerDevHandle); + + if (i == 0) + ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> + PhyData[0].ControllerDevHandle); + ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; ioc->sas_hba.phy[i].phy_id = i; mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], phy_pg0, ioc->sas_hba.parent_dev); } if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.phy[0].handle))) { + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); goto out; } - ioc->sas_hba.handle = le16_to_cpu(sas_device_pg0.DevHandle); ioc->sas_hba.enclosure_handle = le16_to_cpu(sas_device_pg0.EnclosureHandle); ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress); @@ -3423,15 +4190,18 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) Mpi2SasEnclosurePage0_t enclosure_pg0; u32 ioc_status; u16 parent_handle; - __le64 sas_address; + __le64 sas_address, sas_address_parent = 0; int i; unsigned long flags; - struct _sas_port *mpt2sas_port; + struct _sas_port *mpt2sas_port = NULL; int rc = 0; if (!handle) return -1; + if (ioc->shost_recovery || ioc->pci_error_recovery) + return -1; + if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", @@ -3449,10 +4219,16 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) /* handle out of order topology events */ parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle); - if (parent_handle >= ioc->sas_hba.num_phys) { + if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent) + != 0) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return -1; + } + if (sas_address_parent != ioc->sas_hba.sas_address) { spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, - parent_handle); + sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, + sas_address_parent); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_expander) { rc = _scsih_expander_add(ioc, parent_handle); @@ -3461,9 +4237,8 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) } } - sas_address = le64_to_cpu(expander_pg0.SASAddress); - spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_address = le64_to_cpu(expander_pg0.SASAddress); sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, sas_address); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); @@ -3481,14 +4256,12 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) sas_expander->handle = handle; sas_expander->num_phys = expander_pg0.NumPhys; - sas_expander->parent_handle = parent_handle; - sas_expander->enclosure_handle = - le16_to_cpu(expander_pg0.EnclosureHandle); + sas_expander->sas_address_parent = sas_address_parent; sas_expander->sas_address = sas_address; printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x)," " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name, - handle, sas_expander->parent_handle, (unsigned long long) + handle, parent_handle, (unsigned long long) sas_expander->sas_address, sas_expander->num_phys); if (!sas_expander->num_phys) @@ -3504,7 +4277,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) INIT_LIST_HEAD(&sas_expander->sas_port_list); mpt2sas_port = mpt2sas_transport_port_add(ioc, handle, - sas_expander->parent_handle); + sas_address_parent); if (!mpt2sas_port) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -3518,12 +4291,20 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) &expander_pg1, i, handle))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); - continue; + rc = -1; + goto out_fail; } sas_expander->phy[i].handle = handle; sas_expander->phy[i].phy_id = i; - mpt2sas_transport_add_expander_phy(ioc, &sas_expander->phy[i], - expander_pg1, sas_expander->parent_dev); + + if ((mpt2sas_transport_add_expander_phy(ioc, + &sas_expander->phy[i], expander_pg1, + sas_expander->parent_dev))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -1; + goto out_fail; + } } if (sas_expander->enclosure_handle) { @@ -3540,32 +4321,204 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) out_fail: - if (sas_expander) - kfree(sas_expander->phy); + if (mpt2sas_port) + mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, + sas_address_parent); kfree(sas_expander); return rc; } /** - * _scsih_expander_remove - removing expander object + * _scsih_done - scsih callback handler. * @ioc: per adapter object - * @handle: expander handle + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * + * Callback handler when sending internal generated message frames. + * The callback index passed is `ioc->scsih_cb_idx` + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +static u8 +_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) +{ + MPI2DefaultReply_t *mpi_reply; + + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED) + return 1; + if (ioc->scsih_cmds.smid != smid) + return 1; + ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE; + if (mpi_reply) { + memcpy(ioc->scsih_cmds.reply, mpi_reply, + mpi_reply->MsgLength*4); + ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID; + } + ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING; + complete(&ioc->scsih_cmds.done); + return 1; +} + +/** + * mpt2sas_expander_remove - removing expander object + * @ioc: per adapter object + * @sas_address: expander sas_address * * Return nothing. */ -static void -_scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle) +void +mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) { struct _sas_node *sas_expander; unsigned long flags; + if (ioc->shost_recovery) + return; + spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle); + sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, + sas_address); + if (!sas_expander) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + return; + } + list_del(&sas_expander->list); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); _scsih_expander_node_remove(ioc, sas_expander); } /** + * _scsih_check_access_status - check access flags + * @ioc: per adapter object + * @sas_address: sas address + * @handle: sas device handle + * @access_flags: errors returned during discovery of the device + * + * Return 0 for success, else failure + */ +static u8 +_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, + u16 handle, u8 access_status) +{ + u8 rc = 1; + char *desc = NULL; + + switch (access_status) { + case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: + case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: + rc = 0; + break; + case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: + desc = "sata capability failed"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: + desc = "sata affiliation conflict"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: + desc = "route not addressable"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: + desc = "smp error not addressable"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: + desc = "device blocked"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: + desc = "sata initialization failed"; + break; + default: + desc = "unknown"; + break; + } + + if (!rc) + return 0; + + printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), " + "handle(0x%04x)\n", ioc->name, desc, + (unsigned long long)sas_address, handle); + return rc; +} + +static void +_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t sas_device_pg0; + struct _sas_device *sas_device; + u32 ioc_status; + unsigned long flags; + u64 sas_address; + struct scsi_target *starget; + struct MPT2SAS_TARGET *sas_target_priv_data; + u32 device_info; + + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, + MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) + return; + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) + return; + + /* check if this is end device */ + device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); + if (!(_scsih_is_end_device(device_info))) + return; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_address); + + if (!sas_device) { + printk(MPT2SAS_ERR_FMT "device is not present " + "handle(0x%04x), no sas_device!!!\n", ioc->name, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + return; + } + + if (unlikely(sas_device->handle != handle)) { + starget = sas_device->starget; + sas_target_priv_data = starget->hostdata; + starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)" + " to (0x%04x)!!!\n", sas_device->handle, handle); + sas_target_priv_data->handle = handle; + sas_device->handle = handle; + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + /* check if device is present */ + if (!(le16_to_cpu(sas_device_pg0.Flags) & + MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { + printk(MPT2SAS_ERR_FMT "device is not present " + "handle(0x%04x), flags!!!\n", ioc->name, handle); + return; + } + + /* check if there were any issues with discovery */ + if (_scsih_check_access_status(ioc, sas_address, handle, + sas_device_pg0.AccessStatus)) + return; + _scsih_ublock_io_device(ioc, handle); + +} + +/** * _scsih_add_device - creating sas device object * @ioc: per adapter object * @handle: sas device handle @@ -3603,6 +4556,8 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) return -1; } + sas_address = le64_to_cpu(sas_device_pg0.SASAddress); + /* check if device is present */ if (!(le16_to_cpu(sas_device_pg0.Flags) & MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { @@ -3613,15 +4568,10 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) return -1; } - /* check if there were any issus with discovery */ - if (sas_device_pg0.AccessStatus == - MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n", - ioc->name, sas_device_pg0.AccessStatus); + /* check if there were any issues with discovery */ + if (_scsih_check_access_status(ioc, sas_address, handle, + sas_device_pg0.AccessStatus)) return -1; - } /* check if this is end device */ device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); @@ -3631,17 +4581,14 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) return -1; } - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, sas_address); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) { - _scsih_ublock_io_device(ioc, handle); + if (sas_device) return 0; - } sas_device = kzalloc(sizeof(struct _sas_device), GFP_KERNEL); @@ -3652,23 +4599,25 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) } sas_device->handle = handle; - sas_device->parent_handle = - le16_to_cpu(sas_device_pg0.ParentDevHandle); + if (_scsih_get_sas_address(ioc, le16_to_cpu + (sas_device_pg0.ParentDevHandle), + &sas_device->sas_address_parent) != 0) + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); sas_device->enclosure_handle = le16_to_cpu(sas_device_pg0.EnclosureHandle); sas_device->slot = le16_to_cpu(sas_device_pg0.Slot); sas_device->device_info = device_info; sas_device->sas_address = sas_address; - sas_device->hidden_raid_component = is_pd; + sas_device->phy = sas_device_pg0.PhyNum; /* get enclosure_logical_id */ - if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, &enclosure_pg0, - MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, - sas_device->enclosure_handle))) { + if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0( + ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, + sas_device->enclosure_handle))) sas_device->enclosure_logical_id = le64_to_cpu(enclosure_pg0.EnclosureLogicalID); - } /* get device name */ sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); @@ -3684,85 +4633,73 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) /** * _scsih_remove_device - removing sas device object * @ioc: per adapter object - * @handle: sas device handle + * @sas_device_delete: the sas_device object * * Return nothing. */ static void -_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, + struct _sas_device *sas_device) { + struct _sas_device sas_device_backup; struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - unsigned long flags; - Mpi2SasIoUnitControlReply_t mpi_reply; - Mpi2SasIoUnitControlRequest_t mpi_request; - u16 device_handle; - /* lookup sas_device */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!sas_device) return; - } - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle" - "(0x%04x)\n", ioc->name, __func__, handle)); + memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device)); + _scsih_sas_device_remove(ioc, sas_device); - if (sas_device->starget && sas_device->starget->hostdata) { - sas_target_priv_data = sas_device->starget->hostdata; + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: " + "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, + sas_device_backup.handle, (unsigned long long) + sas_device_backup.sas_address)); + + if (sas_device_backup.starget && sas_device_backup.starget->hostdata) { + sas_target_priv_data = sas_device_backup.starget->hostdata; sas_target_priv_data->deleted = 1; } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (ioc->remove_host) - goto out; + _scsih_ublock_io_device(ioc, sas_device_backup.handle); - /* Target Reset to flush out all the outstanding IO */ - device_handle = (sas_device->hidden_raid_component) ? - sas_device->volume_handle : handle; - if (device_handle) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " - "handle(0x%04x)\n", ioc->name, device_handle)); - mutex_lock(&ioc->tm_cmds.mutex); - mpt2sas_scsih_issue_tm(ioc, device_handle, 0, - MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->tm_cmds.mutex); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " - "done: handle(0x%04x)\n", ioc->name, device_handle)); - } - - /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */ - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle" - "(0x%04x)\n", ioc->name, handle)); - memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); - mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; - mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE; - mpi_request.DevHandle = handle; - mpi_request.VF_ID = 0; - if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, - &mpi_request)) != 0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - } + mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address, + sas_device_backup.sas_address_parent); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status" - "(0x%04x), loginfo(0x%08x)\n", ioc->name, - le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo))); + printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" + "(0x%016llx)\n", ioc->name, sas_device_backup.handle, + (unsigned long long) sas_device_backup.sas_address); - out: - mpt2sas_transport_port_remove(ioc, sas_device->sas_address, - sas_device->parent_handle); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: " + "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, + sas_device_backup.handle, (unsigned long long) + sas_device_backup.sas_address)); +} - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" - "(0x%016llx)\n", ioc->name, sas_device->handle, - (unsigned long long) sas_device->sas_address); - _scsih_sas_device_remove(ioc, sas_device); +/** + * mpt2sas_device_remove - removing device object + * @ioc: per adapter object + * @sas_address: expander sas_address + * + * Return nothing. + */ +void +mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) +{ + struct _sas_device *sas_device; + unsigned long flags; + + if (ioc->shost_recovery) + return; - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle" - "(0x%04x)\n", ioc->name, __func__, handle)); + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_address); + if (!sas_device) { + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + return; + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + _scsih_remove_device(ioc, sas_device); } #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -3781,7 +4718,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, u16 reason_code; u8 phy_number; char *status_str = NULL; - char link_rate[25]; + u8 link_rate, prev_link_rate; switch (event_data->ExpStatus) { case MPI2_EVENT_SAS_TOPO_ES_ADDED: @@ -3791,6 +4728,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, status_str = "remove"; break; case MPI2_EVENT_SAS_TOPO_ES_RESPONDING: + case 0: status_str = "responding"; break; case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: @@ -3800,9 +4738,9 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, status_str = "unknown status"; break; } - printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n", + printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n", ioc->name, status_str); - printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) " + printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) " "start_phy(%02d), count(%d)\n", le16_to_cpu(event_data->ExpanderDevHandle), le16_to_cpu(event_data->EnclosureHandle), @@ -3816,30 +4754,30 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_RC_MASK; switch (reason_code) { case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - snprintf(link_rate, 25, ": add, link(0x%02x)", - (event_data->PHY[i].LinkRate >> 4)); - status_str = link_rate; + status_str = "target add"; break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - status_str = ": remove"; + status_str = "target remove"; break; case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: - status_str = ": remove_delay"; + status_str = "delay target remove"; break; case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: - snprintf(link_rate, 25, ": link(0x%02x)", - (event_data->PHY[i].LinkRate >> 4)); - status_str = link_rate; + status_str = "link rate change"; break; case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: - status_str = ": responding"; + status_str = "target responding"; break; default: - status_str = ": unknown"; + status_str = "unknown"; break; } - printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x)%s\n", - phy_number, handle, status_str); + link_rate = event_data->PHY[i].LinkRate >> 4; + prev_link_rate = event_data->PHY[i].LinkRate & 0xF; + printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:" + " link rate: new(0x%02x), old(0x%02x)\n", phy_number, + handle, status_str, link_rate, prev_link_rate); + } } #endif @@ -3847,37 +4785,40 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, /** * _scsih_sas_topology_change_event - handle topology changes * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload - * fw_event: + * @fw_event: The fw_event_work object * Context: user. * */ static void -_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataSasTopologyChangeList_t *event_data, +_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { int i; u16 parent_handle, handle; u16 reason_code; - u8 phy_number; + u8 phy_number, max_phys; struct _sas_node *sas_expander; + struct _sas_device *sas_device; + u64 sas_address; unsigned long flags; - u8 link_rate_; + u8 link_rate, prev_link_rate; + Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_topology_change_event_debug(ioc, event_data); #endif + if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) + return; + if (!ioc->sas_hba.num_phys) _scsih_sas_host_add(ioc); else - _scsih_sas_host_refresh(ioc, 0); + _scsih_sas_host_refresh(ioc); if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander " "event\n", ioc->name)); return; } @@ -3889,66 +4830,84 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, if (_scsih_expander_add(ioc, parent_handle) != 0) return; + spin_lock_irqsave(&ioc->sas_node_lock, flags); + sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, + parent_handle); + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + if (sas_expander) { + sas_address = sas_expander->sas_address; + max_phys = sas_expander->num_phys; + } else if (parent_handle < ioc->sas_hba.num_phys) { + sas_address = ioc->sas_hba.sas_address; + max_phys = ioc->sas_hba.num_phys; + } else + return; + /* handle siblings events */ for (i = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring " "expander event\n", ioc->name)); return; } - if (event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) + return; + phy_number = event_data->StartPhyNum + i; + if (phy_number >= max_phys) + continue; + reason_code = event_data->PHY[i].PhyStatus & + MPI2_EVENT_SAS_TOPO_RC_MASK; + if ((event_data->PHY[i].PhyStatus & + MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) continue; handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); if (!handle) continue; - phy_number = event_data->StartPhyNum + i; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - link_rate_ = event_data->PHY[i].LinkRate >> 4; + link_rate = event_data->PHY[i].LinkRate >> 4; + prev_link_rate = event_data->PHY[i].LinkRate & 0xF; switch (reason_code) { case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: + + if (link_rate == prev_link_rate) + break; + + mpt2sas_transport_update_links(ioc, sas_address, + handle, phy_number, link_rate); + + if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) + break; + + _scsih_check_device(ioc, handle); + break; case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - if (!parent_handle) { - if (phy_number < ioc->sas_hba.num_phys) - _scsih_link_change(ioc, - ioc->sas_hba.phy[phy_number].handle, - handle, phy_number, link_rate_); - } else { - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = - mpt2sas_scsih_expander_find_by_handle(ioc, - parent_handle); - spin_unlock_irqrestore(&ioc->sas_node_lock, - flags); - if (sas_expander) { - if (phy_number < sas_expander->num_phys) - _scsih_link_change(ioc, - sas_expander-> - phy[phy_number].handle, - handle, phy_number, - link_rate_); - } - } - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) { - if (link_rate_ >= MPI2_SAS_NEG_LINK_RATE_1_5) - _scsih_ublock_io_device(ioc, handle); - } - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) { - if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5) - break; - _scsih_add_device(ioc, handle, phy_number, 0); - } + + mpt2sas_transport_update_links(ioc, sas_address, + handle, phy_number, link_rate); + + _scsih_add_device(ioc, handle, phy_number, 0); break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - _scsih_remove_device(ioc, handle); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, + handle); + if (!sas_device) { + spin_unlock_irqrestore(&ioc->sas_device_lock, + flags); + break; + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + _scsih_remove_device(ioc, sas_device); break; } } /* handle expander removal */ - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) - _scsih_expander_remove(ioc, parent_handle); + if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && + sas_expander) + mpt2sas_expander_remove(ioc, sas_address); } @@ -4000,16 +4959,22 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: reason_str = "internal async notification"; break; + case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY: + reason_str = "expander reduced functionality"; + break; + case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY: + reason_str = "expander reduced functionality complete"; + break; default: reason_str = "unknown reason"; break; } - printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n" + printk(MPT2SAS_INFO_FMT "device status change: (%s)\n" "\thandle(0x%04x), sas address(0x%016llx)", ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), (unsigned long long)le64_to_cpu(event_data->SASAddress)); if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) - printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, + printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, event_data->ASC, event_data->ASCQ); printk(KERN_INFO "\n"); } @@ -4018,20 +4983,52 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, /** * _scsih_sas_device_status_change_event - handle device status change * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload + * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void -_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataSasDeviceStatusChange_t *event_data) +_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) { + struct MPT2SAS_TARGET *target_priv_data; + struct _sas_device *sas_device; + __le64 sas_address; + unsigned long flags; + Mpi2EventDataSasDeviceStatusChange_t *event_data = + fw_event->event_data; + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_device_status_change_event_debug(ioc, event_data); + _scsih_sas_device_status_change_event_debug(ioc, + event_data); #endif + + if (event_data->ReasonCode != + MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && + event_data->ReasonCode != + MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET) + return; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_address = le64_to_cpu(event_data->SASAddress); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + if (!sas_device || !sas_device->starget) + return; + + target_priv_data = sas_device->starget->hostdata; + if (!target_priv_data) + return; + + if (event_data->ReasonCode == + MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) + target_priv_data->tm_busy = 1; + else + target_priv_data->tm_busy = 0; } #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -4061,7 +5058,7 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, break; } - printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n" + printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n" "\thandle(0x%04x), enclosure logical id(0x%016llx)" " number slots(%d)\n", ioc->name, reason_str, le16_to_cpu(event_data->EnclosureHandle), @@ -4073,34 +5070,33 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, /** * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload + * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void _scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc, - u8 VF_ID, Mpi2EventDataSasEnclDevStatusChange_t *event_data) + struct fw_event_work *fw_event) { #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_enclosure_dev_status_change_event_debug(ioc, - event_data); + fw_event->event_data); #endif } /** * _scsih_sas_broadcast_primative_event - handle broadcast events * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void -_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataSasBroadcastPrimitive_t *event_data) +_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) { struct scsi_cmnd *scmd; u16 smid, handle; @@ -4109,19 +5105,20 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 termination_count; u32 query_count; Mpi2SCSITaskManagementReply_t *mpi_reply; - - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: " +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING + Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data; +#endif + u16 ioc_status; + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: " "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum, event_data->PortWidth)); - - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); - mutex_lock(&ioc->tm_cmds.mutex); termination_count = 0; query_count = 0; mpi_reply = ioc->tm_cmds.reply; - for (smid = 1; smid <= ioc->request_depth; smid++) { + for (smid = 1; smid <= ioc->scsiio_depth; smid++) { scmd = _scsih_scsi_lookup_get(ioc, smid); if (!scmd) continue; @@ -4141,26 +5138,25 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, lun = sas_device_priv_data->lun; query_count++; - mpt2sas_scsih_issue_tm(ioc, handle, lun, - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30); + mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, + MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL); ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - - if ((mpi_reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) && + ioc_status = le16_to_cpu(mpi_reply->IOCStatus) + & MPI2_IOCSTATUS_MASK; + if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) && (mpi_reply->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || mpi_reply->ResponseCode == MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) continue; - mpt2sas_scsih_issue_tm(ioc, handle, lun, - MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; + mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, + MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL); termination_count += le32_to_cpu(mpi_reply->TerminationCount); } ioc->broadcast_aen_busy = 0; - mutex_unlock(&ioc->tm_cmds.mutex); - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - exit, query_count = %d termination_count = %d\n", ioc->name, __func__, query_count, termination_count)); } @@ -4168,23 +5164,25 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, /** * _scsih_sas_discovery_event - handle discovery events * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void -_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataSasDiscovery_t *event_data) +_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) { + Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data; + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { - printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name, + printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name, (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? "start" : "stop"); if (event_data->DiscoveryStatus) - printk(MPT2SAS_DEBUG_FMT ", discovery_status(0x%08x)", - ioc->name, le32_to_cpu(event_data->DiscoveryStatus)); + printk("discovery_status(0x%08x)", + le32_to_cpu(event_data->DiscoveryStatus)); printk("\n"); } #endif @@ -4250,12 +5248,6 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc, u16 handle = le16_to_cpu(element->VolDevHandle); int rc; -#if 0 /* RAID_HACKS */ - if (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) - return; -#endif - mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); if (!wwid) { printk(MPT2SAS_ERR_FMT @@ -4296,26 +5288,18 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc, /** * _scsih_sas_volume_delete - delete volume * @ioc: per adapter object - * @element: IR config element data + * @handle: volume device handle * Context: user. * * Return nothing. */ static void -_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) +_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle) { struct _raid_device *raid_device; - u16 handle = le16_to_cpu(element->VolDevHandle); unsigned long flags; struct MPT2SAS_TARGET *sas_target_priv_data; -#if 0 /* RAID_HACKS */ - if (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) - return; -#endif - spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); @@ -4326,6 +5310,9 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, sas_target_priv_data->deleted = 1; scsi_remove_target(&raid_device->starget->dev); } + printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" + "(0x%016llx)\n", ioc->name, raid_device->handle, + (unsigned long long) raid_device->wwid); _scsih_raid_device_remove(ioc, raid_device); } @@ -4354,7 +5341,7 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc, /* exposing raid component */ sas_device->volume_handle = 0; sas_device->volume_wwid = 0; - sas_device->hidden_raid_component = 0; + clear_bit(handle, ioc->pd_handles); _scsih_reprobe_target(sas_device->starget, 0); } @@ -4385,7 +5372,7 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, &sas_device->volume_handle); mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle, &sas_device->volume_wwid); - sas_device->hidden_raid_component = 1; + set_bit(handle, ioc->pd_handles); _scsih_reprobe_target(sas_device->starget, 1); } @@ -4410,7 +5397,7 @@ _scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!sas_device) return; - _scsih_remove_device(ioc, handle); + _scsih_remove_device(ioc, sas_device); } /** @@ -4428,14 +5415,41 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, struct _sas_device *sas_device; unsigned long flags; u16 handle = le16_to_cpu(element->PhysDiskDevHandle); + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t sas_device_pg0; + u32 ioc_status; + u64 sas_address; + u16 parent_handle; + + set_bit(handle, ioc->pd_handles); spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (sas_device) - sas_device->hidden_raid_component = 1; - else - _scsih_add_device(ioc, handle, 0, 1); + return; + + 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; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); + if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) + mpt2sas_transport_update_links(ioc, sas_address, handle, + sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); + + _scsih_add_device(ioc, handle, 0, 1); } #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -4458,7 +5472,7 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc, element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n", + printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n", ioc->name, (le32_to_cpu(event_data->Flags) & MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? "foreign" : "native", event_data->NumElements); @@ -4511,7 +5525,7 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc, element_str = "unknown element"; break; } - printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), " + printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), " "pd handle(0x%04x), pd num(0x%02x)\n", element_str, reason_str, le16_to_cpu(element->VolDevHandle), le16_to_cpu(element->PhysDiskDevHandle), @@ -4523,24 +5537,27 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc, /** * _scsih_sas_ir_config_change_event - handle ir configuration change events * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload + * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void -_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataIrConfigChangeList_t *event_data) +_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) { Mpi2EventIrConfigElement_t *element; int i; + u8 foreign_config; + Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data; #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_ir_config_change_event_debug(ioc, event_data); #endif + foreign_config = (le32_to_cpu(event_data->Flags) & + MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; for (i = 0; i < event_data->NumElements; i++, element++) { @@ -4548,11 +5565,14 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, switch (element->ReasonCode) { case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: case MPI2_EVENT_IR_CHANGE_RC_ADDED: - _scsih_sas_volume_add(ioc, element); + if (!foreign_config) + _scsih_sas_volume_add(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: case MPI2_EVENT_IR_CHANGE_RC_REMOVED: - _scsih_sas_volume_delete(ioc, element); + if (!foreign_config) + _scsih_sas_volume_delete(ioc, + le16_to_cpu(element->VolDevHandle)); break; case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: _scsih_sas_pd_hide(ioc, element); @@ -4573,14 +5593,14 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, /** * _scsih_sas_ir_volume_event - IR volume event * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void -_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataIrVolume_t *event_data) +_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) { u64 wwid; unsigned long flags; @@ -4588,37 +5608,31 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u16 handle; u32 state; int rc; - struct MPT2SAS_TARGET *sas_target_priv_data; + Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) return; handle = le16_to_cpu(event_data->VolDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, le32_to_cpu(event_data->PreviousValue), state)); - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - switch (state) { case MPI2_RAID_VOL_STATE_MISSING: case MPI2_RAID_VOL_STATE_FAILED: - if (!raid_device) - break; - if (raid_device->starget) { - sas_target_priv_data = raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - scsi_remove_target(&raid_device->starget->dev); - } - _scsih_raid_device_remove(ioc, raid_device); + _scsih_sas_volume_delete(ioc, handle); break; case MPI2_RAID_VOL_STATE_ONLINE: case MPI2_RAID_VOL_STATE_DEGRADED: case MPI2_RAID_VOL_STATE_OPTIMAL: + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + if (raid_device) break; @@ -4658,19 +5672,24 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, /** * _scsih_sas_ir_physical_disk_event - PD event * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void -_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataIrPhysicalDisk_t *event_data) +_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) { - u16 handle; + u16 handle, parent_handle; u32 state; struct _sas_device *sas_device; unsigned long flags; + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t sas_device_pg0; + u32 ioc_status; + Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data; + u64 sas_address; if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED) return; @@ -4678,34 +5697,54 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, handle = le16_to_cpu(event_data->PhysDiskDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, le32_to_cpu(event_data->PreviousValue), state)); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - switch (state) { -#if 0 - case MPI2_RAID_PD_STATE_OFFLINE: - if (sas_device) - _scsih_remove_device(ioc, handle); - break; -#endif case MPI2_RAID_PD_STATE_ONLINE: case MPI2_RAID_PD_STATE_DEGRADED: case MPI2_RAID_PD_STATE_REBUILDING: case MPI2_RAID_PD_STATE_OPTIMAL: + case MPI2_RAID_PD_STATE_HOT_SPARE: + + set_bit(handle, ioc->pd_handles); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device) - sas_device->hidden_raid_component = 1; - else - _scsih_add_device(ioc, handle, 0, 1); + return; + + 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; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + return; + } + + parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); + if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) + mpt2sas_transport_update_links(ioc, sas_address, handle, + sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); + + _scsih_add_device(ioc, handle, 0, 1); + break; + case MPI2_RAID_PD_STATE_OFFLINE: case MPI2_RAID_PD_STATE_NOT_CONFIGURED: case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: - case MPI2_RAID_PD_STATE_HOT_SPARE: default: break; } @@ -4736,11 +5775,17 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc, case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK: reason_str = "consistency check"; break; - default: - reason_str = "unknown reason"; + case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT: + reason_str = "background init"; + break; + case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT: + reason_str = "make data consistent"; break; } + if (!reason_str) + return; + printk(MPT2SAS_INFO_FMT "raid operational status: (%s)" "\thandle(0x%04x), percent complete(%d)\n", ioc->name, reason_str, @@ -4752,102 +5797,61 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc, /** * _scsih_sas_ir_operation_status_event - handle RAID operation events * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload + * @fw_event: The fw_event_work object * Context: user. * * Return nothing. */ static void -_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataIrOperationStatus_t *event_data) +_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, + struct fw_event_work *fw_event) { + Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data; + static struct _raid_device *raid_device; + unsigned long flags; + u16 handle; + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_ir_operation_status_event_debug(ioc, event_data); + _scsih_sas_ir_operation_status_event_debug(ioc, + event_data); #endif + + /* code added for raid transport support */ + if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { + + handle = le16_to_cpu(event_data->VolDevHandle); + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + + if (!raid_device) + return; + + if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) + raid_device->percent_complete = + event_data->PercentComplete; + } } /** - * _scsih_task_set_full - handle task set full + * _scsih_prep_device_scan - initialize parameters prior to device scan * @ioc: per adapter object - * @event_data: event data payload - * Context: user. * - * Throttle back qdepth. + * Set the deleted flag prior to device scan. If the device is found during + * the scan, then we clear the deleted flag. */ static void -_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, - Mpi2EventDataTaskSetFull_t *event_data) +_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc) { - unsigned long flags; - struct _sas_device *sas_device; - static struct _raid_device *raid_device; + struct MPT2SAS_DEVICE *sas_device_priv_data; struct scsi_device *sdev; - int depth; - u16 current_depth; - u16 handle; - int id, channel; - u64 sas_address; - - current_depth = le16_to_cpu(event_data->CurrentDepth); - handle = le16_to_cpu(event_data->DevHandle); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - id = sas_device->id; - channel = sas_device->channel; - sas_address = sas_device->sas_address; - - /* if hidden raid component, then change to volume characteristics */ - if (sas_device->hidden_raid_component && sas_device->volume_handle) { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle( - ioc, sas_device->volume_handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (raid_device) { - id = raid_device->id; - channel = raid_device->channel; - handle = raid_device->handle; - sas_address = raid_device->wwid; - } - } - - if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL) - starget_printk(KERN_DEBUG, sas_device->starget, "task set " - "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n", - handle, (unsigned long long)sas_address, current_depth); shost_for_each_device(sdev, ioc->shost) { - if (sdev->id == id && sdev->channel == channel) { - if (current_depth > sdev->queue_depth) { - if (ioc->logging_level & - MPT_DEBUG_TASK_SET_FULL) - sdev_printk(KERN_INFO, sdev, "strange " - "observation, the queue depth is" - " (%d) meanwhile fw queue depth " - "is (%d)\n", sdev->queue_depth, - current_depth); - continue; - } - depth = scsi_track_queue_full(sdev, - current_depth - 1); - if (depth > 0) - sdev_printk(KERN_INFO, sdev, "Queue depth " - "reduced to (%d)\n", depth); - else if (depth < 0) - sdev_printk(KERN_INFO, sdev, "Tagged Command " - "Queueing is being disabled\n"); - else if (depth == 0) - if (ioc->logging_level & - MPT_DEBUG_TASK_SET_FULL) - sdev_printk(KERN_INFO, sdev, - "Queue depth not changed yet\n"); - } + sas_device_priv_data = sdev->hostdata; + if (sas_device_priv_data && sas_device_priv_data->sas_target) + sas_device_priv_data->sas_target->deleted = 1; } } @@ -4877,6 +5881,13 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, if (sas_device->sas_address == sas_address && sas_device->slot == slot && sas_device->starget) { sas_device->responding = 1; + starget = sas_device->starget; + if (starget && starget->hostdata) { + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->tm_busy = 0; + sas_target_priv_data->deleted = 0; + } else + sas_target_priv_data = NULL; starget_printk(KERN_INFO, sas_device->starget, "handle(0x%04x), sas_addr(0x%016llx), enclosure " "logical id(0x%016llx), slot(%d)\n", handle, @@ -4889,9 +5900,8 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", sas_device->handle); sas_device->handle = handle; - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->handle = handle; + if (sas_target_priv_data) + sas_target_priv_data->handle = handle; goto out; } } @@ -4966,6 +5976,12 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, spin_lock_irqsave(&ioc->raid_device_lock, flags); list_for_each_entry(raid_device, &ioc->raid_device_list, list) { if (raid_device->wwid == wwid && raid_device->starget) { + starget = raid_device->starget; + if (starget && starget->hostdata) { + sas_target_priv_data = starget->hostdata; + sas_target_priv_data->deleted = 0; + } else + sas_target_priv_data = NULL; raid_device->responding = 1; starget_printk(KERN_INFO, raid_device->starget, "handle(0x%04x), wwid(0x%016llx)\n", handle, @@ -4975,9 +5991,8 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", raid_device->handle); raid_device->handle = handle; - starget = raid_device->starget; - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->handle = handle; + if (sas_target_priv_data) + sas_target_priv_data->handle = handle; goto out; } } @@ -4998,9 +6013,12 @@ static void _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) { Mpi2RaidVolPage1_t volume_pg1; + Mpi2RaidVolPage0_t volume_pg0; + Mpi2RaidPhysDiskPage0_t pd_pg0; Mpi2ConfigReply_t mpi_reply; u16 ioc_status; u16 handle; + u8 phys_disk_num; printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); @@ -5015,8 +6033,32 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) break; handle = le16_to_cpu(volume_pg1.DevHandle); - _scsih_mark_responding_raid_device(ioc, - le64_to_cpu(volume_pg1.WWID), handle); + + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, + &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, + sizeof(Mpi2RaidVolPage0_t))) + continue; + + if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) + _scsih_mark_responding_raid_device(ioc, + le64_to_cpu(volume_pg1.WWID), handle); + } + + /* refresh the pd_handles */ + phys_disk_num = 0xFF; + memset(ioc->pd_handles, 0, ioc->pd_handles_sz); + while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, + phys_disk_num))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + phys_disk_num = pd_pg0.PhysDiskNum; + handle = le16_to_cpu(pd_pg0.DevHandle); + set_bit(handle, ioc->pd_handles); } } @@ -5037,18 +6079,23 @@ _scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, { struct _sas_node *sas_expander; unsigned long flags; + int i; spin_lock_irqsave(&ioc->sas_node_lock, flags); list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->sas_address == sas_address) { - sas_expander->responding = 1; - if (sas_expander->handle != handle) { - printk(KERN_INFO "old handle(0x%04x)\n", - sas_expander->handle); - sas_expander->handle = handle; - } + if (sas_expander->sas_address != sas_address) + continue; + sas_expander->responding = 1; + if (sas_expander->handle == handle) goto out; - } + printk(KERN_INFO "\texpander(0x%016llx): handle changed" + " from(0x%04x) to (0x%04x)!!!\n", + (unsigned long long)sas_expander->sas_address, + sas_expander->handle, handle); + sas_expander->handle = handle; + for (i = 0 ; i < sas_expander->num_phys ; i++) + sas_expander->phy[i].handle = handle; + goto out; } out: spin_unlock_irqrestore(&ioc->sas_node_lock, flags); @@ -5097,31 +6144,18 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) } /** - * _scsih_remove_unresponding_devices - removing unresponding devices + * _scsih_remove_unresponding_sas_devices - removing unresponding devices * @ioc: per adapter object * * Return nothing. */ static void -_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) +_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) { struct _sas_device *sas_device, *sas_device_next; - struct _sas_node *sas_expander, *sas_expander_next; + struct _sas_node *sas_expander; struct _raid_device *raid_device, *raid_device_next; - unsigned long flags; - _scsih_search_responding_sas_devices(ioc); - _scsih_search_responding_raid_devices(ioc); - _scsih_search_responding_expanders(ioc); - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->shost_recovery = 0; - if (ioc->shost->shost_state == SHOST_RECOVERY) { - printk(MPT2SAS_INFO_FMT "putting controller into " - "SHOST_RUNNING\n", ioc->name); - scsi_host_set_state(ioc->shost, SHOST_RUNNING); - } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); list_for_each_entry_safe(sas_device, sas_device_next, &ioc->sas_device_list, list) { @@ -5138,7 +6172,7 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) (unsigned long long) sas_device->enclosure_logical_id, sas_device->slot); - _scsih_remove_device(ioc, sas_device->handle); + _scsih_remove_device(ioc, sas_device); } list_for_each_entry_safe(raid_device, raid_device_next, @@ -5157,16 +6191,64 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc) _scsih_raid_device_remove(ioc, raid_device); } - list_for_each_entry_safe(sas_expander, sas_expander_next, - &ioc->sas_expander_list, list) { + retry_expander_search: + sas_expander = NULL; + list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { if (sas_expander->responding) { sas_expander->responding = 0; continue; } - printk("\tremoving expander: handle(0x%04x), " - " sas_addr(0x%016llx)\n", sas_expander->handle, - (unsigned long long)sas_expander->sas_address); - _scsih_expander_remove(ioc, sas_expander->handle); + mpt2sas_expander_remove(ioc, sas_expander->sas_address); + goto retry_expander_search; + } +} + +/** + * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) + * @ioc: per adapter object + * @reset_phase: phase + * + * The handler for doing any required cleanup or initialization. + * + * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, + * MPT2_IOC_DONE_RESET + * + * Return nothing. + */ +void +mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) +{ + switch (reset_phase) { + case MPT2_IOC_PRE_RESET: + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " + "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT2_IOC_AFTER_RESET: + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " + "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); + if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) { + ioc->scsih_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); + complete(&ioc->scsih_cmds.done); + } + if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { + ioc->tm_cmds.status |= MPT2_CMD_RESET; + mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); + complete(&ioc->tm_cmds.done); + } + _scsih_fw_event_cleanup_queue(ioc); + _scsih_flush_running_cmds(ioc); + _scsih_queue_rescan(ioc); + break; + case MPT2_IOC_DONE_RESET: + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " + "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); + _scsih_sas_host_refresh(ioc); + _scsih_prep_device_scan(ioc); + _scsih_search_responding_sas_devices(ioc); + _scsih_search_responding_raid_devices(ioc); + _scsih_search_responding_expanders(ioc); + break; } } @@ -5182,75 +6264,63 @@ static void _firmware_event_work(struct work_struct *work) { struct fw_event_work *fw_event = container_of(work, - struct fw_event_work, work); + struct fw_event_work, delayed_work.work); unsigned long flags; struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; - /* This is invoked by calling _scsih_queue_rescan(). */ - if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) { - _scsih_fw_event_free(ioc, fw_event); - _scsih_sas_host_refresh(ioc, 1); - _scsih_remove_unresponding_devices(ioc); - return; - } - /* the queue is being flushed so ignore this event */ - spin_lock_irqsave(&ioc->fw_event_lock, flags); - if (ioc->fw_events_off || ioc->remove_host) { - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + if (ioc->remove_host || fw_event->cancel_pending_work || + ioc->pci_error_recovery) { _scsih_fw_event_free(ioc, fw_event); return; } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - _scsih_fw_event_requeue(ioc, fw_event, 1000); + if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) { + _scsih_fw_event_free(ioc, fw_event); + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + if (ioc->shost_recovery) { + init_completion(&ioc->shost_recovery_done); + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, + flags); + wait_for_completion(&ioc->shost_recovery_done); + } else + spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, + flags); + _scsih_remove_unresponding_sas_devices(ioc); return; } - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); switch (fw_event->event) { case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_sas_topology_change_event(ioc, fw_event->VF_ID, - fw_event->event_data, fw_event); + _scsih_sas_topology_change_event(ioc, fw_event); break; case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - _scsih_sas_device_status_change_event(ioc, fw_event->VF_ID, - fw_event->event_data); + _scsih_sas_device_status_change_event(ioc, + fw_event); break; case MPI2_EVENT_SAS_DISCOVERY: - _scsih_sas_discovery_event(ioc, fw_event->VF_ID, - fw_event->event_data); + _scsih_sas_discovery_event(ioc, + fw_event); break; case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: - _scsih_sas_broadcast_primative_event(ioc, fw_event->VF_ID, - fw_event->event_data); + _scsih_sas_broadcast_primative_event(ioc, + fw_event); break; case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: _scsih_sas_enclosure_dev_status_change_event(ioc, - fw_event->VF_ID, fw_event->event_data); + fw_event); break; case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - _scsih_sas_ir_config_change_event(ioc, fw_event->VF_ID, - fw_event->event_data); + _scsih_sas_ir_config_change_event(ioc, fw_event); break; case MPI2_EVENT_IR_VOLUME: - _scsih_sas_ir_volume_event(ioc, fw_event->VF_ID, - fw_event->event_data); + _scsih_sas_ir_volume_event(ioc, fw_event); break; case MPI2_EVENT_IR_PHYSICAL_DISK: - _scsih_sas_ir_physical_disk_event(ioc, fw_event->VF_ID, - fw_event->event_data); + _scsih_sas_ir_physical_disk_event(ioc, fw_event); break; case MPI2_EVENT_IR_OPERATION_STATUS: - _scsih_sas_ir_operation_status_event(ioc, fw_event->VF_ID, - fw_event->event_data); - break; - case MPI2_EVENT_TASK_SET_FULL: - _scsih_task_set_full(ioc, fw_event->VF_ID, - fw_event->event_data); + _scsih_sas_ir_operation_status_event(ioc, fw_event); break; } _scsih_fw_event_free(ioc, fw_event); @@ -5259,32 +6329,30 @@ _firmware_event_work(struct work_struct *work) /** * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time) * @ioc: per adapter object - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * Context: interrupt. * * This function merely adds a new work task into ioc->firmware_event_thread. * The tasks are worked from _firmware_event_work in user context. * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -void -mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +u8 +mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, + u32 reply) { struct fw_event_work *fw_event; Mpi2EventNotificationReply_t *mpi_reply; - unsigned long flags; u16 event; + u16 sz; /* events turned off due to host reset or driver unloading */ - spin_lock_irqsave(&ioc->fw_event_lock, flags); - if (ioc->fw_events_off || ioc->remove_host) { - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - return; - } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + if (ioc->remove_host || ioc->pci_error_recovery) + return 1; - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); event = le16_to_cpu(mpi_reply->Event); switch (event) { @@ -5298,7 +6366,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) if (baen_data->Primitive != MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT || ioc->broadcast_aen_busy) - return; + return 1; ioc->broadcast_aen_busy = 1; break; } @@ -5308,42 +6376,50 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) (Mpi2EventDataSasTopologyChangeList_t *) mpi_reply->EventData); break; - + case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: + _scsih_check_ir_config_unhide_events(ioc, + (Mpi2EventDataIrConfigChangeList_t *) + mpi_reply->EventData); + break; + case MPI2_EVENT_IR_VOLUME: + _scsih_check_volume_delete_events(ioc, + (Mpi2EventDataIrVolume_t *) + mpi_reply->EventData); + break; case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI2_EVENT_IR_OPERATION_STATUS: case MPI2_EVENT_SAS_DISCOVERY: case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - case MPI2_EVENT_IR_VOLUME: case MPI2_EVENT_IR_PHYSICAL_DISK: - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - case MPI2_EVENT_TASK_SET_FULL: break; default: /* ignore the rest */ - return; + return 1; } fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); if (!fw_event) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); - return; + return 1; } - fw_event->event_data = - kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC); + sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; + fw_event->event_data = kzalloc(sz, GFP_ATOMIC); if (!fw_event->event_data) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); kfree(fw_event); - return; + return 1; } memcpy(fw_event->event_data, mpi_reply->EventData, - mpi_reply->EventDataLength*4); + sz); fw_event->ioc = ioc; - fw_event->VF_ID = VF_ID; + fw_event->VF_ID = mpi_reply->VF_ID; + fw_event->VP_ID = mpi_reply->VP_ID; fw_event->event = event; _scsih_fw_event_add(ioc, fw_event); + return 1; } /* shost template */ @@ -5389,70 +6465,143 @@ static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_expander) { - struct _sas_port *mpt2sas_port; - struct _sas_device *sas_device; - struct _sas_node *expander_sibling; - unsigned long flags; - - if (!sas_expander) - return; + struct _sas_port *mpt2sas_port, *next; /* remove sibling ports attached to this expander */ - retry_device_search: - list_for_each_entry(mpt2sas_port, + list_for_each_entry_safe(mpt2sas_port, next, &sas_expander->sas_port_list, port_list) { + if (ioc->shost_recovery) + return; if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = - mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - mpt2sas_port->remote_identify.sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - continue; - _scsih_remove_device(ioc, sas_device->handle); - goto retry_device_search; - } - } - - retry_expander_search: - list_for_each_entry(mpt2sas_port, - &sas_expander->sas_port_list, port_list) { - - if (mpt2sas_port->remote_identify.device_type == - MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || + SAS_END_DEVICE) + mpt2sas_device_remove(ioc, + mpt2sas_port->remote_identify.sas_address); + else if (mpt2sas_port->remote_identify.device_type == + SAS_EDGE_EXPANDER_DEVICE || mpt2sas_port->remote_identify.device_type == - MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) { - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - expander_sibling = - mpt2sas_scsih_expander_find_by_sas_address( - ioc, mpt2sas_port->remote_identify.sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!expander_sibling) - continue; - _scsih_expander_remove(ioc, expander_sibling->handle); - goto retry_expander_search; - } + SAS_FANOUT_EXPANDER_DEVICE) + mpt2sas_expander_remove(ioc, + mpt2sas_port->remote_identify.sas_address); } mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_expander->parent_handle); + sas_expander->sas_address_parent); printk(MPT2SAS_INFO_FMT "expander_remove: handle" "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, sas_expander->handle, (unsigned long long) sas_expander->sas_address); - list_del(&sas_expander->list); kfree(sas_expander->phy); kfree(sas_expander); } /** + * _scsih_ir_shutdown - IR shutdown notification + * @ioc: per adapter object + * + * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that + * the host system is shutting down. + * + * Return nothing. + */ +static void +_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) +{ + Mpi2RaidActionRequest_t *mpi_request; + Mpi2RaidActionReply_t *mpi_reply; + u16 smid; + + /* is IR firmware build loaded ? */ + if (!ioc->ir_firmware) + return; + + /* are there any volumes ? */ + if (list_empty(&ioc->raid_device_list)) + return; + + mutex_lock(&ioc->scsih_cmds.mutex); + + if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n", + ioc->name, __func__); + goto out; + } + ioc->scsih_cmds.status = MPT2_CMD_PENDING; + + smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; + goto out; + } + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->scsih_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); + + mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; + mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; + + printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); + init_completion(&ioc->scsih_cmds.done); + mpt2sas_base_put_smid_default(ioc, smid); + wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); + + if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + goto out; + } + + if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) { + mpi_reply = ioc->scsih_cmds.reply; + + printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " + "ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); + } + + out: + ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; + mutex_unlock(&ioc->scsih_cmds.mutex); +} + +/** + * _scsih_shutdown - routine call during system shutdown + * @pdev: PCI device struct + * + * Return nothing. + */ +static void +_scsih_shutdown(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + struct workqueue_struct *wq; + unsigned long flags; + + ioc->remove_host = 1; + _scsih_fw_event_cleanup_queue(ioc); + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + wq = ioc->firmware_event_thread; + ioc->firmware_event_thread = NULL; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + if (wq) + destroy_workqueue(wq); + + _scsih_ir_shutdown(ioc); + mpt2sas_base_detach(ioc); +} + +/** * _scsih_remove - detach and remove add host * @pdev: PCI device struct * + * Routine called when unloading the driver. * Return nothing. */ static void __devexit @@ -5460,14 +6609,14 @@ _scsih_remove(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct _sas_port *mpt2sas_port; - struct _sas_device *sas_device; - struct _sas_node *expander_sibling; + struct _sas_port *mpt2sas_port, *next_port; + struct _raid_device *raid_device, *next; + struct MPT2SAS_TARGET *sas_target_priv_data; struct workqueue_struct *wq; unsigned long flags; ioc->remove_host = 1; - _scsih_fw_event_off(ioc); + _scsih_fw_event_cleanup_queue(ioc); spin_lock_irqsave(&ioc->fw_event_lock, flags); wq = ioc->firmware_event_thread; @@ -5476,29 +6625,34 @@ _scsih_remove(struct pci_dev *pdev) if (wq) destroy_workqueue(wq); + /* release all the volumes */ + list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, + list) { + if (raid_device->starget) { + sas_target_priv_data = + raid_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + scsi_remove_target(&raid_device->starget->dev); + } + printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" + "(0x%016llx)\n", ioc->name, raid_device->handle, + (unsigned long long) raid_device->wwid); + _scsih_raid_device_remove(ioc, raid_device); + } + /* free ports attached to the sas_host */ - retry_again: - list_for_each_entry(mpt2sas_port, + list_for_each_entry_safe(mpt2sas_port, next_port, &ioc->sas_hba.sas_port_list, port_list) { if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) { - sas_device = - mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - mpt2sas_port->remote_identify.sas_address); - if (sas_device) { - _scsih_remove_device(ioc, sas_device->handle); - goto retry_again; - } - } else { - expander_sibling = - mpt2sas_scsih_expander_find_by_sas_address(ioc, + SAS_END_DEVICE) + mpt2sas_device_remove(ioc, + mpt2sas_port->remote_identify.sas_address); + else if (mpt2sas_port->remote_identify.device_type == + SAS_EDGE_EXPANDER_DEVICE || + mpt2sas_port->remote_identify.device_type == + SAS_FANOUT_EXPANDER_DEVICE) + mpt2sas_expander_remove(ioc, mpt2sas_port->remote_identify.sas_address); - if (expander_sibling) { - _scsih_expander_remove(ioc, - expander_sibling->handle); - goto retry_again; - } - } } /* free phys attached to the sas_host */ @@ -5509,7 +6663,7 @@ _scsih_remove(struct pci_dev *pdev) } sas_remove_host(shost); - mpt2sas_base_detach(ioc); + _scsih_shutdown(pdev); list_del(&ioc->list); scsi_remove_host(shost); scsi_host_put(shost); @@ -5530,7 +6684,8 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) void *device; struct _sas_device *sas_device; struct _raid_device *raid_device; - u16 handle, parent_handle; + u16 handle; + u64 sas_address_parent; u64 sas_address; unsigned long flags; int rc; @@ -5559,17 +6714,17 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) } else { sas_device = device; handle = sas_device->handle; - parent_handle = sas_device->parent_handle; + sas_address_parent = sas_device->sas_address_parent; sas_address = sas_device->sas_address; spin_lock_irqsave(&ioc->sas_device_lock, flags); list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->parent_handle)) { + sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); } else if (!sas_device->starget) { mpt2sas_transport_port_remove(ioc, sas_address, - parent_handle); + sas_address_parent); _scsih_sas_device_remove(ioc, sas_device); } } @@ -5599,7 +6754,7 @@ _scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc) } /** - * _scsih_probe_sas - reporting raid volumes to sas transport + * _scsih_probe_sas - reporting sas devices to sas transport * @ioc: per adapter object * * Called during initial loading of the driver. @@ -5609,8 +6764,6 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) { struct _sas_device *sas_device, *next; unsigned long flags; - u16 handle, parent_handle; - u64 sas_address; /* SAS Device List */ list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, @@ -5619,14 +6772,13 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - handle = sas_device->handle; - parent_handle = sas_device->parent_handle; - sas_address = sas_device->sas_address; - if (!mpt2sas_transport_port_add(ioc, handle, parent_handle)) { + if (!mpt2sas_transport_port_add(ioc, sas_device->handle, + sas_device->sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); } else if (!sas_device->starget) { - mpt2sas_transport_port_remove(ioc, sas_address, - parent_handle); + mpt2sas_transport_port_remove(ioc, + sas_device->sas_address, + sas_device->sas_address_parent); _scsih_sas_device_remove(ioc, sas_device); } } @@ -5695,9 +6847,14 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->ctl_cb_idx = ctl_cb_idx; ioc->base_cb_idx = base_cb_idx; ioc->transport_cb_idx = transport_cb_idx; + ioc->scsih_cb_idx = scsih_cb_idx; ioc->config_cb_idx = config_cb_idx; + ioc->tm_tr_cb_idx = tm_tr_cb_idx; + ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx; + ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; ioc->logging_level = logging_level; /* misc semaphores and spin locks */ + mutex_init(&ioc->reset_in_progress_mutex); spin_lock_init(&ioc->ioc_reset_in_progress_lock); spin_lock_init(&ioc->scsi_lookup_lock); spin_lock_init(&ioc->sas_device_lock); @@ -5711,9 +6868,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&ioc->fw_event_list); INIT_LIST_HEAD(&ioc->raid_device_list); INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); + INIT_LIST_HEAD(&ioc->delayed_tr_list); + INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); /* init shost parameters */ - shost->max_cmd_len = 16; + shost->max_cmd_len = 32; shost->max_lun = max_lun; shost->transportt = mpt2sas_transport_template; shost->unique_id = ioc->id; @@ -5726,7 +6885,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) } scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE3_PROTECTION); + | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION); + scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); /* event thread */ snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), @@ -5774,6 +6934,7 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state) struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); u32 device_state; + mpt2sas_base_stop_watchdog(ioc); flush_scheduled_work(); scsi_block_requests(shost); device_state = pci_choose_state(pdev, state); @@ -5816,22 +6977,155 @@ _scsih_resume(struct pci_dev *pdev) mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET); scsi_unblock_requests(shost); + mpt2sas_base_start_watchdog(ioc); return 0; } #endif /* CONFIG_PM */ +/** + * _scsih_pci_error_detected - Called when a PCI error is detected. + * @pdev: PCI device struct + * @state: PCI channel state + * + * Description: Called when a PCI error is detected. + * + * Return value: + * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT + */ +static pci_ers_result_t +_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n", + ioc->name, state); + + switch (state) { + case pci_channel_io_normal: + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + /* Fatal error, prepare for slot reset */ + ioc->pci_error_recovery = 1; + scsi_block_requests(ioc->shost); + mpt2sas_base_stop_watchdog(ioc); + mpt2sas_base_free_resources(ioc); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + /* Permanent error, prepare for device removal */ + ioc->pci_error_recovery = 1; + mpt2sas_base_stop_watchdog(ioc); + _scsih_flush_running_cmds(ioc); + return PCI_ERS_RESULT_DISCONNECT; + } + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * _scsih_pci_slot_reset - Called when PCI slot has been reset. + * @pdev: PCI device struct + * + * Description: This routine is called by the pci error recovery + * code after the PCI slot has been reset, just before we + * should resume normal operations. + */ +static pci_ers_result_t +_scsih_pci_slot_reset(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + int rc; + + printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", + ioc->name); + + ioc->pci_error_recovery = 0; + ioc->pdev = pdev; + pci_restore_state(pdev); + rc = mpt2sas_base_map_resources(ioc); + if (rc) + return PCI_ERS_RESULT_DISCONNECT; + + + rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + + printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name, + (rc == 0) ? "success" : "failed"); + + if (!rc) + return PCI_ERS_RESULT_RECOVERED; + else + return PCI_ERS_RESULT_DISCONNECT; +} + +/** + * _scsih_pci_resume() - resume normal ops after PCI reset + * @pdev: pointer to PCI device + * + * Called when the error recovery driver tells us that its + * OK to resume normal operation. Use completion to allow + * halted scsi ops to resume. + */ +static void +_scsih_pci_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name); + + pci_cleanup_aer_uncorrect_error_status(pdev); + mpt2sas_base_start_watchdog(ioc); + scsi_unblock_requests(ioc->shost); +} + +/** + * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers + * @pdev: pointer to PCI device + */ +static pci_ers_result_t +_scsih_pci_mmio_enabled(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n", + ioc->name); + + /* TODO - dump whatever for debugging purposes */ + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +static struct pci_error_handlers _scsih_err_handler = { + .error_detected = _scsih_pci_error_detected, + .mmio_enabled = _scsih_pci_mmio_enabled, + .slot_reset = _scsih_pci_slot_reset, + .resume = _scsih_pci_resume, +}; static struct pci_driver scsih_driver = { .name = MPT2SAS_DRIVER_NAME, .id_table = scsih_pci_table, .probe = _scsih_probe, .remove = __devexit_p(_scsih_remove), + .shutdown = _scsih_shutdown, + .err_handler = &_scsih_err_handler, #ifdef CONFIG_PM .suspend = _scsih_suspend, .resume = _scsih_resume, #endif }; +/* raid transport support */ +static struct raid_function_template mpt2sas_raid_functions = { + .cookie = &scsih_driver_template, + .is_raid = _scsih_is_raid, + .get_resync = _scsih_get_resync, + .get_state = _scsih_get_state, +}; /** * _scsih_init - main entry point for this driver. @@ -5851,13 +7145,19 @@ _scsih_init(void) sas_attach_transport(&mpt2sas_transport_functions); if (!mpt2sas_transport_template) return -ENODEV; + /* raid transport support */ + mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions); + if (!mpt2sas_raid_template) { + sas_release_transport(mpt2sas_transport_template); + return -ENODEV; + } mpt2sas_base_initialize_callback_handler(); /* queuecommand callback hander */ scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done); - /* task managment callback handler */ + /* task management callback handler */ tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done); /* base internal commands callback handler */ @@ -5867,6 +7167,9 @@ _scsih_init(void) transport_cb_idx = mpt2sas_base_register_callback_handler( mpt2sas_transport_done); + /* scsih internal commands callback handler */ + scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done); + /* configuration page API internal commands callback handler */ config_cb_idx = mpt2sas_base_register_callback_handler( mpt2sas_config_done); @@ -5874,11 +7177,23 @@ _scsih_init(void) /* ctl module callback handler */ ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done); + tm_tr_cb_idx = mpt2sas_base_register_callback_handler( + _scsih_tm_tr_complete); + + tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler( + _scsih_tm_volume_tr_complete); + + tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler( + _scsih_sas_control_complete); + mpt2sas_ctl_init(); error = pci_register_driver(&scsih_driver); - if (error) + if (error) { + /* raid transport support */ + raid_class_release(mpt2sas_raid_template); sas_release_transport(mpt2sas_transport_template); + } return error; } @@ -5896,15 +7211,24 @@ _scsih_exit(void) pci_unregister_driver(&scsih_driver); - sas_release_transport(mpt2sas_transport_template); + mpt2sas_ctl_exit(); + mpt2sas_base_release_callback_handler(scsi_io_cb_idx); mpt2sas_base_release_callback_handler(tm_cb_idx); mpt2sas_base_release_callback_handler(base_cb_idx); mpt2sas_base_release_callback_handler(transport_cb_idx); + mpt2sas_base_release_callback_handler(scsih_cb_idx); mpt2sas_base_release_callback_handler(config_cb_idx); mpt2sas_base_release_callback_handler(ctl_cb_idx); - mpt2sas_ctl_exit(); + mpt2sas_base_release_callback_handler(tm_tr_cb_idx); + mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx); + mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); + + /* raid transport support */ + raid_class_release(mpt2sas_raid_template); + sas_release_transport(mpt2sas_transport_template); + } module_init(_scsih_init); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 686695b155c..cb1cdecbe0f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -2,7 +2,7 @@ * 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 + * Copyright (C) 2007-2010 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * * This program is free software; you can redistribute it and/or @@ -49,6 +49,7 @@ #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/pci.h> +#include <linux/slab.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -59,24 +60,23 @@ #include "mpt2sas_base.h" /** - * _transport_sas_node_find_by_handle - sas node search + * _transport_sas_node_find_by_sas_address - sas node search * @ioc: per adapter object - * @handle: expander or hba handle (assigned by firmware) + * @sas_address: sas address of expander or sas host * Context: Calling function should acquire ioc->sas_node_lock. * * Search for either hba phys or expander device based on handle, then returns * the sas_node object. */ static struct _sas_node * -_transport_sas_node_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address) { - 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); + if (ioc->sas_hba.sas_address == sas_address) + return &ioc->sas_hba; + else + return mpt2sas_scsih_expander_find_by_sas_address(ioc, + sas_address); } /** @@ -140,11 +140,18 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, u32 device_info; u32 ioc_status; + if (ioc->shost_recovery || ioc->pci_error_recovery) { + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); - return -1; + return -ENXIO; } ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & @@ -153,7 +160,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, 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; + return -EIO; } memset(identify, 0, sizeof(identify)); @@ -205,25 +212,26 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, * mpt2sas_transport_done - internal transport layer callback handler. * @ioc: per adapter object * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS * @reply: reply message frame(lower 32bit addr) * * Callback handler when sending internal generated transport cmds. * The callback index passed is `ioc->transport_cb_idx` * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. */ -void -mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, +u8 +mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) { MPI2DefaultReply_t *mpi_reply; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED) - return; + return 1; if (ioc->transport_cmds.smid != smid) - return; + return 1; ioc->transport_cmds.status |= MPT2_CMD_COMPLETE; if (mpi_reply) { memcpy(ioc->transport_cmds.reply, mpi_reply, @@ -232,6 +240,7 @@ mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, } ioc->transport_cmds.status &= ~MPT2_CMD_PENDING; complete(&ioc->transport_cmds.done); + return 1; } /* report manufacture request structure */ @@ -250,8 +259,7 @@ struct rep_manu_reply{ u8 response_length; u16 expander_change_count; u8 reserved0[2]; - u8 sas_format:1; - u8 reserved1:7; + u8 sas_format; u8 reserved2[3]; u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; @@ -288,21 +296,17 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, 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); + if (ioc->shost_recovery || ioc->pci_error_recovery) { 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); @@ -366,9 +370,12 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; mpi_request->PhysicalPort = 0xFF; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; sas_address_le = (u64 *)&mpi_request->SASAddress; *sas_address_le = cpu_to_le64(sas_address); - mpi_request->RequestDataLength = sizeof(struct rep_manu_request); + mpi_request->RequestDataLength = + cpu_to_le16(sizeof(struct rep_manu_request)); psge = &mpi_request->SGL; /* WRITE sgel first */ @@ -390,10 +397,11 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, sizeof(struct rep_manu_reply), data_out_dma + sizeof(struct rep_manu_request)); - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - " + dtransportprintk(ioc, printk(MPT2SAS_INFO_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 */); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->transport_cmds.done); timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); @@ -407,7 +415,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, goto issue_host_reset; } - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - " + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - " "complete\n", ioc->name)); if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { @@ -415,7 +423,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, mpi_reply = ioc->transport_cmds.reply; - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - reply data transfer size(%d)\n", ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); @@ -430,8 +438,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, 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) { + edev->level = manufacture_reply->sas_format & 1; + if (edev->level) { strncpy(edev->component_vendor_id, manufacture_reply->component_vendor_id, SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); @@ -441,7 +449,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, manufacture_reply->component_revision_id; } } else - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - no reply\n", ioc->name)); issue_host_reset: @@ -458,10 +466,178 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, } /** + * _transport_delete_port - helper function to removing a port + * @ioc: per adapter object + * @mpt2sas_port: mpt2sas per port object + * + * Returns nothing. + */ +static void +_transport_delete_port(struct MPT2SAS_ADAPTER *ioc, + struct _sas_port *mpt2sas_port) +{ + u64 sas_address = mpt2sas_port->remote_identify.sas_address; + enum sas_device_type device_type = + mpt2sas_port->remote_identify.device_type; + + dev_printk(KERN_INFO, &mpt2sas_port->port->dev, + "remove: sas_addr(0x%016llx)\n", + (unsigned long long) sas_address); + + ioc->logging_level |= MPT_DEBUG_TRANSPORT; + if (device_type == SAS_END_DEVICE) + mpt2sas_device_remove(ioc, sas_address); + else if (device_type == SAS_EDGE_EXPANDER_DEVICE || + device_type == SAS_FANOUT_EXPANDER_DEVICE) + mpt2sas_expander_remove(ioc, sas_address); + ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; +} + +/** + * _transport_delete_phy - helper function to removing single phy from port + * @ioc: per adapter object + * @mpt2sas_port: mpt2sas per port object + * @mpt2sas_phy: mpt2sas per phy object + * + * Returns nothing. + */ +static void +_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc, + struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy) +{ + u64 sas_address = mpt2sas_port->remote_identify.sas_address; + + dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, + "remove: sas_addr(0x%016llx), phy(%d)\n", + (unsigned long long) sas_address, mpt2sas_phy->phy_id); + + list_del(&mpt2sas_phy->port_siblings); + mpt2sas_port->num_phys--; + sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); + mpt2sas_phy->phy_belongs_to_port = 0; +} + +/** + * _transport_add_phy - helper function to adding single phy to port + * @ioc: per adapter object + * @mpt2sas_port: mpt2sas per port object + * @mpt2sas_phy: mpt2sas per phy object + * + * Returns nothing. + */ +static void +_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port, + struct _sas_phy *mpt2sas_phy) +{ + u64 sas_address = mpt2sas_port->remote_identify.sas_address; + + dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, + "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) + sas_address, mpt2sas_phy->phy_id); + + list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list); + mpt2sas_port->num_phys++; + sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy); + mpt2sas_phy->phy_belongs_to_port = 1; +} + +/** + * _transport_add_phy_to_an_existing_port - adding new phy to existing port + * @ioc: per adapter object + * @sas_node: sas node object (either expander or sas host) + * @mpt2sas_phy: mpt2sas per phy object + * @sas_address: sas address of device/expander were phy needs to be added to + * + * Returns nothing. + */ +static void +_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc, +struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address) +{ + struct _sas_port *mpt2sas_port; + struct _sas_phy *phy_srch; + + if (mpt2sas_phy->phy_belongs_to_port == 1) + return; + + list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, + port_list) { + if (mpt2sas_port->remote_identify.sas_address != + sas_address) + continue; + list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, + port_siblings) { + if (phy_srch == mpt2sas_phy) + return; + } + _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy); + return; + } + +} + +/** + * _transport_del_phy_from_an_existing_port - delete phy from existing port + * @ioc: per adapter object + * @sas_node: sas node object (either expander or sas host) + * @mpt2sas_phy: mpt2sas per phy object + * + * Returns nothing. + */ +static void +_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc, + struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy) +{ + struct _sas_port *mpt2sas_port, *next; + struct _sas_phy *phy_srch; + + if (mpt2sas_phy->phy_belongs_to_port == 0) + return; + + list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, + port_list) { + list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, + port_siblings) { + if (phy_srch != mpt2sas_phy) + continue; + if (mpt2sas_port->num_phys == 1) + _transport_delete_port(ioc, mpt2sas_port); + else + _transport_delete_phy(ioc, mpt2sas_port, + mpt2sas_phy); + return; + } + } +} + +/** + * _transport_sanity_check - sanity check when adding a new port + * @ioc: per adapter object + * @sas_node: sas node object (either expander or sas host) + * @sas_address: sas address of device being added + * + * See the explanation above from _transport_delete_duplicate_port + */ +static void +_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, + u64 sas_address) +{ + int i; + + for (i = 0; i < sas_node->num_phys; i++) { + if (sas_node->phy[i].remote_identify.sas_address != sas_address) + continue; + if (sas_node->phy[i].phy_belongs_to_port == 1) + _transport_del_phy_from_an_existing_port(ioc, sas_node, + &sas_node->phy[i]); + } +} + +/** * mpt2sas_transport_port_add - insert port to the list * @ioc: per adapter object * @handle: handle of attached device - * @parent_handle: parent handle(either hba or expander) + * @sas_address: sas address of parent expander or sas host * Context: This function will acquire ioc->sas_node_lock. * * Adding new port object to the sas_node->sas_port_list. @@ -470,7 +646,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, */ struct _sas_port * mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u16 parent_handle) + u64 sas_address) { struct _sas_phy *mpt2sas_phy, *next; struct _sas_port *mpt2sas_port; @@ -480,9 +656,6 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, int i; struct sas_port *port; - if (!parent_handle) - return NULL; - mpt2sas_port = kzalloc(sizeof(struct _sas_port), GFP_KERNEL); if (!mpt2sas_port) { @@ -494,17 +667,16 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, 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); + sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); 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); + printk(MPT2SAS_ERR_FMT "%s: Could not find " + "parent sas_address(0x%016llx)!\n", ioc->name, + __func__, (unsigned long long)sas_address); 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", @@ -518,6 +690,9 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, goto out_fail; } + _transport_sanity_check(ioc, sas_node, + mpt2sas_port->remote_identify.sas_address); + for (i = 0; i < sas_node->num_phys; i++) { if (sas_node->phy[i].remote_identify.sas_address != mpt2sas_port->remote_identify.sas_address) @@ -549,6 +724,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, mpt2sas_port->remote_identify.sas_address, mpt2sas_phy->phy_id); sas_port_add_phy(port, mpt2sas_phy->phy); + mpt2sas_phy->phy_belongs_to_port = 1; } mpt2sas_port->port = port; @@ -596,7 +772,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, * 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) + * @sas_address_parent: sas address of parent expander or sas host * Context: This function will acquire ioc->sas_node_lock. * * Removing object and freeing associated memory from the @@ -606,7 +782,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, */ void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 parent_handle) + u64 sas_address_parent) { int i; unsigned long flags; @@ -616,7 +792,8 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, 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); + sas_node = _transport_sas_node_find_by_sas_address(ioc, + sas_address_parent); spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!sas_node) return; @@ -642,11 +819,11 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, &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, + "remove: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) mpt2sas_port->remote_identify.sas_address, mpt2sas_phy->phy_id); + mpt2sas_phy->phy_belongs_to_port = 0; sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); list_del(&mpt2sas_phy->port_siblings); } @@ -789,35 +966,40 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy } /** - * mpt2sas_transport_update_phy_link_change - refreshing phy link changes and attached devices + * mpt2sas_transport_update_links - refreshing phy link changes * @ioc: per adapter object - * @handle: handle to sas_host or expander - * @attached_handle: attached device handle + * @sas_address: sas address of parent expander or sas host + * @handle: attached device handle * @phy_numberv: phy number * @link_rate: new link rate * * Returns nothing. */ void -mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, - u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate) +mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) { unsigned long flags; struct _sas_node *sas_node; struct _sas_phy *mpt2sas_phy; + if (ioc->shost_recovery || ioc->pci_error_recovery) + return; + spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_handle(ioc, handle); + sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); 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->attached_handle = handle; + if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { + _transport_set_identify(ioc, handle, &mpt2sas_phy->remote_identify); - else + _transport_add_phy_to_an_existing_port(ioc, sas_node, + mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address); + } else memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct sas_identify)); @@ -827,13 +1009,11 @@ mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "refresh: handle(0x%04x), sas_addr(0x%016llx),\n" + "refresh: parent 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) + (unsigned long long)sas_address, + link_rate, phy_number, handle, (unsigned long long) mpt2sas_phy->remote_identify.sas_address); } @@ -851,11 +1031,230 @@ rphy_to_ioc(struct sas_rphy *rphy) return shost_priv(shost); } + +/* report phy error log structure */ +struct phy_error_log_request{ + u8 smp_frame_type; /* 0x40 */ + u8 function; /* 0x11 */ + u8 allocated_response_length; + u8 request_length; /* 02 */ + u8 reserved_1[5]; + u8 phy_identifier; + u8 reserved_2[2]; +}; + +/* report phy error log reply structure */ +struct phy_error_log_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x11 */ + u8 function_result; + u8 response_length; + u16 expander_change_count; + u8 reserved_1[3]; + u8 phy_identifier; + u8 reserved_2[2]; + u32 invalid_dword; + u32 running_disparity_error; + u32 loss_of_dword_sync; + u32 phy_reset_problem; +}; + /** - * _transport_get_linkerrors - + * _transport_get_expander_phy_error_log - return expander counters + * @ioc: per adapter object + * @phy: The sas phy object + * + * Returns 0 for success, non-zero for failure. + * + */ +static int +_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, + struct sas_phy *phy) +{ + Mpi2SmpPassthroughRequest_t *mpi_request; + Mpi2SmpPassthroughReply_t *mpi_reply; + struct phy_error_log_request *phy_error_log_request; + struct phy_error_log_reply *phy_error_log_reply; + int rc; + u16 smid; + u32 ioc_state; + unsigned long timeleft; + void *psge; + u32 sgl_flags; + u8 issue_reset = 0; + void *data_out = NULL; + dma_addr_t data_out_dma; + u32 sz; + u64 *sas_address_le; + u16 wait_state_count; + + if (ioc->shost_recovery || ioc->pci_error_recovery) { + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + + 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; + } + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->transport_cmds.smid = smid; + + sz = sizeof(struct phy_error_log_request) + + sizeof(struct phy_error_log_reply); + data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); + if (!data_out) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + rc = -ENOMEM; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + + rc = -EINVAL; + memset(data_out, 0, sz); + phy_error_log_request = data_out; + phy_error_log_request->smp_frame_type = 0x40; + phy_error_log_request->function = 0x11; + phy_error_log_request->request_length = 2; + phy_error_log_request->allocated_response_length = 0; + phy_error_log_request->phy_identifier = phy->number; + + memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; + mpi_request->PhysicalPort = 0xFF; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(phy->identify.sas_address); + mpi_request->RequestDataLength = + cpu_to_le16(sizeof(struct phy_error_log_request)); + psge = &mpi_request->SGL; + + /* WRITE sgel first */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct phy_error_log_request), data_out_dma); + + /* incr sgel */ + psge += ioc->sge_size; + + /* READ sgel last */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct phy_error_log_reply), data_out_dma + + sizeof(struct phy_error_log_request)); + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " + "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name, + (unsigned long long)phy->identify.sas_address, phy->number)); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->transport_cmds.done); + 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_INFO_FMT "phy_error_log - " + "complete\n", ioc->name)); + + if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { + + mpi_reply = ioc->transport_cmds.reply; + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_error_log - reply data transfer size(%d)\n", + ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); + + if (le16_to_cpu(mpi_reply->ResponseDataLength) != + sizeof(struct phy_error_log_reply)) + goto out; + + phy_error_log_reply = data_out + + sizeof(struct phy_error_log_request); + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_error_log - function_result(%d)\n", + ioc->name, phy_error_log_reply->function_result)); + + phy->invalid_dword_count = + be32_to_cpu(phy_error_log_reply->invalid_dword); + phy->running_disparity_error_count = + be32_to_cpu(phy_error_log_reply->running_disparity_error); + phy->loss_of_dword_sync_count = + be32_to_cpu(phy_error_log_reply->loss_of_dword_sync); + phy->phy_reset_problem_count = + be32_to_cpu(phy_error_log_reply->phy_reset_problem); + rc = 0; + } else + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_error_log - no reply\n", ioc->name)); + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + out: + ioc->transport_cmds.status = 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; +} + +/** + * _transport_get_linkerrors - return phy counters for both hba and expanders * @phy: The sas phy object * - * Only support sas_host direct attached phys. * Returns 0 for success, non-zero for failure. * */ @@ -863,23 +1262,24 @@ static int _transport_get_linkerrors(struct sas_phy *phy) { struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - struct _sas_phy *mpt2sas_phy; + unsigned long flags; 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]; + spin_lock_irqsave(&ioc->sas_node_lock, flags); + if (_transport_sas_node_find_by_sas_address(ioc, + phy->identify.sas_address) == NULL) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + return -EINVAL; } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!mpt2sas_phy) /* this phy not on sas_host */ - return -EINVAL; + if (phy->identify.sas_address != ioc->sas_hba.sas_address) + return _transport_get_expander_phy_error_log(ioc, phy); + /* get hba phy error logs */ if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, - mpt2sas_phy->phy_id))) { + phy->number))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return -ENXIO; @@ -888,8 +1288,7 @@ _transport_get_linkerrors(struct sas_phy *phy) 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), + phy->number, le16_to_cpu(mpi_reply.IOCStatus), le32_to_cpu(mpi_reply.IOCLogInfo)); phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount); @@ -913,18 +1312,18 @@ 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; + struct _sas_device *sas_device; unsigned long flags; - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, + 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_node_lock, flags); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_expander) + if (!sas_device) return -ENXIO; - *identifier = sas_expander->enclosure_logical_id; + *identifier = sas_device->enclosure_logical_id; return 0; } @@ -952,38 +1351,260 @@ _transport_get_bay_identifier(struct sas_rphy *rphy) return sas_device->slot; } +/* phy control request structure */ +struct phy_control_request{ + u8 smp_frame_type; /* 0x40 */ + u8 function; /* 0x91 */ + u8 allocated_response_length; + u8 request_length; /* 0x09 */ + u16 expander_change_count; + u8 reserved_1[3]; + u8 phy_identifier; + u8 phy_operation; + u8 reserved_2[13]; + u64 attached_device_name; + u8 programmed_min_physical_link_rate; + u8 programmed_max_physical_link_rate; + u8 reserved_3[6]; +}; + +/* phy control reply structure */ +struct phy_control_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x11 */ + u8 function_result; + u8 response_length; +}; + +#define SMP_PHY_CONTROL_LINK_RESET (0x01) +#define SMP_PHY_CONTROL_HARD_RESET (0x02) +#define SMP_PHY_CONTROL_DISABLE (0x03) + +/** + * _transport_expander_phy_control - expander phy control + * @ioc: per adapter object + * @phy: The sas phy object + * + * Returns 0 for success, non-zero for failure. + * + */ +static int +_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, + struct sas_phy *phy, u8 phy_operation) +{ + Mpi2SmpPassthroughRequest_t *mpi_request; + Mpi2SmpPassthroughReply_t *mpi_reply; + struct phy_control_request *phy_control_request; + struct phy_control_reply *phy_control_reply; + int rc; + u16 smid; + u32 ioc_state; + unsigned long timeleft; + void *psge; + u32 sgl_flags; + u8 issue_reset = 0; + void *data_out = NULL; + dma_addr_t data_out_dma; + u32 sz; + u64 *sas_address_le; + u16 wait_state_count; + + if (ioc->shost_recovery) { + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + + 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; + } + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->transport_cmds.smid = smid; + + sz = sizeof(struct phy_control_request) + + sizeof(struct phy_control_reply); + data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); + if (!data_out) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + rc = -ENOMEM; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + + rc = -EINVAL; + memset(data_out, 0, sz); + phy_control_request = data_out; + phy_control_request->smp_frame_type = 0x40; + phy_control_request->function = 0x91; + phy_control_request->request_length = 9; + phy_control_request->allocated_response_length = 0; + phy_control_request->phy_identifier = phy->number; + phy_control_request->phy_operation = phy_operation; + phy_control_request->programmed_min_physical_link_rate = + phy->minimum_linkrate << 4; + phy_control_request->programmed_max_physical_link_rate = + phy->maximum_linkrate << 4; + + memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; + mpi_request->PhysicalPort = 0xFF; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(phy->identify.sas_address); + mpi_request->RequestDataLength = + cpu_to_le16(sizeof(struct phy_error_log_request)); + psge = &mpi_request->SGL; + + /* WRITE sgel first */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct phy_control_request), data_out_dma); + + /* incr sgel */ + psge += ioc->sge_size; + + /* READ sgel last */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct phy_control_reply), data_out_dma + + sizeof(struct phy_control_request)); + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " + "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name, + (unsigned long long)phy->identify.sas_address, phy->number, + phy_operation)); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->transport_cmds.done); + 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_INFO_FMT "phy_control - " + "complete\n", ioc->name)); + + if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { + + mpi_reply = ioc->transport_cmds.reply; + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_control - reply data transfer size(%d)\n", + ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); + + if (le16_to_cpu(mpi_reply->ResponseDataLength) != + sizeof(struct phy_control_reply)) + goto out; + + phy_control_reply = data_out + + sizeof(struct phy_control_request); + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_control - function_result(%d)\n", + ioc->name, phy_control_reply->function_result)); + + rc = 0; + } else + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_control - no reply\n", ioc->name)); + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + out: + ioc->transport_cmds.status = 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; +} + /** * _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; + unsigned long flags; - 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]; + spin_lock_irqsave(&ioc->sas_node_lock, flags); + if (_transport_sas_node_find_by_sas_address(ioc, + phy->identify.sas_address) == NULL) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + return -EINVAL; } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!mpt2sas_phy) /* this phy not on sas_host */ - return -EINVAL; + /* handle expander phys */ + if (phy->identify.sas_address != ioc->sas_hba.sas_address) + return _transport_expander_phy_control(ioc, phy, + (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET : + SMP_PHY_CONTROL_LINK_RESET); + /* handle hba phys */ memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t)); mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request.Operation = hard_reset ? MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET; - mpi_request.PhyNum = mpt2sas_phy->phy_id; + mpi_request.PhyNum = phy->number; if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", @@ -994,14 +1615,208 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) 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), + phy->number, le16_to_cpu(mpi_reply.IOCStatus), le32_to_cpu(mpi_reply.IOCLogInfo)); return 0; } /** + * _transport_phy_enable - enable/disable phys + * @phy: The sas phy object + * @enable: enable phy when true + * + * Only support sas_host direct attached phys. + * Returns 0 for success, non-zero for failure. + */ +static int +_transport_phy_enable(struct sas_phy *phy, int enable) +{ + struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); + Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + u16 sz; + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + if (_transport_sas_node_find_by_sas_address(ioc, + phy->identify.sas_address) == NULL) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + + /* handle expander phys */ + if (phy->identify.sas_address != ioc->sas_hba.sas_address) + return _transport_expander_phy_control(ioc, phy, + (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET : + SMP_PHY_CONTROL_DISABLE); + + /* handle hba phys */ + + /* sas_iounit page 1 */ + sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit1PhyData_t)); + sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg1) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENOMEM; + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, + sas_iounit_pg1, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -EIO; + goto out; + } + + if (enable) + sas_iounit_pg1->PhyData[phy->number].PhyFlags + &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; + else + sas_iounit_pg1->PhyData[phy->number].PhyFlags + |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; + + mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); + + /* link reset */ + if (enable) + _transport_phy_reset(phy, 0); + + out: + kfree(sas_iounit_pg1); + return rc; +} + +/** + * _transport_phy_speed - set phy min/max link rates + * @phy: The sas phy object + * @rates: rates defined in sas_phy_linkrates + * + * Only support sas_host direct attached phys. + * Returns 0 for success, non-zero for failure. + */ +static int +_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) +{ + struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); + Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2SasPhyPage0_t phy_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 ioc_status; + u16 sz; + int i; + int rc = 0; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_node_lock, flags); + if (_transport_sas_node_find_by_sas_address(ioc, + phy->identify.sas_address) == NULL) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + + if (!rates->minimum_linkrate) + rates->minimum_linkrate = phy->minimum_linkrate; + else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) + rates->minimum_linkrate = phy->minimum_linkrate_hw; + + if (!rates->maximum_linkrate) + rates->maximum_linkrate = phy->maximum_linkrate; + else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) + rates->maximum_linkrate = phy->maximum_linkrate_hw; + + /* handle expander phys */ + if (phy->identify.sas_address != ioc->sas_hba.sas_address) { + phy->minimum_linkrate = rates->minimum_linkrate; + phy->maximum_linkrate = rates->maximum_linkrate; + return _transport_expander_phy_control(ioc, phy, + SMP_PHY_CONTROL_LINK_RESET); + } + + /* handle hba phys */ + + /* sas_iounit page 1 */ + sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * + sizeof(Mpi2SasIOUnit1PhyData_t)); + sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); + if (!sas_iounit_pg1) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENOMEM; + goto out; + } + if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, + sas_iounit_pg1, sz))) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -EIO; + goto out; + } + + for (i = 0; i < ioc->sas_hba.num_phys; i++) { + if (phy->number != i) { + sas_iounit_pg1->PhyData[i].MaxMinLinkRate = + (ioc->sas_hba.phy[i].phy->minimum_linkrate + + (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); + } else { + sas_iounit_pg1->PhyData[i].MaxMinLinkRate = + (rates->minimum_linkrate + + (rates->maximum_linkrate << 4)); + } + } + + if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, + sz)) { + printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__); + rc = -ENXIO; + goto out; + } + + /* link reset */ + _transport_phy_reset(phy, 0); + + /* read phy page 0, then update the rates in the sas transport phy */ + if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, + phy->number)) { + phy->minimum_linkrate = _transport_convert_phy_link_rate( + phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); + phy->maximum_linkrate = _transport_convert_phy_link_rate( + phy_pg0.ProgrammedLinkRate >> 4); + phy->negotiated_linkrate = _transport_convert_phy_link_rate( + phy_pg0.NegotiatedLinkRate & + MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); + } + + out: + kfree(sas_iounit_pg1); + return rc; +} + + +/** * _transport_smp_handler - transport portal for smp passthru * @shost: shost object * @rphy: sas transport rphy object @@ -1025,7 +1840,6 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, 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; @@ -1045,14 +1859,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, 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); + if (ioc->shost_recovery) { 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) @@ -1101,6 +1912,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; mpi_request->PhysicalPort = 0xFF; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; *((u64 *)&mpi_request->SASAddress) = (rphy) ? cpu_to_le64(rphy->identify.sas_address) : cpu_to_le64(ioc->sas_hba.sas_address); @@ -1114,7 +1927,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_out) { - mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); + mpt2sas_base_free_smid(ioc, smid); goto unmap; } @@ -1132,17 +1945,18 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) { - mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); + mpt2sas_base_free_smid(ioc, smid); goto unmap; } ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4), dma_addr_in); - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - " + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " "sending smp request\n", ioc->name, __func__)); - mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->transport_cmds.done); timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); @@ -1156,14 +1970,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, goto issue_host_reset; } - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - " + dtransportprintk(ioc, printk(MPT2SAS_INFO_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 + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - reply data transfer size(%d)\n", ioc->name, __func__, le16_to_cpu(mpi_reply->ResponseDataLength))); @@ -1171,9 +1985,10 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); req->sense_len = sizeof(*mpi_reply); req->resid_len = 0; - rsp->resid_len -= mpi_reply->ResponseDataLength; + rsp->resid_len -= + le16_to_cpu(mpi_reply->ResponseDataLength); } else { - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - no reply\n", ioc->name, __func__)); rc = -ENXIO; } @@ -1204,6 +2019,8 @@ struct sas_function_template mpt2sas_transport_functions = { .get_enclosure_identifier = _transport_get_enclosure_identifier, .get_bay_identifier = _transport_get_bay_identifier, .phy_reset = _transport_phy_reset, + .phy_enable = _transport_phy_enable, + .set_phy_speed = _transport_phy_speed, .smp_handler = _transport_smp_handler, }; |