diff options
Diffstat (limited to 'drivers/scsi/mpt2sas')
| -rw-r--r-- | drivers/scsi/mpt2sas/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2.h | 43 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 347 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_history.txt | 381 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_init.h | 24 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 178 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_raid.h | 79 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_sas.h | 14 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 70 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpi/mpi2_type.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 1469 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 306 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_config.c | 110 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 498 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.h | 3 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_debug.h | 4 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 2736 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 463 | 
18 files changed, 4748 insertions, 1981 deletions
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig index bbb7e4bf30a..39f08dd2055 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-2010  LSI Corporation +# Copyright (C) 2007-2012  LSI Corporation  #  (mailto:DL-MPTFusionLinux@lsi.com)  # This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 4b1c2f0350f..7b14a015c90 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2010 LSI Corporation. + *  Copyright (c) 2000-2013 LSI Corporation.   *   *   *           Name:  mpi2.h @@ -8,7 +8,7 @@   *                  scatter/gather formats.   *  Creation Date:  June 21, 2006   * - *  mpi2.h Version:  02.00.15 + *  mpi2.h Version:  02.00.28   *   *  Version History   *  --------------- @@ -61,6 +61,23 @@   *                      Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.   *                      Added defines for product-specific range of message   *                      function codes, 0xF0 to 0xFF. + *  05-12-10  02.00.16  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Added alternative defines for the SGE Direction bit. + *  08-11-10  02.00.17  Bumped MPI2_HEADER_VERSION_UNIT. + *  11-10-10  02.00.18  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. + *  02-23-11  02.00.19  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Added MPI2_FUNCTION_SEND_HOST_MESSAGE. + *  03-09-11  02.00.20  Bumped MPI2_HEADER_VERSION_UNIT. + *  05-25-11  02.00.21  Bumped MPI2_HEADER_VERSION_UNIT. + *  08-24-11  02.00.22  Bumped MPI2_HEADER_VERSION_UNIT. + *  11-18-11  02.00.23  Bumped MPI2_HEADER_VERSION_UNIT. + *  02-06-12  02.00.24  Bumped MPI2_HEADER_VERSION_UNIT. + *  03-29-12  02.00.25  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Added Hard Reset delay timings. + *  07-10-12  02.00.26  Bumped MPI2_HEADER_VERSION_UNIT. + *  07-26-12  02.00.27  Bumped MPI2_HEADER_VERSION_UNIT. + *  11-27-12  02.00.28  Bumped MPI2_HEADER_VERSION_UNIT.   *  --------------------------------------------------------------------------   */ @@ -86,7 +103,7 @@  #define MPI2_VERSION_02_00                  (0x0200)  /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT            (0x0F) +#define MPI2_HEADER_VERSION_UNIT            (0x1C)  #define MPI2_HEADER_VERSION_DEV             (0x00)  #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)  #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8) @@ -264,6 +281,11 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS  #define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET    (0x000000C4) +/* Hard Reset delay timings */ +#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC     (50000) +#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC    (255000) +#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC    (256000) +  /*****************************************************************************  *  *        Message Descriptors @@ -470,7 +492,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION      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; +Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; @@ -510,6 +532,8 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION  #define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION   (0x2F)  /* Power Management Control */  #define MPI2_FUNCTION_PWR_MGMT_CONTROL              (0x30) +/* Send Host Message */ +#define MPI2_FUNCTION_SEND_HOST_MESSAGE             (0x31)  /* beginning of product-specific range */  #define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC          (0xF0)  /* end of product-specific range */ @@ -929,6 +953,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) @@ -1054,10 +1081,16 @@ typedef struct _MPI2_IEEE_SGE_UNION  #define MPI2_IEEE_SGE_FLAGS_ADDR_MASK           (0x03)  #define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR         (0x00) +						/* IEEE Simple Element only */  #define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR         (0x01) +						/* IEEE Simple Element only */  #define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR         (0x02)  #define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR      (0x03) - +						/* IEEE Simple Element only */ +#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR   (0x03) +						/* IEEE Chain Element only */ +#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR   \ +	(MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */  /****************************************************************************  *  IEEE SGE operation Macros diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index e3728d736d8..88cb7f828bb 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -1,12 +1,12 @@  /* - *  Copyright (c) 2000-2010 LSI Corporation. + *  Copyright (c) 2000-2013 LSI Corporation.   *   *   *           Name:  mpi2_cnfg.h   *          Title:  MPI Configuration messages and pages   *  Creation Date:  November 10, 2006   * - *    mpi2_cnfg.h Version:  02.00.14 + *    mpi2_cnfg.h Version:  02.00.23   *   *  Version History   *  --------------- @@ -121,6 +121,36 @@   *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.   *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.   *                      Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. + *  05-12-10  02.00.15  Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT + *                      define. + *                      Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. + *                      Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. + *  08-11-10  02.00.16  Removed IO Unit Page 1 device path (multi-pathing) + *                      defines. + *  11-10-10  02.00.17  Added ReceptacleID field (replacing Reserved1) to + *                      MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for + *                      the Pinout field. + *                      Added BoardTemperature and BoardTemperatureUnits fields + *                      to MPI2_CONFIG_PAGE_IO_UNIT_7. + *                      Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define + *                      and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. + *  02-23-11  02.00.18  Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. + *                      Added IO Unit Page 8, IO Unit Page 9, + *                      and IO Unit Page 10. + *                      Added SASNotifyPrimitiveMasks field to + *                      MPI2_CONFIG_PAGE_IOC_7. + *  03-09-11  02.00.19  Fixed IO Unit Page 10 (to match the spec). + *  05-25-11  02.00.20  Cleaned up a few comments. + *  08-24-11  02.00.21  Marked the IO Unit Page 7 PowerManagementCapabilities + *                      for PCIe link as obsolete. + *                      Added SpinupFlags field containing a Disable Spin-up + *                      bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of + *                      SAS IO Unit Page 4. + *  11-18-11  02.00.22  Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT. + *                      Added UEFIVersion field to BIOS Page 1 and defined new + *                      BiosOptions bits. + *  11-27-12  02.00.23  Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER. + *			 Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.   *  --------------------------------------------------------------------------   */ @@ -204,6 +234,7 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION  #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING      (0x17)  #define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT            (0x18)  #define MPI2_CONFIG_EXTPAGETYPE_ETHERNET            (0x19) +#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING   (0x1A)  /***************************************************************************** @@ -315,7 +346,9 @@ typedef struct _MPI2_CONFIG_REQUEST      U8                      VP_ID;                      /* 0x08 */      U8                      VF_ID;                      /* 0x09 */      U16                     Reserved1;                  /* 0x0A */ -    U32                     Reserved2;                  /* 0x0C */ +	U8                      Reserved2;                  /* 0x0C */ +	U8                      ProxyVF_ID;                 /* 0x0D */ +	U16                     Reserved4;                  /* 0x0E */      U32                     Reserved3;                  /* 0x10 */      MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x14 */      U32                     PageAddress;                /* 0x18 */ @@ -333,7 +366,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 */ @@ -379,6 +412,8 @@ 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) @@ -390,6 +425,8 @@ typedef struct _MPI2_CONFIG_REPLY  #define MPI2_MFGPAGE_DEVID_SAS2308_3                (0x006E) + +  /* Manufacturing Page 0 */  typedef struct _MPI2_CONFIG_PAGE_MAN_0 @@ -602,23 +639,31 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO      U32                         Pinout;                 /* 0x00 */      U8                          Connector[16];          /* 0x04 */      U8                          Location;               /* 0x14 */ -    U8                          Reserved1;              /* 0x15 */ +	U8                          ReceptacleID;           /* 0x15 */      U16                         Slot;                   /* 0x16 */      U32                         Reserved2;              /* 0x18 */  } MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO,    Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t;  /* defines for the Pinout field */ -#define MPI2_MANPAGE7_PINOUT_SFF_8484_L4                (0x00080000) -#define MPI2_MANPAGE7_PINOUT_SFF_8484_L3                (0x00040000) -#define MPI2_MANPAGE7_PINOUT_SFF_8484_L2                (0x00020000) -#define MPI2_MANPAGE7_PINOUT_SFF_8484_L1                (0x00010000) -#define MPI2_MANPAGE7_PINOUT_SFF_8470_L4                (0x00000800) -#define MPI2_MANPAGE7_PINOUT_SFF_8470_L3                (0x00000400) -#define MPI2_MANPAGE7_PINOUT_SFF_8470_L2                (0x00000200) -#define MPI2_MANPAGE7_PINOUT_SFF_8470_L1                (0x00000100) -#define MPI2_MANPAGE7_PINOUT_SFF_8482                   (0x00000002) -#define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN         (0x00000001) +#define MPI2_MANPAGE7_PINOUT_LANE_MASK                  (0x0000FF00) +#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT                 (8) + +#define MPI2_MANPAGE7_PINOUT_TYPE_MASK                  (0x000000FF) +#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN               (0x00) +#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE                (0x01) +#define MPI2_MANPAGE7_PINOUT_SFF_8482                   (0x02) +#define MPI2_MANPAGE7_PINOUT_SFF_8486                   (0x03) +#define MPI2_MANPAGE7_PINOUT_SFF_8484                   (0x04) +#define MPI2_MANPAGE7_PINOUT_SFF_8087                   (0x05) +#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I                (0x06) +#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I                (0x07) +#define MPI2_MANPAGE7_PINOUT_SFF_8470                   (0x08) +#define MPI2_MANPAGE7_PINOUT_SFF_8088                   (0x09) +#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X                (0x0A) +#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X                (0x0B) +#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X               (0x0C) +#define MPI2_MANPAGE7_PINOUT_SFF_8436                   (0x0D)  /* defines for the Location field */  #define MPI2_MANPAGE7_LOCATION_UNKNOWN                  (0x01) @@ -652,9 +697,10 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7    MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7,    Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; -#define MPI2_MANUFACTURING7_PAGEVERSION                 (0x00) +#define MPI2_MANUFACTURING7_PAGEVERSION                 (0x01)  /* defines for the Flags field */ +#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER       (0x00000002)  #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO                (0x00000001) @@ -729,6 +775,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1  /* 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) @@ -736,8 +783,6 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1  #define MPI2_IOUNITPAGE1_DISABLE_IR                     (0x00000040)  #define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020)  #define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID        (0x00000004) -#define MPI2_IOUNITPAGE1_MULTI_PATHING                  (0x00000002) -#define MPI2_IOUNITPAGE1_SINGLE_PATHING                 (0x00000000)  /* IO Unit Page 3 */ @@ -840,11 +885,13 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {      U16                     IOCTemperature;                         /* 0x10 */      U8                      IOCTemperatureUnits;                    /* 0x12 */      U8                      IOCSpeed;                               /* 0x13 */ -    U32                     Reserved3;                              /* 0x14 */ +	U16                     BoardTemperature;              /* 0x14 */ +	U8                      BoardTemperatureUnits;         /* 0x16 */ +	U8                      Reserved3;                     /* 0x17 */  } 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) +#define MPI2_IOUNITPAGE7_PAGEVERSION                    (0x02)  /* defines for IO Unit Page 7 PCIeWidth field */  #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1              (0x01) @@ -869,9 +916,8 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {  #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) - +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE    (0x00000008) /* obsolete */ +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE    (0x00000004) /* obsolete */  /* defines for IO Unit Page 7 IOCTemperatureUnits field */  #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT       (0x00) @@ -884,6 +930,125 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {  #define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER          (0x04)  #define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH           (0x08) +/* defines for IO Unit Page 7 BoardTemperatureUnits field */ +#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT     (0x00) +#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT      (0x01) +#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS         (0x02) + +/* IO Unit Page 8 */ + +#define MPI2_IOUNIT8_NUM_THRESHOLDS     (4) + +typedef struct _MPI2_IOUNIT8_SENSOR { +	U16                     Flags;                /* 0x00 */ +	U16                     Reserved1;            /* 0x02 */ +	U16 +		Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */ +	U32                     Reserved2;            /* 0x0C */ +	U32                     Reserved3;            /* 0x10 */ +	U32                     Reserved4;            /* 0x14 */ +} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR, +Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t; + +/* defines for IO Unit Page 8 Sensor Flags field */ +#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE         (0x0008) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE         (0x0004) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE         (0x0002) +#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE         (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumSensors at runtime. + */ +#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES +#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES     (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { +	MPI2_CONFIG_PAGE_HEADER Header;               /* 0x00 */ +	U32                     Reserved1;            /* 0x04 */ +	U32                     Reserved2;            /* 0x08 */ +	U8                      NumSensors;           /* 0x0C */ +	U8                      PollingInterval;      /* 0x0D */ +	U16                     Reserved3;            /* 0x0E */ +	MPI2_IOUNIT8_SENSOR +			Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, +Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t; + +#define MPI2_IOUNITPAGE8_PAGEVERSION                    (0x00) + + +/* IO Unit Page 9 */ + +typedef struct _MPI2_IOUNIT9_SENSOR { +	U16                     CurrentTemperature;     /* 0x00 */ +	U16                     Reserved1;              /* 0x02 */ +	U8                      Flags;                  /* 0x04 */ +	U8                      Reserved2;              /* 0x05 */ +	U16                     Reserved3;              /* 0x06 */ +	U32                     Reserved4;              /* 0x08 */ +	U32                     Reserved5;              /* 0x0C */ +} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR, +Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t; + +/* defines for IO Unit Page 9 Sensor Flags field */ +#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID        (0x01) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumSensors at runtime. + */ +#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES +#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES     (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { +	MPI2_CONFIG_PAGE_HEADER Header;                /* 0x00 */ +	U32                     Reserved1;             /* 0x04 */ +	U32                     Reserved2;             /* 0x08 */ +	U8                      NumSensors;            /* 0x0C */ +	U8                      Reserved4;             /* 0x0D */ +	U16                     Reserved3;             /* 0x0E */ +	MPI2_IOUNIT9_SENSOR +			Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, +Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t; + +#define MPI2_IOUNITPAGE9_PAGEVERSION                    (0x00) + + +/* IO Unit Page 10 */ + +typedef struct _MPI2_IOUNIT10_FUNCTION { +	U8                      CreditPercent;      /* 0x00 */ +	U8                      Reserved1;          /* 0x01 */ +	U16                     Reserved2;          /* 0x02 */ +} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION, +Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumFunctions at runtime. + */ +#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES +#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES      (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { +	MPI2_CONFIG_PAGE_HEADER Header;                    /* 0x00 */ +	U8                      NumFunctions;             /* 0x04 */ +	U8                      Reserved1;              /* 0x05 */ +	U16                     Reserved2;              /* 0x06 */ +	U32                     Reserved3;              /* 0x08 */ +	U32                     Reserved4;		/* 0x0C */ +	MPI2_IOUNIT10_FUNCTION +		Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/* 0x10 */ +} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, +Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t; + +#define MPI2_IOUNITPAGE10_PAGEVERSION                   (0x01) +  /**************************************************************************** @@ -971,9 +1136,10 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_6  } MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6,    Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t; -#define MPI2_IOCPAGE6_PAGEVERSION                       (0x04) +#define MPI2_IOCPAGE6_PAGEVERSION                       (0x05)  /* defines for IOC Page 6 CapabilitiesFlags */ +#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT      (0x00000020)  #define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT          (0x00000010)  #define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT           (0x00000008)  #define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT          (0x00000004) @@ -991,12 +1157,12 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_7      U32                     Reserved1;                  /* 0x04 */      U32                     EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */      U16                     SASBroadcastPrimitiveMasks; /* 0x18 */ -    U16                     Reserved2;                  /* 0x1A */ +	U16                     SASNotifyPrimitiveMasks;    /* 0x1A */      U32                     Reserved3;                  /* 0x1C */  } MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7,    Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t; -#define MPI2_IOCPAGE7_PAGEVERSION                       (0x01) +#define MPI2_IOCPAGE7_PAGEVERSION                       (0x02)  /* IOC Page 8 */ @@ -1044,24 +1210,32 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_8  typedef struct _MPI2_CONFIG_PAGE_BIOS_1  { -    MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */ -    U32                     BiosOptions;                /* 0x04 */ -    U32                     IOCSettings;                /* 0x08 */ -    U32                     Reserved1;                  /* 0x0C */ -    U32                     DeviceSettings;             /* 0x10 */ -    U16                     NumberOfDevices;            /* 0x14 */ -    U16                     Reserved2;                  /* 0x16 */ -    U16                     IOTimeoutBlockDevicesNonRM; /* 0x18 */ -    U16                     IOTimeoutSequential;        /* 0x1A */ -    U16                     IOTimeoutOther;             /* 0x1C */ -    U16                     IOTimeoutBlockDevicesRM;    /* 0x1E */ +	MPI2_CONFIG_PAGE_HEADER Header;                     /* 0x00 */ +	U32                     BiosOptions;                /* 0x04 */ +	U32                     IOCSettings;                /* 0x08 */ +	U32                     Reserved1;                  /* 0x0C */ +	U32                     DeviceSettings;             /* 0x10 */ +	U16                     NumberOfDevices;            /* 0x14 */ +	U16                     UEFIVersion;                /* 0x16 */ +	U16                     IOTimeoutBlockDevicesNonRM; /* 0x18 */ +	U16                     IOTimeoutSequential;        /* 0x1A */ +	U16                     IOTimeoutOther;             /* 0x1C */ +	U16                     IOTimeoutBlockDevicesRM;    /* 0x1E */  } MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1,    Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; -#define MPI2_BIOSPAGE1_PAGEVERSION                      (0x04) +#define MPI2_BIOSPAGE1_PAGEVERSION                      (0x05)  /* values for BIOS Page 1 BiosOptions field */ -#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS             (0x00000001) +#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID                  (0x000000F0) +#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID                   (0x00000000) + +#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION   (0x00000006) +#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII              (0x00000000) +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII             (0x00000002) +#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII       (0x00000004) + +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS                 (0x00000001)  /* values for BIOS Page 1 IOCSettings field */  #define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE      (0x00030000) @@ -1088,6 +1262,13 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1  #define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN        (0x00000002)  #define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN         (0x00000001) +/* defines for BIOS Page 1 UEFIVersion field */ +#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK              (0xFF00) +#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT             (8) +#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK              (0x00FF) +#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT             (0) + +  /* BIOS Page 2 */ @@ -1347,6 +1528,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) @@ -1469,11 +1651,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) @@ -1545,6 +1731,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) @@ -1571,6 +1758,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1  #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) @@ -1810,10 +1998,14 @@ typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP  {      U8          MaxTargetSpinup;            /* 0x00 */      U8          SpinupDelay;                /* 0x01 */ -    U16         Reserved1;                  /* 0x02 */ +	U8          SpinupFlags;                /* 0x02 */ +	U8          Reserved1;                  /* 0x03 */  } MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP,    Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t; +/* defines for SAS IO Unit Page 4 SpinupFlags */ +#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG         (0x01) +  /*   * Host code (drivers, BIOS, utilities, etc.) should leave this define set to   * one and check the value returned for NumPhys at runtime. @@ -2032,18 +2224,39 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 {  #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) - - +#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD          (0x00001000) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE        (0x00000800) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE        (0x00000400) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE       (0x00000200) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE       (0x00000100) +#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD        (0x00000010) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE      (0x00000008) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE      (0x00000004) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE     (0x00000002) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE     (0x00000001) + + + +/* SAS IO Unit Page 16 */ + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 { +	MPI2_CONFIG_EXTENDED_PAGE_HEADER  Header;                  /* 0x00 */ +	U64                         TimeStamp;                     /* 0x08 */ +	U32                         Reserved1;                     /* 0x10 */ +	U32                         Reserved2;                     /* 0x14 */ +	U32                         FastPathPendedRequests;        /* 0x18 */ +	U32                         FastPathUnPendedRequests;      /* 0x1C */ +	U32                         FastPathHostRequestStarts;     /* 0x20 */ +	U32                         FastPathFirmwareRequestStarts; /* 0x24 */ +	U32                         FastPathHostCompletions;       /* 0x28 */ +	U32                         FastPathFirmwareCompletions;   /* 0x2C */ +	U32                         NonFastPathRequestStarts;      /* 0x30 */ +	U32			    NonFastPathHostCompletions;    /* 0x30 */ +} MPI2_CONFIG_PAGE_SASIOUNIT16, +MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16, +Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t; + +#define MPI2_SASIOUNITPAGE16_PAGEVERSION    (0x00)  /**************************************************************************** @@ -2161,13 +2374,12 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1  /* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ -  /* values for SAS Expander Page 1 DiscoveryInfo field */  #define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED    (0x04)  #define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE  (0x02)  #define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES  (0x01) +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */  /****************************************************************************  *   SAS Device Config Pages @@ -2228,6 +2440,7 @@ 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_UNAUTHORIZED_DEVICE          (0x8000)  #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) @@ -2286,6 +2499,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0  #define MPI2_SASPHY0_PAGEVERSION            (0x03) +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ +  /* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */  /* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ @@ -2293,12 +2508,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0  /* values for SAS PHY Page 0 Flags field */  #define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC             (0x01) -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ +/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */  /* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ -/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ -  /* SAS PHY Page 1 */ @@ -2783,5 +2996,25 @@ typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 {  #define MPI2_ETHPG1_MS_DATA_RATE_1GBIT              (0x03) +/**************************************************************************** +*   Extended Manufacturing Config Pages +****************************************************************************/ + +/* + * Generic structure to use for product-specific extended manufacturing pages + * (currently Extended Manufacturing Page 40 through Extended Manufacturing + * Page 60). + */ + +typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { +	MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                 /* 0x00 */ +	U32                                 ProductSpecificInfo;    /* 0x08 */ +}	MPI2_CONFIG_PAGE_EXT_MAN_PS, +	MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, +	Mpi2ExtManufacturingPagePS_t, +	MPI2_POINTER pMpi2ExtManufacturingPagePS_t; + +/* PageVersion should be provided by product-specific code */ +  #endif diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt deleted file mode 100644 index bd6c92b5fae..00000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt +++ /dev/null @@ -1,381 +0,0 @@ - ============================== - 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. - *  -------------------------------------------------------------------------- - -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. - *  -------------------------------------------------------------------------- - -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. - *  -------------------------------------------------------------------------- - -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 c4c99dfcb82..9d284dae655 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -1,12 +1,12 @@  /* - *  Copyright (c) 2000-2010 LSI Corporation. + *  Copyright (c) 2000-2013 LSI Corporation.   *   *   *           Name:  mpi2_init.h   *          Title:  MPI SCSI initiator mode messages and structures   *  Creation Date:  June 23, 2006   * - *    mpi2_init.h Version:  02.00.09 + *    mpi2_init.h Version:  02.00.14   *   *  Version History   *  --------------- @@ -21,7 +21,7 @@   *  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 + *                      Moved LUN field defines to mpi2.h because they are   *                      common to many structures.   *  05-06-09  02.00.07  Changed task management type of Query Unit Attention to   *                      Query Asynchronous Event. @@ -32,6 +32,11 @@   *                      Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.   *                      Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.   *  02-10-10  02.00.09  Removed unused structure that had "#if 0" around it. + *  05-12-10  02.00.10  Added optional vendor-unique region to SCSI IO Request. + *  11-10-10  02.00.11  Added MPI2_SCSIIO_NUM_SGLOFFSETS define. + *  02-06-12  02.00.13  Added alternate defines for Task Priority / Command + *                      Priority to match SAM-4. + *  07-10-12  02.00.14  Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION.   *  --------------------------------------------------------------------------   */ @@ -98,7 +103,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; @@ -132,6 +143,9 @@ typedef struct _MPI2_SCSI_IO_REQUEST  #define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT             (4)  #define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT             (0) +/* number of SGLOffset fields */ +#define MPI2_SCSIIO_NUM_SGLOFFSETS                  (4) +  /* SCSI IO IoFlags bits */  /* Large CDB Address Space */ @@ -176,6 +190,7 @@ typedef struct _MPI2_SCSI_IO_REQUEST  #define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT     (26)  #define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK  (0x03000000) +#define MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION (24)  #define MPI2_SCSIIO_CONTROL_NODATATRANSFER      (0x00000000)  #define MPI2_SCSIIO_CONTROL_WRITE               (0x01000000)  #define MPI2_SCSIIO_CONTROL_READ                (0x02000000) @@ -183,6 +198,9 @@ typedef struct _MPI2_SCSI_IO_REQUEST  #define MPI2_SCSIIO_CONTROL_TASKPRI_MASK        (0x00007800)  #define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT       (11) +/* alternate name for the previous field; called Command Priority in SAM-4 */ +#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK         (0x00007800) +#define MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT        (11)  #define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK  (0x00000700)  #define MPI2_SCSIIO_CONTROL_SIMPLEQ             (0x00000000) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 495bedc4d1f..d159c5f24aa 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -1,12 +1,12 @@  /* - *  Copyright (c) 2000-2010 LSI Corporation. + *  Copyright (c) 2000-2013 LSI Corporation.   *   *   *           Name:  mpi2_ioc.h   *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages   *  Creation Date:  October 11, 2006   * - *  mpi2_ioc.h Version:  02.00.14 + *  mpi2_ioc.h Version:  02.00.22   *   *  Version History   *  --------------- @@ -101,6 +101,26 @@   *  02-10-10  02.00.14  Added SAS Quiesce Event structure and defines.   *                      Added PowerManagementControl Request structures and   *                      defines. + *  05-12-10  02.00.15  Marked Task Set Full Event as obsolete. + *                      Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. + *  11-10-10  02.00.16  Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. + *  02-23-11  02.00.17  Added SAS NOTIFY Primitive event, and added + *                      SASNotifyPrimitiveMasks field to + *                      MPI2_EVENT_NOTIFICATION_REQUEST. + *                      Added Temperature Threshold Event. + *                      Added Host Message Event. + *                      Added Send Host Message request and reply. + *  05-25-11  02.00.18  For Extended Image Header, added + *                      MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and + *                      MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. + *                      Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. + *  08-24-11  02.00.19  Added PhysicalPort field to + *                      MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. + *                      Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. + *  03-29-12  02.00.21  Added a product specific range to event values. + *  07-26-12  02.00.22  Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE. + *                      Added ElapsedSeconds field to + *                      MPI2_EVENT_DATA_IR_OPERATION_STATUS.   *  --------------------------------------------------------------------------   */ @@ -267,6 +287,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY  #define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT              (0)  /* IOCExceptions */ +#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE     (0x0200)  #define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX      (0x0100)  #define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK              (0x00E0) @@ -418,7 +439,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST      U32                     Reserved6;                      /* 0x10 */      U32                     EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */      U16                     SASBroadcastPrimitiveMasks;     /* 0x24 */ -    U16                     Reserved7;                      /* 0x26 */ +	 U16                     SASNotifyPrimitiveMasks;        /* 0x26 */      U32                     Reserved8;                      /* 0x28 */  } MPI2_EVENT_NOTIFICATION_REQUEST,    MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST, @@ -456,7 +477,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) @@ -473,7 +494,11 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY  #define MPI2_EVENT_GPIO_INTERRUPT                   (0x0023)  #define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY         (0x0024)  #define MPI2_EVENT_SAS_QUIESCE                      (0x0025) - +#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE             (0x0026) +#define MPI2_EVENT_TEMP_THRESHOLD                   (0x0027) +#define MPI2_EVENT_HOST_MESSAGE                     (0x0028) +#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC             (0x006E) +#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC             (0x007F)  /* Log Entry Added Event data */ @@ -504,6 +529,39 @@ typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT {    MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT,    Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; +/* Temperature Threshold Event data */ + +typedef struct _MPI2_EVENT_DATA_TEMPERATURE { +	U16         Status;                             /* 0x00 */ +	U8          SensorNum;                          /* 0x02 */ +	U8          Reserved1;                          /* 0x03 */ +	U16         CurrentTemperature;                 /* 0x04 */ +	U16         Reserved2;                          /* 0x06 */ +	U32         Reserved3;                          /* 0x08 */ +	U32         Reserved4;                          /* 0x0C */ +} MPI2_EVENT_DATA_TEMPERATURE, +MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE, +Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t; + +/* Temperature Threshold Event data Status bits */ +#define MPI2_EVENT_TEMPERATURE3_EXCEEDED            (0x0008) +#define MPI2_EVENT_TEMPERATURE2_EXCEEDED            (0x0004) +#define MPI2_EVENT_TEMPERATURE1_EXCEEDED            (0x0002) +#define MPI2_EVENT_TEMPERATURE0_EXCEEDED            (0x0001) + + +/* Host Message Event data */ + +typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE { +	U8          SourceVF_ID;                        /* 0x00 */ +	U8          Reserved1;                          /* 0x01 */ +	U16         Reserved2;                          /* 0x02 */ +	U32         Reserved3;                          /* 0x04 */ +	U32         HostData[1];                        /* 0x08 */ +} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE, +Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_t; + +  /* Hard Reset Received Event data */  typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED @@ -517,6 +575,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  { @@ -532,7 +591,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE  {      U16                     TaskTag;                        /* 0x00 */      U8                      ReasonCode;                     /* 0x02 */ -    U8                      Reserved1;                      /* 0x03 */ +	U8                      PhysicalPort;                   /* 0x03 */      U8                      ASC;                            /* 0x04 */      U8                      ASCQ;                           /* 0x05 */      U16                     DevHandle;                      /* 0x06 */ @@ -569,7 +628,7 @@ typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS      U8                      RAIDOperation;              /* 0x04 */      U8                      PercentComplete;            /* 0x05 */      U16                     Reserved2;                  /* 0x06 */ -    U32                     Resereved3;                 /* 0x08 */ +	U32                     ElapsedSeconds;             /* 0x08 */  } MPI2_EVENT_DATA_IR_OPERATION_STATUS,    MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS,    Mpi2EventDataIrOperationStatus_t, @@ -745,6 +804,24 @@ typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE  #define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED               (0x07)  #define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED               (0x08) +/* SAS Notify Primitive Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE { +	U8                      PhyNum;                     /* 0x00 */ +	U8                      Port;                       /* 0x01 */ +	U8                      Reserved1;                  /* 0x02 */ +	U8                      Primitive;                  /* 0x03 */ +} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, +MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, +Mpi2EventDataSasNotifyPrimitive_t, +MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t; + +/* defines for the Primitive field */ +#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP                     (0x01) +#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED               (0x02) +#define MPI2_EVENT_NOTIFY_RESERVED1                         (0x03) +#define MPI2_EVENT_NOTIFY_RESERVED2                         (0x04) +  /* SAS Initiator Device Status Change Event data */ @@ -831,6 +908,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) @@ -996,6 +1074,53 @@ typedef struct _MPI2_EVENT_ACK_REPLY  /**************************************************************************** +*  SendHostMessage message +****************************************************************************/ + +/* SendHostMessage Request message */ +typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST { +	U16                     HostDataLength;                 /* 0x00 */ +	U8                      ChainOffset;                    /* 0x02 */ +	U8                      Function;                       /* 0x03 */ +	U16                     Reserved1;                      /* 0x04 */ +	U8                      Reserved2;                      /* 0x06 */ +	U8                      MsgFlags;                       /* 0x07 */ +	U8                      VP_ID;                          /* 0x08 */ +	U8                      VF_ID;                          /* 0x09 */ +	U16                     Reserved3;                      /* 0x0A */ +	U8                      Reserved4;                      /* 0x0C */ +	U8                      DestVF_ID;                      /* 0x0D */ +	U16                     Reserved5;                      /* 0x0E */ +	U32                     Reserved6;                      /* 0x10 */ +	U32                     Reserved7;                      /* 0x14 */ +	U32                     Reserved8;                      /* 0x18 */ +	U32                     Reserved9;                      /* 0x1C */ +	U32                     Reserved10;                     /* 0x20 */ +	U32                     HostData[1];                    /* 0x24 */ +} MPI2_SEND_HOST_MESSAGE_REQUEST, +MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST, +Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t; + + +/* SendHostMessage Reply message */ +typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY { +	U16                     HostDataLength;                 /* 0x00 */ +	U8                      MsgLength;                      /* 0x02 */ +	U8                      Function;                       /* 0x03 */ +	U16                     Reserved1;                      /* 0x04 */ +	U8                      Reserved2;                      /* 0x06 */ +	U8                      MsgFlags;                       /* 0x07 */ +	U8                      VP_ID;                          /* 0x08 */ +	U8                      VF_ID;                          /* 0x09 */ +	U16                     Reserved3;                      /* 0x0A */ +	U16                     Reserved4;                      /* 0x0C */ +	U16                     IOCStatus;                      /* 0x0E */ +	U32                     IOCLogInfo;                     /* 0x10 */ +} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY, +Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_t; + + +/****************************************************************************  *  FWDownload message  ****************************************************************************/ @@ -1028,6 +1153,7 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST  #define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID             (0x09)  #define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE             (0x0A)  #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK    (0x0B) +#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)  /* FWDownload TransactionContext Element */  typedef struct _MPI2_FW_DOWNLOAD_TCSGE @@ -1253,16 +1379,18 @@ typedef struct _MPI2_EXT_IMAGE_HEADER  #define MPI2_EXT_IMAGE_HEADER_SIZE              (0x40)  /* defines for the ImageType field */ -#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED         (0x00) -#define MPI2_EXT_IMAGE_TYPE_FW                  (0x01) -#define MPI2_EXT_IMAGE_TYPE_NVDATA              (0x03) -#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER          (0x04) -#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION      (0x05) -#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT        (0x06) -#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES   (0x07) -#define MPI2_EXT_IMAGE_TYPE_MEGARAID            (0x08) - -#define MPI2_EXT_IMAGE_TYPE_MAX                 (MPI2_EXT_IMAGE_TYPE_MEGARAID) +#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED				(0x00) +#define MPI2_EXT_IMAGE_TYPE_FW						(0x01) +#define MPI2_EXT_IMAGE_TYPE_NVDATA					(0x03) +#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER				(0x04) +#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION			(0x05) +#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT			(0x06) +#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES		(0x07) +#define MPI2_EXT_IMAGE_TYPE_MEGARAID				(0x08) +#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC    (0x80) +#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC    (0xFF) +#define MPI2_EXT_IMAGE_TYPE_MAX                   \ +	(MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC)	/* deprecated */ @@ -1455,7 +1583,7 @@ typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST {  /* 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_PCIE_LINK               (0x03) /* obsolete */  #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) @@ -1484,14 +1612,14 @@ typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST {  /* 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) +#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS            (0x00) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS            (0x01) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS            (0x02) /* obsolete */  /* Parameter2 indicates desired PCIe link width using these defines */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1                 (0x01) -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2                 (0x02) -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4                 (0x04) -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8                 (0x08) +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1                 (0x01) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2                 (0x02) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4                 (0x04) /* obsolete */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8                 (0x08) /* obsolete */  /* Parameter3 and Parameter4 are reserved */  /* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h index 5160c33d2a0..0d202a2c6db 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-2013 LSI Corporation.   *   *   *           Name:  mpi2_raid.h   *          Title:  MPI Integrated RAID messages and structures   *  Creation Date:  April 26, 2007   * - *    mpi2_raid.h Version:  02.00.04 + *    mpi2_raid.h Version:  02.00.09   *   *  Version History   *  --------------- @@ -22,6 +22,13 @@   *                      can be sized by the build environment.   *  07-30-09  02.00.04  Added proper define for the Use Default Settings bit of   *                      VolumeCreationFlags and marked the old one as obsolete. + *  05-12-10  02.00.05  Added MPI2_RAID_VOL_FLAGS_OP_MDC define. + *  08-24-10  02.00.06  Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with + *                      related structures and defines. + *                      Added product-specific range to RAID Action values. + *  02-06-12  02.00.08  Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN. + *  07-26-12  02.00.09  Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR. + *                      Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.   *  --------------------------------------------------------------------------   */ @@ -175,7 +182,10 @@ typedef struct _MPI2_RAID_ACTION_REQUEST  #define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED  (0x20)  #define MPI2_RAID_ACTION_START_RAID_FUNCTION        (0x21)  #define MPI2_RAID_ACTION_STOP_RAID_FUNCTION         (0x22) - +#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK        (0x23) +#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN            (0x24) +#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC       (0x80) +#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC       (0xFF)  /* RAID Volume Creation Structure */ @@ -243,6 +253,23 @@ typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION    Mpi2RaidOnlineCapacityExpansion_t,    MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t; +/* RAID Compatibility Input Structure */ + +typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT { +	U16                     SourceDevHandle;               /* 0x00 */ +	U16                     CandidateDevHandle;             /* 0x02 */ +	U32                     Flags;                          /* 0x04 */ +	U32                     Reserved1;                      /* 0x08 */ +	U32                     Reserved2;                      /* 0x0C */ +} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, +MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, +Mpi2RaidCompatibilityInputStruct_t, +MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t; + +/* defines for RAID Compatibility Structure Flags field */ +#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG      (0x00000002) +#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG    (0x00000001) +  /* RAID Volume Indicator Structure */ @@ -251,25 +278,59 @@ typedef struct _MPI2_RAID_VOL_INDICATOR      U64                     TotalBlocks;                    /* 0x00 */      U64                     BlocksRemaining;                /* 0x08 */      U32                     Flags;                          /* 0x10 */ +	U32                     ElapsedSeconds;                 /* 0x14 */  } MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR,    Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t;  /* defines for RAID Volume Indicator Flags field */ +#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID   (0x80000000) +  #define MPI2_RAID_VOL_FLAGS_OP_MASK                 (0x0000000F)  #define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT      (0x00000000)  #define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)  #define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK    (0x00000002)  #define MPI2_RAID_VOL_FLAGS_OP_RESYNC               (0x00000003) - +#define MPI2_RAID_VOL_FLAGS_OP_MDC                  (0x00000004) + +/* RAID Compatibility Result Structure */ + +typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT { +	U8                      State;                          /* 0x00 */ +	U8                      Reserved1;                      /* 0x01 */ +	U16                     Reserved2;                      /* 0x02 */ +	U32                     GenericAttributes;              /* 0x04 */ +	U32                     OEMSpecificAttributes;          /* 0x08 */ +	U32                     Reserved3;                      /* 0x0C */ +	U32                     Reserved4;                      /* 0x10 */ +} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, +MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, +Mpi2RaidCompatibilityResultStruct_t, +MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t; + +/* defines for RAID Compatibility Result Structure State field */ +#define MPI2_RAID_COMPAT_STATE_COMPATIBLE           (0x00) +#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE       (0x01) + +/* defines for RAID Compatibility Result Structure GenericAttributes field */ +#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR            (0x00000010) + +#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK           (0x0000000C) +#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE    (0x00000008) +#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE      (0x00000004) + +#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK        (0x00000003) +#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL         (0x00000002) +#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL        (0x00000001)  /* RAID Action Reply ActionData union */  typedef union _MPI2_RAID_ACTION_REPLY_DATA  { -    U32                     Word[5]; -    MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; -    U16                     VolDevHandle; -    U8                      VolumeState; -    U8                      PhysDiskNum; +	U32                                     Word[6]; +	MPI2_RAID_VOL_INDICATOR                 RaidVolumeIndicator; +	U16                                     VolDevHandle; +	U8                                      VolumeState; +	U8                                      PhysDiskNum; +	MPI2_RAID_COMPATIBILITY_RESULT_STRUCT   RaidCompatibilityResult;  } MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA,    Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t; diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h index 2d8aeed5139..50b39ccd526 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-2013 LSI Corporation.   *   *   *           Name:  mpi2_sas.h   *          Title:  MPI Serial Attached SCSI structures and definitions   *  Creation Date:  February 9, 2007   * - *  mpi2.h Version:  02.00.03 + *  mpi2_sas.h Version:  02.00.05   *   *  Version History   *  --------------- @@ -20,6 +20,8 @@   *                      Request.   *  10-28-09  02.00.03  Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST   *                      to MPI2_SGE_IO_UNION since it supports chained SGLs. + *  05-12-10  02.00.04  Modified some comments. + *  08-11-10  02.00.05  Added NCQ operations to SAS IO Unit Control.   *  --------------------------------------------------------------------------   */ @@ -110,7 +112,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 */ @@ -162,7 +164,7 @@ typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST      U32                     Reserved4;          /* 0x14 */      U32                     DataLength;         /* 0x18 */      U8                      CommandFIS[20];     /* 0x1C */ -    MPI2_SGE_IO_UNION       SGL;                /* 0x20 */ +    MPI2_SGE_IO_UNION       SGL;                /* 0x30 */  } MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,    Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; @@ -174,7 +176,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 */ @@ -245,6 +247,8 @@ typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST  #define MPI2_SAS_OP_REMOVE_DEVICE               (0x0D)  #define MPI2_SAS_OP_LOOKUP_MAPPING              (0x0E)  #define MPI2_SAS_OP_SET_IOC_PARAMETER           (0x0F) +#define MPI2_SAS_OP_DEV_ENABLE_NCQ              (0x14) +#define MPI2_SAS_OP_DEV_DISABLE_NCQ             (0x15)  #define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN        (0x80)  /* values for the PrimFlags field */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 686b09b8121..11b2ac4e7c6 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -1,12 +1,12 @@  /* - *  Copyright (c) 2000-2010 LSI Corporation. + *  Copyright (c) 2000-2013 LSI Corporation.   *   *   *           Name:  mpi2_tool.h   *          Title:  MPI diagnostic tool structures and definitions   *  Creation Date:  March 26, 2007   * - *    mpi2_tool.h Version:  02.00.04 + *    mpi2_tool.h Version:  02.00.10   *   *  Version History   *  --------------- @@ -22,6 +22,13 @@   *                      and reply messages.   *                      Added MPI2_DIAG_BUF_TYPE_EXTENDED.   *                      Incremented MPI2_DIAG_BUF_TYPE_COUNT. + *  05-12-10  02.00.05  Added Diagnostic Data Upload tool. + *  08-11-10  02.00.06  Added defines that were missing for Diagnostic Buffer + *                      Post Request. + *  05-25-11  02.00.07  Added Flags field and related defines to + *                      MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. + *  07-26-12  02.00.10  Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that + *			it uses MPI Chain SGE as well as MPI Simple SGE.   *  --------------------------------------------------------------------------   */ @@ -37,6 +44,7 @@  /* 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) @@ -102,8 +110,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 */ @@ -120,6 +127,44 @@ 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  ****************************************************************************/ @@ -140,7 +185,7 @@ typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST {      U8                      DevIndex;                   /* 0x14 */      U8                      Action;                     /* 0x15 */      U8                      SGLFlags;                   /* 0x16 */ -    U8                      Reserved7;                  /* 0x17 */ +	 U8                      Flags;                      /* 0x17 */      U16                     TxDataLength;               /* 0x18 */      U16                     RxDataLength;               /* 0x1A */      U32                     Reserved8;                  /* 0x1C */ @@ -162,8 +207,11 @@ typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST {  #define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS          (0x11)  #define MPI2_TOOL_ISTWI_ACTION_RESET                (0x12) -/* values for SGLFlags field are in the SGL section of mpi2.h */ +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ +/* values for the Flags field */ +#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE   (0x80) +#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK         (0x07)  /* Toolbox ISTWI Read Write Tool reply message */  typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { @@ -224,7 +272,7 @@ typedef struct _MPI2_TOOLBOX_BEACON_REQUEST  #define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH    (0x5C) -/* Toolbox Diagnostic CLI Tool request message */ +/* MPI v2.0 Toolbox Diagnostic CLI Tool request message */  typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {      U8                      Tool;                       /* 0x00 */      U8                      Reserved1;                  /* 0x01 */ @@ -242,13 +290,13 @@ typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {      U32                     DataLength;                 /* 0x10 */      U8                      DiagnosticCliCommand  		[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];     /* 0x14 */ -    MPI2_SGE_SIMPLE_UNION   SGL;                        /* 0x70 */ +	MPI2_MPI_SGE_IO_UNION   SGL;                        /* 0x70 */  } MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,    MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,    Mpi2ToolboxDiagnosticCliRequest_t,    MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; -/* values for SGLFlags field are in the SGL section of mpi2.h */ +/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */  /* Toolbox Diagnostic CLI Tool reply message */ @@ -315,6 +363,10 @@ typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST  /* count of the number of buffer types */  #define MPI2_DIAG_BUF_TYPE_COUNT                    (0x03) +/* values for the Flags field */ +#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL          (0x00000002) +#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE        (0x00000001) +  /****************************************************************************  *  Diagnostic Buffer Post reply diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h index cfde017bf16..0b128b68a5e 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_type.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_type.h @@ -1,5 +1,5 @@  /* - *  Copyright (c) 2000-2007 LSI Corporation. + *  Copyright (c) 2000-2013 LSI Corporation.   *   *   *           Name:  mpi2_type.h diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 12faf64f91b..8b88118e20e 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-2010  LSI Corporation + * Copyright (C) 2007-2013  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -42,7 +42,6 @@   * USA.   */ -#include <linux/version.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/errno.h> @@ -58,6 +57,7 @@  #include <linux/sort.h>  #include <linux/io.h>  #include <linux/time.h> +#include <linux/kthread.h>  #include <linux/aer.h>  #include "mpt2sas_base.h" @@ -65,8 +65,9 @@  static MPT_CALLBACK	mpt_callbacks[MPT_MAX_CALLBACKS];  #define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ -#define MPT2SAS_MAX_REQUEST_QUEUE 600 /* maximum controller queue depth */ +#define MAX_HBA_QUEUE_DEPTH	30000 +#define MAX_CHAIN_DEPTH		100000  static int max_queue_depth = -1;  module_param(max_queue_depth, int, 0);  MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); @@ -79,21 +80,9 @@ static int msix_disable = -1;  module_param(msix_disable, int, 0);  MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); -/* 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; +static int mpt2sas_fwfault_debug;  MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " -    "and halt firmware - (default=0)"); +	"and halt firmware - (default=0)");  static int disable_discovery = -1;  module_param(disable_discovery, int, 0); @@ -117,10 +106,34 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)  		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);  /** + *  mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc + * @arg: input argument, used to derive ioc + * + * Return 0 if controller is removed from pci subsystem. + * Return -1 for other case. + */ +static int mpt2sas_remove_dead_ioc_func(void *arg) +{ +		struct MPT2SAS_ADAPTER *ioc = (struct MPT2SAS_ADAPTER *)arg; +		struct pci_dev *pdev; + +		if ((ioc == NULL)) +			return -1; + +		pdev = ioc->pdev; +		if ((pdev == NULL)) +			return -1; +		pci_stop_and_remove_bus_device_locked(pdev); +		return 0; +} + + +/**   * _base_fault_reset_work - workq handling ioc fault conditions   * @work: input argument, used to derive ioc   * Context: sleep. @@ -135,13 +148,63 @@ _base_fault_reset_work(struct work_struct *work)  	unsigned long	 flags;  	u32 doorbell;  	int rc; +	struct task_struct *p;  	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); -	if (ioc->shost_recovery) +	if (ioc->shost_recovery || ioc->pci_error_recovery)  		goto rearm_timer;  	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);  	doorbell = mpt2sas_base_get_iocstate(ioc, 0); +	if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) { +		printk(MPT2SAS_INFO_FMT "%s : SAS host is non-operational !!!!\n", +			ioc->name, __func__); + +		/* It may be possible that EEH recovery can resolve some of +		 * pci bus failure issues rather removing the dead ioc function +		 * by considering controller is in a non-operational state. So +		 * here priority is given to the EEH recovery. If it doesn't +		 * not resolve this issue, mpt2sas driver will consider this +		 * controller to non-operational state and remove the dead ioc +		 * function. +		 */ +		if (ioc->non_operational_loop++ < 5) { +			spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, +							 flags); +			goto rearm_timer; +		} + +		/* +		 * Call _scsih_flush_pending_cmds callback so that we flush all +		 * pending commands back to OS. This call is required to aovid +		 * deadlock at block layer. Dead IOC will fail to do diag reset, +		 * and this call is safe since dead ioc will never return any +		 * command back from HW. +		 */ +		ioc->schedule_dead_ioc_flush_running_cmds(ioc); +		/* +		 * Set remove_host flag early since kernel thread will +		 * take some time to execute. +		 */ +		ioc->remove_host = 1; +		/*Remove the Dead Host */ +		p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc, +		    "mpt2sas_dead_ioc_%d", ioc->id); +		if (IS_ERR(p)) { +			printk(MPT2SAS_ERR_FMT +			"%s: Running mpt2sas_dead_ioc thread failed !!!!\n", +			ioc->name, __func__); +		} else { +		    printk(MPT2SAS_ERR_FMT +			"%s: Running mpt2sas_dead_ioc thread success !!!!\n", +			ioc->name, __func__); +		} + +		return; /* don't rearm timer */ +	} + +	ioc->non_operational_loop = 0; +  	if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {  		rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,  		    FORCE_BIG_HAMMER); @@ -515,14 +578,12 @@ _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;  	case MPI2_EVENT_IR_OPERATION_STATUS: -		desc = "IR Operation Status"; +		if (!ioc->hide_ir_msg) +			desc = "IR Operation Status";  		break;  	case MPI2_EVENT_SAS_DISCOVERY:  	{ @@ -553,16 +614,20 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,  		desc = "SAS Enclosure Device Status Change";  		break;  	case MPI2_EVENT_IR_VOLUME: -		desc = "IR Volume"; +		if (!ioc->hide_ir_msg) +			desc = "IR Volume";  		break;  	case MPI2_EVENT_IR_PHYSICAL_DISK: -		desc = "IR Physical Disk"; +		if (!ioc->hide_ir_msg) +			desc = "IR Physical Disk";  		break;  	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: -		desc = "IR Configuration Change List"; +		if (!ioc->hide_ir_msg) +			desc = "IR Configuration Change List";  		break;  	case MPI2_EVENT_LOG_ENTRY_ADDED: -		desc = "Log Entry Added"; +		if (!ioc->hide_ir_msg) +			desc = "Log Entry Added";  		break;  	} @@ -604,7 +669,7 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)  		return;  	/* eat the loginfos associated with task aborts */ -	if (ioc->ignore_loginfos && (log_info == 30050000 || log_info == +	if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info ==  	    0x31140000 || log_info == 0x31130000))  		return; @@ -616,7 +681,10 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)  		originator_str = "PL";  		break;  	case 2: -		originator_str = "IR"; +		if (!ioc->hide_ir_msg) +			originator_str = "IR"; +		else +			originator_str = "WarpDrive";  		break;  	} @@ -643,6 +711,11 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,  	u16 ioc_status;  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); +	if (unlikely(!mpi_reply)) { +		printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", +			ioc->name, __FILE__, __LINE__, __func__); +		return; +	}  	ioc_status = le16_to_cpu(mpi_reply->IOCStatus);  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	if ((ioc_status & MPI2_IOCSTATUS_MASK) && @@ -684,6 +757,7 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,  		memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);  	}  	ioc->base_cmds.status &= ~MPT2_CMD_PENDING; +  	complete(&ioc->base_cmds.done);  	return 1;  } @@ -694,10 +768,9 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,   * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * - * Return 1 meaning mf should be freed from _base_interrupt - *        0 means the mf is freed from this function. + * Returns void.   */ -static u8 +static void  _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)  {  	Mpi2EventNotificationReply_t *mpi_reply; @@ -706,9 +779,9 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);  	if (!mpi_reply) -		return 1; +		return;  	if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) -		return 1; +		return;  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	_base_display_event_data(ioc, mpi_reply);  #endif @@ -738,7 +811,7 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)  	/* ctl callback handler */  	mpt2sas_ctl_event_callback(ioc, msix_index, reply); -	return 1; +	return;  }  /** @@ -752,20 +825,19 @@ static u8  _base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid)  {  	int i; -	u8 cb_idx = 0xFF; +	u8 cb_idx; -	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 { -			i = smid - ioc->internal_smid; -			cb_idx = ioc->internal_lookup[i].cb_idx; -		} -	} else { +	if (smid < ioc->hi_priority_smid) {  		i = smid - 1;  		cb_idx = ioc->scsi_lookup[i].cb_idx; -	} +	} else if (smid < ioc->internal_smid) { +		i = smid - ioc->hi_priority_smid; +		cb_idx = ioc->hpr_lookup[i].cb_idx; +	} else if (smid <= ioc->hba_queue_depth) { +		i = smid - ioc->internal_smid; +		cb_idx = ioc->internal_lookup[i].cb_idx; +	} else +		cb_idx = 0xFF;  	return cb_idx;  } @@ -827,55 +899,65 @@ union reply_descriptor {  static irqreturn_t  _base_interrupt(int irq, void *bus_id)  { +	struct adapter_reply_queue *reply_q = bus_id;  	union reply_descriptor rd;  	u32 completed_cmds;  	u8 request_desript_type;  	u16 smid;  	u8 cb_idx;  	u32 reply; -	u8 msix_index; -	struct MPT2SAS_ADAPTER *ioc = bus_id; +	u8 msix_index = reply_q->msix_index; +	struct MPT2SAS_ADAPTER *ioc = reply_q->ioc;  	Mpi2ReplyDescriptorsUnion_t *rpf;  	u8 rc;  	if (ioc->mask_interrupts)  		return IRQ_NONE; -	rpf = &ioc->reply_post_free[ioc->reply_post_host_index]; +	if (!atomic_add_unless(&reply_q->busy, 1, 1)) +		return IRQ_NONE; + +	rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index];  	request_desript_type = rpf->Default.ReplyFlags  	     & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; -	if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) +	if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { +		atomic_dec(&reply_q->busy);  		return IRQ_NONE; +	}  	completed_cmds = 0; +	cb_idx = 0xFF;  	do { -		rd.word = rpf->Words; +		rd.word = le64_to_cpu(rpf->Words);  		if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)  			goto out;  		reply = 0; -		cb_idx = 0xFF;  		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  				(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;  		else if (request_desript_type ==  		    MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)  			goto next; -		if (smid) +		if (smid) {  			cb_idx = _base_get_cb_idx(ioc, smid); -		if (smid && cb_idx != 0xFF) { -			rc = mpt_callbacks[cb_idx](ioc, smid, msix_index, -			    reply); +		if ((likely(cb_idx < MPT_MAX_CALLBACKS)) +			    && (likely(mpt_callbacks[cb_idx] != NULL))) { +				rc = mpt_callbacks[cb_idx](ioc, smid, +				    msix_index, reply);  			if (reply) -				_base_display_reply_info(ioc, smid, msix_index, -				    reply); +				_base_display_reply_info(ioc, smid, +				    msix_index, reply);  			if (rc)  				mpt2sas_base_free_smid(ioc, smid); +			}  		}  		if (!smid)  			_base_async_event(ioc, msix_index, reply); @@ -895,34 +977,88 @@ _base_interrupt(int irq, void *bus_id)   next: -		rpf->Words = ULLONG_MAX; -		ioc->reply_post_host_index = (ioc->reply_post_host_index == +		rpf->Words = cpu_to_le64(ULLONG_MAX); +		reply_q->reply_post_host_index = +		    (reply_q->reply_post_host_index ==  		    (ioc->reply_post_queue_depth - 1)) ? 0 : -		    ioc->reply_post_host_index + 1; +		    reply_q->reply_post_host_index + 1;  		request_desript_type = -		    ioc->reply_post_free[ioc->reply_post_host_index].Default. -		    ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; +		    reply_q->reply_post_free[reply_q->reply_post_host_index]. +		    Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;  		completed_cmds++;  		if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)  			goto out; -		if (!ioc->reply_post_host_index) -			rpf = ioc->reply_post_free; +		if (!reply_q->reply_post_host_index) +			rpf = reply_q->reply_post_free;  		else  			rpf++;  	} while (1);   out: -	if (!completed_cmds) +	if (!completed_cmds) { +		atomic_dec(&reply_q->busy);  		return IRQ_NONE; - +	}  	wmb(); -	writel(ioc->reply_post_host_index, &ioc->chip->ReplyPostHostIndex); +	if (ioc->is_warpdrive) { +		writel(reply_q->reply_post_host_index, +		ioc->reply_post_host_index[msix_index]); +		atomic_dec(&reply_q->busy); +		return IRQ_HANDLED; +	} +	writel(reply_q->reply_post_host_index | (msix_index << +	    MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex); +	atomic_dec(&reply_q->busy);  	return IRQ_HANDLED;  }  /** - * mpt2sas_base_release_callback_handler - clear interupt callback handler + * _base_is_controller_msix_enabled - is controller support muli-reply queues + * @ioc: per adapter object + * + */ +static inline int +_base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc) +{ +	return (ioc->facts.IOCCapabilities & +	    MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable; +} + +/** + * mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues + * @ioc: per adapter object + * Context: ISR conext + * + * Called when a Task Management request has completed. We want + * to flush the other reply queues so all the outstanding IO has been + * completed back to OS before we process the TM completetion. + * + * Return nothing. + */ +void +mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc) +{ +	struct adapter_reply_queue *reply_q; + +	/* If MSIX capability is turned off +	 * then multi-queues are not enabled +	 */ +	if (!_base_is_controller_msix_enabled(ioc)) +		return; + +	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { +		if (ioc->shost_recovery) +			return; +		/* TMs are on msix_index == 0 */ +		if (reply_q->msix_index == 0) +			continue; +		_base_interrupt(reply_q->vector, (void *)reply_q); +	} +} + +/** + * mpt2sas_base_release_callback_handler - clear interrupt callback handler   * @cb_idx: callback index   *   * Return nothing. @@ -1071,74 +1207,178 @@ _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)  }  /** - * _base_save_msix_table - backup msix vector table + * _base_check_enable_msix - checks MSIX capabable.   * @ioc: per adapter object   * - * This address an errata where diag reset clears out the table + * Check to see if card is capable of MSIX, and set number + * of available msix vectors   */ -static void -_base_save_msix_table(struct MPT2SAS_ADAPTER *ioc) +static int +_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)  { -	int i; +	int base; +	u16 message_control; -	if (!ioc->msix_enable || ioc->msix_table_backup == NULL) -		return; -	for (i = 0; i < ioc->msix_vector_count; i++) -		ioc->msix_table_backup[i] = ioc->msix_table[i]; +	/* Check whether controller SAS2008 B0 controller, +	   if it is SAS2008 B0 controller use IO-APIC instead of MSIX */ +	if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && +	    ioc->pdev->revision == 0x01) { +		return -EINVAL; +	} + +	base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); +	if (!base) { +		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " +		    "supported\n", ioc->name)); +		return -EINVAL; +	} + +	/* get msix vector count */ +	/* NUMA_IO not supported for older controllers */ +	if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || +	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || +	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || +	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || +	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || +	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || +	    ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) +		ioc->msix_vector_count = 1; +	else { +		pci_read_config_word(ioc->pdev, base + 2, &message_control); +		ioc->msix_vector_count = (message_control & 0x3FF) + 1; +	} +	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " +	    "vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); + +	return 0;  }  /** - * _base_restore_msix_table - this restores the msix vector table + * _base_free_irq - free irq   * @ioc: per adapter object   * + * Freeing respective reply_queue from the list.   */  static void -_base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc) +_base_free_irq(struct MPT2SAS_ADAPTER *ioc)  { -	int i; +	struct adapter_reply_queue *reply_q, *next; -	if (!ioc->msix_enable || ioc->msix_table_backup == NULL) +	if (list_empty(&ioc->reply_queue_list))  		return; -	for (i = 0; i < ioc->msix_vector_count; i++) -		ioc->msix_table[i] = ioc->msix_table_backup[i]; +	list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { +		list_del(&reply_q->list); +		synchronize_irq(reply_q->vector); +		free_irq(reply_q->vector, reply_q); +		kfree(reply_q); +	}  }  /** - * _base_check_enable_msix - checks MSIX capabable. + * _base_request_irq - request irq   * @ioc: per adapter object + * @index: msix index into vector table + * @vector: irq vector   * - * Check to see if card is capable of MSIX, and set number - * of avaliable msix vectors + * Inserting respective reply_queue into the list.   */  static int -_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) +_base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector)  { -	int base; -	u16 message_control; -	u32 msix_table_offset; +	struct adapter_reply_queue *reply_q; +	int r; -	base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); -	if (!base) { -		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " -		    "supported\n", ioc->name)); -		return -EINVAL; +	reply_q =  kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); +	if (!reply_q) { +		printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n", +		    ioc->name, (int)sizeof(struct adapter_reply_queue)); +		return -ENOMEM; +	} +	reply_q->ioc = ioc; +	reply_q->msix_index = index; +	reply_q->vector = vector; +	atomic_set(&reply_q->busy, 0); +	if (ioc->msix_enable) +		snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", +		    MPT2SAS_DRIVER_NAME, ioc->id, index); +	else +		snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", +		    MPT2SAS_DRIVER_NAME, ioc->id); +	r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, +	    reply_q); +	if (r) { +		printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n", +		    reply_q->name, vector); +		kfree(reply_q); +		return -EBUSY;  	} -	/* get msix vector count */ -	pci_read_config_word(ioc->pdev, base + 2, &message_control); -	ioc->msix_vector_count = (message_control & 0x3FF) + 1; +	INIT_LIST_HEAD(&reply_q->list); +	list_add_tail(&reply_q->list, &ioc->reply_queue_list); +	return 0; +} + +/** + * _base_assign_reply_queues - assigning msix index for each cpu + * @ioc: per adapter object + * + * The enduser would need to set the affinity via /proc/irq/#/smp_affinity + * + * It would nice if we could call irq_set_affinity, however it is not + * an exported symbol + */ +static void +_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc) +{ +	struct adapter_reply_queue *reply_q; +	int cpu_id; +	int cpu_grouping, loop, grouping, grouping_mod; -	/* get msix table  */ -	pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset); -	msix_table_offset &= 0xFFFFFFF8; -	ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset); +	if (!_base_is_controller_msix_enabled(ioc)) +		return; -	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " -	    "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name, -	    ioc->msix_vector_count, msix_table_offset, ioc->msix_table)); -	return 0; +	memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); +	/* when there are more cpus than available msix vectors, +	 * then group cpus togeather on same irq +	 */ +	if (ioc->cpu_count > ioc->msix_vector_count) { +		grouping = ioc->cpu_count / ioc->msix_vector_count; +		grouping_mod = ioc->cpu_count % ioc->msix_vector_count; +		if (grouping < 2 || (grouping == 2 && !grouping_mod)) +			cpu_grouping = 2; +		else if (grouping < 4 || (grouping == 4 && !grouping_mod)) +			cpu_grouping = 4; +		else if (grouping < 8 || (grouping == 8 && !grouping_mod)) +			cpu_grouping = 8; +		else +			cpu_grouping = 16; +	} else +		cpu_grouping = 0; + +	loop = 0; +	reply_q = list_entry(ioc->reply_queue_list.next, +	     struct adapter_reply_queue, list); +	for_each_online_cpu(cpu_id) { +		if (!cpu_grouping) { +			ioc->cpu_msix_table[cpu_id] = reply_q->msix_index; +			reply_q = list_entry(reply_q->list.next, +			    struct adapter_reply_queue, list); +		} else { +			if (loop < cpu_grouping) { +				ioc->cpu_msix_table[cpu_id] = +					reply_q->msix_index; +				loop++; +			} else { +				reply_q = list_entry(reply_q->list.next, +				    struct adapter_reply_queue, list); +				ioc->cpu_msix_table[cpu_id] = +					reply_q->msix_index; +				loop = 1; +			} +		} +	}  }  /** @@ -1151,8 +1391,6 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc)  {  	if (ioc->msix_enable) {  		pci_disable_msix(ioc->pdev); -		kfree(ioc->msix_table_backup); -		ioc->msix_table_backup = NULL;  		ioc->msix_enable = 0;  	}  } @@ -1165,8 +1403,9 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc)  static int  _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)  { -	struct msix_entry entries; +	struct msix_entry *entries, *a;  	int r; +	int i;  	u8 try_msix = 0;  	if (msix_disable == -1 || msix_disable == 0) @@ -1178,51 +1417,48 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)  	if (_base_check_enable_msix(ioc) != 0)  		goto try_ioapic; -	ioc->msix_table_backup = kcalloc(ioc->msix_vector_count, -	    sizeof(u32), GFP_KERNEL); -	if (!ioc->msix_table_backup) { -		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " -		    "msix_table_backup failed!!!\n", ioc->name)); +	ioc->reply_queue_count = min_t(int, ioc->cpu_count, +	    ioc->msix_vector_count); + +	entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry), +	    GFP_KERNEL); +	if (!entries) { +		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc " +		    "failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__, +		    __LINE__, __func__));  		goto try_ioapic;  	} -	memset(&entries, 0, sizeof(struct msix_entry)); -	r = pci_enable_msix(ioc->pdev, &entries, 1); +	for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) +		a->entry = i; + +	r = pci_enable_msix(ioc->pdev, entries, ioc->reply_queue_count);  	if (r) {  		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix "  		    "failed (r=%d) !!!\n", ioc->name, r)); +		kfree(entries);  		goto try_ioapic;  	} -	r = request_irq(entries.vector, _base_interrupt, IRQF_SHARED, -	    ioc->name, ioc); -	if (r) { -		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "unable to allocate " -		    "interrupt %d !!!\n", ioc->name, entries.vector)); -		pci_disable_msix(ioc->pdev); -		goto try_ioapic; +	ioc->msix_enable = 1; +	for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) { +		r = _base_request_irq(ioc, i, a->vector); +		if (r) { +			_base_free_irq(ioc); +			_base_disable_msix(ioc); +			kfree(entries); +			goto try_ioapic; +		}  	} -	ioc->pci_irq = entries.vector; -	ioc->msix_enable = 1; +	kfree(entries);  	return 0;  /* failback to io_apic interrupt routing */   try_ioapic: -	r = request_irq(ioc->pdev->irq, _base_interrupt, IRQF_SHARED, -	    ioc->name, ioc); -	if (r) { -		printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n", -		    ioc->name, ioc->pdev->irq); -		r = -EBUSY; -		goto out_fail; -	} +	r = _base_request_irq(ioc, 0, ioc->pdev->irq); -	ioc->pci_irq = ioc->pdev->irq; -	return 0; - - out_fail:  	return r;  } @@ -1241,6 +1477,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	int i, r = 0;  	u64 pio_chip = 0;  	u64 chip_phys = 0; +	struct adapter_reply_queue *reply_q;  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",  	    ioc->name, __func__)); @@ -1249,6 +1486,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	if (pci_enable_device_mem(pdev)) {  		printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "  		    "failed\n", ioc->name); +		ioc->bars = 0;  		return -ENODEV;  	} @@ -1257,6 +1495,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	    MPT2SAS_DRIVER_NAME)) {  		printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "  		    "failed\n", ioc->name); +		ioc->bars = 0;  		r = -ENODEV;  		goto out_fail;  	} @@ -1303,9 +1542,11 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	if (r)  		goto out_fail; -	printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", -	    ioc->name,  ((ioc->msix_enable) ? "PCI-MSI-X enabled" : -	    "IO-APIC enabled"), ioc->pci_irq); +	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) +		printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", +		    reply_q->name,  ((ioc->msix_enable) ? "PCI-MSI-X enabled" : +		    "IO-APIC enabled"), reply_q->vector); +  	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", @@ -1320,7 +1561,6 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  	if (ioc->chip_phys)  		iounmap(ioc->chip);  	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); @@ -1426,7 +1666,7 @@ mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,      struct scsi_cmnd *scmd)  {  	unsigned long flags; -	struct request_tracker *request; +	struct scsiio_tracker *request;  	u16 smid;  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); @@ -1438,7 +1678,7 @@ mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,  	}  	request = list_entry(ioc->free_list.next, -	    struct request_tracker, tracker_list); +	    struct scsiio_tracker, tracker_list);  	request->scmd = scmd;  	request->cb_idx = cb_idx;  	smid = request->smid; @@ -1489,42 +1729,51 @@ 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); -	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); +	if (smid < ioc->hi_priority_smid) { +		/* scsiio queue */ +		i = smid - 1; +		if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { +			list_for_each_entry_safe(chain_req, next, +			    &ioc->scsi_lookup[i].chain_list, tracker_list) { +				list_del_init(&chain_req->tracker_list); +				list_add(&chain_req->tracker_list, +				    &ioc->free_chain_list); +			}  		} +		ioc->scsi_lookup[i].cb_idx = 0xFF; +		ioc->scsi_lookup[i].scmd = NULL; +		ioc->scsi_lookup[i].direct_io = 0; +		list_add(&ioc->scsi_lookup[i].tracker_list, +		    &ioc->free_list);  		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + +		/* +		 * See _wait_for_commands_to_complete() call with regards +		 * to this code. +		 */ +		if (ioc->shost_recovery && ioc->pending_io_count) { +			if (ioc->pending_io_count == 1) +				wake_up(&ioc->reset_wq); +			ioc->pending_io_count--; +		}  		return; +	} else if (smid < ioc->internal_smid) { +		/* hi-priority */ +		i = smid - ioc->hi_priority_smid; +		ioc->hpr_lookup[i].cb_idx = 0xFF; +		list_add(&ioc->hpr_lookup[i].tracker_list, +		    &ioc->hpr_free_list); +	} else if (smid <= ioc->hba_queue_depth) { +		/* internal queue */ +		i = smid - ioc->internal_smid; +		ioc->internal_lookup[i].cb_idx = 0xFF; +		list_add(&ioc->internal_lookup[i].tracker_list, +		    &ioc->internal_free_list);  	} - -	/* scsiio queue */ -	i = smid - 1; -	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); - -	/* -	 * See _wait_for_commands_to_complete() call with regards to this code. -	 */ -	if (ioc->shost_recovery && ioc->pending_io_count) { -		if (ioc->pending_io_count == 1) -			wake_up(&ioc->reset_wq); -		ioc->pending_io_count--; -	}  }  /** @@ -1558,6 +1807,12 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr,  }  #endif +static inline u8 +_base_get_msix_index(struct MPT2SAS_ADAPTER *ioc) +{ +	return ioc->cpu_msix_table[raw_smp_processor_id()]; +} +  /**   * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware   * @ioc: per adapter object @@ -1574,7 +1829,7 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle)  	descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; -	descriptor.SCSIIO.MSIxIndex = 0; /* TODO */ +	descriptor.SCSIIO.MSIxIndex =  _base_get_msix_index(ioc);  	descriptor.SCSIIO.SMID = cpu_to_le16(smid);  	descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);  	descriptor.SCSIIO.LMID = 0; @@ -1584,7 +1839,7 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle)  /** - * mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware + * mpt2sas_base_put_smid_hi_priority - send Task Management request to firmware   * @ioc: per adapter object   * @smid: system request message index   * @@ -1598,7 +1853,7 @@ mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid)  	descriptor.HighPriority.RequestFlags =  	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; -	descriptor.HighPriority.MSIxIndex = 0; /* TODO */ +	descriptor.HighPriority.MSIxIndex =  0;  	descriptor.HighPriority.SMID = cpu_to_le16(smid);  	descriptor.HighPriority.LMID = 0;  	descriptor.HighPriority.Reserved1 = 0; @@ -1620,7 +1875,7 @@ mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid)  	u64 *request = (u64 *)&descriptor;  	descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; -	descriptor.Default.MSIxIndex = 0; /* TODO */ +	descriptor.Default.MSIxIndex =  _base_get_msix_index(ioc);  	descriptor.Default.SMID = cpu_to_le16(smid);  	descriptor.Default.LMID = 0;  	descriptor.Default.DescriptorTypeDependent = 0; @@ -1645,7 +1900,7 @@ mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,  	descriptor.SCSITarget.RequestFlags =  	    MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; -	descriptor.SCSITarget.MSIxIndex = 0; /* TODO */ +	descriptor.SCSITarget.MSIxIndex =  _base_get_msix_index(ioc);  	descriptor.SCSITarget.SMID = cpu_to_le16(smid);  	descriptor.SCSITarget.LMID = 0;  	descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index); @@ -1712,6 +1967,122 @@ _base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc)  }  /** + * _base_display_intel_branding - Display branding string + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) +{ +	if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) +		return; + +	switch (ioc->pdev->device) { +	case MPI2_MFGPAGE_DEVID_SAS2008: +		switch (ioc->pdev->subsystem_device) { +		case MPT2SAS_INTEL_RMS2LL080_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RMS2LL080_BRANDING); +			break; +		case MPT2SAS_INTEL_RMS2LL040_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RMS2LL040_BRANDING); +			break; +		case MPT2SAS_INTEL_SSD910_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_SSD910_BRANDING); +			break; +		default: +			break; +		} +	case MPI2_MFGPAGE_DEVID_SAS2308_2: +		switch (ioc->pdev->subsystem_device) { +		case MPT2SAS_INTEL_RS25GB008_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RS25GB008_BRANDING); +			break; +		case MPT2SAS_INTEL_RMS25JB080_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RMS25JB080_BRANDING); +			break; +		case MPT2SAS_INTEL_RMS25JB040_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RMS25JB040_BRANDING); +			break; +		case MPT2SAS_INTEL_RMS25KB080_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RMS25KB080_BRANDING); +			break; +		case MPT2SAS_INTEL_RMS25KB040_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RMS25KB040_BRANDING); +			break; +		case MPT2SAS_INTEL_RMS25LB040_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RMS25LB040_BRANDING); +			break; +		case MPT2SAS_INTEL_RMS25LB080_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_INTEL_RMS25LB080_BRANDING); +			break; +		default: +			break; +		} +	default: +		break; +	} +} + +/** + * _base_display_hp_branding - Display branding string + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_base_display_hp_branding(struct MPT2SAS_ADAPTER *ioc) +{ +	if (ioc->pdev->subsystem_vendor != MPT2SAS_HP_3PAR_SSVID) +		return; + +	switch (ioc->pdev->device) { +	case MPI2_MFGPAGE_DEVID_SAS2004: +		switch (ioc->pdev->subsystem_device) { +		case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); +			break; +		default: +			break; +		} +	case MPI2_MFGPAGE_DEVID_SAS2308_2: +		switch (ioc->pdev->subsystem_device) { +		case MPT2SAS_HP_2_4_INTERNAL_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_HP_2_4_INTERNAL_BRANDING); +			break; +		case MPT2SAS_HP_2_4_EXTERNAL_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_HP_2_4_EXTERNAL_BRANDING); +			break; +		case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); +			break; +		case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: +			printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, +			    MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); +			break; +		default: +			break; +		} +	default: +		break; +	} +} + +/**   * _base_display_ioc_capabilities - Disply IOC's capabilities.   * @ioc: per adapter object   * @@ -1722,10 +2093,10 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)  {  	int i = 0;  	char desc[16]; -	u8 revision;  	u32 iounit_pg1_flags; +	u32 bios_version; -	pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); +	bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);  	strncpy(desc, ioc->manu_pg0.ChipName, 16);  	printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "  	   "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n", @@ -1734,13 +2105,15 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)  	   (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,  	   (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,  	   ioc->facts.FWVersion.Word & 0x000000FF, -	   revision, -	   (ioc->bios_pg3.BiosVersion & 0xFF000000) >> 24, -	   (ioc->bios_pg3.BiosVersion & 0x00FF0000) >> 16, -	   (ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8, -	    ioc->bios_pg3.BiosVersion & 0x000000FF); +	   ioc->pdev->revision, +	   (bios_version & 0xFF000000) >> 24, +	   (bios_version & 0x00FF0000) >> 16, +	   (bios_version & 0x0000FF00) >> 8, +	    bios_version & 0x000000FF);  	_base_display_dell_branding(ioc); +	_base_display_intel_branding(ioc); +	_base_display_hp_branding(ioc);  	printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); @@ -1758,10 +2131,12 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)  	printk("), ");  	printk("Capabilities=("); -	if (ioc->facts.IOCCapabilities & -	    MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { -		printk("Raid"); -		i++; +	if (!ioc->hide_ir_msg) { +		if (ioc->facts.IOCCapabilities & +		    MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { +			printk("Raid"); +			i++; +		}  	}  	if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { @@ -1819,6 +2194,97 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)  }  /** + * mpt2sas_base_update_missing_delay - change the missing delay timers + * @ioc: per adapter object + * @device_missing_delay: amount of time till device is reported missing + * @io_missing_delay: interval IO is returned when there is a missing device + * + * Return nothing. + * + * Passed on the command line, this function will modify the device missing + * delay, as well as the io missing delay. This should be called at driver + * load time. + */ +void +mpt2sas_base_update_missing_delay(struct 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   * @@ -1855,6 +2321,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)  		    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); +  }  /** @@ -1868,6 +2335,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)  static void  _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)  { +	int i; +  	dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); @@ -1932,6 +2401,18 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)  	}  	kfree(ioc->hpr_lookup);  	kfree(ioc->internal_lookup); +	if (ioc->chain_lookup) { +		for (i = 0; i < ioc->chain_depth; i++) { +			if (ioc->chain_lookup[i].chain_buffer) +				pci_pool_free(ioc->chain_dma_pool, +				    ioc->chain_lookup[i].chain_buffer, +				    ioc->chain_lookup[i].chain_buffer_dma); +		} +		if (ioc->chain_dma_pool) +			pci_pool_destroy(ioc->chain_dma_pool); +		free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); +		ioc->chain_lookup = NULL; +	}  } @@ -1945,14 +2426,13 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)  static int  _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  { -	Mpi2IOCFactsReply_t *facts; -	u32 queue_size, queue_diff; +	struct mpt2sas_facts *facts;  	u16 max_sge_elements; -	u16 num_of_reply_frames;  	u16 chains_needed_per_io; -	u32 sz, total_sz; +	u32 sz, total_sz, reply_post_free_sz;  	u32 retry_sz;  	u16 max_request_credit; +	int i;  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); @@ -1970,14 +2450,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) { -		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; -	} +	if (max_queue_depth != -1 && max_queue_depth != 0) { +		max_request_credit = min_t(u16, max_queue_depth + +			ioc->hi_priority_depth + ioc->internal_depth, +			facts->RequestCredit); +		if (max_request_credit > MAX_HBA_QUEUE_DEPTH) +			max_request_credit =  MAX_HBA_QUEUE_DEPTH; +	} else +		max_request_credit = min_t(u16, facts->RequestCredit, +		    MAX_HBA_QUEUE_DEPTH);  	ioc->hba_queue_depth = max_request_credit;  	ioc->hi_priority_depth = facts->HighPriorityCredit; @@ -2018,50 +2499,27 @@ _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->hba_queue_depth + 32; - -	/* number of replies frames can't be a multiple of 16 */ -	/* decrease number of reply frames by 1 */ -	if (!(num_of_reply_frames % 16)) -		num_of_reply_frames--; - -	/* calculate number of reply free queue entries -	 *  (must be multiple of 16) -	 */ - -	/* (we know reply_free_queue_depth is not a multiple of 16) */ -	queue_size = num_of_reply_frames; -	queue_size += 16 - (queue_size % 16); -	ioc->reply_free_queue_depth = queue_size; - -	/* reply descriptor post queue sizing */ -	/* this size should be the number of request frames + number of reply -	 * frames -	 */ - -	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); - -	/* check against IOC maximum reply post queue depth */ -	if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) { -		queue_diff = queue_size - -		    facts->MaxReplyDescriptorPostQueueDepth; - -		/* round queue_diff up to multiple of 16 */ -		if (queue_diff % 16) -			queue_diff += 16 - (queue_diff % 16); - -		/* adjust hba_queue_depth, reply_free_queue_depth, -		 * and queue_size -		 */ -		ioc->hba_queue_depth -= queue_diff; -		ioc->reply_free_queue_depth -= queue_diff; -		queue_size -= queue_diff; +	/* reply free queue sizing - taking into account for 64 FW events */ +	ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; + +	/* calculate reply descriptor post queue depth */ +	ioc->reply_post_queue_depth = ioc->hba_queue_depth + +					ioc->reply_free_queue_depth +  1; +	/* align the reply post queue on the next 16 count boundary */ +	if (ioc->reply_post_queue_depth % 16) +		ioc->reply_post_queue_depth += 16 - +			(ioc->reply_post_queue_depth % 16); + + +	if (ioc->reply_post_queue_depth > +	    facts->MaxReplyDescriptorPostQueueDepth) { +		ioc->reply_post_queue_depth = +			facts->MaxReplyDescriptorPostQueueDepth - +		    (facts->MaxReplyDescriptorPostQueueDepth % 16); +		ioc->hba_queue_depth = +			((ioc->reply_post_queue_depth - 64) / 2) - 1; +		ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;  	} -	ioc->reply_post_queue_depth = queue_size;  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "  	    "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " @@ -2075,7 +2533,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	/* set the scsi host can_queue depth  	 * with some internal commands that could be outstanding  	 */ -	ioc->shost->can_queue = ioc->scsiio_depth - (2); +	ioc->shost->can_queue = ioc->scsiio_depth;  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: "  	    "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); @@ -2083,7 +2541,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	 * "frame for smid=0  	 */  	ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; -	sz = ((ioc->scsiio_depth + 1 + ioc->chain_depth) * ioc->request_sz); +	sz = ((ioc->scsiio_depth + 1) * ioc->request_sz);  	/* hi-priority queue */  	sz += (ioc->hi_priority_depth * ioc->request_sz); @@ -2124,26 +2582,18 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *  	    ioc->request_sz); -	ioc->chain = ioc->internal + (ioc->internal_depth * -	    ioc->request_sz); -	ioc->chain_dma = ioc->internal_dma + (ioc->internal_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->hba_queue_depth, ioc->request_sz,  	    (ioc->hba_queue_depth * 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));  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",  	    ioc->name, (unsigned long long) ioc->request_dma));  	total_sz += sz; -	sz = ioc->scsiio_depth * sizeof(struct request_tracker); +	sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker);  	ioc->scsi_lookup_pages = get_order(sz); -	ioc->scsi_lookup = (struct request_tracker *)__get_free_pages( +	ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages(  	    GFP_KERNEL, ioc->scsi_lookup_pages);  	if (!ioc->scsi_lookup) {  		printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, " @@ -2155,6 +2605,40 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	    "depth(%d)\n", ioc->name, ioc->request,  	    ioc->scsiio_depth)); +	ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); +	sz = ioc->chain_depth * sizeof(struct chain_tracker); +	ioc->chain_pages = get_order(sz); + +	ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( +	    GFP_KERNEL, ioc->chain_pages); +	if (!ioc->chain_lookup) { +		printk(MPT2SAS_ERR_FMT "chain_lookup: get_free_pages failed, " +		    "sz(%d)\n", ioc->name, (int)sz); +		goto out; +	} +	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); @@ -2221,6 +2705,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)); @@ -2253,7 +2739,12 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	total_sz += sz;  	/* reply post queue, 16 byte align */ -	sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t); +	reply_post_free_sz = ioc->reply_post_queue_depth * +	    sizeof(Mpi2DefaultReplyDescriptor_t); +	if (_base_is_controller_msix_enabled(ioc)) +		sz = reply_post_free_sz * ioc->reply_queue_count; +	else +		sz = reply_post_free_sz;  	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",  	    ioc->pdev, sz, 16, 0);  	if (!ioc->reply_post_free_dma_pool) { @@ -2302,7 +2793,6 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	return 0;   out: -	_base_release_memory_pools(ioc);  	return -ENOMEM;  } @@ -2382,7 +2872,7 @@ _base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,  		int_status = readl(&ioc->chip->HostInterruptStatus);  		if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {  			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " -			    "successfull count(%d), timeout(%d)\n", ioc->name, +			    "successful count(%d), timeout(%d)\n", ioc->name,  			    __func__, count, timeout));  			return 0;  		} @@ -2423,7 +2913,7 @@ _base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,  		int_status = readl(&ioc->chip->HostInterruptStatus);  		if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {  			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " -			    "successfull count(%d), timeout(%d)\n", ioc->name, +			    "successful count(%d), timeout(%d)\n", ioc->name,  			    __func__, count, timeout));  			return 0;  		} else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { @@ -2471,7 +2961,7 @@ _base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,  		doorbell_reg = readl(&ioc->chip->Doorbell);  		if (!(doorbell_reg & MPI2_DOORBELL_USED)) {  			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " -			    "successfull count(%d), timeout(%d)\n", ioc->name, +			    "successful count(%d), timeout(%d)\n", ioc->name,  			    __func__, count, timeout));  			return 0;  		} @@ -2555,7 +3045,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,  	int i;  	u8 failed;  	u16 dummy; -	u32 *mfp; +	__le32 *mfp;  	/* make sure doorbell is not in use */  	if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { @@ -2643,7 +3133,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,  	writel(0, &ioc->chip->HostInterruptStatus);  	if (ioc->logging_level & MPT_DEBUG_INIT) { -		mfp = (u32 *)reply; +		mfp = (__le32 *)reply;  		printk(KERN_INFO "\toffset:data\n");  		for (i = 0; i < reply_bytes/4; i++)  			printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, @@ -2724,8 +3214,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);  	init_completion(&ioc->base_cmds.done); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,  	    msecs_to_jiffies(10000));  	if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || @@ -2826,8 +3316,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);  	init_completion(&ioc->base_cmds.done); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,  	    msecs_to_jiffies(10000));  	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { @@ -2869,7 +3359,8 @@ static int  _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)  {  	Mpi2PortFactsRequest_t mpi_request; -	Mpi2PortFactsReply_t mpi_reply, *pfacts; +	Mpi2PortFactsReply_t mpi_reply; +	struct mpt2sas_port_facts *pfacts;  	int mpi_reply_sz, mpi_request_sz, r;  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, @@ -2890,7 +3381,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)  	}  	pfacts = &ioc->pfacts[port]; -	memset(pfacts, 0, sizeof(Mpi2PortFactsReply_t)); +	memset(pfacts, 0, sizeof(struct mpt2sas_port_facts));  	pfacts->PortNumber = mpi_reply.PortNumber;  	pfacts->VP_ID = mpi_reply.VP_ID;  	pfacts->VF_ID = mpi_reply.VF_ID; @@ -2911,7 +3402,8 @@ static int  _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  {  	Mpi2IOCFactsRequest_t mpi_request; -	Mpi2IOCFactsReply_t mpi_reply, *facts; +	Mpi2IOCFactsReply_t mpi_reply; +	struct mpt2sas_facts *facts;  	int mpi_reply_sz, mpi_request_sz, r;  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, @@ -2931,7 +3423,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	}  	facts = &ioc->facts; -	memset(facts, 0, sizeof(Mpi2IOCFactsReply_t)); +	memset(facts, 0, sizeof(struct mpt2sas_facts));  	facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);  	facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);  	facts->VP_ID = mpi_reply.VP_ID; @@ -2940,6 +3432,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	facts->MaxChainDepth = mpi_reply.MaxChainDepth;  	facts->WhoInit = mpi_reply.WhoInit;  	facts->NumberOfPorts = mpi_reply.NumberOfPorts; +	facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;  	facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);  	facts->MaxReplyDescriptorPostQueueDepth =  	    le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); @@ -2997,43 +3490,25 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);  	mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); -	/* In MPI Revision I (0xA), the SystemReplyFrameSize(offset 0x18) was -	 * removed and made reserved.  For those with older firmware will need -	 * this fix. It was decided that the Reply and Request frame sizes are -	 * the same. -	 */ -	if ((ioc->facts.HeaderVersion >> 8) < 0xA) { -		mpi_request.Reserved7 = cpu_to_le16(ioc->reply_sz); -/*		mpi_request.SystemReplyFrameSize = - *		 cpu_to_le16(ioc->reply_sz); - */ -	} - +	if (_base_is_controller_msix_enabled(ioc)) +		mpi_request.HostMSIxVectors = ioc->reply_queue_count;  	mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);  	mpi_request.ReplyDescriptorPostQueueDepth =  	    cpu_to_le16(ioc->reply_post_queue_depth);  	mpi_request.ReplyFreeQueueDepth =  	    cpu_to_le16(ioc->reply_free_queue_depth); -#if BITS_PER_LONG > 32  	mpi_request.SenseBufferAddressHigh = -	    cpu_to_le32(ioc->sense_dma >> 32); +	    cpu_to_le32((u64)ioc->sense_dma >> 32);  	mpi_request.SystemReplyAddressHigh = -	    cpu_to_le32(ioc->reply_dma >> 32); -	mpi_request.SystemRequestFrameBaseAddress = -	    cpu_to_le64(ioc->request_dma); -	mpi_request.ReplyFreeQueueAddress = -	    cpu_to_le64(ioc->reply_free_dma); -	mpi_request.ReplyDescriptorPostQueueAddress = -	    cpu_to_le64(ioc->reply_post_free_dma); -#else +	    cpu_to_le32((u64)ioc->reply_dma >> 32);  	mpi_request.SystemRequestFrameBaseAddress = -	    cpu_to_le32(ioc->request_dma); +	    cpu_to_le64((u64)ioc->request_dma);  	mpi_request.ReplyFreeQueueAddress = -	    cpu_to_le32(ioc->reply_free_dma); +	    cpu_to_le64((u64)ioc->reply_free_dma);  	mpi_request.ReplyDescriptorPostQueueAddress = -	    cpu_to_le32(ioc->reply_post_free_dma); -#endif +	    cpu_to_le64((u64)ioc->reply_post_free_dma); +  	/* This time stamp specifies number of milliseconds  	 * since epoch ~ midnight January 1, 1970. @@ -3043,10 +3518,10 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	    (current_time.tv_usec / 1000));  	if (ioc->logging_level & MPT_DEBUG_INIT) { -		u32 *mfp; +		__le32 *mfp;  		int i; -		mfp = (u32 *)&mpi_request; +		mfp = (__le32 *)&mpi_request;  		printk(KERN_INFO "\toffset:data\n");  		for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)  			printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, @@ -3075,6 +3550,58 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  }  /** + * mpt2sas_port_enable_done - command completion routine for port enable + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function. + */ +u8 +mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply) +{ +	MPI2DefaultReply_t *mpi_reply; +	u16 ioc_status; + +	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); +	if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) +		return 1; + +	if (ioc->port_enable_cmds.status == MPT2_CMD_NOT_USED) +		return 1; + +	ioc->port_enable_cmds.status |= MPT2_CMD_COMPLETE; +	if (mpi_reply) { +		ioc->port_enable_cmds.status |= MPT2_CMD_REPLY_VALID; +		memcpy(ioc->port_enable_cmds.reply, mpi_reply, +		    mpi_reply->MsgLength*4); +	} +	ioc->port_enable_cmds.status &= ~MPT2_CMD_PENDING; + +	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; + +	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) +		ioc->port_enable_failed = 1; + +	if (ioc->is_driver_loading) { +		if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { +			mpt2sas_port_enable_complete(ioc); +			return 1; +		} else { +			ioc->start_scan_failed = ioc_status; +			ioc->start_scan = 0; +			return 1; +		} +	} +	complete(&ioc->port_enable_cmds.done); +	return 1; +} + + +/**   * _base_send_port_enable - send port_enable(discovery stuff) to firmware   * @ioc: per adapter object   * @sleep_flag: CAN_SLEEP or NO_SLEEP @@ -3085,67 +3612,151 @@ static int  _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  {  	Mpi2PortEnableRequest_t *mpi_request; -	u32 ioc_state; +	Mpi2PortEnableReply_t *mpi_reply;  	unsigned long timeleft;  	int r = 0;  	u16 smid; +	u16 ioc_status;  	printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); -	if (ioc->base_cmds.status & MPT2_CMD_PENDING) { +	if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) {  		printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",  		    ioc->name, __func__);  		return -EAGAIN;  	} -	smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); +	smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx);  	if (!smid) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__);  		return -EAGAIN;  	} -	ioc->base_cmds.status = MPT2_CMD_PENDING; +	ioc->port_enable_cmds.status = MPT2_CMD_PENDING;  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); -	ioc->base_cmds.smid = smid; +	ioc->port_enable_cmds.smid = smid;  	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));  	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; -	mpi_request->VF_ID = 0; /* TODO */ -	mpi_request->VP_ID = 0; +	init_completion(&ioc->port_enable_cmds.done);  	mpt2sas_base_put_smid_default(ioc, smid); -	init_completion(&ioc->base_cmds.done); -	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, +	timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done,  	    300*HZ); -	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { +	if (!(ioc->port_enable_cmds.status & MPT2_CMD_COMPLETE)) {  		printk(MPT2SAS_ERR_FMT "%s: timeout\n",  		    ioc->name, __func__);  		_debug_dump_mf(mpi_request,  		    sizeof(Mpi2PortEnableRequest_t)/4); -		if (ioc->base_cmds.status & MPT2_CMD_RESET) +		if (ioc->port_enable_cmds.status & MPT2_CMD_RESET)  			r = -EFAULT;  		else  			r = -ETIME;  		goto out; -	} else -		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", -		    ioc->name, __func__)); +	} +	mpi_reply = ioc->port_enable_cmds.reply; -	ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL, -	    60, sleep_flag); -	if (ioc_state) { -		printk(MPT2SAS_ERR_FMT "%s: failed going to operational state " -		    " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); +	ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; +	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +		printk(MPT2SAS_ERR_FMT "%s: failed with (ioc_status=0x%08x)\n", +		    ioc->name, __func__, ioc_status);  		r = -EFAULT; +		goto out;  	}   out: -	ioc->base_cmds.status = MPT2_CMD_NOT_USED; -	printk(MPT2SAS_INFO_FMT "port enable: %s\n", -	    ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); +	ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; +	printk(MPT2SAS_INFO_FMT "port enable: %s\n", ioc->name, ((r == 0) ? +	    "SUCCESS" : "FAILED"));  	return r;  }  /** + * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply) + * @ioc: per adapter object + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc) +{ +	Mpi2PortEnableRequest_t *mpi_request; +	u16 smid; + +	printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); + +	if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { +		printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", +		    ioc->name, __func__); +		return -EAGAIN; +	} + +	smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); +	if (!smid) { +		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", +		    ioc->name, __func__); +		return -EAGAIN; +	} + +	ioc->port_enable_cmds.status = MPT2_CMD_PENDING; +	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); +	ioc->port_enable_cmds.smid = smid; +	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); +	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; + +	mpt2sas_base_put_smid_default(ioc, smid); +	return 0; +} + +/** + * _base_determine_wait_on_discovery - desposition + * @ioc: per adapter object + * + * Decide whether to wait on discovery to complete. Used to either + * locate boot device, or report volumes ahead of physical devices. + * + * Returns 1 for wait, 0 for don't wait + */ +static int +_base_determine_wait_on_discovery(struct MPT2SAS_ADAPTER *ioc) +{ +	/* We wait for discovery to complete if IR firmware is loaded. +	 * The sas topology events arrive before PD events, so we need time to +	 * turn on the bit in ioc->pd_handles to indicate PD +	 * Also, it maybe required to report Volumes ahead of physical +	 * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. +	 */ +	if (ioc->ir_firmware) +		return 1; + +	/* if no Bios, then we don't need to wait */ +	if (!ioc->bios_pg3.BiosVersion) +		return 0; + +	/* Bios is present, then we drop down here. +	 * +	 * If there any entries in the Bios Page 2, then we wait +	 * for discovery to complete. +	 */ + +	/* Current Boot Device */ +	if ((ioc->bios_pg2.CurrentBootDeviceForm & +	    MPI2_BIOSPAGE2_FORM_MASK) == +	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && +	/* Request Boot Device */ +	   (ioc->bios_pg2.ReqBootDeviceForm & +	    MPI2_BIOSPAGE2_FORM_MASK) == +	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && +	/* Alternate Request Boot Device */ +	   (ioc->bios_pg2.ReqAltBootDeviceForm & +	    MPI2_BIOSPAGE2_FORM_MASK) == +	    MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) +		return 0; + +	return 1; +} + + +/**   * _base_unmask_events - turn on notification for this event   * @ioc: per adapter object   * @event: firmware event @@ -3213,8 +3824,8 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)  		mpi_request->EventMasks[i] =  		    cpu_to_le32(ioc->event_masks[i]); -	mpt2sas_base_put_smid_default(ioc, smid);  	init_completion(&ioc->base_cmds.done); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);  	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {  		printk(MPT2SAS_ERR_FMT "%s: timeout\n", @@ -3285,9 +3896,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	u32 hcb_size;  	printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name); - -	_base_save_msix_table(ioc); -  	drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",  	    ioc->name)); @@ -3329,11 +3937,15 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,  	     &ioc->chip->HostDiagnostic); -	/* don't access any registers for 50 milliseconds */ -	msleep(50); +	/* This delay allows the chip PCIe hardware time to finish reset tasks*/ +	if (sleep_flag == CAN_SLEEP) +		msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); +	else +		mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); -	/* 300 second max wait */ -	for (count = 0; count < 3000000 ; count++) { +	/* Approximately 300 second max wait */ +	for (count = 0; count < (300000000 / +	    MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) {  		host_diagnostic = readl(&ioc->chip->HostDiagnostic); @@ -3342,11 +3954,13 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  		if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))  			break; -		/* wait 100 msec */ +		/* Wait to pass the second read delay window */  		if (sleep_flag == CAN_SLEEP) -			msleep(1); +			msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC +			       /1000);  		else -			mdelay(1); +			mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC +			       /1000);  	}  	if (host_diagnostic & MPI2_DIAG_HCB_MODE) { @@ -3383,7 +3997,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  		goto out;  	} -	_base_restore_msix_table(ioc);  	printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);  	return 0; @@ -3463,6 +4076,10 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	u32 reply_address;  	u16 smid;  	struct _tr_list *delayed_tr, *delayed_tr_next; +	u8 hide_flag; +	struct adapter_reply_queue *reply_q; +	long reply_post_free; +	u32 reply_post_free_sz;  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); @@ -3485,9 +4102,11 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	INIT_LIST_HEAD(&ioc->free_list);  	smid = 1;  	for (i = 0; i < ioc->scsiio_depth; i++, smid++) { +		INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list);  		ioc->scsi_lookup[i].cb_idx = 0xFF;  		ioc->scsi_lookup[i].smid = smid;  		ioc->scsi_lookup[i].scmd = NULL; +		ioc->scsi_lookup[i].direct_io = 0;  		list_add_tail(&ioc->scsi_lookup[i].tracker_list,  		    &ioc->free_list);  	} @@ -3511,6 +4130,13 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  		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 */ @@ -3519,21 +4145,47 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	    ioc->reply_sz)  		ioc->reply_free[i] = cpu_to_le32(reply_address); +	/* initialize reply queues */ +	if (ioc->is_driver_loading) +		_base_assign_reply_queues(ioc); +  	/* initialize Reply Post Free Queue */ -	for (i = 0; i < ioc->reply_post_queue_depth; i++) -		ioc->reply_post_free[i].Words = ULLONG_MAX; +	reply_post_free = (long)ioc->reply_post_free; +	reply_post_free_sz = ioc->reply_post_queue_depth * +	    sizeof(Mpi2DefaultReplyDescriptor_t); +	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { +		reply_q->reply_post_host_index = 0; +		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *) +		    reply_post_free; +		for (i = 0; i < ioc->reply_post_queue_depth; i++) +			reply_q->reply_post_free[i].Words = +							cpu_to_le64(ULLONG_MAX); +		if (!_base_is_controller_msix_enabled(ioc)) +			goto skip_init_reply_post_free_queue; +		reply_post_free += reply_post_free_sz; +	} + skip_init_reply_post_free_queue:  	r = _base_send_ioc_init(ioc, sleep_flag);  	if (r)  		return r; -	/* initialize the index's */ +	/* initialize reply free host index */  	ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; -	ioc->reply_post_host_index = 0;  	writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); -	writel(0, &ioc->chip->ReplyPostHostIndex); + +	/* initialize reply post host index */ +	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { +		writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT, +		    &ioc->chip->ReplyPostHostIndex); +		if (!_base_is_controller_msix_enabled(ioc)) +			goto skip_init_reply_post_host_index; +	} + + skip_init_reply_post_host_index:  	_base_unmask_interrupts(ioc); +  	r = _base_event_notification(ioc, sleep_flag);  	if (r)  		return r; @@ -3541,13 +4193,20 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	if (sleep_flag == CAN_SLEEP)  		_base_static_config_pages(ioc); -	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; -	} +	if (ioc->is_driver_loading) { +		if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier +		    == 0x80) { +			hide_flag = (u8) ( +			    le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & +			    MFG_PAGE10_HIDE_SSDS_MASK); +			if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) +				ioc->mfg_pg10_hide_flag = hide_flag; +		} +		ioc->wait_for_discovery_to_complete = +		    _base_determine_wait_on_discovery(ioc); +		return r; /* scan_start and scan_finished support */ +	}  	r = _base_send_port_enable(ioc, sleep_flag);  	if (r)  		return r; @@ -3569,22 +4228,25 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)  	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); +	if (ioc->chip_phys && ioc->chip) { +		_base_mask_interrupts(ioc); +		ioc->shost_recovery = 1; +		_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); +		ioc->shost_recovery = 0;  	} + +	_base_free_irq(ioc);  	_base_disable_msix(ioc); -	if (ioc->chip_phys) + +	if (ioc->chip_phys && ioc->chip)  		iounmap(ioc->chip); -	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); + +	if (pci_is_enabled(pdev)) { +		pci_release_selected_regions(ioc->pdev, ioc->bars); +		pci_disable_pcie_error_reporting(pdev); +		pci_disable_device(pdev); +	}  	return;  } @@ -3598,13 +4260,49 @@ int  mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  {  	int r, i; +	int cpu_id, last_cpu_id = 0;  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); +	/* setup cpu_msix_table */ +	ioc->cpu_count = num_online_cpus(); +	for_each_online_cpu(cpu_id) +		last_cpu_id = cpu_id; +	ioc->cpu_msix_table_sz = last_cpu_id + 1; +	ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); +	ioc->reply_queue_count = 1; +	if (!ioc->cpu_msix_table) { +		dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " +		    "cpu_msix_table failed!!!\n", ioc->name)); +		r = -ENOMEM; +		goto out_free_resources; +	} + +	if (ioc->is_warpdrive) { +		ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, +		    sizeof(resource_size_t *), GFP_KERNEL); +		if (!ioc->reply_post_host_index) { +			dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation " +				"for cpu_msix_table failed!!!\n", ioc->name)); +			r = -ENOMEM; +			goto out_free_resources; +		} +	} +  	r = mpt2sas_base_map_resources(ioc);  	if (r) -		return r; +		goto out_free_resources; + +	if (ioc->is_warpdrive) { +		ioc->reply_post_host_index[0] = +		    (resource_size_t *)&ioc->chip->ReplyPostHostIndex; + +		for (i = 1; i < ioc->cpu_msix_table_sz; i++) +			ioc->reply_post_host_index[i] = (resource_size_t *) +			((u8 *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) +			* 4))); +	}  	pci_set_drvdata(ioc->pdev, ioc->shost);  	r = _base_get_ioc_facts(ioc, CAN_SLEEP); @@ -3616,7 +4314,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  		goto out_free_resources;  	ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, -	    sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); +	    sizeof(struct mpt2sas_port_facts), GFP_KERNEL);  	if (!ioc->pfacts) {  		r = -ENOMEM;  		goto out_free_resources; @@ -3633,7 +4331,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  		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) @@ -3644,7 +4341,12 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  		r = -ENOMEM;  		goto out_free_resources;  	} - +	ioc->blocking_handles = kzalloc(ioc->pd_handles_sz, +	    GFP_KERNEL); +	if (!ioc->blocking_handles) { +		r = -ENOMEM; +		goto out_free_resources; +	}  	ioc->fwfault_debug = mpt2sas_fwfault_debug;  	/* base internal command bits */ @@ -3652,6 +4354,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);  	ioc->base_cmds.status = MPT2_CMD_NOT_USED; +	/* port_enable command bits */ +	ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); +	ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; +  	/* transport internal command bits */  	ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);  	ioc->transport_cmds.status = MPT2_CMD_NOT_USED; @@ -3693,8 +4399,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  		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; @@ -3708,13 +4412,13 @@ 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);  	r = _base_make_ioc_operational(ioc, CAN_SLEEP);  	if (r)  		goto out_free_resources; -	mpt2sas_base_start_watchdog(ioc); +	ioc->non_operational_loop = 0; +  	return 0;   out_free_resources: @@ -3723,12 +4427,17 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	mpt2sas_base_free_resources(ioc);  	_base_release_memory_pools(ioc);  	pci_set_drvdata(ioc->pdev, NULL); +	kfree(ioc->cpu_msix_table); +	if (ioc->is_warpdrive) +		kfree(ioc->reply_post_host_index);  	kfree(ioc->pd_handles); +	kfree(ioc->blocking_handles);  	kfree(ioc->tm_cmds.reply);  	kfree(ioc->transport_cmds.reply);  	kfree(ioc->scsih_cmds.reply);  	kfree(ioc->config_cmds.reply);  	kfree(ioc->base_cmds.reply); +	kfree(ioc->port_enable_cmds.reply);  	kfree(ioc->ctl_cmds.reply);  	kfree(ioc->ctl_cmds.sense);  	kfree(ioc->pfacts); @@ -3760,11 +4469,16 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)  	mpt2sas_base_free_resources(ioc);  	_base_release_memory_pools(ioc);  	pci_set_drvdata(ioc->pdev, NULL); +	kfree(ioc->cpu_msix_table); +	if (ioc->is_warpdrive) +		kfree(ioc->reply_post_host_index);  	kfree(ioc->pd_handles); +	kfree(ioc->blocking_handles);  	kfree(ioc->pfacts);  	kfree(ioc->ctl_cmds.reply);  	kfree(ioc->ctl_cmds.sense);  	kfree(ioc->base_cmds.reply); +	kfree(ioc->port_enable_cmds.reply);  	kfree(ioc->tm_cmds.reply);  	kfree(ioc->transport_cmds.reply);  	kfree(ioc->scsih_cmds.reply); @@ -3786,6 +4500,8 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)  static void  _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  { +	mpt2sas_scsih_reset_handler(ioc, reset_phase); +	mpt2sas_ctl_reset_handler(ioc, reset_phase);  	switch (reset_phase) {  	case MPT2_IOC_PRE_RESET:  		dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " @@ -3804,6 +4520,20 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  			mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid);  			complete(&ioc->base_cmds.done);  		} +		if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { +			ioc->port_enable_failed = 1; +			ioc->port_enable_cmds.status |= MPT2_CMD_RESET; +			mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); +			if (ioc->is_driver_loading) { +				ioc->start_scan_failed = +				    MPI2_IOCSTATUS_INTERNAL_ERROR; +				ioc->start_scan = 0; +				ioc->port_enable_cmds.status = +						MPT2_CMD_NOT_USED; +			} else +				complete(&ioc->port_enable_cmds.done); + +		}  		if (ioc->config_cmds.status & MPT2_CMD_PENDING) {  			ioc->config_cmds.status |= MPT2_CMD_RESET;  			mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); @@ -3816,8 +4546,6 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  		    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));  		break;  	} -	mpt2sas_scsih_reset_handler(ioc, reset_phase); -	mpt2sas_ctl_reset_handler(ioc, reset_phase);  }  /** @@ -3879,7 +4607,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  		printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n",  		    ioc->name, __func__);  		r = 0; -		goto out; +		goto out_unlocked;  	}  	if (mpt2sas_fwfault_debug) @@ -3913,6 +4641,15 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  	if (r)  		goto out;  	_base_reset_handler(ioc, MPT2_IOC_AFTER_RESET); + +	/* If this hard reset is called while port enable is active, then +	 * there is no reason to call make_ioc_operational +	 */ +	if (ioc->is_driver_loading && ioc->port_enable_failed) { +		ioc->remove_host = 1; +		r = -EFAULT; +		goto out; +	}  	r = _base_make_ioc_operational(ioc, sleep_flag);  	if (!r)  		_base_reset_handler(ioc, MPT2_IOC_DONE_RESET); @@ -3923,10 +4660,10 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);  	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); + out_unlocked:  	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 0b15a8bdebf..fd3b998c75b 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-2010  LSI Corporation + * Copyright (C) 2007-2013  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -69,8 +69,8 @@  #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		"06.100.00.00" -#define MPT2SAS_MAJOR_VERSION		06 +#define MPT2SAS_DRIVER_VERSION		"16.100.00.00" +#define MPT2SAS_MAJOR_VERSION		16  #define MPT2SAS_MINOR_VERSION		100  #define MPT2SAS_BUILD_VERSION		00  #define MPT2SAS_RELEASE_VERSION		00 @@ -101,7 +101,8 @@  #define MPT_NAME_LENGTH			32	/* generic length of strings */  #define MPT_STRING_LENGTH		64 -#define	MPT_MAX_CALLBACKS		16 +#define MPT_MAX_CALLBACKS		16 +  #define	 CAN_SLEEP			1  #define  NO_SLEEP			0 @@ -154,6 +155,72 @@  #define MPT2SAS_DELL_6GBPS_SAS_SSDID               0x1F22  /* + * Intel HBA branding + */ +#define MPT2SAS_INTEL_RMS25JB080_BRANDING    \ +				"Intel(R) Integrated RAID Module RMS25JB080" +#define MPT2SAS_INTEL_RMS25JB040_BRANDING    \ +				"Intel(R) Integrated RAID Module RMS25JB040" +#define MPT2SAS_INTEL_RMS25KB080_BRANDING    \ +				"Intel(R) Integrated RAID Module RMS25KB080" +#define MPT2SAS_INTEL_RMS25KB040_BRANDING    \ +				"Intel(R) Integrated RAID Module RMS25KB040" +#define MPT2SAS_INTEL_RMS25LB040_BRANDING	\ +				"Intel(R) Integrated RAID Module RMS25LB040" +#define MPT2SAS_INTEL_RMS25LB080_BRANDING	\ +				"Intel(R) Integrated RAID Module RMS25LB080" +#define MPT2SAS_INTEL_RMS2LL080_BRANDING	\ +				"Intel Integrated RAID Module RMS2LL080" +#define MPT2SAS_INTEL_RMS2LL040_BRANDING	\ +				"Intel Integrated RAID Module RMS2LL040" +#define MPT2SAS_INTEL_RS25GB008_BRANDING       \ +				"Intel(R) RAID Controller RS25GB008" +#define MPT2SAS_INTEL_SSD910_BRANDING          \ +				"Intel(R) SSD 910 Series" +/* + * Intel HBA SSDIDs + */ +#define MPT2SAS_INTEL_RMS25JB080_SSDID         0x3516 +#define MPT2SAS_INTEL_RMS25JB040_SSDID         0x3517 +#define MPT2SAS_INTEL_RMS25KB080_SSDID         0x3518 +#define MPT2SAS_INTEL_RMS25KB040_SSDID         0x3519 +#define MPT2SAS_INTEL_RMS25LB040_SSDID         0x351A +#define MPT2SAS_INTEL_RMS25LB080_SSDID         0x351B +#define MPT2SAS_INTEL_RMS2LL080_SSDID          0x350E +#define MPT2SAS_INTEL_RMS2LL040_SSDID          0x350F +#define MPT2SAS_INTEL_RS25GB008_SSDID          0x3000 +#define MPT2SAS_INTEL_SSD910_SSDID             0x3700 + +/* + * HP HBA branding + */ +#define MPT2SAS_HP_3PAR_SSVID                0x1590 +#define MPT2SAS_HP_2_4_INTERNAL_BRANDING        "HP H220 Host Bus Adapter" +#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING        "HP H221 Host Bus Adapter" +#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING "HP H222 Host Bus Adapter" +#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING    "HP H220i Host Bus Adapter" +#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING    "HP H210i Host Bus Adapter" + +/* + * HO HBA SSDIDs + */ +#define MPT2SAS_HP_2_4_INTERNAL_SSDID            0x0041 +#define MPT2SAS_HP_2_4_EXTERNAL_SSDID            0x0042 +#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID    0x0043 +#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID        0x0044 +#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID        0x0046 + +/* + *  WarpDrive Specific Log codes + */ + +#define MPT2_WARPDRIVE_LOGENTRY		(0x8002) +#define MPT2_WARPDRIVE_LC_SSDT		(0x41) +#define MPT2_WARPDRIVE_LC_SSDLW		(0x43) +#define MPT2_WARPDRIVE_LC_SSDLF		(0x44) +#define MPT2_WARPDRIVE_LC_BRMF		(0x4D) + +/*   * per target private data   */  #define MPT_TARGET_FLAGS_RAID_COMPONENT	0x01 @@ -164,6 +231,7 @@   * struct MPT2SAS_TARGET - starget private hostdata   * @starget: starget object   * @sas_address: target sas address + * @raid_device: raid_device pointer to access volume data   * @handle: device handle   * @num_luns: number luns   * @flags: MPT_TARGET_FLAGS_XXX flags @@ -173,6 +241,7 @@  struct MPT2SAS_TARGET {  	struct scsi_target *starget;  	u64	sas_address; +	struct _raid_device *raid_device;  	u16	handle;  	int	num_luns;  	u32	flags; @@ -180,6 +249,7 @@ struct MPT2SAS_TARGET {  	u8	tm_busy;  }; +  /*   * per device private data   */ @@ -227,6 +297,12 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_10 {    MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10,    Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t; +#define MFG_PAGE10_HIDE_SSDS_MASK	(0x00000003) +#define MFG_PAGE10_HIDE_ALL_DISKS	(0x00) +#define MFG_PAGE10_EXPOSE_ALL_DISKS	(0x01) +#define MFG_PAGE10_HIDE_IF_VOL_PRESENT	(0x02) + +  struct MPT2SAS_DEVICE {  	struct MPT2SAS_TARGET *sas_target;  	unsigned int	lun; @@ -306,6 +382,7 @@ struct _sas_device {   * @sdev: scsi device struct (volumes are single lun)   * @wwid: unique identifier for the volume   * @handle: device handle + * @block_size: Block size of the volume   * @id: target id   * @channel: target channel   * @volume_type: the raid level @@ -313,20 +390,35 @@ struct _sas_device {   * @num_pds: number of hidden raid components   * @responding: used in _scsih_raid_device_mark_responding   * @percent_complete: resync percent complete + * @direct_io_enabled: Whether direct io to PDs are allowed or not + * @stripe_exponent: X where 2powX is the stripe sz in blocks + * @block_exponent: X where 2powX is the block sz in bytes + * @max_lba: Maximum number of LBA in the volume + * @stripe_sz: Stripe Size of the volume + * @device_info: Device info of the volume member disk + * @pd_handle: Array of handles of the physical drives for direct I/O in le16   */ +#define MPT_MAX_WARPDRIVE_PDS		8  struct _raid_device {  	struct list_head list;  	struct scsi_target *starget;  	struct scsi_device *sdev;  	u64	wwid;  	u16	handle; +	u16	block_sz;  	int	id;  	int	channel;  	u8	volume_type; -	u32	device_info;  	u8	num_pds;  	u8	responding;  	u8	percent_complete; +	u8	direct_io_enabled; +	u8	stripe_exponent; +	u8	block_exponent; +	u64	max_lba; +	u32	stripe_sz; +	u32	device_info; +	u16	pd_handle[MPT_MAX_WARPDRIVE_PDS];  };  /** @@ -419,17 +511,44 @@ enum reset_type {  };  /** - * struct request_tracker - firmware request tracker + * struct chain_tracker - firmware chain tracker + * @chain_buffer: chain buffer + * @chain_buffer_dma: physical address + * @tracker_list: list of free request (ioc->free_chain_list) + */ +struct chain_tracker { +	void *chain_buffer; +	dma_addr_t chain_buffer_dma; +	struct list_head tracker_list; +}; + +/** + * struct scsiio_tracker - scsi mf request tracker   * @smid: system message id   * @scmd: scsi request pointer   * @cb_idx: callback index + * @direct_io: To indicate whether I/O is direct (WARPDRIVE)   * @chain_list: list of chains associated to this IO   * @tracker_list: list of free request (ioc->free_list)   */ -struct request_tracker { +struct scsiio_tracker {  	u16	smid;  	struct scsi_cmnd *scmd;  	u8	cb_idx; +	u8	direct_io; +	struct list_head chain_list; +	struct list_head tracker_list; +}; + +/** + * struct request_tracker - firmware request tracker + * @smid: system message id + * @cb_idx: callback index + * @tracker_list: list of free request (ioc->free_list) + */ +struct request_tracker { +	u16	smid; +	u8	cb_idx;  	struct list_head tracker_list;  }; @@ -447,11 +566,91 @@ struct _tr_list {  typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);  /** + * struct adapter_reply_queue - the reply queue struct + * @ioc: per adapter object + * @msix_index: msix index into vector table + * @vector: irq vector + * @reply_post_host_index: head index in the pool where FW completes IO + * @reply_post_free: reply post base virt address + * @name: the name registered to request_irq() + * @busy: isr is actively processing replies on another cpu + * @list: this list +*/ +struct adapter_reply_queue { +	struct MPT2SAS_ADAPTER	*ioc; +	u8			msix_index; +	unsigned int		vector; +	u32			reply_post_host_index; +	Mpi2ReplyDescriptorsUnion_t *reply_post_free; +	char			name[MPT_NAME_LENGTH]; +	atomic_t		busy; +	struct list_head	list; +}; + +/* IOC Facts and Port Facts converted from little endian to cpu */ +union mpi2_version_union { +	MPI2_VERSION_STRUCT		Struct; +	u32				Word; +}; + +struct mpt2sas_facts { +	u16			MsgVersion; +	u16			HeaderVersion; +	u8			IOCNumber; +	u8			VP_ID; +	u8			VF_ID; +	u16			IOCExceptions; +	u16			IOCStatus; +	u32			IOCLogInfo; +	u8			MaxChainDepth; +	u8			WhoInit; +	u8			NumberOfPorts; +	u8			MaxMSIxVectors; +	u16			RequestCredit; +	u16			ProductID; +	u32			IOCCapabilities; +	union mpi2_version_union	FWVersion; +	u16			IOCRequestFrameSize; +	u16			Reserved3; +	u16			MaxInitiators; +	u16			MaxTargets; +	u16			MaxSasExpanders; +	u16			MaxEnclosures; +	u16			ProtocolFlags; +	u16			HighPriorityCredit; +	u16			MaxReplyDescriptorPostQueueDepth; +	u8			ReplyFrameSize; +	u8			MaxVolumes; +	u16			MaxDevHandle; +	u16			MaxPersistentEntries; +	u16			MinDevHandle; +}; + +struct mpt2sas_port_facts { +	u8			PortNumber; +	u8			VP_ID; +	u8			VF_ID; +	u8			PortType; +	u16			MaxPostedCmdBuffers; +}; + +/** + * enum mutex_type - task management mutex type + * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it + * @TM_MUTEX_ON: mutex is required + */ +enum mutex_type { +	TM_MUTEX_OFF = 0, +	TM_MUTEX_ON = 1, +}; + +typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); +/**   * struct MPT2SAS_ADAPTER - per adapter struct   * @list: ioc_list   * @shost: shost object   * @id: unique adapter id - * @pci_irq: irq number + * @cpu_count: number online cpus   * @name: generic ioc string   * @tmp_string: tmp string used for logging   * @pdev: pci pdev object @@ -478,11 +677,17 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);   * @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: + * @wait_for_discovery_to_complete: flag set at driver load time when + *                                               waiting on reporting devices + * @is_driver_loading: flag set at driver load time + * @port_enable_failed: flag set when port enable has failed + * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work + * @start_scan_failed: means port enable failed, return's the ioc_status   * @msix_enable: flag indicating msix is enabled   * @msix_vector_count: number msix vectors - * @msix_table: virt address to the msix table - * @msix_table_backup: backup msix table + * @cpu_msix_table: table for mapping cpus to msix index + * @cpu_msix_table_sz: table size + * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands   * @scsi_io_cb_idx: shost generated commands   * @tm_cb_idx: task management commands   * @scsih_cb_idx: scsih internal commands @@ -521,6 +726,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);   * @io_missing_delay: time for IO completed by fw when PDR enabled   * @device_missing_delay: time for device missing by fw when PDR enabled   * @sas_id : used for setting volume target IDs + * @blocking_handles: bitmask used to identify which devices need blocking   * @pd_handles : bitmask for PD handles   * @pd_handles_sz : size of pd_handle bitmask   * @config_page_sz: config page size @@ -573,7 +779,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);   * @reply_post_queue_depth: reply post queue depth   * @reply_post_free: pool for reply post (64bit descriptor)   * @reply_post_free_dma: - * @reply_post_free_dma_pool: + * @reply_queue_count: number of reply queue's + * @reply_queue_list: link list contaning the reply queue info   * @reply_post_host_index: head index in the pool where FW completes IO   * @delayed_tr_list: target reset link list   * @delayed_tr_volume_list: volume target reset link list @@ -582,7 +789,7 @@ struct MPT2SAS_ADAPTER {  	struct list_head list;  	struct Scsi_Host *shost;  	u8		id; -	u32		pci_irq; +	int		cpu_count;  	char		name[MPT_NAME_LENGTH];  	char		tmp_string[MPT_STRING_LENGTH];  	struct pci_dev	*pdev; @@ -608,24 +815,33 @@ struct MPT2SAS_ADAPTER {  	 /* misc flags */  	int		aen_event_read_flag;  	u8		broadcast_aen_busy; +	u16		broadcast_aen_pending;  	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		ioc_reset_in_progress_status;  	u8		ignore_loginfos;  	u8		remove_host;  	u8		pci_error_recovery; -	u8		wait_for_port_enable_to_complete; +	u8		wait_for_discovery_to_complete; +	struct completion	port_enable_done; +	u8		is_driver_loading; +	u8		port_enable_failed; + +	u8		start_scan; +	u16		start_scan_failed;  	u8		msix_enable;  	u16		msix_vector_count; -	u32		*msix_table; -	u32		*msix_table_backup; +	u8		*cpu_msix_table; +	resource_size_t	**reply_post_host_index; +	u16		cpu_msix_table_sz;  	u32		ioc_reset_count; +	MPT2SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; +	u32             non_operational_loop;  	/* internal commands, callback index */  	u8		scsi_io_cb_idx; @@ -634,11 +850,13 @@ struct MPT2SAS_ADAPTER {  	u8		scsih_cb_idx;  	u8		ctl_cb_idx;  	u8		base_cb_idx; +	u8		port_enable_cb_idx;  	u8		config_cb_idx;  	u8		tm_tr_cb_idx;  	u8		tm_tr_volume_cb_idx;  	u8		tm_sas_control_cb_idx;  	struct _internal_cmd base_cmds; +	struct _internal_cmd port_enable_cmds;  	struct _internal_cmd transport_cmds;  	struct _internal_cmd scsih_cmds;  	struct _internal_cmd tm_cmds; @@ -654,8 +872,8 @@ struct MPT2SAS_ADAPTER {  	u32		event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];  	/* static config pages */ -	Mpi2IOCFactsReply_t facts; -	Mpi2PortFactsReply_t *pfacts; +	struct mpt2sas_facts facts; +	struct mpt2sas_port_facts *pfacts;  	Mpi2ManufacturingPage0_t manu_pg0;  	Mpi2BiosPage2_t	bios_pg2;  	Mpi2BiosPage3_t	bios_pg3; @@ -679,7 +897,7 @@ struct MPT2SAS_ADAPTER {  	u8		io_missing_delay;  	u16		device_missing_delay;  	int		sas_id; - +	void		*blocking_handles;  	void		*pd_handles;  	u16		pd_handles_sz; @@ -696,7 +914,7 @@ struct MPT2SAS_ADAPTER {  	u8		*request;  	dma_addr_t	request_dma;  	u32		request_dma_sz; -	struct request_tracker *scsi_lookup; +	struct scsiio_tracker *scsi_lookup;  	ulong		scsi_lookup_pages;  	spinlock_t 	scsi_lookup_lock;  	struct list_head free_list; @@ -704,8 +922,10 @@ struct MPT2SAS_ADAPTER {  	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; @@ -737,11 +957,13 @@ 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 */  	u16 		reply_free_queue_depth; -	u32		*reply_free; +	__le32		*reply_free;  	dma_addr_t	reply_free_dma;  	struct dma_pool *reply_free_dma_pool;  	u32		reply_free_host_index; @@ -751,7 +973,8 @@ struct MPT2SAS_ADAPTER {  	Mpi2ReplyDescriptorsUnion_t *reply_post_free;  	dma_addr_t	reply_post_free_dma;  	struct dma_pool *reply_post_free_dma_pool; -	u32		reply_post_host_index; +	u8		reply_queue_count; +	struct list_head reply_queue_list;  	struct list_head delayed_tr_list;  	struct list_head delayed_tr_volume_list; @@ -767,6 +990,11 @@ struct MPT2SAS_ADAPTER {  	u32		diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];  	u32		ring_buffer_offset;  	u32		ring_buffer_sz; +	u8		is_warpdrive; +	u8		hide_ir_msg; +	u8		mfg_pg10_hide_flag; +	u8		hide_drives; +  };  typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, @@ -790,6 +1018,7 @@ 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);  __le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,      u16 smid); +void mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc);  /* hi-priority queue */  u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); @@ -810,6 +1039,8 @@ void mpt2sas_base_release_callback_handler(u8 cb_idx);  u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,      u32 reply); +u8 mpt2sas_port_enable_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); @@ -824,14 +1055,22 @@ void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_ty  void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); +void mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc, +	u16 device_missing_delay, u8 io_missing_delay); + +int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc); +  /* scsih shared API */ -u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, +void 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); +	uint channel, uint id, uint lun, u8 type, u16 smid_task, +	ulong timeout, enum mutex_type m_type);  void mpt2sas_scsih_set_tm_flag(struct 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_by_sas_address(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 @@ -839,6 +1078,8 @@ 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_port_enable_complete(struct MPT2SAS_ADAPTER *ioc); +  void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);  /* config shared API */ @@ -865,6 +1106,8 @@ int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t      *mpi_reply, Mpi2IOUnitPage1_t *config_page);  int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t      *mpi_reply, Mpi2IOUnitPage1_t *config_page); +int mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);  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, @@ -901,7 +1144,7 @@ void mpt2sas_ctl_exit(void);  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); -u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, +void 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); @@ -927,6 +1170,7 @@ 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); +extern int scsi_internal_device_unblock(struct scsi_device *sdev, +					enum scsi_device_state new_state);  #endif /* MPT2SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index 6afd67b324f..0c47425c73f 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-2010  LSI Corporation + * Copyright (C) 2007-2013  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -41,7 +41,6 @@   * USA.   */ -#include <linux/version.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/init.h> @@ -93,7 +92,7 @@ struct config_request{   * @mpi_reply: reply message frame   * Context: none.   * - * Function for displaying debug info helpfull when debugging issues + * Function for displaying debug info helpful when debugging issues   * in this module.   */  static void @@ -150,7 +149,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,  			desc = "raid_config";  			break;  		case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING: -			desc = "driver_mappping"; +			desc = "driver_mapping";  			break;  		}  		break; @@ -684,6 +683,42 @@ mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,  }  /** + * mpt2sas_config_get_iounit_pg3 - obtain iounit page 3 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc, +	Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz) +{ +	Mpi2ConfigRequest_t mpi_request; +	int r; + +	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); +	mpi_request.Function = MPI2_FUNCTION_CONFIG; +	mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; +	mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; +	mpi_request.Header.PageNumber = 3; +	mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION; +	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_READ_CURRENT; +	r = _config_request(ioc, &mpi_request, mpi_reply, +	    MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + out: +	return r; +} + +/**   * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8   * @ioc: per adapter object   * @mpi_reply: reply mf payload returned from firmware @@ -1357,6 +1392,9 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,  	Mpi2ConfigReply_t mpi_reply;  	int r, i, config_page_sz;  	u16 ioc_status; +	int config_num; +	u16 element_type; +	u16 phys_disk_dev_handle;  	*volume_handle = 0;  	memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); @@ -1372,35 +1410,53 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,  	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;  	config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4);  	config_page = kmalloc(config_page_sz, GFP_KERNEL); -	if (!config_page) +	if (!config_page) { +		r = -1;  		goto out; -	r = _config_request(ioc, &mpi_request, &mpi_reply, -	    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 out; -	for (i = 0; i < config_page->NumElements; i++) { -		if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) & -		    MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) != -		    MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT) -			continue; -		if (le16_to_cpu(config_page->ConfigElement[i]. -		    PhysDiskDevHandle) == pd_handle) { -			*volume_handle = le16_to_cpu(config_page-> -			    ConfigElement[i].VolDevHandle); -			r = 0; +	} +	config_num = 0xff; +	while (1) { +		mpi_request.PageAddress = cpu_to_le32(config_num + +		    MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM); +		r = _config_request(ioc, &mpi_request, &mpi_reply, +		    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 out; +		for (i = 0; i < config_page->NumElements; i++) { +			element_type = le16_to_cpu(config_page-> +			    ConfigElement[i].ElementFlags) & +			    MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE; +			if (element_type == +			    MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT || +			    element_type == +			    MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) { +				phys_disk_dev_handle = +				    le16_to_cpu(config_page->ConfigElement[i]. +				    PhysDiskDevHandle); +				if (phys_disk_dev_handle == pd_handle) { +					*volume_handle = +					    le16_to_cpu(config_page-> +					    ConfigElement[i].VolDevHandle); +					r = 0; +					goto out; +				} +			} else if (element_type == +			    MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) { +				*volume_handle = 0; +				r = 0; +				goto out; +			}  		} +		config_num = config_page->ConfigNum;  	}   out:  	kfree(config_page); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 40cb8aeb21b..62df8f9d427 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-2010  LSI Corporation + * Copyright (C) 2007-2013  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -42,7 +42,6 @@   * USA.   */ -#include <linux/version.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/errno.h> @@ -81,6 +80,7 @@ enum block_state {  	BLOCKING,  }; +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING  /**   * _ctl_sas_device_find_by_handle - sas device search   * @ioc: per adapter object @@ -107,7 +107,6 @@ _ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	return r;  } -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING  /**   * _ctl_display_some_debug - debug routine   * @ioc: per adapter object @@ -116,7 +115,7 @@ _ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)   * @mpi_reply: reply message frame   * Context: none.   * - * Function for displaying debug info helpfull when debugging issues + * Function for displaying debug info helpful when debugging issues   * in this module.   */  static void @@ -398,18 +397,22 @@ mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,   * This function merely adds a new work task into ioc->firmware_event_thread.   * The tasks are worked from _firmware_event_work in user context.   * - * Return 1 meaning mf should be freed from _base_interrupt - *        0 means the mf is freed from this function. + * Returns void.   */ -u8 +void  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); +	if (unlikely(!mpi_reply)) { +		printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		return; +	}  	mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); -	return 1; +	return;  }  /** @@ -506,19 +509,6 @@ _ctl_fasync(int fd, struct file *filep, int mode)  }  /** - * _ctl_release - - * @inode - - * @filep - - * - * Called when application releases the fasyn callback handler. - */ -static int -_ctl_release(struct inode *inode, struct file *filep) -{ -	return fasync_helper(-1, filep, 0, &async_queue); -} - -/**   * _ctl_poll -   * @file -   * @wait - @@ -621,11 +611,10 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,   * @ioc: per adapter object   * @karg - (struct mpt2_ioctl_command)   * @mf - pointer to mf in user space - * @state - NON_BLOCKING or BLOCKING   */  static long -_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, -    struct mpt2_ioctl_command karg, void __user *mf, enum block_state state) +_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg, +	void __user *mf)  {  	MPI2RequestHeader_t *mpi_request = NULL, *request;  	MPI2DefaultReply_t *mpi_reply; @@ -648,11 +637,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	issue_reset = 0; -	if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) -		return -EAGAIN; -	else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) -		return -ERESTARTSYS; -  	if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {  		printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",  		    ioc->name, __func__); @@ -688,6 +672,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		goto out;  	} +	/* Check for overflow and wraparound */ +	if (karg.data_sge_offset * 4 > ioc->request_sz || +	    karg.data_sge_offset > (UINT_MAX / 4)) { +		ret = -EINVAL; +		goto out; +	} +  	/* copy in request message frame from user */  	if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {  		printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, @@ -812,6 +803,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	_ctl_display_some_debug(ioc, smid, "ctl_request", NULL);  #endif +	init_completion(&ioc->ctl_cmds.done);  	switch (mpi_request->Function) {  	case MPI2_FUNCTION_SCSI_IO_REQUEST:  	case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: @@ -864,8 +856,16 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		if (smp_request->PassthroughFlags &  		    MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE)  			data = (u8 *)&smp_request->SGL; -		else +		else { +			if (unlikely(data_out == NULL)) { +				printk(KERN_ERR "failure at %s:%d/%s()!\n", +				    __FILE__, __LINE__, __func__); +				mpt2sas_base_free_smid(ioc, smid); +				ret = -EINVAL; +				goto out; +			}  			data = data_out; +		}  		if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) {  			ioc->ioc_link_reset_in_progress = 1; @@ -897,7 +897,6 @@ _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) { @@ -979,7 +978,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		ret = -ENODATA;  		if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||  		    mpi_request->Function == -		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { +		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || +		    mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) {  			printk(MPT2SAS_INFO_FMT "issue target reset: handle "  			    "= (0x%04x)\n", ioc->name,  			    le16_to_cpu(mpi_request->FunctionDependent1)); @@ -987,7 +987,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  			mpt2sas_scsih_issue_tm(ioc,  			    le16_to_cpu(mpi_request->FunctionDependent1), 0, 0,  			    0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, -			    NULL); +			    TM_MUTEX_ON);  			ioc->tm_cmds.status = MPT2_CMD_NOT_USED;  		} else  			mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, @@ -1007,38 +1007,36 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  	kfree(mpi_request);  	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->ctl_cmds.mutex);  	return ret;  }  /**   * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content   */  static long -_ctl_getiocinfo(void __user *arg) +_ctl_getiocinfo(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_ioctl_iocinfo karg; -	struct MPT2SAS_ADAPTER *ioc; -	u8 revision;  	if (copy_from_user(&karg, arg, sizeof(karg))) {  		printk(KERN_ERR "failure at %s:%d/%s()!\n",  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__));  	memset(&karg, 0 , sizeof(karg)); -	karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; +	if (ioc->is_warpdrive) +		karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; +	else +		karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;  	if (ioc->pfacts)  		karg.port_number = ioc->pfacts[0].PortNumber; -	pci_read_config_byte(ioc->pdev, PCI_CLASS_REVISION, &revision); -	karg.hw_rev = revision; +	karg.hw_rev = ioc->pdev->revision;  	karg.pci_id = ioc->pdev->device;  	karg.subsystem_device = ioc->pdev->subsystem_device;  	karg.subsystem_vendor = ioc->pdev->subsystem_vendor; @@ -1062,21 +1060,19 @@ _ctl_getiocinfo(void __user *arg)  /**   * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content   */  static long -_ctl_eventquery(void __user *arg) +_ctl_eventquery(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_ioctl_eventquery karg; -	struct MPT2SAS_ADAPTER *ioc;  	if (copy_from_user(&karg, arg, sizeof(karg))) {  		printk(KERN_ERR "failure at %s:%d/%s()!\n",  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__)); @@ -1095,21 +1091,19 @@ _ctl_eventquery(void __user *arg)  /**   * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content   */  static long -_ctl_eventenable(void __user *arg) +_ctl_eventenable(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_ioctl_eventenable karg; -	struct MPT2SAS_ADAPTER *ioc;  	if (copy_from_user(&karg, arg, sizeof(karg))) {  		printk(KERN_ERR "failure at %s:%d/%s()!\n",  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__)); @@ -1135,13 +1129,13 @@ _ctl_eventenable(void __user *arg)  /**   * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content   */  static long -_ctl_eventreport(void __user *arg) +_ctl_eventreport(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_ioctl_eventreport karg; -	struct MPT2SAS_ADAPTER *ioc;  	u32 number_bytes, max_events, max;  	struct mpt2_ioctl_eventreport __user *uarg = arg; @@ -1150,8 +1144,6 @@ _ctl_eventreport(void __user *arg)  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__)); @@ -1181,13 +1173,13 @@ _ctl_eventreport(void __user *arg)  /**   * _ctl_do_reset - main handler for MPT2HARDRESET opcode + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content   */  static long -_ctl_do_reset(void __user *arg) +_ctl_do_reset(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_ioctl_diag_reset karg; -	struct MPT2SAS_ADAPTER *ioc;  	int retval;  	if (copy_from_user(&karg, arg, sizeof(karg))) { @@ -1195,9 +1187,10 @@ _ctl_do_reset(void __user *arg)  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV; +	if (ioc->shost_recovery || ioc->pci_error_recovery || +		ioc->is_driver_loading) +		return -EAGAIN;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,  	    __func__)); @@ -1282,13 +1275,13 @@ _ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc,  /**   * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content   */  static long -_ctl_btdh_mapping(void __user *arg) +_ctl_btdh_mapping(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_ioctl_btdh_mapping karg; -	struct MPT2SAS_ADAPTER *ioc;  	int rc;  	if (copy_from_user(&karg, arg, sizeof(karg))) { @@ -1296,8 +1289,6 @@ _ctl_btdh_mapping(void __user *arg)  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); @@ -1465,8 +1456,8 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,  		mpi_request->ProductSpecific[i] =  			cpu_to_le32(ioc->product_specific[buffer_type][i]); -	mpt2sas_base_put_smid_default(ioc, smid);  	init_completion(&ioc->ctl_cmds.done); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,  	    MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1566,17 +1557,16 @@ mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register)  /**   * _ctl_diag_register - application register with driver + * @ioc: per adapter object   * @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) +_ctl_diag_register(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_diag_register karg; -	struct MPT2SAS_ADAPTER *ioc;  	long rc;  	if (copy_from_user(&karg, arg, sizeof(karg))) { @@ -1584,30 +1574,23 @@ _ctl_diag_register(void __user *arg, enum block_state state)  		    __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;  }  /**   * _ctl_diag_unregister - application unregister with driver + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content   *   * This will allow the driver to cleanup any memory allocated for diag   * messages and to free up any resources.   */  static long -_ctl_diag_unregister(void __user *arg) +_ctl_diag_unregister(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_diag_unregister karg; -	struct MPT2SAS_ADAPTER *ioc;  	void *request_data;  	dma_addr_t request_data_dma;  	u32 request_data_sz; @@ -1618,8 +1601,6 @@ _ctl_diag_unregister(void __user *arg)  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); @@ -1668,6 +1649,7 @@ _ctl_diag_unregister(void __user *arg)  /**   * _ctl_diag_query - query relevant info associated with diag buffers + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content   *   * The application will send only buffer_type and unique_id.  Driver will @@ -1675,10 +1657,9 @@ _ctl_diag_unregister(void __user *arg)   * 0x00, the driver will return info specified by Buffer Type.   */  static long -_ctl_diag_query(void __user *arg) +_ctl_diag_query(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_diag_query karg; -	struct MPT2SAS_ADAPTER *ioc;  	void *request_data;  	int i;  	u8 buffer_type; @@ -1688,8 +1669,6 @@ _ctl_diag_query(void __user *arg)  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); @@ -1809,8 +1788,8 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)  	mpi_request->VF_ID = 0; /* TODO */  	mpi_request->VP_ID = 0; -	mpt2sas_base_put_smid_default(ioc, smid);  	init_completion(&ioc->ctl_cmds.done); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,  	    MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1856,17 +1835,15 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)  /**   * _ctl_diag_release - request to send Diag Release Message to firmware   * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING   *   * This allows ownership of the specified buffer to returned to the driver,   * allowing an application to read the buffer without fear that firmware is   * overwritting information in the buffer.   */  static long -_ctl_diag_release(void __user *arg, enum block_state state) +_ctl_diag_release(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_diag_release karg; -	struct MPT2SAS_ADAPTER *ioc;  	void *request_data;  	int rc;  	u8 buffer_type; @@ -1877,8 +1854,6 @@ _ctl_diag_release(void __user *arg, enum block_state state)  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); @@ -1932,38 +1907,31 @@ _ctl_diag_release(void __user *arg, enum block_state state)  		return 0;  	} -	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_send_release(ioc, buffer_type, &issue_reset);  	if (issue_reset)  		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,  		    FORCE_BIG_HAMMER); -	mutex_unlock(&ioc->ctl_cmds.mutex);  	return rc;  }  /**   * _ctl_diag_read_buffer - request for copy of the diag buffer + * @ioc: per adapter object   * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING   */  static long -_ctl_diag_read_buffer(void __user *arg, enum block_state state) +_ctl_diag_read_buffer(struct MPT2SAS_ADAPTER *ioc, void __user *arg)  {  	struct mpt2_diag_read_buffer karg;  	struct mpt2_diag_read_buffer __user *uarg = arg; -	struct MPT2SAS_ADAPTER *ioc;  	void *request_data, *diag_data;  	Mpi2DiagBufferPostRequest_t *mpi_request;  	Mpi2DiagBufferPostReply_t *mpi_reply;  	int rc, i;  	u8 buffer_type; -	unsigned long timeleft; +	unsigned long timeleft, request_size, copy_size;  	u16 smid;  	u16 ioc_status;  	u8 issue_reset = 0; @@ -1973,8 +1941,6 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  		    __FILE__, __LINE__, __func__);  		return -EFAULT;  	} -	if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV;  	dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,  	    __func__)); @@ -1999,6 +1965,8 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  		return -ENOMEM;  	} +	request_size = ioc->diag_buffer_sz[buffer_type]; +  	if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) {  		printk(MPT2SAS_ERR_FMT "%s: either the starting_offset "  		    "or bytes_to_read are not 4 byte aligned\n", ioc->name, @@ -2006,13 +1974,23 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  		return -EINVAL;  	} +	if (karg.starting_offset > request_size) +		return -EINVAL; +  	diag_data = (void *)(request_data + karg.starting_offset);  	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)); +	/* Truncate data on requests that are too large */ +	if ((diag_data + karg.bytes_to_read < diag_data) || +	    (diag_data + karg.bytes_to_read > request_data + request_size)) +		copy_size = request_size - karg.starting_offset; +	else +		copy_size = karg.bytes_to_read; +  	if (copy_to_user((void __user *)uarg->diagnostic_data, -	    diag_data, karg.bytes_to_read)) { +	    diag_data, copy_size)) {  		printk(MPT2SAS_ERR_FMT "%s: Unable to write "  		    "mpt_diag_read_buffer_t data @ %p\n", ioc->name,  		    __func__, diag_data); @@ -2033,10 +2011,6 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  	}  	/* Get a free request frame and save the message context.  	*/ -	if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) -		return -EAGAIN; -	else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) -		return -ERESTARTSYS;  	if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {  		printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", @@ -2071,8 +2045,8 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  	mpi_request->VF_ID = 0; /* TODO */  	mpi_request->VP_ID = 0; -	mpt2sas_base_put_smid_default(ioc, smid);  	init_completion(&ioc->ctl_cmds.done); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,  	    MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -2117,114 +2091,172 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)   out:  	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->ctl_cmds.mutex);  	return rc;  } + +#ifdef CONFIG_COMPAT +/** + * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. + * @ioc: per adapter object + * @cmd - ioctl opcode + * @arg - (struct mpt2_ioctl_command32) + * + * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. + */ +static long +_ctl_compat_mpt_command(struct MPT2SAS_ADAPTER *ioc, unsigned cmd, +	void __user *arg) +{ +	struct mpt2_ioctl_command32 karg32; +	struct mpt2_ioctl_command32 __user *uarg; +	struct mpt2_ioctl_command karg; + +	if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) +		return -EINVAL; + +	uarg = (struct mpt2_ioctl_command32 __user *) arg; + +	if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { +		printk(KERN_ERR "failure at %s:%d/%s()!\n", +		    __FILE__, __LINE__, __func__); +		return -EFAULT; +	} + +	memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); +	karg.hdr.ioc_number = karg32.hdr.ioc_number; +	karg.hdr.port_number = karg32.hdr.port_number; +	karg.hdr.max_data_size = karg32.hdr.max_data_size; +	karg.timeout = karg32.timeout; +	karg.max_reply_bytes = karg32.max_reply_bytes; +	karg.data_in_size = karg32.data_in_size; +	karg.data_out_size = karg32.data_out_size; +	karg.max_sense_bytes = karg32.max_sense_bytes; +	karg.data_sge_offset = karg32.data_sge_offset; +	karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); +	karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); +	karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); +	karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); +	return _ctl_do_mpt_command(ioc, karg, &uarg->mf); +} +#endif +  /**   * _ctl_ioctl_main - main ioctl entry point   * @file - (struct file)   * @cmd - ioctl opcode   * @arg - + * compat - handles 32 bit applications in 64bit os   */  static long -_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) +_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, +	u8 compat)  { +	struct MPT2SAS_ADAPTER *ioc; +	struct mpt2_ioctl_header ioctl_header;  	enum block_state state;  	long ret = -EINVAL; -	state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : -	    BLOCKING; +	/* get IOCTL header */ +	if (copy_from_user(&ioctl_header, (char __user *)arg, +	    sizeof(struct mpt2_ioctl_header))) { +		printk(KERN_ERR "failure at %s:%d/%s()!\n", +		    __FILE__, __LINE__, __func__); +		return -EFAULT; +	} + +	if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc) +		return -ENODEV; +	if (ioc->shost_recovery || ioc->pci_error_recovery || +	    ioc->is_driver_loading) +		return -EAGAIN; + +	state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; +	if (state == NON_BLOCKING) { +		if (!mutex_trylock(&ioc->ctl_cmds.mutex)) +			return -EAGAIN; +	} else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { +		return -ERESTARTSYS; +	}  	switch (cmd) {  	case MPT2IOCINFO:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo)) -			ret = _ctl_getiocinfo(arg); +			ret = _ctl_getiocinfo(ioc, arg);  		break; +#ifdef CONFIG_COMPAT +	case MPT2COMMAND32: +#endif  	case MPT2COMMAND:  	{ -		struct mpt2_ioctl_command karg;  		struct mpt2_ioctl_command __user *uarg; -		struct MPT2SAS_ADAPTER *ioc; - +		struct mpt2_ioctl_command karg; +#ifdef CONFIG_COMPAT +		if (compat) { +			ret = _ctl_compat_mpt_command(ioc, cmd, arg); +			break; +		} +#endif  		if (copy_from_user(&karg, arg, sizeof(karg))) {  			printk(KERN_ERR "failure at %s:%d/%s()!\n",  			    __FILE__, __LINE__, __func__); -			return -EFAULT; +			ret = -EFAULT; +			break;  		} -		if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || -		    !ioc) -			return -ENODEV; - -		if (ioc->shost_recovery || ioc->pci_error_recovery) -			return -EAGAIN; -  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {  			uarg = arg; -			ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); +			ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);  		}  		break;  	}  	case MPT2EVENTQUERY:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery)) -			ret = _ctl_eventquery(arg); +			ret = _ctl_eventquery(ioc, arg);  		break;  	case MPT2EVENTENABLE:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable)) -			ret = _ctl_eventenable(arg); +			ret = _ctl_eventenable(ioc, arg);  		break;  	case MPT2EVENTREPORT: -		ret = _ctl_eventreport(arg); +		ret = _ctl_eventreport(ioc, arg);  		break;  	case MPT2HARDRESET:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset)) -			ret = _ctl_do_reset(arg); +			ret = _ctl_do_reset(ioc, arg);  		break;  	case MPT2BTDHMAPPING:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping)) -			ret = _ctl_btdh_mapping(arg); +			ret = _ctl_btdh_mapping(ioc, arg);  		break;  	case MPT2DIAGREGISTER:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register)) -			ret = _ctl_diag_register(arg, state); +			ret = _ctl_diag_register(ioc, arg);  		break;  	case MPT2DIAGUNREGISTER:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister)) -			ret = _ctl_diag_unregister(arg); +			ret = _ctl_diag_unregister(ioc, arg);  		break;  	case MPT2DIAGQUERY:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query)) -			ret = _ctl_diag_query(arg); +			ret = _ctl_diag_query(ioc, arg);  		break;  	case MPT2DIAGRELEASE:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release)) -			ret = _ctl_diag_release(arg, state); +			ret = _ctl_diag_release(ioc, arg);  		break;  	case MPT2DIAGREADBUFFER:  		if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer)) -			ret = _ctl_diag_read_buffer(arg, state); +			ret = _ctl_diag_read_buffer(ioc, arg);  		break;  	default: -	{ -		struct mpt2_ioctl_command karg; -		struct MPT2SAS_ADAPTER *ioc; - -		if (copy_from_user(&karg, arg, sizeof(karg))) { -			printk(KERN_ERR "failure at %s:%d/%s()!\n", -			    __FILE__, __LINE__, __func__); -			return -EFAULT; -		} - -		if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || -		    !ioc) -			return -ENODEV;  		dctlprintk(ioc, printk(MPT2SAS_INFO_FMT  		    "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));  		break;  	} -	} + +	mutex_unlock(&ioc->ctl_cmds.mutex);  	return ret;  } @@ -2239,65 +2271,11 @@ _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  {  	long ret; -	mutex_lock(&_ctl_mutex); -	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); -	mutex_unlock(&_ctl_mutex); +	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0);  	return ret;  } -  #ifdef CONFIG_COMPAT  /** - * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. - * @file - (struct file) - * @cmd - ioctl opcode - * @arg - (struct mpt2_ioctl_command32) - * - * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. - */ -static long -_ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) -{ -	struct mpt2_ioctl_command32 karg32; -	struct mpt2_ioctl_command32 __user *uarg; -	struct mpt2_ioctl_command karg; -	struct MPT2SAS_ADAPTER *ioc; -	enum block_state state; - -	if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) -		return -EINVAL; - -	uarg = (struct mpt2_ioctl_command32 __user *) arg; - -	if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { -		printk(KERN_ERR "failure at %s:%d/%s()!\n", -		    __FILE__, __LINE__, __func__); -		return -EFAULT; -	} -	if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc) -		return -ENODEV; - -	if (ioc->shost_recovery || ioc->pci_error_recovery) -		return -EAGAIN; - -	memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); -	karg.hdr.ioc_number = karg32.hdr.ioc_number; -	karg.hdr.port_number = karg32.hdr.port_number; -	karg.hdr.max_data_size = karg32.hdr.max_data_size; -	karg.timeout = karg32.timeout; -	karg.max_reply_bytes = karg32.max_reply_bytes; -	karg.data_in_size = karg32.data_in_size; -	karg.data_out_size = karg32.data_out_size; -	karg.max_sense_bytes = karg32.max_sense_bytes; -	karg.data_sge_offset = karg32.data_sge_offset; -	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); -} - -/**   * _ctl_ioctl_compat - main ioctl entry point (compat)   * @file -   * @cmd - @@ -2310,12 +2288,7 @@ _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)  {  	long ret; -	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); -	mutex_unlock(&_ctl_mutex); +	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1);  	return ret;  }  #endif @@ -2683,14 +2656,110 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,  static DEVICE_ATTR(ioc_reset_count, S_IRUGO,      _ctl_ioc_reset_count_show, NULL); +/** + * _ctl_ioc_reply_queue_count_show - number of reply queues + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is number of reply queues + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_ioc_reply_queue_count_show(struct device *cdev, +	 struct device_attribute *attr, char *buf) +{ +	u8 reply_queue_count; +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	if ((ioc->facts.IOCCapabilities & +	    MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable) +		reply_queue_count = ioc->reply_queue_count; +	else +		reply_queue_count = 1; +	return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); +} +static DEVICE_ATTR(reply_queue_count, S_IRUGO, +	 _ctl_ioc_reply_queue_count_show, NULL); + +/** + * _ctl_BRM_status_show - Backup Rail Monitor Status + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is number of reply queues + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, +	char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(cdev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	Mpi2IOUnitPage3_t *io_unit_pg3 = NULL; +	Mpi2ConfigReply_t mpi_reply; +	u16 backup_rail_monitor_status = 0; +	u16 ioc_status; +	int sz; +	ssize_t rc = 0; + +	if (!ioc->is_warpdrive) { +		printk(MPT2SAS_ERR_FMT "%s: BRM attribute is only for"\ +		    "warpdrive\n", ioc->name, __func__); +		goto out; +	} + +	/* allocate upto GPIOVal 36 entries */ +	sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); +	io_unit_pg3 = kzalloc(sz, GFP_KERNEL); +	if (!io_unit_pg3) { +		printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"\ +		    "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz); +		goto out; +	} + +	if (mpt2sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != +	    0) { +		printk(MPT2SAS_ERR_FMT +		    "%s: failed reading iounit_pg3\n", ioc->name, +		    __func__); +		goto out; +	} + +	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; +	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +		printk(MPT2SAS_ERR_FMT "%s: iounit_pg3 failed with"\ +		    "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status); +		goto out; +	} + +	if (io_unit_pg3->GPIOCount < 25) { +		printk(MPT2SAS_ERR_FMT "%s: iounit_pg3->GPIOCount less than"\ +		     "25 entries, detected (%d) entries\n", ioc->name, __func__, +		    io_unit_pg3->GPIOCount); +		goto out; +	} + +	/* BRM status is in bit zero of GPIOVal[24] */ +	backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]); +	rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1)); + + out: +	kfree(io_unit_pg3); +	return rc; +} +static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); +  struct DIAG_BUFFER_START { -	u32 Size; -	u32 DiagVersion; +	__le32 Size; +	__le32 DiagVersion;  	u8 BufferType;  	u8 Reserved[3]; -	u32 Reserved1; -	u32 Reserved2; -	u32 Reserved3; +	__le32 Reserved1; +	__le32 Reserved2; +	__le32 Reserved3;  };  /**   * _ctl_host_trace_buffer_size_show - host buffer size (trace only) @@ -2833,7 +2902,7 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev,  	struct mpt2_diag_register diag_register;  	u8 issue_reset = 0; -	if (sscanf(buf, "%s", str) != 1) +	if (sscanf(buf, "%9s", str) != 1)  		return -EINVAL;  	if (!strcmp(str, "post")) { @@ -2893,6 +2962,8 @@ struct device_attribute *mpt2sas_host_attrs[] = {  	&dev_attr_host_trace_buffer_size,  	&dev_attr_host_trace_buffer,  	&dev_attr_host_trace_buffer_enable, +	&dev_attr_reply_queue_count, +	&dev_attr_BRM_status,  	NULL,  }; @@ -2947,7 +3018,6 @@ struct device_attribute *mpt2sas_dev_attrs[] = {  static const struct file_operations ctl_fops = {  	.owner = THIS_MODULE,  	.unlocked_ioctl = _ctl_ioctl, -	.release = _ctl_release,  	.poll = _ctl_poll,  	.fasync = _ctl_fasync,  #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 69916e46e04..8b2ac1869dc 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-2010  LSI Corporation + * Copyright (C) 2007-2013  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -133,6 +133,7 @@ struct mpt2_ioctl_pci_info {  #define MPT2_IOCTL_INTERFACE_FC_IP	(0x02)  #define MPT2_IOCTL_INTERFACE_SAS	(0x03)  #define MPT2_IOCTL_INTERFACE_SAS2	(0x04) +#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200	(0x05)  #define MPT2_IOCTL_VERSION_LENGTH	(32)  /** diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h index 3dcddfeb6f4..a9021cbd662 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-2010  LSI Corporation + * Copyright (C) 2007-2013  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -164,7 +164,7 @@ static inline void  _debug_dump_mf(void *mpi_request, int sz)  {  	int i; -	u32 *mfp = (u32 *)mpi_request; +	__le32 *mfp = (__le32 *)mpi_request;  	printk(KERN_INFO "mf:\n\t");  	for (i = 0; i < sz; i++) { diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 16e99b68635..5055f925d2c 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-2010  LSI Corporation + * Copyright (C) 2007-2013  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -41,7 +41,6 @@   * USA.   */ -#include <linux/version.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/init.h> @@ -72,6 +71,9 @@ static void _firmware_event_work(struct work_struct *work);  static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid); +static void _scsih_scan_start(struct Scsi_Host *shost); +static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); +  /* global parameters */  LIST_HEAD(mpt2sas_ioc_list); @@ -80,6 +82,7 @@ static u8 scsi_io_cb_idx = -1;  static u8 tm_cb_idx = -1;  static u8 ctl_cb_idx = -1;  static u8 base_cb_idx = -1; +static u8 port_enable_cb_idx = -1;  static u8 transport_cb_idx = -1;  static u8 scsih_cb_idx = -1;  static u8 config_cb_idx = -1; @@ -94,12 +97,41 @@ static u32 logging_level;  MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "      "(default=0)"); +static ushort max_sectors = 0xFFFF; +module_param(max_sectors, ushort, 0); +MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767  default=32767"); + +static int missing_delay[2] = {-1, -1}; +module_param_array(missing_delay, int, NULL, 0); +MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); +  /* scsi-mid layer global parmeter is max_report_luns, which is 511 */  #define MPT2SAS_MAX_LUN (16895)  static int max_lun = MPT2SAS_MAX_LUN;  module_param(max_lun, int, 0);  MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); +/* diag_buffer_enable is bitwise + * bit 0 set = TRACE + * bit 1 set = SNAPSHOT + * bit 2 set = EXTENDED + * + * Either bit can be set, or both + */ +static int diag_buffer_enable = -1; +module_param(diag_buffer_enable, int, 0); +MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " +	"(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); + +static int disable_discovery = -1; +module_param(disable_discovery, int, 0); +MODULE_PARM_DESC(disable_discovery, " disable discovery "); + +/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ +static int prot_mask = 0; +module_param(prot_mask, int, 0); +MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); +  /**   * struct sense_info - common structure for obtaining sense keys   * @skey: sense key @@ -113,14 +145,16 @@ struct sense_info {  }; -#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF) - +#define MPT2SAS_TURN_ON_FAULT_LED (0xFFFC) +#define MPT2SAS_PORT_ENABLE_COMPLETE (0xFFFD) +#define MPT2SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF)  /**   * struct fw_event_work - firmware event struct   * @list: link list framework   * @work: work object (ioc->fault_reset_work_q)   * @cancel_pending_work: flag set during reset handling   * @ioc: per adapter object + * @device_handle: device handle   * @VF_ID: virtual function id   * @VP_ID: virtual port id   * @ignore: flag meaning this event has been marked to ignore @@ -134,6 +168,7 @@ struct fw_event_work {  	u8			cancel_pending_work;  	struct delayed_work	delayed_work;  	struct MPT2SAS_ADAPTER *ioc; +	u16			device_handle;  	u8			VF_ID;  	u8			VP_ID;  	u8			ignore; @@ -233,6 +268,9 @@ static struct pci_device_id scsih_pci_table[] = {  		PCI_ANY_ID, PCI_ANY_ID },  	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,  		PCI_ANY_ID, PCI_ANY_ID }, +	/* SSS6200 */ +	{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, +		PCI_ANY_ID, PCI_ANY_ID },  	{0}	/* Terminating entry */  };  MODULE_DEVICE_TABLE(pci, scsih_pci_table); @@ -363,31 +401,34 @@ _scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,  	Mpi2SasDevicePage0_t sas_device_pg0;  	Mpi2ConfigReply_t mpi_reply;  	u32 ioc_status; +	*sas_address = 0;  	if (handle <= ioc->sas_hba.num_phys) {  		*sas_address = ioc->sas_hba.sas_address;  		return 0; -	} 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__); +		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; +	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; +	if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { +		*sas_address = le64_to_cpu(sas_device_pg0.SASAddress); +		return 0;  	} -	*sas_address = le64_to_cpu(sas_device_pg0.SASAddress); -	return 0; +	/* we hit this becuase the given parent handle doesn't exist */ +	if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) +		return -ENXIO; +	/* else error case */ +	printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x), " +	    "failure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, +	     __FILE__, __LINE__, __func__); +	return -EIO;  }  /** @@ -397,7 +438,7 @@ _scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,   * @is_raid: [flag] 1 = raid object, 0 = sas object   *   * Determines whether this device should be first reported device to - * to scsi-ml or sas transport, this purpose is for persistant boot device. + * to scsi-ml or sas transport, this purpose is for persistent boot device.   * There are primary, alternate, and current entries in bios page 2. The order   * priority is primary, alternate, then current.  This routine saves   * the corresponding device object and is_raid flag in the ioc object. @@ -415,7 +456,11 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,  	u16 slot;  	 /* only process this function when driver loads */ -	if (!ioc->wait_for_port_enable_to_complete) +	if (!ioc->is_driver_loading) +		return; + +	 /* no Bios, return immediately */ +	if (!ioc->bios_pg3.BiosVersion)  		return;  	if (!is_raid) { @@ -547,14 +592,12 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,  		return;  	spin_lock_irqsave(&ioc->sas_device_lock, flags); -	if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc, -	    sas_device->sas_address)) { -		list_del(&sas_device->list); -		kfree(sas_device); -	} +	list_del(&sas_device->list); +	kfree(sas_device);  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  } +  /**   * _scsih_sas_device_add - insert sas_device to the list.   * @ioc: per adapter object @@ -578,8 +621,20 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  	if (!mpt2sas_transport_port_add(ioc, sas_device->handle, -	     sas_device->sas_address_parent)) +	     sas_device->sas_address_parent)) {  		_scsih_sas_device_remove(ioc, sas_device); +	} else if (!sas_device->starget) { +		/* When asyn scanning is enabled, its not possible to remove +		 * devices while scanning is turned on due to an oops in +		 * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start() +		 */ +		if (!ioc->is_driver_loading) { +			mpt2sas_transport_port_remove(ioc, +			sas_device->sas_address, +			sas_device->sas_address_parent); +			_scsih_sas_device_remove(ioc, sas_device); +		} +	}  }  /** @@ -602,8 +657,8 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	list_add_tail(&sas_device->list, &ioc->sas_device_init_list); -	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  	_scsih_determine_boot_device(ioc, sas_device, 0); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  }  /** @@ -712,7 +767,6 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,   * @ioc: per adapter object   * @raid_device: raid_device object   * - * This is removed from the raid_device_list link list.   */  static void  _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc, @@ -722,7 +776,6 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,  	spin_lock_irqsave(&ioc->raid_device_lock, flags);  	list_del(&raid_device->list); -	memset(raid_device, 0, sizeof(struct _raid_device));  	kfree(raid_device);  	spin_unlock_irqrestore(&ioc->raid_device_lock, flags);  } @@ -819,7 +872,7 @@ _scsih_is_end_device(u32 device_info)  }  /** - * mptscsih_get_scsi_lookup - returns scmd entry + * _scsih_scsi_lookup_get - returns scmd entry   * @ioc: per adapter object   * @smid: system request message index   * @@ -832,6 +885,28 @@ _scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)  }  /** + * _scsih_scsi_lookup_get_clear - returns scmd entry + * @ioc: per adapter object + * @smid: system request message index + * + * Returns the smid stored scmd pointer. + * Then will derefrence the stored scmd pointer. + */ +static inline struct scsi_cmnd * +_scsih_scsi_lookup_get_clear(struct 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_find_by_scmd - scmd lookup   * @ioc: per adapter object   * @smid: system request message index @@ -931,31 +1006,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); +		dfailprintk(ioc, 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;  }  /** @@ -986,6 +1062,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,  	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); @@ -1033,8 +1110,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 : @@ -1070,8 +1150,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); @@ -1094,28 +1177,24 @@ _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 - * @reason: calling context   * - * Returns queue depth. + * + * Returns nothing   */ -static int -_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) +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; -	if (reason != SCSI_QDEPTH_DEFAULT) -		return -EOPNOTSUPP; -  	max_depth = shost->can_queue;  	/* limit max device queue for SATA to 32 */ @@ -1130,10 +1209,10 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)  	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; +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);   not_sata: @@ -1141,8 +1220,27 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)  		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), " @@ -1211,6 +1309,8 @@ _scsih_target_alloc(struct scsi_target *starget)  			sas_target_priv_data->handle = raid_device->handle;  			sas_target_priv_data->sas_address = raid_device->wwid;  			sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; +			if (ioc->is_warpdrive) +				sas_target_priv_data->raid_device = raid_device;  			raid_device->starget = starget;  		}  		spin_unlock_irqrestore(&ioc->raid_device_lock, flags); @@ -1303,6 +1403,7 @@ _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); @@ -1331,6 +1432,19 @@ _scsih_slave_alloc(struct scsi_device *sdev)  		spin_unlock_irqrestore(&ioc->raid_device_lock, flags);  	} +	if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, +				sas_target_priv_data->sas_address); +		if (sas_device && (sas_device->starget == NULL)) { +			sdev_printk(KERN_INFO, sdev, +			     "%s : sas_device->starget set to starget @ %d\n", +			     __func__, __LINE__); +			sas_device->starget = starget; +		} +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	} +  	return 0;  } @@ -1345,6 +1459,10 @@ _scsih_slave_destroy(struct scsi_device *sdev)  {  	struct MPT2SAS_TARGET *sas_target_priv_data;  	struct scsi_target *starget; +	struct Scsi_Host *shost; +	struct MPT2SAS_ADAPTER *ioc; +	struct _sas_device *sas_device; +	unsigned long flags;  	if (!sdev->hostdata)  		return; @@ -1352,6 +1470,19 @@ _scsih_slave_destroy(struct scsi_device *sdev)  	starget = scsi_target(sdev);  	sas_target_priv_data = starget->hostdata;  	sas_target_priv_data->num_luns--; + +	shost = dev_to_shost(&starget->dev); +	ioc = shost_priv(shost); + +	if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, +		   sas_target_priv_data->sas_address); +		if (sas_device && !sas_target_priv_data->num_luns) +			sas_device->starget = NULL; +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	} +  	kfree(sdev->hostdata);  	sdev->hostdata = NULL;  } @@ -1359,12 +1490,12 @@ _scsih_slave_destroy(struct scsi_device *sdev)  /**   * _scsih_display_sata_capabilities - sata capabilities   * @ioc: per adapter object - * @sas_device: the sas_device object + * @handle: device handle   * @sdev: scsi device struct   */  static void  _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, -    struct _sas_device *sas_device, struct scsi_device *sdev) +	u16 handle, struct scsi_device *sdev)  {  	Mpi2ConfigReply_t mpi_reply;  	Mpi2SasDevicePage0_t sas_device_pg0; @@ -1373,7 +1504,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,  	u32 device_info;  	if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, -	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) { +	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__);  		return; @@ -1410,7 +1541,10 @@ static int  _scsih_is_raid(struct device *dev)  {  	struct scsi_device *sdev = to_scsi_device(dev); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); +	if (ioc->is_warpdrive) +		return 0;  	return (sdev->channel == RAID_CHANNEL) ? 1 : 0;  } @@ -1428,27 +1562,40 @@ _scsih_get_resync(struct device *dev)  	Mpi2RaidVolPage0_t vol_pg0;  	Mpi2ConfigReply_t mpi_reply;  	u32 volume_status_flags; -	u8 percent_complete = 0; +	u8 percent_complete; +	u16 handle; + +	percent_complete = 0; +	handle = 0; +	if (ioc->is_warpdrive) +		goto out;  	spin_lock_irqsave(&ioc->raid_device_lock, flags);  	raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,  	    sdev->channel); +	if (raid_device) { +		handle = raid_device->handle; +		percent_complete = raid_device->percent_complete; +	}  	spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -	if (!raid_device) +	if (!handle)  		goto out;  	if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, -	     MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, +	     MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,  	     sizeof(Mpi2RaidVolPage0_t))) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); +		percent_complete = 0;  		goto out;  	}  	volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); -	if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) -		percent_complete = raid_device->percent_complete; +	if (!(volume_status_flags & +	    MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)) +		percent_complete = 0; +   out:  	raid_set_resync(mpt2sas_raid_template, dev, percent_complete);  } @@ -1468,17 +1615,20 @@ _scsih_get_state(struct device *dev)  	Mpi2ConfigReply_t mpi_reply;  	u32 volstate;  	enum raid_state state = RAID_STATE_UNKNOWN; +	u16 handle = 0;  	spin_lock_irqsave(&ioc->raid_device_lock, flags);  	raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,  	    sdev->channel); +	if (raid_device) +		handle = raid_device->handle;  	spin_unlock_irqrestore(&ioc->raid_device_lock, flags);  	if (!raid_device)  		goto out;  	if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, -	     MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, +	     MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,  	     sizeof(Mpi2RaidVolPage0_t))) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); @@ -1511,14 +1661,14 @@ _scsih_get_state(struct device *dev)  /**   * _scsih_set_level - set raid level   * @sdev: scsi device struct - * @raid_device: raid_device object + * @volume_type: volume type   */  static void -_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device) +_scsih_set_level(struct scsi_device *sdev, u8 volume_type)  {  	enum raid_level level = RAID_LEVEL_UNKNOWN; -	switch (raid_device->volume_type) { +	switch (volume_type) {  	case MPI2_RAID_VOL_TYPE_RAID0:  		level = RAID_LEVEL_0;  		break; @@ -1540,8 +1690,10 @@ _scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)   * _scsih_get_volume_capabilities - volume capabilities   * @ioc: per adapter object   * @sas_device: the raid_device object + * + * Returns 0 for success, else 1   */ -static void +static int  _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,      struct _raid_device *raid_device)  { @@ -1554,9 +1706,10 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,  	if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,  	    &num_pds)) || !num_pds) { -		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", -		    ioc->name, __FILE__, __LINE__, __func__); -		return; +		dfailprintk(ioc, printk(MPT2SAS_WARN_FMT +		    "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, +		    __func__)); +		return 1;  	}  	raid_device->num_pds = num_pds; @@ -1564,17 +1717,19 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,  	    sizeof(Mpi2RaidVol0PhysDisk_t));  	vol_pg0 = kzalloc(sz, GFP_KERNEL);  	if (!vol_pg0) { -		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", -		    ioc->name, __FILE__, __LINE__, __func__); -		return; +		dfailprintk(ioc, printk(MPT2SAS_WARN_FMT +		    "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, +		    __func__)); +		return 1;  	}  	if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,  	     MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { -		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", -		    ioc->name, __FILE__, __LINE__, __func__); +		dfailprintk(ioc, printk(MPT2SAS_WARN_FMT +		    "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, +		    __func__));  		kfree(vol_pg0); -		return; +		return 1;  	}  	raid_device->volume_type = vol_pg0->VolumeType; @@ -1594,6 +1749,221 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,  	}  	kfree(vol_pg0); +	return 0; +} +/** + * _scsih_disable_ddio - Disable direct I/O for all the volumes + * @ioc: per adapter object + */ +static void +_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc) +{ +	Mpi2RaidVolPage1_t vol_pg1; +	Mpi2ConfigReply_t mpi_reply; +	struct _raid_device *raid_device; +	u16 handle; +	u16 ioc_status; +	unsigned long flags; + +	handle = 0xFFFF; +	while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, +	    &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { +		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +		    MPI2_IOCSTATUS_MASK; +		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) +			break; +		handle = le16_to_cpu(vol_pg1.DevHandle); +		spin_lock_irqsave(&ioc->raid_device_lock, flags); +		raid_device = _scsih_raid_device_find_by_handle(ioc, handle); +		if (raid_device) +			raid_device->direct_io_enabled = 0; +		spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +	} +	return; +} + + +/** + * _scsih_get_num_volumes - Get number of volumes in the ioc + * @ioc: per adapter object + */ +static u8 +_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc) +{ +	Mpi2RaidVolPage1_t vol_pg1; +	Mpi2ConfigReply_t mpi_reply; +	u16 handle; +	u8 vol_cnt = 0; +	u16 ioc_status; + +	handle = 0xFFFF; +	while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, +	    &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { +		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +		    MPI2_IOCSTATUS_MASK; +		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) +			break; +		vol_cnt++; +		handle = le16_to_cpu(vol_pg1.DevHandle); +	} +	return vol_cnt; +} + + +/** + * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O. + * @ioc: per adapter object + * @raid_device: the raid_device object + */ +static void +_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, +	struct _raid_device *raid_device) +{ +	Mpi2RaidVolPage0_t *vol_pg0; +	Mpi2RaidPhysDiskPage0_t pd_pg0; +	Mpi2ConfigReply_t mpi_reply; +	u16 sz; +	u8 num_pds, count; +	unsigned long stripe_sz, block_sz; +	u8 stripe_exp, block_exp; +	u64 dev_max_lba; + +	if (!ioc->is_warpdrive) +		return; + +	if (ioc->mfg_pg10_hide_flag ==  MFG_PAGE10_EXPOSE_ALL_DISKS) { +		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " +		    "globally as drives are exposed\n", ioc->name); +		return; +	} +	if (_scsih_get_num_volumes(ioc) > 1) { +		_scsih_disable_ddio(ioc); +		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " +		    "globally as number of drives > 1\n", ioc->name); +		return; +	} +	if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, +	    &num_pds)) || !num_pds) { +		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " +		    "Failure in computing number of drives\n", ioc->name); +		return; +	} + +	sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * +	    sizeof(Mpi2RaidVol0PhysDisk_t)); +	vol_pg0 = kzalloc(sz, GFP_KERNEL); +	if (!vol_pg0) { +		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " +		    "Memory allocation failure for RVPG0\n", ioc->name); +		return; +	} + +	if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, +	     MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { +		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " +		    "Failure in retrieving RVPG0\n", ioc->name); +		kfree(vol_pg0); +		return; +	} + +	/* +	 * WARPDRIVE:If number of physical disks in a volume exceeds the max pds +	 * assumed for WARPDRIVE, disable direct I/O +	 */ +	if (num_pds > MPT_MAX_WARPDRIVE_PDS) { +		printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled " +		    "for the drive with handle(0x%04x): num_mem=%d, " +		    "max_mem_allowed=%d\n", ioc->name, raid_device->handle, +		    num_pds, MPT_MAX_WARPDRIVE_PDS); +		kfree(vol_pg0); +		return; +	} +	for (count = 0; count < num_pds; count++) { +		if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, +		    &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, +		    vol_pg0->PhysDisk[count].PhysDiskNum) || +		     le16_to_cpu(pd_pg0.DevHandle) == +		    MPT2SAS_INVALID_DEVICE_HANDLE) { +			printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " +			    "disabled for the drive with handle(0x%04x) member" +			    "handle retrieval failed for member number=%d\n", +			    ioc->name, raid_device->handle, +			    vol_pg0->PhysDisk[count].PhysDiskNum); +			goto out_error; +		} +		/* Disable direct I/O if member drive lba exceeds 4 bytes */ +		dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); +		if (dev_max_lba >> 32) { +			printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " +			    "disabled for the drive with handle(0x%04x) member" +			    "handle (0x%04x) unsupported max lba 0x%016llx\n", +			    ioc->name, raid_device->handle, +			    le16_to_cpu(pd_pg0.DevHandle), +			    (unsigned long long)dev_max_lba); +			goto out_error; +		} + +		raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); +	} + +	/* +	 * Assumption for WD: Direct I/O is not supported if the volume is +	 * not RAID0 +	 */ +	if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { +		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " +		    "for the drive with handle(0x%04x): type=%d, " +		    "s_sz=%uK, blk_size=%u\n", ioc->name, +		    raid_device->handle, raid_device->volume_type, +		    (le32_to_cpu(vol_pg0->StripeSize) * +		    le16_to_cpu(vol_pg0->BlockSize)) / 1024, +		    le16_to_cpu(vol_pg0->BlockSize)); +		goto out_error; +	} + +	stripe_sz = le32_to_cpu(vol_pg0->StripeSize); +	stripe_exp = find_first_bit(&stripe_sz, 32); +	if (stripe_exp == 32) { +		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " +		"for the drive with handle(0x%04x) invalid stripe sz %uK\n", +		    ioc->name, raid_device->handle, +		    (le32_to_cpu(vol_pg0->StripeSize) * +		    le16_to_cpu(vol_pg0->BlockSize)) / 1024); +		goto out_error; +	} +	raid_device->stripe_exponent = stripe_exp; +	block_sz = le16_to_cpu(vol_pg0->BlockSize); +	block_exp = find_first_bit(&block_sz, 16); +	if (block_exp == 16) { +		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " +		    "for the drive with handle(0x%04x) invalid block sz %u\n", +		    ioc->name, raid_device->handle, +		    le16_to_cpu(vol_pg0->BlockSize)); +		goto out_error; +	} +	raid_device->block_exponent = block_exp; +	raid_device->direct_io_enabled = 1; + +	printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive" +	    " with handle(0x%04x)\n", ioc->name, raid_device->handle); +	/* +	 * WARPDRIVE: Though the following fields are not used for direct IO, +	 * stored for future purpose: +	 */ +	raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); +	raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); +	raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); + + +	kfree(vol_pg0); +	return; + +out_error: +	raid_device->direct_io_enabled = 0; +	for (count = 0; count < num_pds; count++) +		raid_device->pd_handle[count] = 0; +	kfree(vol_pg0); +	return;  }  /** @@ -1643,27 +2013,39 @@ _scsih_slave_configure(struct scsi_device *sdev)  	u8 ssp_target = 0;  	char *ds = "";  	char *r_level = ""; +	u16 handle, volume_handle = 0; +	u64 volume_wwid = 0;  	qdepth = 1;  	sas_device_priv_data = sdev->hostdata;  	sas_device_priv_data->configured_lun = 1;  	sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;  	sas_target_priv_data = sas_device_priv_data->sas_target; +	handle = sas_target_priv_data->handle;  	/* raid volume handling */  	if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {  		spin_lock_irqsave(&ioc->raid_device_lock, flags); -		raid_device = _scsih_raid_device_find_by_handle(ioc, -		     sas_target_priv_data->handle); +		raid_device = _scsih_raid_device_find_by_handle(ioc, handle);  		spin_unlock_irqrestore(&ioc->raid_device_lock, flags);  		if (!raid_device) { -			printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", -			    ioc->name, __FILE__, __LINE__, __func__); -			return 0; +			dfailprintk(ioc, printk(MPT2SAS_WARN_FMT +			    "failure at %s:%d/%s()!\n", ioc->name, __FILE__, +			    __LINE__, __func__)); +			return 1;  		} -		_scsih_get_volume_capabilities(ioc, raid_device); +		if (_scsih_get_volume_capabilities(ioc, raid_device)) { +			dfailprintk(ioc, printk(MPT2SAS_WARN_FMT +			    "failure at %s:%d/%s()!\n", ioc->name, __FILE__, +			    __LINE__, __func__)); +			return 1; +		} +		/* +		 * WARPDRIVE: Initialize the required data for Direct IO +		 */ +		_scsih_init_warpdrive_properties(ioc, raid_device);  		/* RAID Queue Depth Support  		 * IS volume = underlying qdepth of drive type, either @@ -1690,7 +2072,7 @@ _scsih_slave_configure(struct scsi_device *sdev)  		case MPI2_RAID_VOL_TYPE_RAID1E:  			qdepth = MPT2SAS_RAID_QUEUE_DEPTH;  			if (ioc->manu_pg10.OEMIdentifier && -			    (ioc->manu_pg10.GenericFlags0 & +			    (le32_to_cpu(ioc->manu_pg10.GenericFlags0) &  			    MFG10_GF0_R10_DISPLAY) &&  			    !(raid_device->num_pds % 2))  				r_level = "RAID10"; @@ -1712,59 +2094,76 @@ _scsih_slave_configure(struct scsi_device *sdev)  			break;  		} -		sdev_printk(KERN_INFO, sdev, "%s: " -		    "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n", -		    r_level, raid_device->handle, -		    (unsigned long long)raid_device->wwid, -		    raid_device->num_pds, ds); +		if (!ioc->hide_ir_msg) +			sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " +			    "wwid(0x%016llx), pd_count(%d), type(%s)\n", +			    r_level, raid_device->handle, +			    (unsigned long long)raid_device->wwid, +			    raid_device->num_pds, ds);  		_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);  		/* raid transport support */ -		_scsih_set_level(sdev, raid_device); +		if (!ioc->is_warpdrive) +			_scsih_set_level(sdev, raid_device->volume_type);  		return 0;  	}  	/* non-raid handling */ +	if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { +		if (mpt2sas_config_get_volume_handle(ioc, handle, +		    &volume_handle)) { +			dfailprintk(ioc, printk(MPT2SAS_WARN_FMT +			    "failure at %s:%d/%s()!\n", ioc->name, +			    __FILE__, __LINE__, __func__)); +			return 1; +		} +		if (volume_handle && mpt2sas_config_get_volume_wwid(ioc, +		    volume_handle, &volume_wwid)) { +			dfailprintk(ioc, printk(MPT2SAS_WARN_FMT +			    "failure at %s:%d/%s()!\n", ioc->name, +			    __FILE__, __LINE__, __func__)); +			return 1; +		} +	} +  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = mpt2sas_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) { -		if (sas_target_priv_data->flags & -		    MPT_TARGET_FLAGS_RAID_COMPONENT) { -			mpt2sas_config_get_volume_handle(ioc, -			    sas_device->handle, &sas_device->volume_handle); -			mpt2sas_config_get_volume_wwid(ioc, -			    sas_device->volume_handle, -			    &sas_device->volume_wwid); -		} -		if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { -			qdepth = MPT2SAS_SAS_QUEUE_DEPTH; -			ssp_target = 1; -			ds = "SSP"; -		} else { -			qdepth = MPT2SAS_SATA_QUEUE_DEPTH; -			if (sas_device->device_info & -			    MPI2_SAS_DEVICE_INFO_STP_TARGET) -				ds = "STP"; -			else if (sas_device->device_info & -			    MPI2_SAS_DEVICE_INFO_SATA_DEVICE) -				ds = "SATA"; -		} +	if (!sas_device) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		dfailprintk(ioc, printk(MPT2SAS_WARN_FMT +			"failure at %s:%d/%s()!\n", ioc->name, __FILE__, +			__LINE__, __func__)); +		return 1; +	} +	sas_device->volume_handle = volume_handle; +	sas_device->volume_wwid = volume_wwid; +	if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { +		qdepth = MPT2SAS_SAS_QUEUE_DEPTH; +		ssp_target = 1; +		ds = "SSP"; +	} else { +		qdepth = MPT2SAS_SATA_QUEUE_DEPTH; +		if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) +			ds = "STP"; +		else if (sas_device->device_info & +		    MPI2_SAS_DEVICE_INFO_SATA_DEVICE) +			ds = "SATA"; +	} +	sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " +	    "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", +	    ds, 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, +	    (unsigned long long) sas_device->enclosure_logical_id, +	    sas_device->slot); -		sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " -		    "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, -		    (unsigned long long) sas_device->enclosure_logical_id, -		    sas_device->slot); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	if (!ssp_target) +		_scsih_display_sata_capabilities(ioc, handle, sdev); -		if (!ssp_target) -			_scsih_display_sata_capabilities(ioc, sas_device, sdev); -	}  	_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); @@ -1890,6 +2289,7 @@ _scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  		return 1;  	if (ioc->tm_cmds.smid != smid)  		return 1; +	mpt2sas_base_flush_reply_queues(ioc);  	ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;  	mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);  	if (mpi_reply) { @@ -1968,6 +2368,7 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)   * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)   * @smid_task: smid assigned to the task   * @timeout: timeout in seconds + * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF   * Context: user   *   * A generic API for sending task management requests to firmware. @@ -1979,17 +2380,18 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)  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) +	enum mutex_type m_type)  {  	Mpi2SCSITaskManagementRequest_t *mpi_request;  	Mpi2SCSITaskManagementReply_t *mpi_reply;  	u16 smid = 0;  	u32 ioc_state;  	unsigned long timeleft; -	struct scsi_cmnd *scmd_lookup; +	struct scsiio_tracker *scsi_lookup = NULL;  	int rc; -	mutex_lock(&ioc->tm_cmds.mutex); +	if (m_type == TM_MUTEX_ON) +		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); @@ -2009,18 +2411,18 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,  	if (ioc_state & MPI2_DOORBELL_USED) {  		dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "  		    "active!\n", ioc->name)); -		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +		rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,  		    FORCE_BIG_HAMMER); -		rc = SUCCESS; +		rc = (!rc) ? SUCCESS : FAILED;  		goto err_out;  	}  	if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {  		mpt2sas_base_fault_info(ioc, ioc_state &  		    MPI2_DOORBELL_DATA_MASK); -		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +		rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,  		    FORCE_BIG_HAMMER); -		rc = SUCCESS; +		rc = (!rc) ? SUCCESS : FAILED;  		goto err_out;  	} @@ -2032,6 +2434,9 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,  		goto err_out;  	} +	if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) +		scsi_lookup = &ioc->scsi_lookup[smid_task - 1]; +  	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"  	    " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,  	    smid_task)); @@ -2039,6 +2444,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);  	ioc->tm_cmds.smid = smid;  	memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); +	memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t));  	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;  	mpi_request->DevHandle = cpu_to_le16(handle);  	mpi_request->TaskType = type; @@ -2054,9 +2460,9 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,  		_debug_dump_mf(mpi_request,  		    sizeof(Mpi2SCSITaskManagementRequest_t)/4);  		if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { -			mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, +			rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,  			    FORCE_BIG_HAMMER); -			rc = SUCCESS; +			rc = (!rc) ? SUCCESS : FAILED;  			ioc->tm_cmds.status = MPT2_CMD_NOT_USED;  			mpt2sas_scsih_clear_tm_flag(ioc, handle);  			goto err_out; @@ -2078,21 +2484,12 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,  		}  	} -	/* 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; +		rc = SUCCESS; +		if (scsi_lookup->scmd == NULL) +			break; +		rc = FAILED;  		break;  	case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: @@ -2102,24 +2499,31 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,  			rc = SUCCESS;  		break; +	case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:  	case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:  		if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))  			rc = FAILED;  		else  			rc = SUCCESS;  		break; +	case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: +		rc = SUCCESS; +		break; +	default: +		rc = FAILED; +		break;  	} - bypass_sanity_checks: -  	mpt2sas_scsih_clear_tm_flag(ioc, handle);  	ioc->tm_cmds.status = MPT2_CMD_NOT_USED; -	mutex_unlock(&ioc->tm_cmds.mutex); +	if (m_type == TM_MUTEX_ON) +		mutex_unlock(&ioc->tm_cmds.mutex);  	return rc;   err_out: -	mutex_unlock(&ioc->tm_cmds.mutex); +	if (m_type == TM_MUTEX_ON) +		mutex_unlock(&ioc->tm_cmds.mutex);  	return rc;  } @@ -2137,16 +2541,20 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)  	struct MPT2SAS_TARGET *priv_target = starget->hostdata;  	struct _sas_device *sas_device = NULL;  	unsigned long flags; +	char *device_str = NULL;  	if (!priv_target)  		return; +	if (ioc->hide_ir_msg) +		device_str = "WarpDrive"; +	else +		device_str = "volume";  	scsi_print_command(scmd);  	if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { -		starget_printk(KERN_INFO, starget, "volume handle(0x%04x), " -		    "volume wwid(0x%016llx)\n", -		    priv_target->handle, -		    (unsigned long long)priv_target->sas_address); +		starget_printk(KERN_INFO, starget, "%s handle(0x%04x), " +		    "%s wwid(0x%016llx)\n", device_str, priv_target->handle, +		    device_str, (unsigned long long)priv_target->sas_address);  	} else {  		spin_lock_irqsave(&ioc->sas_device_lock, flags);  		sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, @@ -2225,7 +2633,7 @@ _scsih_abort(struct scsi_cmnd *scmd)  	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); +	    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, TM_MUTEX_ON);   out:  	sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", @@ -2251,13 +2659,13 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)  	struct scsi_target *starget = scmd->device->sdev_target; -	starget_printk(KERN_INFO, starget, "attempting target reset! " +	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) { -		starget_printk(KERN_INFO, starget, "target been deleted! " +		starget_printk(KERN_INFO, starget, "device been deleted! "  		    "scmd(%p)\n", scmd);  		scmd->result = DID_NO_CONNECT << 16;  		scmd->scsi_done(scmd); @@ -2286,7 +2694,7 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)  	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); +	    MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, TM_MUTEX_ON);   out:  	sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", @@ -2346,7 +2754,7 @@ _scsih_target_reset(struct scsi_cmnd *scmd)  	r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,  	    scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, -	    30, scmd); +	    30, TM_MUTEX_ON);   out:  	starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", @@ -2431,22 +2839,43 @@ _scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work  /** - * _scsih_queue_rescan - queue a topology rescan from user context + * _scsih_error_recovery_delete_devices - remove devices not responding   * @ioc: per adapter object   *   * Return nothing.   */  static void -_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc) +_scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc)  {  	struct fw_event_work *fw_event; -	if (ioc->wait_for_port_enable_to_complete) +	if (ioc->is_driver_loading)  		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->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES; +	fw_event->ioc = ioc; +	_scsih_fw_event_add(ioc, fw_event); +} + +/** + * mpt2sas_port_enable_complete - port enable completed (fake event) + * @ioc: per adapter object + * + * Return nothing. + */ +void +mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc) +{ +	struct fw_event_work *fw_event; + +	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) +		return; +	fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE;  	fw_event->ioc = ioc;  	_scsih_fw_event_add(ioc, fw_event);  } @@ -2479,6 +2908,31 @@ _scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)  }  /** + * _scsih_ublock_io_all_device - unblock every device + * @ioc: per adapter object + * + * change the device state from block to running + */ +static void +_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc) +{ +	struct MPT2SAS_DEVICE *sas_device_priv_data; +	struct scsi_device *sdev; + +	shost_for_each_device(sdev, ioc->shost) { +		sas_device_priv_data = sdev->hostdata; +		if (!sas_device_priv_data) +			continue; +		if (!sas_device_priv_data->block) +			continue; +		sas_device_priv_data->block = 0; +		dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, " +		    "handle(0x%04x)\n", +		    sas_device_priv_data->sas_target->handle)); +		scsi_internal_device_unblock(sdev, SDEV_RUNNING); +	} +} +/**   * _scsih_ublock_io_device - set the device state to SDEV_RUNNING   * @ioc: per adapter object   * @handle: device handle @@ -2486,7 +2940,7 @@ _scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)   * During device pull we need to appropiately set the sdev state.   */  static void -_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) +_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)  {  	struct MPT2SAS_DEVICE *sas_device_priv_data;  	struct scsi_device *sdev; @@ -2497,17 +2951,47 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)  			continue;  		if (!sas_device_priv_data->block)  			continue; -		if (sas_device_priv_data->sas_target->handle == handle) { +		if (sas_device_priv_data->sas_target->sas_address == +								sas_address) {  			dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,  			    MPT2SAS_INFO_FMT "SDEV_RUNNING: " -			    "handle(0x%04x)\n", ioc->name, handle)); +			    "sas address(0x%016llx)\n", ioc->name, +				(unsigned long long)sas_address));  			sas_device_priv_data->block = 0; -			scsi_internal_device_unblock(sdev); +			scsi_internal_device_unblock(sdev, SDEV_RUNNING);  		}  	}  }  /** + * _scsih_block_io_all_device - set the device state to SDEV_BLOCK + * @ioc: per adapter object + * @handle: device handle + * + * During device pull we need to appropiately set the sdev state. + */ +static void +_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc) +{ +	struct MPT2SAS_DEVICE *sas_device_priv_data; +	struct scsi_device *sdev; + +	shost_for_each_device(sdev, ioc->shost) { +		sas_device_priv_data = sdev->hostdata; +		if (!sas_device_priv_data) +			continue; +		if (sas_device_priv_data->block) +			continue; +		sas_device_priv_data->block = 1; +		dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, " +		    "handle(0x%04x)\n", +		    sas_device_priv_data->sas_target->handle)); +		scsi_internal_device_block(sdev); +	} +} + + +/**   * _scsih_block_io_device - set the device state to SDEV_BLOCK   * @ioc: per adapter object   * @handle: device handle @@ -2565,10 +3049,10 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,  			sas_device =  			    mpt2sas_scsih_sas_device_find_by_sas_address(ioc,  			   mpt2sas_port->remote_identify.sas_address); +			if (sas_device) +				set_bit(sas_device->handle, +				    ioc->blocking_handles);  			spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -			if (!sas_device) -				continue; -			_scsih_block_io_device(ioc, sas_device->handle);  		}  	} @@ -2576,15 +3060,12 @@ _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) { - -			spin_lock_irqsave(&ioc->sas_node_lock, flags); +		    SAS_FANOUT_EXPANDER_DEVICE) {  			expander_sibling =  			    mpt2sas_scsih_expander_find_by_sas_address(  			    ioc, mpt2sas_port->remote_identify.sas_address); -			spin_unlock_irqrestore(&ioc->sas_node_lock, flags);  			_scsih_block_io_to_children_attached_to_ex(ioc,  			    expander_sibling);  		} @@ -2626,10 +3107,10 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,   * @handle: device handle   * Context: interrupt time.   * - * This code is to initiate the device removal handshake protocal + * This code is to initiate the device removal handshake protocol   * with controller firmware.  This function will issue target reset   * using high priority request queue.  It will send a sas iounit - * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. + * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.   *   * This is designed to send muliple task management request at the same   * time to the fifo. If the fifo is full, we will append the request, @@ -2641,14 +3122,27 @@ _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; +	struct MPT2SAS_TARGET *sas_target_priv_data = NULL; +	u64 sas_address = 0;  	unsigned long flags;  	struct _tr_list *delayed_tr; +	u32 ioc_state; -	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)); +	if (ioc->remove_host) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " +		    "removed: handle(0x%04x)\n", __func__, ioc->name, handle)); +		return; +	} else if (ioc->pci_error_recovery) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " +		    "error recovery: handle(0x%04x)\n", __func__, ioc->name, +		    handle)); +		return; +	} +	ioc_state = mpt2sas_base_get_iocstate(ioc, 1); +	if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " +		   "operational: handle(0x%04x)\n", __func__, ioc->name, +		   handle));  		return;  	} @@ -2662,13 +3156,18 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	     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)); +		sas_address = sas_device->sas_address;  	}  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	if (sas_target_priv_data) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: " +		"handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle, +			(unsigned long long)sas_address)); +		_scsih_ublock_io_device(ioc, sas_address); +		sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; +	} +  	smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);  	if (!smid) {  		delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); @@ -2704,9 +3203,9 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)   * @reply: reply message frame(lower 32bit addr)   * Context: interrupt time.   * - * This is the sas iounit controll completion routine. + * This is the sas iounit control completion routine.   * This code is part of the code to initiate the device removal - * handshake protocal with controller firmware. + * handshake protocol with controller firmware.   *   * Return 1 meaning mf should be freed from _base_interrupt   *        0 means the mf is freed from this function. @@ -2717,13 +3216,17 @@ _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,  {  	Mpi2SasIoUnitControlReply_t *mpi_reply =  	    mpt2sas_base_get_reply_virt_addr(ioc, reply); - -	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))); +	if (likely(mpi_reply)) { +		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))); +	} else { +		printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +	}  	return 1;  } @@ -2802,7 +3305,11 @@ _scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,  		   "progress!\n", __func__, ioc->name));  		return 1;  	} - +	if (unlikely(!mpi_reply)) { +		printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		return 1; +	}  	mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);  	handle = le16_to_cpu(mpi_request_tm->DevHandle);  	if (handle != le16_to_cpu(mpi_reply->DevHandle)) { @@ -2832,8 +3339,8 @@ _scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,   *   * 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) + * handshake protocol with controller firmware. + * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE)   *   * Return 1 meaning mf should be freed from _base_interrupt   *        0 means the mf is freed from this function. @@ -2848,14 +3355,28 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,  	    mpt2sas_base_get_reply_virt_addr(ioc, reply);  	Mpi2SasIoUnitControlRequest_t *mpi_request;  	u16 smid_sas_ctrl; +	u32 ioc_state; -	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)); +	if (ioc->remove_host) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " +		   "removed\n", __func__, ioc->name)); +		return 1; +	} else if (ioc->pci_error_recovery) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " +		    "error recovery\n", __func__, ioc->name)); +		return 1; +	} +	ioc_state = mpt2sas_base_get_iocstate(ioc, 1); +	if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " +		    "operational\n", __func__, ioc->name)); +		return 1; +	} +	if (unlikely(!mpi_reply)) { +		printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__);  		return 1;  	} -  	mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);  	handle = le16_to_cpu(mpi_request_tm->DevHandle);  	if (handle != le16_to_cpu(mpi_reply->DevHandle)) { @@ -2938,7 +3459,7 @@ _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid)   *   * This routine added to better handle cable breaker.   * - * This handles the case where driver recieves multiple expander + * This handles the case where driver receives multiple expander   * add and delete events in a single shot.  When there is a delete event   * the routine will void any pending add events waiting in the event queue.   * @@ -2957,9 +3478,6 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,  	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; @@ -2974,14 +3492,20 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,  		_scsih_block_io_to_children_attached_directly(ioc, event_data);  		return;  	} - -	if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING -	 || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) { +	if (event_data->ExpStatus == +	    MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) { +		/* put expander attached devices into blocking state */  		spin_lock_irqsave(&ioc->sas_node_lock, flags);  		sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,  		    expander_handle); -		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);  		_scsih_block_io_to_children_attached_to_ex(ioc, sas_expander); +		spin_unlock_irqrestore(&ioc->sas_node_lock, flags); +		do { +			handle = find_first_bit(ioc->blocking_handles, +			    ioc->facts.MaxDevHandle); +			if (handle < ioc->facts.MaxDevHandle) +				_scsih_block_io_device(ioc, handle); +		} while (test_and_clear_bit(handle, ioc->blocking_handles));  	} else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)  		_scsih_block_io_to_children_attached_directly(ioc, event_data); @@ -3087,6 +3611,9 @@ _scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,  	a = 0;  	b = 0; +	if (ioc->is_warpdrive) +		return; +  	/* Volume Resets for Deleted or Removed */  	element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];  	for (i = 0; i < event_data->NumElements; i++, element++) { @@ -3186,7 +3713,7 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)  	u16 count = 0;  	for (smid = 1; smid <= ioc->scsiio_depth; smid++) { -		scmd = _scsih_scsi_lookup_get(ioc, smid); +		scmd = _scsih_scsi_lookup_get_clear(ioc, smid);  		if (!scmd)  			continue;  		count++; @@ -3230,6 +3757,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)  	switch (prot_type) {  	case SCSI_PROT_DIF_TYPE1: +	case SCSI_PROT_DIF_TYPE2:  		/*  		* enable ref/guard checking @@ -3242,13 +3770,6 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)  		    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:  		/* @@ -3272,8 +3793,6 @@ static void  _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)  {  	u8 ascq; -	u8 sk; -	u8 host_byte;  	switch (ioc_status) {  	case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: @@ -3290,20 +3809,136 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)  		break;  	} -	if (scmd->sc_data_direction == DMA_TO_DEVICE) { -		sk = ILLEGAL_REQUEST; -		host_byte = DID_ABORT; -	} else { -		sk = ABORTED_COMMAND; -		host_byte = DID_OK; -	} - -	scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq); -	scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) | +	scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x10, ascq); +	scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) |  	    SAM_STAT_CHECK_CONDITION;  }  /** + * _scsih_scsi_direct_io_get - returns direct io flag + * @ioc: per adapter object + * @smid: system request message index + * + * Returns the smid stored scmd pointer. + */ +static inline u8 +_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ +	return ioc->scsi_lookup[smid - 1].direct_io; +} + +/** + * _scsih_scsi_direct_io_set - sets direct io flag + * @ioc: per adapter object + * @smid: system request message index + * @direct_io: Zero or non-zero value to set in the direct_io flag + * + * Returns Nothing. + */ +static inline void +_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io) +{ +	ioc->scsi_lookup[smid - 1].direct_io = direct_io; +} + + +/** + * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O + * @ioc: per adapter object + * @scmd: pointer to scsi command object + * @raid_device: pointer to raid device data structure + * @mpi_request: pointer to the SCSI_IO reqest message frame + * @smid: system request message index + * + * Returns nothing + */ +static void +_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, +	struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, +	u16 smid) +{ +	u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size; +	u32 stripe_sz, stripe_exp; +	u8 num_pds, *cdb_ptr, i; +	u8 cdb0 = scmd->cmnd[0]; +	u64 v_llba; + +	/* +	 * Try Direct I/O to RAID memeber disks +	 */ +	if (cdb0 == READ_16 || cdb0 == READ_10 || +	    cdb0 == WRITE_16 || cdb0 == WRITE_10) { +		cdb_ptr = mpi_request->CDB.CDB32; + +		if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4] +			| cdb_ptr[5])) { +			io_size = scsi_bufflen(scmd) >> +			    raid_device->block_exponent; +			i = (cdb0 < READ_16) ? 2 : 6; +			/* get virtual lba */ +			v_lba = be32_to_cpu(*(__be32 *)(&cdb_ptr[i])); + +			if (((u64)v_lba + (u64)io_size - 1) <= +			    (u32)raid_device->max_lba) { +				stripe_sz = raid_device->stripe_sz; +				stripe_exp = raid_device->stripe_exponent; +				stripe_off = v_lba & (stripe_sz - 1); + +				/* Check whether IO falls within a stripe */ +				if ((stripe_off + io_size) <= stripe_sz) { +					num_pds = raid_device->num_pds; +					p_lba = v_lba >> stripe_exp; +					stripe_unit = p_lba / num_pds; +					column = p_lba % num_pds; +					p_lba = (stripe_unit << stripe_exp) + +					    stripe_off; +					mpi_request->DevHandle = +						cpu_to_le16(raid_device-> +						    pd_handle[column]); +					(*(__be32 *)(&cdb_ptr[i])) = +						cpu_to_be32(p_lba); +					/* +					* WD: To indicate this I/O is directI/O +					*/ +					_scsih_scsi_direct_io_set(ioc, smid, 1); +				} +			} +		} else { +			io_size = scsi_bufflen(scmd) >> +			    raid_device->block_exponent; +			/* get virtual lba */ +			v_llba = be64_to_cpu(*(__be64 *)(&cdb_ptr[2])); + +			if ((v_llba + (u64)io_size - 1) <= +			    raid_device->max_lba) { +				stripe_sz = raid_device->stripe_sz; +				stripe_exp = raid_device->stripe_exponent; +				stripe_off = (u32) (v_llba & (stripe_sz - 1)); + +				/* Check whether IO falls within a stripe */ +				if ((stripe_off + io_size) <= stripe_sz) { +					num_pds = raid_device->num_pds; +					p_lba = (u32)(v_llba >> stripe_exp); +					stripe_unit = p_lba / num_pds; +					column = p_lba % num_pds; +					p_lba = (stripe_unit << stripe_exp) + +					    stripe_off; +					mpi_request->DevHandle = +						cpu_to_le16(raid_device-> +						    pd_handle[column]); +					(*(__be64 *)(&cdb_ptr[2])) = +					    cpu_to_be64((u64)p_lba); +					/* +					* WD: To indicate this I/O is directI/O +					*/ +					_scsih_scsi_direct_io_set(ioc, smid, 1); +				} +			} +		} +	} +} + +/**   * _scsih_qcmd - main scsi request entry point   * @scmd: pointer to scsi command object   * @done: function pointer to be invoked on completion @@ -3315,16 +3950,16 @@ _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(struct Scsi_Host *shost, struct scsi_cmnd *scmd)  { -	struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);  	struct MPT2SAS_DEVICE *sas_device_priv_data;  	struct MPT2SAS_TARGET *sas_target_priv_data; +	struct _raid_device *raid_device;  	Mpi2SCSIIORequest_t *mpi_request;  	u32 mpi_control;  	u16 smid; -	scmd->scsi_done = done;  	sas_device_priv_data = scmd->device->hostdata;  	if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {  		scmd->result = DID_NO_CONNECT << 16; @@ -3332,7 +3967,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  		return 0;  	} -	if (ioc->pci_error_recovery) { +	if (ioc->pci_error_recovery || ioc->remove_host) {  		scmd->result = DID_NO_CONNECT << 16;  		scmd->scsi_done(scmd);  		return 0; @@ -3374,15 +4009,13 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  			else  				mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;  		} else -/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */ -/*			mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED; - */ -			mpi_control |= (0x500); - +			mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;  	} else  		mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; -	/* Make sure Device is not raid volume */ -	if (!_scsih_is_raid(&scmd->device->sdev_gendev) && +	/* Make sure Device is not raid volume. +	 * We do not expose raid functionality to upper layer for warpdrive. +	 */ +	if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&  	    sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)  		mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; @@ -3402,7 +4035,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  	    MPT_TARGET_FLAGS_RAID_COMPONENT)  		mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;  	else -		mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; +	mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;  	mpi_request->DevHandle =  	    cpu_to_le16(sas_device_priv_data->sas_target->handle);  	mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); @@ -3430,9 +4063,14 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  		}  	} +	raid_device = sas_target_priv_data->raid_device; +	if (raid_device && raid_device->direct_io_enabled) +		_scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request, +		    smid); +  	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); +		    le16_to_cpu(mpi_request->DevHandle));  	else  		mpt2sas_base_put_smid_default(ioc, smid);  	return 0; @@ -3466,7 +4104,7 @@ _scsih_normalize_sense(char *sense_buffer, struct sense_info *data)  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  /** - * _scsih_scsi_ioc_info - translated non-successfull SCSI_IO request + * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request   * @ioc: per adapter object   * @scmd: pointer to scsi command object   * @mpi_reply: reply mf payload returned from firmware @@ -3495,10 +4133,16 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,  	unsigned long flags;  	struct scsi_target *starget = scmd->device->sdev_target;  	struct MPT2SAS_TARGET *priv_target = starget->hostdata; +	char *device_str = NULL;  	if (!priv_target)  		return; +	if (ioc->hide_ir_msg) +		device_str = "WarpDrive"; +	else +		device_str = "volume"; +  	if (log_info == 0x31170000)  		return; @@ -3615,8 +4259,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,  	scsi_print_command(scmd);  	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); +		printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name, +		    device_str, (unsigned long long)priv_target->sas_address);  	} else {  		spin_lock_irqsave(&ioc->sas_device_lock, flags);  		sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, @@ -3663,17 +4307,75 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,  #endif  /** - * _scsih_smart_predicted_fault - illuminate Fault LED + * _scsih_turn_on_fault_led - illuminate Fault LED   * @ioc: per adapter object   * @handle: device handle + * Context: process   *   * Return nothing.   */  static void -_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) +_scsih_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)  {  	Mpi2SepReply_t mpi_reply;  	Mpi2SepRequest_t mpi_request; + +	memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); +	mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; +	mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; +	mpi_request.SlotStatus = +	    cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); +	mpi_request.DevHandle = cpu_to_le16(handle); +	mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; +	if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, +	    &mpi_request)) != 0) { +		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, +		__FILE__, __LINE__, __func__); +		return; +	} + +	if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: " +		    "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name, +		    le16_to_cpu(mpi_reply.IOCStatus), +		    le32_to_cpu(mpi_reply.IOCLogInfo))); +		return; +	} +} + +/** + * _scsih_send_event_to_turn_on_fault_led - fire delayed event + * @ioc: per adapter object + * @handle: device handle + * Context: interrupt. + * + * Return nothing. + */ +static void +_scsih_send_event_to_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ +	struct fw_event_work *fw_event; + +	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); +	if (!fw_event) +		return; +	fw_event->event = MPT2SAS_TURN_ON_FAULT_LED; +	fw_event->device_handle = handle; +	fw_event->ioc = ioc; +	_scsih_fw_event_add(ioc, fw_event); +} + +/** + * _scsih_smart_predicted_fault - process smart errors + * @ioc: per adapter object + * @handle: device handle + * Context: interrupt. + * + * Return nothing. + */ +static void +_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{  	struct scsi_target *starget;  	struct MPT2SAS_TARGET *sas_target_priv_data;  	Mpi2EventNotificationReply_t *event_reply; @@ -3700,35 +4402,13 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	starget_printk(KERN_WARNING, starget, "predicted fault\n");  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -	if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) { -		memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); -		mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; -		mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; -		mpi_request.SlotStatus = -		    cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); -		mpi_request.DevHandle = cpu_to_le16(handle); -		mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; -		if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, -		    &mpi_request)) != 0) { -			printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", -			    ioc->name, __FILE__, __LINE__, __func__); -			return; -		} - -		if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { -			dewtprintk(ioc, printk(MPT2SAS_INFO_FMT -			    "enclosure_processor: ioc_status (0x%04x), " -			    "loginfo(0x%08x)\n", ioc->name, -			    le16_to_cpu(mpi_reply.IOCStatus), -			    le32_to_cpu(mpi_reply.IOCLogInfo))); -			return; -		} -	} +	if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) +		_scsih_send_event_to_turn_on_fault_led(ioc, handle);  	/* insert into event log */  	sz = offsetof(Mpi2EventNotificationReply_t, EventData) +  	     sizeof(Mpi2EventDataSasDeviceStatusChange_t); -	event_reply = kzalloc(sz, GFP_KERNEL); +	event_reply = kzalloc(sz, GFP_ATOMIC);  	if (!event_reply) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); @@ -3776,9 +4456,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  	u32 log_info;  	struct MPT2SAS_DEVICE *sas_device_priv_data;  	u32 response_code = 0; +	unsigned long flags;  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -	scmd = _scsih_scsi_lookup_get(ioc, smid); +	scmd = _scsih_scsi_lookup_get_clear(ioc, smid);  	if (scmd == NULL)  		return 1; @@ -3795,6 +4476,26 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  		scmd->result = DID_NO_CONNECT << 16;  		goto out;  	} +	ioc_status = le16_to_cpu(mpi_reply->IOCStatus); +	/* +	 * WARPDRIVE: If direct_io is set then it is directIO, +	 * the failed direct I/O should be redirected to volume +	 */ +	if (_scsih_scsi_direct_io_get(ioc, smid) && +	    ((ioc_status & MPI2_IOCSTATUS_MASK) +	    != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { +		spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); +		ioc->scsi_lookup[smid - 1].scmd = scmd; +		_scsih_scsi_direct_io_set(ioc, smid, 0); +		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +		memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); +		mpi_request->DevHandle = +		    cpu_to_le16(sas_device_priv_data->sas_target->handle); +		mpt2sas_base_put_smid_scsi_io(ioc, smid, +		    sas_device_priv_data->sas_target->handle); +		return 0; +	} +  	/* turning off TLR */  	scsi_state = mpi_reply->SCSIState; @@ -3803,7 +4504,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  		    le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;  	if (!sas_device_priv_data->tlr_snoop_check) {  		sas_device_priv_data->tlr_snoop_check++; -	if (!_scsih_is_raid(&scmd->device->sdev_gendev) && +	/* Make sure Device is not raid volume. +	 * We do not expose raid functionality to upper layer for warpdrive. +	 */ +	if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&  		sas_is_tlr_enabled(scmd->device) &&  		    response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {  			sas_disable_tlr(scmd->device); @@ -3813,7 +4517,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  	xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);  	scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); -	ioc_status = le16_to_cpu(mpi_reply->IOCStatus);  	if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)  		log_info =  le32_to_cpu(mpi_reply->IOCLogInfo);  	else @@ -3857,6 +4560,8 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  			scmd->result = DID_TRANSPORT_DISRUPTED << 16;  			goto out;  		} +		scmd->result = DID_SOFT_ERROR << 16; +		break;  	case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:  	case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:  		scmd->result = DID_RESET << 16; @@ -3961,6 +4666,7 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)  	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", @@ -3982,15 +4688,17 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)  	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, sas_iounit_pg0->PhyData[i]. -		    NegotiatedLinkRate >> 4); +		    attached_handle, i, link_rate);  	}   out:  	kfree(sas_iounit_pg0); @@ -4161,7 +4869,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	Mpi2SasEnclosurePage0_t enclosure_pg0;  	u32 ioc_status;  	u16 parent_handle; -	__le64 sas_address, sas_address_parent = 0; +	u64 sas_address, sas_address_parent = 0;  	int i;  	unsigned long flags;  	struct _sas_port *mpt2sas_port = NULL; @@ -4334,14 +5042,14 @@ _scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  }  /** - * _scsih_expander_remove - removing expander object + * 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, u64 sas_address) +void +mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)  {  	struct _sas_node *sas_expander;  	unsigned long flags; @@ -4352,8 +5060,11 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)  	spin_lock_irqsave(&ioc->sas_node_lock, flags);  	sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,  	    sas_address); +	if (sas_expander) +		list_del(&sas_expander->list);  	spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -	_scsih_expander_node_remove(ioc, sas_expander); +	if (sas_expander) +		_scsih_expander_node_remove(ioc, sas_expander);  }  /** @@ -4433,6 +5144,7 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	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; @@ -4466,21 +5178,24 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 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); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  		return;  	}  	/* check if there were any issues with discovery */  	if (_scsih_check_access_status(ioc, sas_address, handle, -	    sas_device_pg0.AccessStatus)) +	    sas_device_pg0.AccessStatus)) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  		return; -	_scsih_ublock_io_device(ioc, handle); +	} +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	_scsih_ublock_io_device(ioc, sas_address);  } @@ -4588,7 +5303,7 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)  	/* get device name */  	sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); -	if (ioc->wait_for_port_enable_to_complete) +	if (ioc->wait_for_discovery_to_complete)  		_scsih_sas_device_init_add(ioc, sas_device);  	else  		_scsih_sas_device_add(ioc, sas_device); @@ -4607,40 +5322,87 @@ static void  _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; -	if (!sas_device) -		return; - -	memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device)); -	_scsih_sas_device_remove(ioc, sas_device); -  	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)); +		sas_device->handle, (unsigned long long) +	    sas_device->sas_address)); -	if (sas_device_backup.starget && sas_device_backup.starget->hostdata) { -		sas_target_priv_data = sas_device_backup.starget->hostdata; +	if (sas_device->starget && sas_device->starget->hostdata) { +		sas_target_priv_data = sas_device->starget->hostdata;  		sas_target_priv_data->deleted = 1; +		_scsih_ublock_io_device(ioc, sas_device->sas_address); +		sas_target_priv_data->handle = +		     MPT2SAS_INVALID_DEVICE_HANDLE;  	} -	_scsih_ublock_io_device(ioc, sas_device_backup.handle); - -	mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address, -	    sas_device_backup.sas_address_parent); +	if (!ioc->hide_drives) +		mpt2sas_transport_port_remove(ioc, +		    sas_device->sas_address, +		    sas_device->sas_address_parent);  	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); +	    "(0x%016llx)\n", ioc->name, sas_device->handle, +	    (unsigned long long) sas_device->sas_address);  	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)); +	    sas_device->handle, (unsigned long long) +	    sas_device->sas_address)); +	kfree(sas_device); +} +/** + * _scsih_device_remove_by_handle - removing device object by handle + * @ioc: per adapter object + * @handle: device handle + * + * Return nothing. + */ +static void +_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ +	struct _sas_device *sas_device; +	unsigned long flags; + +	if (ioc->shost_recovery) +		return; + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +	if (sas_device) +		list_del(&sas_device->list); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	if (sas_device) +		_scsih_remove_device(ioc, sas_device);  } +/** + * mpt2sas_device_remove_by_sas_address - removing device object by sas address + * @ioc: per adapter object + * @sas_address: device sas_address + * + * Return nothing. + */ +void +mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc, +	u64 sas_address) +{ +	struct _sas_device *sas_device; +	unsigned long flags; + +	if (ioc->shost_recovery) +		return; + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, +	    sas_address); +	if (sas_device) +		list_del(&sas_device->list); +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +	if (sas_device) +		_scsih_remove_device(ioc, sas_device); +}  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  /**   * _scsih_sas_topology_change_event_debug - debug for topology event @@ -4735,9 +5497,8 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  	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, prev_link_rate; @@ -4748,7 +5509,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  		_scsih_sas_topology_change_event_debug(ioc, event_data);  #endif -	if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) +	if (ioc->remove_host || ioc->pci_error_recovery)  		return;  	if (!ioc->sas_hba.num_phys) @@ -4772,13 +5533,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  	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 (sas_expander) {  		sas_address = sas_expander->sas_address; -	else if (parent_handle < ioc->sas_hba.num_phys) +		max_phys = sas_expander->num_phys; +	} else if (parent_handle < ioc->sas_hba.num_phys) {  		sas_address = ioc->sas_hba.sas_address; -	else +		max_phys = ioc->sas_hba.num_phys; +	} else { +	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);  		return; +	} +	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);  	/* handle siblings events */  	for (i = 0; i < event_data->NumEntries; i++) { @@ -4791,6 +5556,8 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  		    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 & @@ -4805,6 +5572,9 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  		switch (reason_code) {  		case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: +			if (ioc->shost_recovery) +				break; +  			if (link_rate == prev_link_rate)  				break; @@ -4818,6 +5588,9 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  			break;  		case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: +			if (ioc->shost_recovery) +				break; +  			mpt2sas_transport_update_links(ioc, sas_address,  			    handle, phy_number, link_rate); @@ -4825,16 +5598,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  			break;  		case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: -			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); +			_scsih_device_remove_by_handle(ioc, handle);  			break;  		}  	} @@ -4842,7 +5606,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,  	/* handle expander removal */  	if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&  	    sas_expander) -		_scsih_expander_remove(ioc, sas_address); +		mpt2sas_expander_remove(ioc, sas_address);  } @@ -4905,9 +5669,10 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,  		break;  	}  	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)); +	    "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", +	    ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), +	    (unsigned long long)le64_to_cpu(event_data->SASAddress), +	    le16_to_cpu(event_data->TaskTag));  	if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)  		printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,  		    event_data->ASC, event_data->ASCQ); @@ -4929,7 +5694,7 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,  {  	struct MPT2SAS_TARGET *target_priv_data;  	struct _sas_device *sas_device; -	__le64 sas_address; +	u64 sas_address;  	unsigned long flags;  	Mpi2EventDataSasDeviceStatusChange_t *event_data =  	    fw_event->event_data; @@ -4940,6 +5705,12 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,  		     event_data);  #endif +	/* In MPI Revision K (0xC), the internal device reset complete was +	 * implemented, so avoid setting tm_busy flag for older firmware. +	 */ +	if ((ioc->facts.HeaderVersion >> 8) < 0xC) +		return; +  	if (event_data->ReasonCode !=  	    MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&  	   event_data->ReasonCode != @@ -4950,20 +5721,24 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,  	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) +	if (!sas_device || !sas_device->starget) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  		return; +	}  	target_priv_data = sas_device->starget->hostdata; -	if (!target_priv_data) +	if (!target_priv_data) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  		return; +	}  	if (event_data->ReasonCode ==  	    MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)  		target_priv_data->tm_busy = 1;  	else  		target_priv_data->tm_busy = 0; +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  }  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -5022,7 +5797,7 @@ _scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,  }  /** - * _scsih_sas_broadcast_primative_event - handle broadcast events + * _scsih_sas_broadcast_primitive_event - handle broadcast events   * @ioc: per adapter object   * @fw_event: The fw_event_work object   * Context: user. @@ -5030,34 +5805,55 @@ _scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,   * Return nothing.   */  static void -_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, +_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc,      struct fw_event_work *fw_event)  {  	struct scsi_cmnd *scmd; +	struct scsi_device *sdev;  	u16 smid, handle;  	u32 lun;  	struct MPT2SAS_DEVICE *sas_device_priv_data;  	u32 termination_count;  	u32 query_count;  	Mpi2SCSITaskManagementReply_t *mpi_reply; -#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_INFO_FMT "%s: enter\n", ioc->name, -	    __func__)); +	unsigned long flags; +	int r; +	u8 max_retries = 0; +	u8 task_abort_retries; + +	mutex_lock(&ioc->tm_cmds.mutex); +	pr_info(MPT2SAS_FMT +		"%s: enter: phy number(%d), width(%d)\n", +		ioc->name, __func__, event_data->PhyNum, +		event_data->PortWidth); + +	_scsih_block_io_all_device(ioc); + +	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); +	mpi_reply = ioc->tm_cmds.reply; +broadcast_aen_retry: + +	/* sanity checks for retrying this loop */ +	if (max_retries++ == 5) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n", +		    ioc->name, __func__)); +		goto out; +	} else if (max_retries > 1) +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n", +		    ioc->name, __func__, max_retries - 1));  	termination_count = 0;  	query_count = 0; -	mpi_reply = ioc->tm_cmds.reply;  	for (smid = 1; smid <= ioc->scsiio_depth; smid++) { +		if (ioc->shost_recovery) +			goto out;  		scmd = _scsih_scsi_lookup_get(ioc, smid);  		if (!scmd)  			continue; -		sas_device_priv_data = scmd->device->hostdata; +		sdev = scmd->device; +		sas_device_priv_data = sdev->hostdata;  		if (!sas_device_priv_data || !sas_device_priv_data->sas_target)  			continue;  		 /* skip hidden raid components */ @@ -5073,27 +5869,90 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,  		lun = sas_device_priv_data->lun;  		query_count++; -		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 (ioc->shost_recovery) +			goto out; + +		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +		r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, +		    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, +		    TM_MUTEX_OFF); +		if (r == FAILED) { +			sdev_printk(KERN_WARNING, sdev, +			    "mpt2sas_scsih_issue_tm: FAILED when sending " +			    "QUERY_TASK: scmd(%p)\n", scmd); +			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); +			goto broadcast_aen_retry; +		}  		ioc_status = le16_to_cpu(mpi_reply->IOCStatus)  		    & MPI2_IOCSTATUS_MASK; -		if ((ioc_status == MPI2_IOCSTATUS_SUCCESS) && -		    (mpi_reply->ResponseCode == +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +			sdev_printk(KERN_WARNING, sdev, "query task: FAILED " +			    "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status, +			    scmd); +			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); +			goto broadcast_aen_retry; +		} + +		/* see if IO is still owned by IOC and target */ +		if (mpi_reply->ResponseCode ==  		     MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||  		     mpi_reply->ResponseCode == -		     MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) +		     MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) { +			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);  			continue; +		} +		task_abort_retries = 0; + tm_retry: +		if (task_abort_retries++ == 60) { +			dewtprintk(ioc, printk(MPT2SAS_INFO_FMT +			    "%s: ABORT_TASK: giving up\n", ioc->name, +			    __func__)); +			spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); +			goto broadcast_aen_retry; +		} + +		if (ioc->shost_recovery) +			goto out_no_lock; + +		r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, +		    sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, +		    TM_MUTEX_OFF); +		if (r == FAILED) { +			sdev_printk(KERN_WARNING, sdev, +			    "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : " +			    "scmd(%p)\n", scmd); +			goto tm_retry; +		} + +		if (task_abort_retries > 1) +			sdev_printk(KERN_WARNING, sdev, +			    "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):" +			    " scmd(%p)\n", +			    task_abort_retries - 1, scmd); -		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); +		spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);  	} -	ioc->broadcast_aen_busy = 0; -	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT +	if (ioc->broadcast_aen_pending) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to" +		     " pending AEN\n", ioc->name, __func__)); +		 ioc->broadcast_aen_pending = 0; +		 goto broadcast_aen_retry; +	} + + out: +	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + out_no_lock: + +	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT  	    "%s - exit, query_count = %d termination_count = %d\n",  	    ioc->name, __func__, query_count, termination_count)); + +	ioc->broadcast_aen_busy = 0; +	if (!ioc->shost_recovery) +		_scsih_ublock_io_all_device(ioc); +	mutex_unlock(&ioc->tm_cmds.mutex);  }  /** @@ -5123,8 +5982,14 @@ _scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,  #endif  	if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && -	    !ioc->sas_hba.num_phys) +	    !ioc->sas_hba.num_phys) { +		if (disable_discovery > 0 && ioc->shost_recovery) { +			/* Wait for the reset to complete */ +			while (ioc->shost_recovery) +				ssleep(1); +		}  		_scsih_sas_host_add(ioc); +	}  }  /** @@ -5145,27 +6010,6 @@ _scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)  }  /** - * _scsih_reprobe_target - reprobing target - * @starget: scsi target struct - * @no_uld_attach: sdev->no_uld_attach flag setting - * - * Note: no_uld_attach flag determines whether the disk device is attached - * to block layer. A value of `1` means to not attach. - **/ -static void -_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach) -{ -	struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata; - -	if (no_uld_attach) -		sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; -	else -		sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; - -	starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL, -	    _scsih_reprobe_lun); -} -/**   * _scsih_sas_volume_add - add new volume   * @ioc: per adapter object   * @element: IR config element data @@ -5211,13 +6055,16 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,  	raid_device->handle = handle;  	raid_device->wwid = wwid;  	_scsih_raid_device_add(ioc, raid_device); -	if (!ioc->wait_for_port_enable_to_complete) { +	if (!ioc->wait_for_discovery_to_complete) {  		rc = scsi_add_device(ioc->shost, RAID_CHANNEL,  		    raid_device->id, 0);  		if (rc)  			_scsih_raid_device_remove(ioc, raid_device); -	} else +	} else { +		spin_lock_irqsave(&ioc->raid_device_lock, flags);  		_scsih_determine_boot_device(ioc, raid_device, 1); +		spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +	}  }  /** @@ -5234,21 +6081,25 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	struct _raid_device *raid_device;  	unsigned long flags;  	struct MPT2SAS_TARGET *sas_target_priv_data; +	struct scsi_target *starget = NULL;  	spin_lock_irqsave(&ioc->raid_device_lock, flags);  	raid_device = _scsih_raid_device_find_by_handle(ioc, handle); -	spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -	if (!raid_device) -		return; -	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); +	if (raid_device) { +		if (raid_device->starget) { +			starget = raid_device->starget; +			sas_target_priv_data = starget->hostdata; +			sas_target_priv_data->deleted = 1; +		} +		printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" +		    "(0x%016llx)\n", ioc->name,  raid_device->handle, +		    (unsigned long long) raid_device->wwid); +		list_del(&raid_device->list); +		kfree(raid_device);  	} -	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); +	spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +	if (starget) +		scsi_remove_target(&starget->dev);  }  /** @@ -5264,20 +6115,31 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,      Mpi2EventIrConfigElement_t *element)  {  	struct _sas_device *sas_device; +	struct scsi_target *starget = NULL; +	struct MPT2SAS_TARGET *sas_target_priv_data;  	unsigned long flags;  	u16 handle = le16_to_cpu(element->PhysDiskDevHandle);  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +	if (sas_device) { +		sas_device->volume_handle = 0; +		sas_device->volume_wwid = 0; +		clear_bit(handle, ioc->pd_handles); +		if (sas_device->starget && sas_device->starget->hostdata) { +			starget = sas_device->starget; +			sas_target_priv_data = starget->hostdata; +			sas_target_priv_data->flags &= +			    ~MPT_TARGET_FLAGS_RAID_COMPONENT; +		} +	}  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  	if (!sas_device)  		return;  	/* exposing raid component */ -	sas_device->volume_handle = 0; -	sas_device->volume_wwid = 0; -	clear_bit(handle, ioc->pd_handles); -	_scsih_reprobe_target(sas_device->starget, 0); +	if (starget) +		starget_for_each_device(starget, NULL, _scsih_reprobe_lun);  }  /** @@ -5293,22 +6155,38 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,      Mpi2EventIrConfigElement_t *element)  {  	struct _sas_device *sas_device; +	struct scsi_target *starget = NULL; +	struct MPT2SAS_TARGET *sas_target_priv_data;  	unsigned long flags;  	u16 handle = le16_to_cpu(element->PhysDiskDevHandle); +	u16 volume_handle = 0; +	u64 volume_wwid = 0; + +	mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle); +	if (volume_handle) +		mpt2sas_config_get_volume_wwid(ioc, volume_handle, +		    &volume_wwid);  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +	if (sas_device) { +		set_bit(handle, ioc->pd_handles); +		if (sas_device->starget && sas_device->starget->hostdata) { +			starget = sas_device->starget; +			sas_target_priv_data = starget->hostdata; +			sas_target_priv_data->flags |= +			    MPT_TARGET_FLAGS_RAID_COMPONENT; +			sas_device->volume_handle = volume_handle; +			sas_device->volume_wwid = volume_wwid; +		} +	}  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  	if (!sas_device)  		return;  	/* hiding raid component */ -	mpt2sas_config_get_volume_handle(ioc, handle, -	    &sas_device->volume_handle); -	mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle, -	    &sas_device->volume_wwid); -	set_bit(handle, ioc->pd_handles); -	_scsih_reprobe_target(sas_device->starget, 1); +	if (starget) +		starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);  }  /** @@ -5323,16 +6201,9 @@ static void  _scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,      Mpi2EventIrConfigElement_t *element)  { -	struct _sas_device *sas_device; -	unsigned long flags;  	u16 handle = le16_to_cpu(element->PhysDiskDevHandle); -	spin_lock_irqsave(&ioc->sas_device_lock, flags); -	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); -	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -	if (!sas_device) -		return; -	_scsih_remove_device(ioc, sas_device); +	_scsih_device_remove_by_handle(ioc, handle);  }  /** @@ -5487,10 +6358,15 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,  	Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING -	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +	if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +	    && !ioc->hide_ir_msg)  		_scsih_sas_ir_config_change_event_debug(ioc, event_data);  #endif + +	if (ioc->shost_recovery) +		return; +  	foreign_config = (le32_to_cpu(event_data->Flags) &  	    MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; @@ -5510,16 +6386,20 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,  				    le16_to_cpu(element->VolDevHandle));  			break;  		case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: -			_scsih_sas_pd_hide(ioc, element); +			if (!ioc->is_warpdrive) +				_scsih_sas_pd_hide(ioc, element);  			break;  		case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: -			_scsih_sas_pd_expose(ioc, element); +			if (!ioc->is_warpdrive) +				_scsih_sas_pd_expose(ioc, element);  			break;  		case MPI2_EVENT_IR_CHANGE_RC_HIDE: -			_scsih_sas_pd_add(ioc, element); +			if (!ioc->is_warpdrive) +				_scsih_sas_pd_add(ioc, element);  			break;  		case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: -			_scsih_sas_pd_delete(ioc, element); +			if (!ioc->is_warpdrive) +				_scsih_sas_pd_delete(ioc, element);  			break;  		}  	} @@ -5545,14 +6425,18 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,  	int rc;  	Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; +	if (ioc->shost_recovery) +		return; +  	if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)  		return;  	handle = le16_to_cpu(event_data->VolDevHandle);  	state = le32_to_cpu(event_data->NewValue); -	dewtprintk(ioc, 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)); +	if (!ioc->hide_ir_msg) +		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));  	switch (state) {  	case MPI2_RAID_VOL_STATE_MISSING: @@ -5626,15 +6510,19 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,  	Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;  	u64 sas_address; +	if (ioc->shost_recovery) +		return; +  	if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)  		return;  	handle = le16_to_cpu(event_data->PhysDiskDevHandle);  	state = le32_to_cpu(event_data->NewValue); -	dewtprintk(ioc, 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)); +	if (!ioc->hide_ir_msg) +		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));  	switch (state) {  	case MPI2_RAID_PD_STATE_ONLINE: @@ -5643,7 +6531,8 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,  	case MPI2_RAID_PD_STATE_OPTIMAL:  	case MPI2_RAID_PD_STATE_HOT_SPARE: -		set_bit(handle, ioc->pd_handles); +		if (!ioc->is_warpdrive) +			set_bit(handle, ioc->pd_handles);  		spin_lock_irqsave(&ioc->sas_device_lock, flags);  		sas_device = _scsih_sas_device_find_by_handle(ioc, handle); @@ -5747,7 +6636,8 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,  	u16 handle;  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING -	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +	if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) +	    && !ioc->hide_ir_msg)  		_scsih_sas_ir_operation_status_event_debug(ioc,  		     event_data);  #endif @@ -5755,102 +6645,13 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,  	/* 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); +		handle = le16_to_cpu(event_data->VolDevHandle);  		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) +		if (raid_device)  			raid_device->percent_complete =  			    event_data->PercentComplete; -	} -} - -/** - * _scsih_task_set_full - handle task set full - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Throttle back qdepth. - */ -static void -_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work -	*fw_event) -{ -	unsigned long flags; -	struct _sas_device *sas_device; -	static struct _raid_device *raid_device; -	struct scsi_device *sdev; -	int depth; -	u16 current_depth; -	u16 handle; -	int id, channel; -	u64 sas_address; -	Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data; - -	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 (test_bit(handle, ioc->pd_handles) && 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_INFO, 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"); -		}  	}  } @@ -5890,7 +6691,7 @@ static void  _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,      u16 slot, u16 handle)  { -	struct MPT2SAS_TARGET *sas_target_priv_data; +	struct MPT2SAS_TARGET *sas_target_priv_data = NULL;  	struct scsi_target *starget;  	struct _sas_device *sas_device;  	unsigned long flags; @@ -5898,7 +6699,7 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	list_for_each_entry(sas_device, &ioc->sas_device_list, list) {  		if (sas_device->sas_address == sas_address && -		    sas_device->slot == slot && sas_device->starget) { +		    sas_device->slot == slot) {  			sas_device->responding = 1;  			starget = sas_device->starget;  			if (starget && starget->hostdata) { @@ -5907,13 +6708,15 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  				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, -			    (unsigned long long)sas_device->sas_address, -			    (unsigned long long) -			    sas_device->enclosure_logical_id, -			    sas_device->slot); +			if (starget) +				starget_printk(KERN_INFO, starget, +				    "handle(0x%04x), sas_addr(0x%016llx), " +				    "enclosure logical id(0x%016llx), " +				    "slot(%d)\n", handle, +				    (unsigned long long)sas_device->sas_address, +				    (unsigned long long) +				    sas_device->enclosure_logical_id, +				    sas_device->slot);  			if (sas_device->handle == handle)  				goto out;  			printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", @@ -5948,10 +6751,10 @@ _scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)  	u32 device_info;  	u16 slot; -	printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); +	printk(MPT2SAS_INFO_FMT "search for end-devices: start\n", ioc->name);  	if (list_empty(&ioc->sas_device_list)) -		return; +		goto out;  	handle = 0xFFFF;  	while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, @@ -5959,7 +6762,7 @@ _scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)  	    handle))) {  		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &  		    MPI2_IOCSTATUS_MASK; -		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS)  			break;  		handle = le16_to_cpu(sas_device_pg0.DevHandle);  		device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); @@ -5970,6 +6773,9 @@ _scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)  		_scsih_mark_responding_sas_device(ioc, sas_address, slot,  		    handle);  	} +out: +	printk(MPT2SAS_INFO_FMT "search for end-devices: complete\n", +	    ioc->name);  }  /** @@ -6002,20 +6808,32 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,  			} else  				sas_target_priv_data = NULL;  			raid_device->responding = 1; +			spin_unlock_irqrestore(&ioc->raid_device_lock, flags);  			starget_printk(KERN_INFO, raid_device->starget,  			    "handle(0x%04x), wwid(0x%016llx)\n", handle,  			    (unsigned long long)raid_device->wwid); -			if (raid_device->handle == handle) -				goto out; +			/* +			 * WARPDRIVE: The handles of the PDs might have changed +			 * across the host reset so re-initialize the +			 * required data for Direct IO +			 */ +			_scsih_init_warpdrive_properties(ioc, raid_device); +			spin_lock_irqsave(&ioc->raid_device_lock, flags); +			if (raid_device->handle == handle) { +				spin_unlock_irqrestore(&ioc->raid_device_lock, +				    flags); +				return; +			}  			printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",  			    raid_device->handle);  			raid_device->handle = handle;  			if (sas_target_priv_data)  				sas_target_priv_data->handle = handle; -			goto out; +			spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +			return;  		}  	} - out: +  	spin_unlock_irqrestore(&ioc->raid_device_lock, flags);  } @@ -6039,17 +6857,21 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)  	u16 handle;  	u8 phys_disk_num; -	printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); +	if (!ioc->ir_firmware) +		return; + +	printk(MPT2SAS_INFO_FMT "search for raid volumes: start\n", +	    ioc->name);  	if (list_empty(&ioc->raid_device_list)) -		return; +		goto out;  	handle = 0xFFFF;  	while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,  	    &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {  		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &  		    MPI2_IOCSTATUS_MASK; -		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS)  			break;  		handle = le16_to_cpu(volume_pg1.DevHandle); @@ -6066,19 +6888,24 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)  	}  	/* 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); +	if (!ioc->is_warpdrive) { +		phys_disk_num = 0xFF; +		memset(ioc->pd_handles, 0, ioc->pd_handles_sz); +		while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, +		    &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, +		    phys_disk_num))) { +			ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +			    MPI2_IOCSTATUS_MASK; +			if (ioc_status != MPI2_IOCSTATUS_SUCCESS) +				break; +			phys_disk_num = pd_pg0.PhysDiskNum; +			handle = le16_to_cpu(pd_pg0.DevHandle); +			set_bit(handle, ioc->pd_handles); +		}  	} +out: +	printk(MPT2SAS_INFO_FMT "search for responding raid volumes: " +	    "complete\n", ioc->name);  }  /** @@ -6135,13 +6962,13 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)  	Mpi2ExpanderPage0_t expander_pg0;  	Mpi2ConfigReply_t mpi_reply;  	u16 ioc_status; -	__le64 sas_address; +	u64 sas_address;  	u16 handle; -	printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); +	printk(MPT2SAS_INFO_FMT "search for expanders: start\n", ioc->name);  	if (list_empty(&ioc->sas_expander_list)) -		return; +		goto out;  	handle = 0xFFFF;  	while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, @@ -6149,7 +6976,7 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)  		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &  		    MPI2_IOCSTATUS_MASK; -		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS)  			break;  		handle = le16_to_cpu(expander_pg0.DevHandle); @@ -6160,6 +6987,8 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)  		_scsih_mark_responding_expander(ioc, sas_address, handle);  	} + out: +	printk(MPT2SAS_INFO_FMT "search for expanders: complete\n", ioc->name);  }  /** @@ -6172,56 +7001,334 @@ static void  _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)  {  	struct _sas_device *sas_device, *sas_device_next; -	struct _sas_node *sas_expander; +	struct _sas_node *sas_expander, *sas_expander_next;  	struct _raid_device *raid_device, *raid_device_next; +	struct list_head tmp_list; +	unsigned long flags; +	printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n", +	    ioc->name); +	/* removing unresponding end devices */ +	printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n", +	    ioc->name);  	list_for_each_entry_safe(sas_device, sas_device_next,  	    &ioc->sas_device_list, list) { -		if (sas_device->responding) { +		if (!sas_device->responding) +			mpt2sas_device_remove_by_sas_address(ioc, +				sas_device->sas_address); +		else  			sas_device->responding = 0; +	} + +	/* removing unresponding volumes */ +	if (ioc->ir_firmware) { +		printk(MPT2SAS_INFO_FMT "removing unresponding devices: " +		    "volumes\n", ioc->name); +		list_for_each_entry_safe(raid_device, raid_device_next, +		    &ioc->raid_device_list, list) { +			if (!raid_device->responding) +				_scsih_sas_volume_delete(ioc, +				    raid_device->handle); +			else +				raid_device->responding = 0; +		} +	} +	/* removing unresponding expanders */ +	printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n", +	    ioc->name); +	spin_lock_irqsave(&ioc->sas_node_lock, flags); +	INIT_LIST_HEAD(&tmp_list); +	list_for_each_entry_safe(sas_expander, sas_expander_next, +	    &ioc->sas_expander_list, list) { +		if (!sas_expander->responding) +			list_move_tail(&sas_expander->list, &tmp_list); +		else +			sas_expander->responding = 0; +	} +	spin_unlock_irqrestore(&ioc->sas_node_lock, flags); +	list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list, +	    list) { +		list_del(&sas_expander->list); +		_scsih_expander_node_remove(ioc, sas_expander); +	} +	printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n", +	    ioc->name); +	/* unblock devices */ +	_scsih_ublock_io_all_device(ioc); +} + +static void +_scsih_refresh_expander_links(struct MPT2SAS_ADAPTER *ioc, +	struct _sas_node *sas_expander, u16 handle) +{ +	Mpi2ExpanderPage1_t expander_pg1; +	Mpi2ConfigReply_t mpi_reply; +	int i; + +	for (i = 0 ; i < sas_expander->num_phys ; i++) { +		if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, +		    &expander_pg1, i, handle))) { +			printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", +			    ioc->name, __FILE__, __LINE__, __func__); +			return; +		} + +		mpt2sas_transport_update_links(ioc, sas_expander->sas_address, +		    le16_to_cpu(expander_pg1.AttachedDevHandle), i, +		    expander_pg1.NegotiatedLinkRate >> 4); +	} +} + +/** + * _scsih_scan_for_devices_after_reset - scan for devices after host reset + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) +{ +	Mpi2ExpanderPage0_t expander_pg0; +	Mpi2SasDevicePage0_t sas_device_pg0; +	Mpi2RaidVolPage1_t volume_pg1; +	Mpi2RaidVolPage0_t volume_pg0; +	Mpi2RaidPhysDiskPage0_t pd_pg0; +	Mpi2EventIrConfigElement_t element; +	Mpi2ConfigReply_t mpi_reply; +	u8 phys_disk_num; +	u16 ioc_status; +	u16 handle, parent_handle; +	u64 sas_address; +	struct _sas_device *sas_device; +	struct _sas_node *expander_device; +	static struct _raid_device *raid_device; +	u8 retry_count; +	unsigned long flags; + +	printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name); + +	_scsih_sas_host_refresh(ioc); + +	printk(MPT2SAS_INFO_FMT "\tscan devices: expanders start\n", +		ioc->name); +	/* expanders */ +	handle = 0xFFFF; +	while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, +	    MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { +		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +		    MPI2_IOCSTATUS_MASK; +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +			printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: " +				"ioc_status(0x%04x), loginfo(0x%08x)\n", +				ioc->name, ioc_status, +				le32_to_cpu(mpi_reply.IOCLogInfo)); +			break; +		} +		handle = le16_to_cpu(expander_pg0.DevHandle); +		spin_lock_irqsave(&ioc->sas_node_lock, flags); +		expander_device = mpt2sas_scsih_expander_find_by_sas_address( +		    ioc, le64_to_cpu(expander_pg0.SASAddress)); +		spin_unlock_irqrestore(&ioc->sas_node_lock, flags); +		if (expander_device) +			_scsih_refresh_expander_links(ioc, expander_device, +			    handle); +		else { +			printk(MPT2SAS_INFO_FMT "\tBEFORE adding expander: " +				"handle (0x%04x), sas_addr(0x%016llx)\n", +				ioc->name, handle, (unsigned long long) +				le64_to_cpu(expander_pg0.SASAddress)); +			_scsih_expander_add(ioc, handle); +			printk(MPT2SAS_INFO_FMT "\tAFTER adding expander: " +				"handle (0x%04x), sas_addr(0x%016llx)\n", +				ioc->name, handle, (unsigned long long) +				le64_to_cpu(expander_pg0.SASAddress)); +		} +	} + +	printk(MPT2SAS_INFO_FMT "\tscan devices: expanders complete\n", +		ioc->name); + +	if (!ioc->ir_firmware) +		goto skip_to_sas; + +	printk(MPT2SAS_INFO_FMT "\tscan devices phys disk start\n", ioc->name); +	/* phys disk */ +	phys_disk_num = 0xFF; +	while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, +	    &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, +	    phys_disk_num))) { +		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +		    MPI2_IOCSTATUS_MASK; +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +			printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:" +				"ioc_status(0x%04x), loginfo(0x%08x)\n", +				ioc->name, ioc_status, +				le32_to_cpu(mpi_reply.IOCLogInfo)); +			break; +		} +		phys_disk_num = pd_pg0.PhysDiskNum; +		handle = le16_to_cpu(pd_pg0.DevHandle); +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		if (sas_device)  			continue; +		if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, +		    &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, +		    handle) != 0) +			continue; +		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +			MPI2_IOCSTATUS_MASK; +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +			printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan " +				"ioc_status(0x%04x), loginfo(0x%08x)\n", +				ioc->name, ioc_status, +				le32_to_cpu(mpi_reply.IOCLogInfo)); +			break; +		} +		parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); +		if (!_scsih_get_sas_address(ioc, parent_handle, +		    &sas_address)) { +			printk(MPT2SAS_INFO_FMT "\tBEFORE adding phys disk: " +				" handle (0x%04x), sas_addr(0x%016llx)\n", +				ioc->name, handle, (unsigned long long) +				le64_to_cpu(sas_device_pg0.SASAddress)); +			mpt2sas_transport_update_links(ioc, sas_address, +			    handle, sas_device_pg0.PhyNum, +			    MPI2_SAS_NEG_LINK_RATE_1_5); +			set_bit(handle, ioc->pd_handles); +			retry_count = 0; +			/* This will retry adding the end device. +			* _scsih_add_device() will decide on retries and +			* return "1" when it should be retried +			*/ +			while (_scsih_add_device(ioc, handle, retry_count++, +				1)) { +					ssleep(1); +			} +			printk(MPT2SAS_INFO_FMT "\tAFTER adding phys disk: " +				" handle (0x%04x), sas_addr(0x%016llx)\n", +				ioc->name, handle, (unsigned long long) +				le64_to_cpu(sas_device_pg0.SASAddress));  		} -		if (sas_device->starget) -			starget_printk(KERN_INFO, sas_device->starget, -			    "removing: handle(0x%04x), sas_addr(0x%016llx), " -			    "enclosure logical id(0x%016llx), slot(%d)\n", -			    sas_device->handle, -			    (unsigned long long)sas_device->sas_address, -			    (unsigned long long) -			    sas_device->enclosure_logical_id, -			    sas_device->slot); -		_scsih_remove_device(ioc, sas_device);  	} -	list_for_each_entry_safe(raid_device, raid_device_next, -	    &ioc->raid_device_list, list) { -		if (raid_device->responding) { -			raid_device->responding = 0; +	printk(MPT2SAS_INFO_FMT "\tscan devices: phys disk complete\n", +		ioc->name); + +	printk(MPT2SAS_INFO_FMT "\tscan devices: volumes start\n", ioc->name); +	/* volumes */ +	handle = 0xFFFF; +	while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, +	    &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { +		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +		    MPI2_IOCSTATUS_MASK; +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +			printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: " +				"ioc_status(0x%04x), loginfo(0x%08x)\n", +				ioc->name, ioc_status, +				le32_to_cpu(mpi_reply.IOCLogInfo)); +			break; +		} +		handle = le16_to_cpu(volume_pg1.DevHandle); +		spin_lock_irqsave(&ioc->raid_device_lock, flags); +		raid_device = _scsih_raid_device_find_by_wwid(ioc, +		    le64_to_cpu(volume_pg1.WWID)); +		spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +		if (raid_device) +			continue; +		if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, +		    &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, +		     sizeof(Mpi2RaidVolPage0_t)))  			continue; +		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +			MPI2_IOCSTATUS_MASK; +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +			printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: " +				"ioc_status(0x%04x), loginfo(0x%08x)\n", +				ioc->name, ioc_status, +				le32_to_cpu(mpi_reply.IOCLogInfo)); +			break;  		} -		if (raid_device->starget) { -			starget_printk(KERN_INFO, raid_device->starget, -			    "removing: handle(0x%04x), wwid(0x%016llx)\n", -			      raid_device->handle, -			    (unsigned long long)raid_device->wwid); -			scsi_remove_target(&raid_device->starget->dev); +		if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || +		    volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || +		    volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { +			memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); +			element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; +			element.VolDevHandle = volume_pg1.DevHandle; +			printk(MPT2SAS_INFO_FMT "\tBEFORE adding volume: " +				" handle (0x%04x)\n", ioc->name, +				volume_pg1.DevHandle); +			_scsih_sas_volume_add(ioc, &element); +			printk(MPT2SAS_INFO_FMT "\tAFTER adding volume: " +				" handle (0x%04x)\n", ioc->name, +				volume_pg1.DevHandle);  		} -		_scsih_raid_device_remove(ioc, raid_device);  	} - 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; +	printk(MPT2SAS_INFO_FMT "\tscan devices: volumes complete\n", +		ioc->name); + + skip_to_sas: + +	printk(MPT2SAS_INFO_FMT "\tscan devices: end devices start\n", +		ioc->name); +	/* sas devices */ +	handle = 0xFFFF; +	while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, +	    &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, +	    handle))) { +		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & +		    MPI2_IOCSTATUS_MASK; +		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { +			printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:" +				" ioc_status(0x%04x), loginfo(0x%08x)\n", +				ioc->name, ioc_status, +				le32_to_cpu(mpi_reply.IOCLogInfo)); +				break; +		} +		handle = le16_to_cpu(sas_device_pg0.DevHandle); +		if (!(_scsih_is_end_device( +		    le32_to_cpu(sas_device_pg0.DeviceInfo))))  			continue; +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, +		    le64_to_cpu(sas_device_pg0.SASAddress)); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		if (sas_device) +			continue; +		parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); +		if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { +			printk(MPT2SAS_INFO_FMT "\tBEFORE adding end device: " +				"handle (0x%04x), sas_addr(0x%016llx)\n", +				ioc->name, handle, (unsigned long long) +				le64_to_cpu(sas_device_pg0.SASAddress)); +			mpt2sas_transport_update_links(ioc, sas_address, handle, +			    sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); +			retry_count = 0; +			/* This will retry adding the end device. +			 * _scsih_add_device() will decide on retries and +			 * return "1" when it should be retried +			 */ +			while (_scsih_add_device(ioc, handle, retry_count++, +				0)) { +					ssleep(1); +			} +			printk(MPT2SAS_INFO_FMT "\tAFTER adding end device: " +				"handle (0x%04x), sas_addr(0x%016llx)\n", +				ioc->name, handle, (unsigned long long) +				le64_to_cpu(sas_device_pg0.SASAddress));  		} -		_scsih_expander_remove(ioc, sas_expander->sas_address); -		goto retry_expander_search;  	} + +	printk(MPT2SAS_INFO_FMT "\tscan devices: end devices complete\n", +		ioc->name); + +	printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name);  } +  /**   * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)   * @ioc: per adapter object @@ -6257,7 +7364,6 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  		}  		_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: " @@ -6267,6 +7373,14 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)  		_scsih_search_responding_sas_devices(ioc);  		_scsih_search_responding_raid_devices(ioc);  		_scsih_search_responding_expanders(ioc); +		if ((!ioc->is_driver_loading) && !(disable_discovery > 0 && +		    !ioc->sas_hba.num_phys)) { +			_scsih_prep_device_scan(ioc); +			_scsih_search_responding_sas_devices(ioc); +			_scsih_search_responding_raid_devices(ioc); +			_scsih_search_responding_expanders(ioc); +			_scsih_error_recovery_delete_devices(ioc); +		}  		break;  	}  } @@ -6284,7 +7398,6 @@ _firmware_event_work(struct work_struct *work)  {  	struct fw_event_work *fw_event = container_of(work,  	    struct fw_event_work, delayed_work.work); -	unsigned long flags;  	struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;  	/* the queue is being flushed so ignore this event */ @@ -6294,22 +7407,26 @@ _firmware_event_work(struct work_struct *work)  		return;  	} -	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); +	switch (fw_event->event) { +	case MPT2SAS_REMOVE_UNRESPONDING_DEVICES: +		while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery) +			ssleep(1);  		_scsih_remove_unresponding_sas_devices(ioc); -		return; -	} +		_scsih_scan_for_devices_after_reset(ioc); +		break; +	case MPT2SAS_PORT_ENABLE_COMPLETE: +		ioc->start_scan = 0; -	switch (fw_event->event) { +		if (missing_delay[0] != -1 && missing_delay[1] != -1) +			mpt2sas_base_update_missing_delay(ioc, missing_delay[0], +				missing_delay[1]); + +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete " +		    "from worker thread\n", ioc->name)); +		break; +	case MPT2SAS_TURN_ON_FAULT_LED: +		_scsih_turn_on_fault_led(ioc, fw_event->device_handle); +		break;  	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:  		_scsih_sas_topology_change_event(ioc, fw_event);  		break; @@ -6322,7 +7439,7 @@ _firmware_event_work(struct work_struct *work)  		    fw_event);  		break;  	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: -		_scsih_sas_broadcast_primative_event(ioc, +		_scsih_sas_broadcast_primitive_event(ioc,  		    fw_event);  		break;  	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: @@ -6341,9 +7458,6 @@ _firmware_event_work(struct work_struct *work)  	case MPI2_EVENT_IR_OPERATION_STATUS:  		_scsih_sas_ir_operation_status_event(ioc, fw_event);  		break; -	case MPI2_EVENT_TASK_SET_FULL: -		_scsih_task_set_full(ioc, fw_event); -		break;  	}  	_scsih_fw_event_free(ioc, fw_event);  } @@ -6358,10 +7472,9 @@ _firmware_event_work(struct work_struct *work)   * This function merely adds a new work task into ioc->firmware_event_thread.   * The tasks are worked from _firmware_event_work in user context.   * - * Return 1 meaning mf should be freed from _base_interrupt - *        0 means the mf is freed from this function. + * Returns void.   */ -u8 +void  mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  	u32 reply)  { @@ -6372,9 +7485,16 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  	/* events turned off due to host reset or driver unloading */  	if (ioc->remove_host || ioc->pci_error_recovery) -		return 1; +		return;  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); + +	if (unlikely(!mpi_reply)) { +		printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", +		    ioc->name, __FILE__, __LINE__, __func__); +		return; +	} +  	event = le16_to_cpu(mpi_reply->Event);  	switch (event) { @@ -6386,10 +7506,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  		    mpi_reply->EventData;  		if (baen_data->Primitive != -		    MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT || -		    ioc->broadcast_aen_busy) -			return 1; -		ioc->broadcast_aen_busy = 1; +		    MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) +			return; + +		if (ioc->broadcast_aen_busy) { +			ioc->broadcast_aen_pending++; +			return; +		} else +			ioc->broadcast_aen_busy = 1;  		break;  	} @@ -6408,23 +7532,69 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  		    (Mpi2EventDataIrVolume_t *)  		    mpi_reply->EventData);  		break; +	case MPI2_EVENT_LOG_ENTRY_ADDED: +	{ +		Mpi2EventDataLogEntryAdded_t *log_entry; +		__le32 *log_code; + +		if (!ioc->is_warpdrive) +			break; + +		log_entry = (Mpi2EventDataLogEntryAdded_t *) +		    mpi_reply->EventData; +		log_code = (__le32 *)log_entry->LogData; + +		if (le16_to_cpu(log_entry->LogEntryQualifier) +		    != MPT2_WARPDRIVE_LOGENTRY) +			break; + +		switch (le32_to_cpu(*log_code)) { +		case MPT2_WARPDRIVE_LC_SSDT: +			printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " +			    "IO Throttling has occurred in the WarpDrive " +			    "subsystem. Check WarpDrive documentation for " +			    "additional details.\n", ioc->name); +			break; +		case MPT2_WARPDRIVE_LC_SSDLW: +			printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " +			    "Program/Erase Cycles for the WarpDrive subsystem " +			    "in degraded range. Check WarpDrive documentation " +			    "for additional details.\n", ioc->name); +			break; +		case MPT2_WARPDRIVE_LC_SSDLF: +			printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " +			    "There are no Program/Erase Cycles for the " +			    "WarpDrive subsystem. The storage device will be " +			    "in read-only mode. Check WarpDrive documentation " +			    "for additional details.\n", ioc->name); +			break; +		case MPT2_WARPDRIVE_LC_BRMF: +			printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " +			    "The Backup Rail Monitor has failed on the " +			    "WarpDrive subsystem. Check WarpDrive " +			    "documentation for additional details.\n", +			    ioc->name); +			break; +		} + +		break; +	}  	case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:  	case MPI2_EVENT_IR_OPERATION_STATUS:  	case MPI2_EVENT_SAS_DISCOVERY:  	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:  	case MPI2_EVENT_IR_PHYSICAL_DISK: -	case MPI2_EVENT_TASK_SET_FULL:  		break;  	default: /* ignore the rest */ -		return 1; +		return;  	}  	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 1; +		return;  	}  	sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;  	fw_event->event_data = kzalloc(sz, GFP_ATOMIC); @@ -6432,7 +7602,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__);  		kfree(fw_event); -		return 1; +		return;  	}  	memcpy(fw_event->event_data, mpi_reply->EventData, @@ -6442,7 +7612,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,  	fw_event->VP_ID = mpi_reply->VP_ID;  	fw_event->event = event;  	_scsih_fw_event_add(ioc, fw_event); -	return 1; +	return;  }  /* shost template */ @@ -6456,6 +7626,8 @@ static struct scsi_host_template scsih_driver_template = {  	.slave_configure		= _scsih_slave_configure,  	.target_destroy			= _scsih_target_destroy,  	.slave_destroy			= _scsih_slave_destroy, +	.scan_finished			= _scsih_scan_finished, +	.scan_start			= _scsih_scan_start,  	.change_queue_depth 		= _scsih_change_queue_depth,  	.change_queue_type		= _scsih_change_queue_type,  	.eh_abort_handler		= _scsih_abort, @@ -6466,7 +7638,7 @@ static struct scsi_host_template scsih_driver_template = {  	.can_queue			= 1,  	.this_id			= -1,  	.sg_tablesize			= MPT2SAS_SG_DEPTH, -	.max_sectors			= 8192, +	.max_sectors			= 32767,  	.cmd_per_lun			= 7,  	.use_clustering			= ENABLE_CLUSTERING,  	.shost_attrs			= mpt2sas_host_attrs, @@ -6488,56 +7660,23 @@ 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); -			if (ioc->shost_recovery) -				return; -			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_by_sas_address(ioc, +			    mpt2sas_port->remote_identify.sas_address); +		else if (mpt2sas_port->remote_identify.device_type == +		    SAS_EDGE_EXPANDER_DEVICE ||  		    mpt2sas_port->remote_identify.device_type == -		    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->sas_address); -			if (ioc->shost_recovery) -				return; -			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, @@ -6548,7 +7687,6 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,  	    sas_expander->handle, (unsigned long long)  	    sas_expander->sas_address); -	list_del(&sas_expander->list);  	kfree(sas_expander->phy);  	kfree(sas_expander);  } @@ -6573,10 +7711,6 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)  	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) { @@ -6601,7 +7735,8 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)  	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); +	if (!ioc->hide_ir_msg) +		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); @@ -6615,10 +7750,11 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)  	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)); +		if (!ioc->hide_ir_msg) +			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: @@ -6661,14 +7797,12 @@ _scsih_shutdown(struct pci_dev *pdev)   * Routine called when unloading the driver.   * Return nothing.   */ -static void __devexit +static void  _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; @@ -6685,6 +7819,7 @@ _scsih_remove(struct pci_dev *pdev)  		destroy_workqueue(wq);  	/* release all the volumes */ +	_scsih_ir_shutdown(ioc);  	list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,  	    list) {  		if (raid_device->starget) { @@ -6700,28 +7835,18 @@ _scsih_remove(struct pci_dev *pdev)  	}  	/* 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); -				goto retry_again; -			} -		} else { -			expander_sibling = -			    mpt2sas_scsih_expander_find_by_sas_address(ioc, +		    SAS_END_DEVICE) +			mpt2sas_device_remove_by_sas_address(ioc, +			    mpt2sas_port->remote_identify.sas_address); +		else if (mpt2sas_port->remote_identify.device_type == +		    SAS_EDGE_EXPANDER_DEVICE || +		    mpt2sas_port->remote_identify.device_type == +		    SAS_FANOUT_EXPANDER_DEVICE) +			mpt2sas_expander_remove(ioc,  			    mpt2sas_port->remote_identify.sas_address); -			if (expander_sibling) { -				_scsih_expander_remove(ioc, -				    expander_sibling->sas_address); -				goto retry_again; -			} -		}  	}  	/* free phys attached to the sas_host */ @@ -6732,7 +7857,7 @@ _scsih_remove(struct pci_dev *pdev)  	}  	sas_remove_host(shost); -	_scsih_shutdown(pdev); +	mpt2sas_base_detach(ioc);  	list_del(&ioc->list);  	scsi_remove_host(shost);  	scsi_host_put(shost); @@ -6759,7 +7884,12 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)  	unsigned long flags;  	int rc; +	 /* no Bios, return immediately */ +	if (!ioc->bios_pg3.BiosVersion) +		return; +  	device = NULL; +	is_raid = 0;  	if (ioc->req_boot_device.device) {  		device =  ioc->req_boot_device.device;  		is_raid = ioc->req_boot_device.is_raid; @@ -6781,20 +7911,26 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)  		if (rc)  			_scsih_raid_device_remove(ioc, raid_device);  	} else { +		spin_lock_irqsave(&ioc->sas_device_lock, flags);  		sas_device = device;  		handle = sas_device->handle;  		sas_address_parent = sas_device->sas_address_parent;  		sas_address = sas_device->sas_address; -		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 (ioc->hide_drives) +			return;  		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, -			    sas_address_parent); -			_scsih_sas_device_remove(ioc, sas_device); +			if (!ioc->is_driver_loading) { +				mpt2sas_transport_port_remove(ioc, +					sas_address, +					sas_address_parent); +				_scsih_sas_device_remove(ioc, sas_device); +			}  		}  	}  } @@ -6837,19 +7973,28 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)  	/* SAS Device List */  	list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,  	    list) { -		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 (ioc->hide_drives) +			continue;  		if (!mpt2sas_transport_port_add(ioc, sas_device->handle,  		    sas_device->sas_address_parent)) { -			_scsih_sas_device_remove(ioc, sas_device); +			list_del(&sas_device->list); +			kfree(sas_device); +			continue;  		} else if (!sas_device->starget) { -			mpt2sas_transport_port_remove(ioc, -			    sas_device->sas_address, -			    sas_device->sas_address_parent); -			_scsih_sas_device_remove(ioc, sas_device); +			if (!ioc->is_driver_loading) { +				mpt2sas_transport_port_remove(ioc, +					sas_device->sas_address, +					sas_device->sas_address_parent); +				list_del(&sas_device->list); +				kfree(sas_device); +				continue; +			}  		} +		spin_lock_irqsave(&ioc->sas_device_lock, flags); +		list_move_tail(&sas_device->list, &ioc->sas_device_list); +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);  	}  } @@ -6862,9 +8007,7 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)  static void  _scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)  { -	u16 volume_mapping_flags = -	    le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & -	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; +	u16 volume_mapping_flags;  	if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))  		return;  /* return when IOC doesn't support initiator mode */ @@ -6872,18 +8015,102 @@ _scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)  	_scsih_probe_boot_devices(ioc);  	if (ioc->ir_firmware) { -		if ((volume_mapping_flags & -		     MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) { -			_scsih_probe_sas(ioc); +		volume_mapping_flags = +		    le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & +		    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; +		if (volume_mapping_flags == +		    MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {  			_scsih_probe_raid(ioc); +			_scsih_probe_sas(ioc);  		} else { -			_scsih_probe_raid(ioc);  			_scsih_probe_sas(ioc); +			_scsih_probe_raid(ioc);  		}  	} else  		_scsih_probe_sas(ioc);  } + +/** + * _scsih_scan_start - scsi lld callback for .scan_start + * @shost: SCSI host pointer + * + * The shost has the ability to discover targets on its own instead + * of scanning the entire bus.  In our implemention, we will kick off + * firmware discovery. + */ +static void +_scsih_scan_start(struct Scsi_Host *shost) +{ +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); +	int rc; + +	if (diag_buffer_enable != -1 && diag_buffer_enable != 0) +		mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); + +	if (disable_discovery > 0) +		return; + +	ioc->start_scan = 1; +	rc = mpt2sas_port_enable(ioc); + +	if (rc != 0) +		printk(MPT2SAS_INFO_FMT "port enable: FAILED\n", ioc->name); +} + +/** + * _scsih_scan_finished - scsi lld callback for .scan_finished + * @shost: SCSI host pointer + * @time: elapsed time of the scan in jiffies + * + * This function will be called periodically until it returns 1 with the + * scsi_host and the elapsed time of the scan in jiffies. In our implemention, + * we wait for firmware discovery to complete, then return 1. + */ +static int +_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ +	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + +	if (disable_discovery > 0) { +		ioc->is_driver_loading = 0; +		ioc->wait_for_discovery_to_complete = 0; +		return 1; +	} + +	if (time >= (300 * HZ)) { +		ioc->base_cmds.status = MPT2_CMD_NOT_USED; +		printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout " +		    "(timeout=300s)\n", ioc->name); +		ioc->is_driver_loading = 0; +		return 1; +	} + +	if (ioc->start_scan) +		return 0; + +	if (ioc->start_scan_failed) { +		printk(MPT2SAS_INFO_FMT "port enable: FAILED with " +		    "(ioc_status=0x%08x)\n", ioc->name, ioc->start_scan_failed); +		ioc->is_driver_loading = 0; +		ioc->wait_for_discovery_to_complete = 0; +		ioc->remove_host = 1; +		return 1; +	} + +	printk(MPT2SAS_INFO_FMT "port enable: SUCCESS\n", ioc->name); +	ioc->base_cmds.status = MPT2_CMD_NOT_USED; + +	if (ioc->wait_for_discovery_to_complete) { +		ioc->wait_for_discovery_to_complete = 0; +		_scsih_probe_devices(ioc); +	} +	mpt2sas_base_start_watchdog(ioc); +	ioc->is_driver_loading = 0; +	return 1; +} + +  /**   * _scsih_probe - attach and add scsi host   * @pdev: PCI device struct @@ -6911,10 +8138,16 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	ioc->id = mpt_ids++;  	sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);  	ioc->pdev = pdev; +	if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) { +		ioc->is_warpdrive = 1; +		ioc->hide_ir_msg = 1; +	} else +		ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;  	ioc->scsi_io_cb_idx = scsi_io_cb_idx;  	ioc->tm_cb_idx = tm_cb_idx;  	ioc->ctl_cb_idx = ctl_cb_idx;  	ioc->base_cb_idx = base_cb_idx; +	ioc->port_enable_cb_idx = port_enable_cb_idx;  	ioc->transport_cb_idx = transport_cb_idx;  	ioc->scsih_cb_idx = scsih_cb_idx;  	ioc->config_cb_idx = config_cb_idx; @@ -6922,6 +8155,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx;  	ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;  	ioc->logging_level = logging_level; +	ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds;  	/* misc semaphores and spin locks */  	mutex_init(&ioc->reset_in_progress_mutex);  	spin_lock_init(&ioc->ioc_reset_in_progress_lock); @@ -6939,6 +8173,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);  	INIT_LIST_HEAD(&ioc->delayed_tr_list);  	INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); +	INIT_LIST_HEAD(&ioc->reply_queue_list);  	/* init shost parameters */  	shost->max_cmd_len = 32; @@ -6946,6 +8181,25 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	shost->transportt = mpt2sas_transport_template;  	shost->unique_id = ioc->id; +	if (max_sectors != 0xFFFF) { +		if (max_sectors < 64) { +			shost->max_sectors = 64; +			printk(MPT2SAS_WARN_FMT "Invalid value %d passed " +			    "for max_sectors, range is 64 to 32767. Assigning " +			    "value of 64.\n", ioc->name, max_sectors); +		} else if (max_sectors > 32767) { +			shost->max_sectors = 32767; +			printk(MPT2SAS_WARN_FMT "Invalid value %d passed " +			    "for max_sectors, range is 64 to 8192. Assigning " +			    "default value of 32767.\n", ioc->name, +			    max_sectors); +		} else { +			shost->max_sectors = max_sectors & 0xFFFE; +			printk(MPT2SAS_INFO_FMT "The max_sectors value is " +			    "set to %d\n", ioc->name, shost->max_sectors); +		} +	} +  	if ((scsi_add_host(shost, &pdev->dev))) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); @@ -6953,8 +8207,14 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  		goto out_add_shost_fail;  	} -	scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION -	    | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION); +	/* register EEDP capabilities with SCSI layer */ +	if (prot_mask) +		scsi_host_set_prot(shost, prot_mask); +	else +		scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION +				   | SHOST_DIF_TYPE2_PROTECTION +				   | SHOST_DIF_TYPE3_PROTECTION); +  	scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);  	/* event thread */ @@ -6968,15 +8228,28 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  		goto out_thread_fail;  	} -	ioc->wait_for_port_enable_to_complete = 1; +	ioc->is_driver_loading = 1;  	if ((mpt2sas_base_attach(ioc))) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__);  		goto out_attach_fail;  	} -	ioc->wait_for_port_enable_to_complete = 0; -	_scsih_probe_devices(ioc); +	if (ioc->is_warpdrive) { +		if (ioc->mfg_pg10_hide_flag ==  MFG_PAGE10_EXPOSE_ALL_DISKS) +			ioc->hide_drives = 0; +		else if (ioc->mfg_pg10_hide_flag ==  MFG_PAGE10_HIDE_ALL_DISKS) +			ioc->hide_drives = 1; +		else { +			if (_scsih_get_num_volumes(ioc)) +				ioc->hide_drives = 1; +			else +				ioc->hide_drives = 0; +		} +	} else +		ioc->hide_drives = 0; +	scsi_scan_host(shost); +  	return 0;   out_attach_fail: @@ -6985,6 +8258,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	list_del(&ioc->list);  	scsi_remove_host(shost);   out_add_shost_fail: +	scsi_host_put(shost);  	return -ENODEV;  } @@ -7001,11 +8275,11 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)  {  	struct Scsi_Host *shost = pci_get_drvdata(pdev);  	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); -	u32 device_state; +	pci_power_t device_state;  	mpt2sas_base_stop_watchdog(ioc); -	flush_scheduled_work();  	scsi_block_requests(shost); +	_scsih_ir_shutdown(ioc);  	device_state = pci_choose_state(pdev, state);  	printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "  	    "operating state [D%d]\n", ioc->name, pdev, @@ -7013,7 +8287,6 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)  	mpt2sas_base_free_resources(ioc);  	pci_save_state(pdev); -	pci_disable_device(pdev);  	pci_set_power_state(pdev, device_state);  	return 0;  } @@ -7029,7 +8302,7 @@ _scsih_resume(struct pci_dev *pdev)  {  	struct Scsi_Host *shost = pci_get_drvdata(pdev);  	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); -	u32 device_state = pdev->current_state; +	pci_power_t device_state = pdev->current_state;  	int r;  	printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous " @@ -7168,7 +8441,7 @@ _scsih_pci_mmio_enabled(struct pci_dev *pdev)  	return PCI_ERS_RESULT_NEED_RESET;  } -static struct pci_error_handlers _scsih_err_handler = { +static const 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, @@ -7179,7 +8452,7 @@ static struct pci_driver scsih_driver = {  	.name		= MPT2SAS_DRIVER_NAME,  	.id_table	= scsih_pci_table,  	.probe		= _scsih_probe, -	.remove		= __devexit_p(_scsih_remove), +	.remove		= _scsih_remove,  	.shutdown	= _scsih_shutdown,  	.err_handler	= &_scsih_err_handler,  #ifdef CONFIG_PM @@ -7231,6 +8504,8 @@ _scsih_init(void)  	/* base internal commands callback handler */  	base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done); +	port_enable_cb_idx = mpt2sas_base_register_callback_handler( +		mpt2sas_port_enable_done);  	/* transport internal commands callback handler */  	transport_cb_idx = mpt2sas_base_register_callback_handler( @@ -7285,6 +8560,7 @@ _scsih_exit(void)  	mpt2sas_base_release_callback_handler(scsi_io_cb_idx);  	mpt2sas_base_release_callback_handler(tm_cb_idx);  	mpt2sas_base_release_callback_handler(base_cb_idx); +	mpt2sas_base_release_callback_handler(port_enable_cb_idx);  	mpt2sas_base_release_callback_handler(transport_cb_idx);  	mpt2sas_base_release_callback_handler(scsih_cb_idx);  	mpt2sas_base_release_callback_handler(config_cb_idx); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index b55c6dc0747..410f4a3e888 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-2010  LSI Corporation + * Copyright (C) 2007-2013  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -163,12 +163,15 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,  		return -EIO;  	} -	memset(identify, 0, sizeof(identify)); +	memset(identify, 0, sizeof(struct sas_identify));  	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);  	/* sas_address */  	identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress); +	/* phy number of the parent device this device is linked to */ +	identify->phy_identifier = sas_device_pg0.PhyNum; +  	/* device_type */  	switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {  	case MPI2_SAS_DEVICE_INFO_NO_DEVICE: @@ -299,7 +302,6 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,  	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) { @@ -372,8 +374,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,  	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->SASAddress = cpu_to_le64(sas_address);  	mpi_request->RequestDataLength =  	    cpu_to_le16(sizeof(struct rep_manu_request));  	psge = &mpi_request->SGL; @@ -400,8 +401,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,  	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);  	init_completion(&ioc->transport_cmds.done); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,  	    10*HZ); @@ -465,62 +466,149 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,  	return rc;  } +/** + * _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_by_sas_address(ioc, sas_address); +	else if (device_type == SAS_EDGE_EXPANDER_DEVICE || +	    device_type == SAS_FANOUT_EXPANDER_DEVICE) +		mpt2sas_expander_remove(ioc, sas_address); +	ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; +}  /** - * _transport_delete_duplicate_port - (see below description) + * _transport_delete_phy - helper function to removing single phy from port   * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @sas_address: sas address of device being added - * @phy_num: phy number + * @mpt2sas_port: mpt2sas per port object + * @mpt2sas_phy: mpt2sas per phy object   * - * This function is called when attempting to add a new port that is claiming - * the same phy resources already in use by another port.  If we don't release - * the claimed phy resources, the sas transport layer will hang from the BUG - * in sas_port_add_phy. + * 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   * - * The reason we would hit this issue is becuase someone is changing the - * sas address of a device on the fly, meanwhile controller firmware sends - * EVENTs out of order when removing the previous instance of the device. + * Returns nothing.   */  static void -_transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc, -    struct _sas_node *sas_node, u64 sas_address, int phy_num) +_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port, +	struct _sas_phy *mpt2sas_phy)  { -	struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate; -	struct _sas_phy *mpt2sas_phy; +	u64 sas_address = mpt2sas_port->remote_identify.sas_address; -	printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), " -	    "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address, -	    phy_num); +	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); -	mpt2sas_port_duplicate = NULL; -	list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) { -		dev_printk(KERN_ERR, &mpt2sas_port->port->dev, -		    "existing device at sas_addr(0x%016llx), num_phys(%d)\n", -		    (unsigned long long) -		    mpt2sas_port->remote_identify.sas_address, -		    mpt2sas_port->num_phys); -		list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, +	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) { -			dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev, -			    "phy_number(%d)\n", mpt2sas_phy->phy_id); -			if (mpt2sas_phy->phy_id == phy_num) -				mpt2sas_port_duplicate = mpt2sas_port; +			if (phy_srch == mpt2sas_phy) +				return;  		} +		_transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy); +			return;  	} -	if (!mpt2sas_port_duplicate) +} + +/** + * _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; -	dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev, -	    "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n", -	    (unsigned long long) -	    mpt2sas_port_duplicate->remote_identify.sas_address, phy_num); -	ioc->logging_level |= MPT_DEBUG_TRANSPORT; -	mpt2sas_transport_port_remove(ioc, -	    mpt2sas_port_duplicate->remote_identify.sas_address, -	    sas_node->sas_address); -	ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; +	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; +		} +	}  }  /** @@ -537,11 +625,13 @@ _transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node,  {  	int i; -	for (i = 0; i < sas_node->num_phys; i++) -		if (sas_node->phy[i].remote_identify.sas_address == sas_address) -			if (sas_node->phy[i].phy_belongs_to_port) -				_transport_delete_duplicate_port(ioc, sas_node, -					sas_address, 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]); +	}  }  /** @@ -705,9 +795,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  	spin_lock_irqsave(&ioc->sas_node_lock, flags);  	sas_node = _transport_sas_node_find_by_sas_address(ioc,  	    sas_address_parent); -	spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -	if (!sas_node) +	if (!sas_node) { +		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);  		return; +	}  	list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,  	    port_list) {  		if (mpt2sas_port->remote_identify.sas_address != sas_address) @@ -717,8 +808,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  		goto out;  	}   out: -	if (!found) +	if (!found) { +		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);  		return; +	}  	for (i = 0; i < sas_node->num_phys; i++) {  		if (sas_node->phy[i].remote_identify.sas_address == sas_address) @@ -726,6 +819,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  			    sizeof(struct sas_identify));  	} +	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);  	list_for_each_entry_safe(mpt2sas_phy, next_phy,  	    &mpt2sas_port->phy_list, port_siblings) {  		if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) @@ -899,18 +993,25 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,  	spin_lock_irqsave(&ioc->sas_node_lock, flags);  	sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); -	spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -	if (!sas_node) +	if (!sas_node) { +		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);  		return; +	}  	mpt2sas_phy = &sas_node->phy[phy_number];  	mpt2sas_phy->attached_handle = handle; -	if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) +	spin_unlock_irqrestore(&ioc->sas_node_lock, flags); +	if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {  		_transport_set_identify(ioc, handle,  		    &mpt2sas_phy->remote_identify); -	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)); +		_transport_del_phy_from_an_existing_port(ioc, sas_node, +		    mpt2sas_phy); +	}  	if (mpt2sas_phy->phy)  		mpt2sas_phy->phy->negotiated_linkrate = @@ -958,14 +1059,14 @@ struct phy_error_log_reply{  	u8 function; /* 0x11 */  	u8 function_result;  	u8 response_length; -	u16 expander_change_count; +	__be16 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; +	__be32 invalid_dword; +	__be32 running_disparity_error; +	__be32 loss_of_dword_sync; +	__be32 phy_reset_problem;  };  /** @@ -994,7 +1095,6 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc,  	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) { @@ -1069,8 +1169,7 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc,  	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->SASAddress = cpu_to_le64(phy->identify.sas_address);  	mpi_request->RequestDataLength =  	    cpu_to_le16(sizeof(struct phy_error_log_request));  	psge = &mpi_request->SGL; @@ -1097,8 +1196,8 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc,  	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); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,  	    10*HZ); @@ -1223,17 +1322,20 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)  	struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);  	struct _sas_device *sas_device;  	unsigned long flags; +	int rc;  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,  	    rphy->identify.sas_address); +	if (sas_device) { +		*identifier = sas_device->enclosure_logical_id; +		rc = 0; +	} else { +		*identifier = 0; +		rc = -ENXIO; +	}  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -	if (!sas_device) -		return -ENXIO; - -	*identifier = sas_device->enclosure_logical_id; -	return 0; +	return rc;  }  /** @@ -1248,16 +1350,17 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)  	struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);  	struct _sas_device *sas_device;  	unsigned long flags; +	int rc;  	spin_lock_irqsave(&ioc->sas_device_lock, flags);  	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,  	    rphy->identify.sas_address); +	if (sas_device) +		rc = sas_device->slot; +	else +		rc = -ENXIO;  	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -	if (!sas_device) -		return -ENXIO; - -	return sas_device->slot; +	return rc;  }  /* phy control request structure */ @@ -1315,7 +1418,6 @@ _transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc,  	void *data_out = NULL;  	dma_addr_t data_out_dma;  	u32 sz; -	u64 *sas_address_le;  	u16 wait_state_count;  	if (ioc->shost_recovery) { @@ -1395,8 +1497,7 @@ _transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc,  	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->SASAddress = cpu_to_le64(phy->identify.sas_address);  	mpi_request->RequestDataLength =  	    cpu_to_le16(sizeof(struct phy_error_log_request));  	psge = &mpi_request->SGL; @@ -1424,8 +1525,9 @@ _transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc,  	    "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); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,  	    10*HZ); @@ -1543,11 +1645,13 @@ _transport_phy_enable(struct sas_phy *phy, int enable)  {  	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);  	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; +	Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;  	Mpi2ConfigReply_t mpi_reply;  	u16 ioc_status;  	u16 sz;  	int rc = 0;  	unsigned long flags; +	int i, discovery_active;  	spin_lock_irqsave(&ioc->sas_node_lock, flags);  	if (_transport_sas_node_find_by_sas_address(ioc, @@ -1565,7 +1669,50 @@ _transport_phy_enable(struct sas_phy *phy, int enable)  	/* handle hba phys */ -	/* sas_iounit page 1 */ +	/* read sas_iounit page 0 */ +	sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * +	    sizeof(Mpi2SasIOUnit0PhyData_t)); +	sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); +	if (!sas_iounit_pg0) { +		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_pg0(ioc, &mpi_reply, +	    sas_iounit_pg0, 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; +	} + +	/* unable to enable/disable phys when when discovery is active */ +	for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) { +		if (sas_iounit_pg0->PhyData[i].PortFlags & +		    MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) { +			printk(MPT2SAS_ERR_FMT "discovery is active on " +			    "port = %d, phy = %d: unable to enable/disable " +			    "phys, try again later!\n", ioc->name, +			    sas_iounit_pg0->PhyData[i].Port, i); +			discovery_active = 1; +		} +	} + +	if (discovery_active) { +		rc = -EAGAIN; +		goto out; +	} + +	/* read sas_iounit page 1 */  	sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *  	    sizeof(Mpi2SasIOUnit1PhyData_t));  	sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); @@ -1590,7 +1737,18 @@ _transport_phy_enable(struct sas_phy *phy, int enable)  		rc = -EIO;  		goto out;  	} - +	/* copy Port/PortFlags/PhyFlags from page 0 */ +	for (i = 0; i < ioc->sas_hba.num_phys ; i++) { +		sas_iounit_pg1->PhyData[i].Port = +		    sas_iounit_pg0->PhyData[i].Port; +		sas_iounit_pg1->PhyData[i].PortFlags = +		    (sas_iounit_pg0->PhyData[i].PortFlags & +		    MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG); +		sas_iounit_pg1->PhyData[i].PhyFlags = +		    (sas_iounit_pg0->PhyData[i].PhyFlags & +		    (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED + +		    MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)); +	}  	if (enable)  		sas_iounit_pg1->PhyData[phy->number].PhyFlags  		    &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; @@ -1606,6 +1764,7 @@ _transport_phy_enable(struct sas_phy *phy, int enable)   out:  	kfree(sas_iounit_pg1); +	kfree(sas_iounit_pg0);  	return rc;  } @@ -1751,24 +1910,21 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  	u8 issue_reset = 0;  	dma_addr_t dma_addr_in = 0;  	dma_addr_t dma_addr_out = 0; +	dma_addr_t pci_dma_in = 0; +	dma_addr_t pci_dma_out = 0; +	void *pci_addr_in = NULL; +	void *pci_addr_out = NULL;  	u16 wait_state_count;  	struct request *rsp = req->next_rq; +	struct bio_vec bvec; +	struct bvec_iter iter;  	if (!rsp) {  		printk(MPT2SAS_ERR_FMT "%s: the smp response space is "  		    "missing\n", ioc->name, __func__);  		return -EINVAL;  	} - -	/* do we need to support multiple segments? */ -	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { -		printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, " -		    "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt, -		    blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); -		return -EINVAL; -	} - -	if (ioc->shost_recovery) { +	if (ioc->shost_recovery || ioc->pci_error_recovery) {  		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",  		    __func__, ioc->name);  		return -EFAULT; @@ -1786,6 +1942,59 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  	}  	ioc->transport_cmds.status = MPT2_CMD_PENDING; +	/* Check if the request is split across multiple segments */ +	if (bio_multiple_segments(req->bio)) { +		u32 offset = 0; + +		/* Allocate memory and copy the request */ +		pci_addr_out = pci_alloc_consistent(ioc->pdev, +		    blk_rq_bytes(req), &pci_dma_out); +		if (!pci_addr_out) { +			printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n", +			    ioc->name, __func__); +			rc = -ENOMEM; +			goto out; +		} + +		bio_for_each_segment(bvec, req->bio, iter) { +			memcpy(pci_addr_out + offset, +			    page_address(bvec.bv_page) + bvec.bv_offset, +			    bvec.bv_len); +			offset += bvec.bv_len; +		} +	} else { +		dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), +		    blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); +		if (!dma_addr_out) { +			printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n", +			    ioc->name, __func__); +			rc = -ENOMEM; +			goto free_pci; +		} +	} + +	/* Check if the response needs to be populated across +	 * multiple segments */ +	if (bio_multiple_segments(rsp->bio)) { +		pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), +		    &pci_dma_in); +		if (!pci_addr_in) { +			printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n", +			    ioc->name, __func__); +			rc = -ENOMEM; +			goto unmap; +		} +	} else { +		dma_addr_in =  pci_map_single(ioc->pdev, bio_data(rsp->bio), +		    blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); +		if (!dma_addr_in) { +			printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n", +			    ioc->name, __func__); +			rc = -ENOMEM; +			goto unmap; +		} +	} +  	wait_state_count = 0;  	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);  	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { @@ -1794,7 +2003,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  			    "%s: failed due to ioc not operational\n",  			    ioc->name, __func__);  			rc = -EFAULT; -			goto out; +			goto unmap;  		}  		ssleep(1);  		ioc_state = mpt2sas_base_get_iocstate(ioc, 1); @@ -1811,7 +2020,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__);  		rc = -EAGAIN; -		goto out; +		goto unmap;  	}  	rc = 0; @@ -1823,7 +2032,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  	mpi_request->PhysicalPort = 0xFF;  	mpi_request->VF_ID = 0; /* TODO */  	mpi_request->VP_ID = 0; -	*((u64 *)&mpi_request->SASAddress) = (rphy) ? +	mpi_request->SASAddress = (rphy) ?  	    cpu_to_le64(rphy->identify.sas_address) :  	    cpu_to_le64(ioc->sas_hba.sas_address);  	mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); @@ -1833,16 +2042,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |  	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);  	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -	dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), -		blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); -	if (!dma_addr_out) { -		mpt2sas_base_free_smid(ioc, smid); -		goto unmap; +	if (bio_multiple_segments(req->bio)) { +		ioc->base_add_sg_single(psge, sgl_flags | +		    (blk_rq_bytes(req) - 4), pci_dma_out); +	} else { +		ioc->base_add_sg_single(psge, sgl_flags | +		    (blk_rq_bytes(req) - 4), dma_addr_out);  	} -	ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4), -	    dma_addr_out); -  	/* incr sgel */  	psge += ioc->sge_size; @@ -1851,21 +2058,19 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  	    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |  	    MPI2_SGE_FLAGS_END_OF_LIST);  	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; -	dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), -				     blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); -	if (!dma_addr_in) { -		mpt2sas_base_free_smid(ioc, smid); -		goto unmap; +	if (bio_multiple_segments(rsp->bio)) { +		ioc->base_add_sg_single(psge, sgl_flags | +		    (blk_rq_bytes(rsp) + 4), pci_dma_in); +	} else { +		ioc->base_add_sg_single(psge, sgl_flags | +		    (blk_rq_bytes(rsp) + 4), dma_addr_in);  	} -	ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4), -	    dma_addr_in); -  	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "  	    "sending smp request\n", ioc->name, __func__)); -	mpt2sas_base_put_smid_default(ioc, smid);  	init_completion(&ioc->transport_cmds.done); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,  	    10*HZ); @@ -1896,6 +2101,27 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  		req->resid_len = 0;  		rsp->resid_len -=  		    le16_to_cpu(mpi_reply->ResponseDataLength); +		/* check if the resp needs to be copied from the allocated +		 * pci mem */ +		if (bio_multiple_segments(rsp->bio)) { +			u32 offset = 0; +			u32 bytes_to_copy = +			    le16_to_cpu(mpi_reply->ResponseDataLength); +			bio_for_each_segment(bvec, rsp->bio, iter) { +				if (bytes_to_copy <= bvec.bv_len) { +					memcpy(page_address(bvec.bv_page) + +					    bvec.bv_offset, pci_addr_in + +					    offset, bytes_to_copy); +					break; +				} else { +					memcpy(page_address(bvec.bv_page) + +					    bvec.bv_offset, pci_addr_in + +					    offset, bvec.bv_len); +					bytes_to_copy -= bvec.bv_len; +				} +				offset += bvec.bv_len; +			} +		}  	} else {  		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT  		    "%s - no reply\n", ioc->name, __func__)); @@ -1917,6 +2143,15 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  		pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),  		    PCI_DMA_BIDIRECTIONAL); + free_pci: +	if (pci_addr_out) +		pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out, +		    pci_dma_out); + +	if (pci_addr_in) +		pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in, +		    pci_dma_in); +   out:  	ioc->transport_cmds.status = MPT2_CMD_NOT_USED;  	mutex_unlock(&ioc->transport_cmds.mutex);  | 
