diff options
Diffstat (limited to 'drivers/message')
43 files changed, 7249 insertions, 3845 deletions
diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile index 95c9532cb07..d182a24b319 100644 --- a/drivers/message/fusion/Makefile +++ b/drivers/message/fusion/Makefile @@ -2,7 +2,7 @@ # enable verbose logging # CONFIG_FUSION_LOGGING needs to be enabled in Kconfig -#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE +#ccflags-y := -DMPT_DEBUG_VERBOSE #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h index 1acbdd61b67..11c0f461320 100644 --- a/drivers/message/fusion/lsi/mpi.h +++ b/drivers/message/fusion/lsi/mpi.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2007 LSI Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi.h * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * mpi.h Version: 01.05.13 + * mpi.h Version: 01.05.16 * * Version History * --------------- @@ -79,6 +79,9 @@ * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT. * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT. + * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT. + * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT. + * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -109,7 +112,7 @@ /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x10) +#define MPI_HEADER_VERSION_UNIT (0x13) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h index 2bd8adae0f0..d9bcfba6b04 100644 --- a/drivers/message/fusion/lsi/mpi_cnfg.h +++ b/drivers/message/fusion/lsi/mpi_cnfg.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2007 LSI Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_cnfg.h * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * mpi_cnfg.h Version: 01.05.15 + * mpi_cnfg.h Version: 01.05.18 * * Version History * --------------- @@ -308,6 +308,20 @@ * Expander Page 0 Flags field. * Fixed define for * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED. + * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT + * define. + * Added BIOS Page 4 structure. + * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID + * Physcial Disk Page 1. + * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of + * Manufacturing Page 4. + * Added Solid State Drives Supported bit to IOC Page 6 + * Capabilities Flags. + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field + * to control coercion size and the mixing of SAS and SATA + * SSD drives. * -------------------------------------------------------------------------- */ @@ -569,6 +583,7 @@ typedef struct _MSG_CONFIG_REPLY #define MPI_MANUFACTPAGE_DEVID_SAS1066E (0x005A) #define MPI_MANUFACTPAGE_DEVID_SAS1068 (0x0054) #define MPI_MANUFACTPAGE_DEVID_SAS1068E (0x0058) +#define MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP (0x0059) #define MPI_MANUFACTPAGE_DEVID_SAS1078 (0x0062) @@ -686,6 +701,14 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4 #define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) /* defines for the ExtFlags field */ +#define MPI_MANPAGE4_EXTFLAGS_MASK_COERCION_SIZE (0x0180) +#define MPI_MANPAGE4_EXTFLAGS_SHIFT_COERCION_SIZE (7) +#define MPI_MANPAGE4_EXTFLAGS_1GB_COERCION_SIZE (0) +#define MPI_MANPAGE4_EXTFLAGS_128MB_COERCION_SIZE (1) + +#define MPI_MANPAGE4_EXTFLAGS_NO_MIX_SSD_SAS_SATA (0x0040) +#define MPI_MANPAGE4_EXTFLAGS_MIX_SSD_AND_NON_SSD (0x0020) +#define MPI_MANPAGE4_EXTFLAGS_DUAL_PORT_SUPPORT (0x0010) #define MPI_MANPAGE4_EXTFLAGS_HIDE_NON_IR_METADATA (0x0008) #define MPI_MANPAGE4_EXTFLAGS_SAS_CACHE_DISABLE (0x0004) #define MPI_MANPAGE4_EXTFLAGS_SATA_CACHE_DISABLE (0x0002) @@ -1159,6 +1182,8 @@ typedef struct _CONFIG_PAGE_IOC_6 /* IOC Page 6 Capabilities Flags */ +#define MPI_IOCPAGE6_CAP_FLAGS_SSD_SUPPORT (0x00000020) +#define MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT (0x00000010) #define MPI_IOCPAGE6_CAP_FLAGS_DISABLE_SMART_POLLING (0x00000008) #define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006) @@ -1428,6 +1453,15 @@ typedef struct _CONFIG_PAGE_BIOS_2 #define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05) #define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) +typedef struct _CONFIG_PAGE_BIOS_4 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U64 ReassignmentBaseWWID; /* 04h */ +} CONFIG_PAGE_BIOS_4, MPI_POINTER PTR_CONFIG_PAGE_BIOS_4, + BIOSPage4_t, MPI_POINTER pBIOSPage4_t; + +#define MPI_BIOSPAGE4_PAGEVERSION (0x00) + /**************************************************************************** * SCSI Port Config Pages @@ -2419,6 +2453,15 @@ typedef struct _RAID_PHYS_DISK1_PATH #define MPI_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) #define MPI_RAID_PHYSDISK1_FLAG_INVALID (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumPhysDiskPaths at runtime. + */ +#ifndef MPI_RAID_PHYS_DISK1_PATH_MAX +#define MPI_RAID_PHYS_DISK1_PATH_MAX (1) +#endif + typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1 { CONFIG_PAGE_HEADER Header; /* 00h */ @@ -2426,7 +2469,7 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1 U8 PhysDiskNum; /* 05h */ U16 Reserved2; /* 06h */ U32 Reserved1; /* 08h */ - RAID_PHYS_DISK1_PATH Path[1]; /* 0Ch */ + RAID_PHYS_DISK1_PATH Path[MPI_RAID_PHYS_DISK1_PATH_MAX];/* 0Ch */ } CONFIG_PAGE_RAID_PHYS_DISK_1, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_1, RaidPhysDiskPage1_t, MPI_POINTER pRaidPhysDiskPage1_t; @@ -2551,6 +2594,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 #define MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE (0x03) #define MPI_SAS_IOUNIT0_RATE_1_5 (0x08) #define MPI_SAS_IOUNIT0_RATE_3_0 (0x09) +#define MPI_SAS_IOUNIT0_RATE_6_0 (0x0A) /* see mpi_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ @@ -2844,6 +2888,7 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_0 #define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) #define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) #define MPI_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) /* specific values for SATA Init failures */ #define MPI_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) #define MPI_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) diff --git a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h index 627acfbb862..7d663ce76f8 100644 --- a/drivers/message/fusion/lsi/mpi_fc.h +++ b/drivers/message/fusion/lsi/mpi_fc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_fc.h diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt index 241592ab13a..fa9249b4971 100644 --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -3,28 +3,28 @@ MPI Header File Change History ============================== - Copyright (c) 2000-2007 LSI Corporation. + Copyright (c) 2000-2008 LSI Corporation. --------------------------------------- - Header Set Release Version: 01.05.16 - Header Set Release Date: 05-24-07 + Header Set Release Version: 01.05.19 + Header Set Release Date: 03-28-08 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - mpi.h 01.05.13 01.05.12 - mpi_ioc.h 01.05.14 01.05.13 - mpi_cnfg.h 01.05.15 01.05.14 + mpi.h 01.05.16 01.05.15 + mpi_ioc.h 01.05.16 01.05.15 + mpi_cnfg.h 01.05.18 01.05.17 mpi_init.h 01.05.09 01.05.09 mpi_targ.h 01.05.06 01.05.06 mpi_fc.h 01.05.01 01.05.01 mpi_lan.h 01.05.01 01.05.01 - mpi_raid.h 01.05.03 01.05.03 + mpi_raid.h 01.05.05 01.05.05 mpi_tool.h 01.05.03 01.05.03 mpi_inb.h 01.05.01 01.05.01 - mpi_sas.h 01.05.04 01.05.04 + mpi_sas.h 01.05.05 01.05.05 mpi_type.h 01.05.02 01.05.02 - mpi_history.txt 01.05.14 01.05.14 + mpi_history.txt 01.05.19 01.05.18 * Date Version Description @@ -96,6 +96,9 @@ mpi.h * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT. * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT. + * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT. + * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT. + * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- mpi_ioc.h @@ -127,7 +130,7 @@ mpi_ioc.h * 08-08-01 01.02.01 Original release for v1.2 work. * New format for FWVersion and ProductId in * MSG_IOC_FACTS_REPLY and MPI_FW_HEADER. - * 08-31-01 01.02.02 Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and + * 08-31-01 01.02.02 Added event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and * related structure and defines. * Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED. * Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE. @@ -187,7 +190,7 @@ mpi_ioc.h * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED. * Added MaxInitiators field to PortFacts reply. * Added SAS Device Status Change ReasonCode for - * asynchronous notificaiton. + * asynchronous notification. * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event * data structure. * Added new ImageType values for FWDownload and FWUpload @@ -199,6 +202,16 @@ mpi_ioc.h * added _MULTI_PORT_DOMAIN. * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request. * Added Common Boot Block type to FWUpload Request. + * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define. + * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and + * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data. + * Added SASAddress field to SAS Initiator Device Table + * Overflow event data structure. + * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status + * Change Event data to indicate completion of internally + * generated task management. + * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define. + * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define. * -------------------------------------------------------------------------- mpi_cnfg.h @@ -496,6 +509,20 @@ mpi_cnfg.h * Expander Page 0 Flags field. * Fixed define for * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED. + * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT + * define. + * Added BIOS Page 4 structure. + * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID + * Physcial Disk Page 1. + * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of + * Manufacturing Page 4. + * Added Solid State Drives Supported bit to IOC Page 6 + * Capabilities Flags. + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field + * to control coercion size and the mixing of SAS and SATA + * SSD drives. * -------------------------------------------------------------------------- mpi_init.h @@ -596,7 +623,7 @@ mpi_fc.h * 11-02-00 01.01.01 Original release for post 1.0 work * 12-04-00 01.01.02 Added messages for Common Transport Send and * Primitive Send. - * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix + * 01-09-01 01.01.03 Modified some of the new flags to have an MPI prefix * and modified the FcPrimitiveSend flags. * 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger * field. @@ -661,6 +688,9 @@ mpi_raid.h * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE. * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and * associated defines. + * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord + * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME. + * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME. * -------------------------------------------------------------------------- mpi_tool.h @@ -694,6 +724,10 @@ mpi_sas.h * reply. * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO * Unit Control request. + * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER, + * including adding IOCParameter and IOCParameter value + * fields to SAS IO Unit Control Request. + * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define. * -------------------------------------------------------------------------- mpi_type.h @@ -709,20 +743,20 @@ mpi_type.h mpi_history.txt Parts list history -Filename 01.05.15 01.05.15 ----------- -------- -------- -mpi.h 01.05.12 01.05.13 -mpi_ioc.h 01.05.13 01.05.14 -mpi_cnfg.h 01.05.14 01.05.15 -mpi_init.h 01.05.09 01.05.09 -mpi_targ.h 01.05.06 01.05.06 -mpi_fc.h 01.05.01 01.05.01 -mpi_lan.h 01.05.01 01.05.01 -mpi_raid.h 01.05.03 01.05.03 -mpi_tool.h 01.05.03 01.05.03 -mpi_inb.h 01.05.01 01.05.01 -mpi_sas.h 01.05.04 01.05.04 -mpi_type.h 01.05.02 01.05.02 +Filename 01.05.19 01.05.18 01.05.17 01.05.16 01.05.15 +---------- -------- -------- -------- -------- -------- +mpi.h 01.05.16 01.05.15 01.05.14 01.05.13 01.05.12 +mpi_ioc.h 01.05.16 01.05.15 01.05.15 01.05.14 01.05.13 +mpi_cnfg.h 01.05.18 01.05.17 01.05.16 01.05.15 01.05.14 +mpi_init.h 01.05.09 01.05.09 01.05.09 01.05.09 01.05.09 +mpi_targ.h 01.05.06 01.05.06 01.05.06 01.05.06 01.05.06 +mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_raid.h 01.05.05 01.05.05 01.05.04 01.05.03 01.05.03 +mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 +mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_sas.h 01.05.05 01.05.05 01.05.04 01.05.04 01.05.04 +mpi_type.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 Filename 01.05.14 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 ---------- -------- -------- -------- -------- -------- -------- diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h index a9e3693601a..4295d062caa 100644 --- a/drivers/message/fusion/lsi/mpi_init.h +++ b/drivers/message/fusion/lsi/mpi_init.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2007 LSI Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_init.h diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h index 5cbb6bd048e..19fb21b8f0c 100644 --- a/drivers/message/fusion/lsi/mpi_ioc.h +++ b/drivers/message/fusion/lsi/mpi_ioc.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2007 LSI Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * mpi_ioc.h Version: 01.05.14 + * mpi_ioc.h Version: 01.05.16 * * Version History * --------------- @@ -113,6 +113,16 @@ * added _MULTI_PORT_DOMAIN. * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request. * Added Common Boot Block type to FWUpload Request. + * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define. + * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and + * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data. + * Added SASAddress field to SAS Initiator Device Table + * Overflow event data structure. + * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status + * Change Event data to indicate completion of internally + * generated task management. + * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define. + * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define. * -------------------------------------------------------------------------- */ @@ -612,6 +622,8 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE #define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) #define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) #define MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) +#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET (0x0E) +#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_TASK_ABORT_INTERNAL (0x0F) /* SCSI Event data for Queue Full event */ @@ -708,6 +720,8 @@ typedef struct _MPI_EVENT_DATA_IR2 #define MPI_EVENT_IR2_RC_PD_REMOVED (0x05) #define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED (0x06) #define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR (0x07) +#define MPI_EVENT_IR2_RC_DUAL_PORT_ADDED (0x08) +#define MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED (0x09) /* defines for logical disk states */ #define MPI_LD_STATE_OPTIMAL (0x00) @@ -827,6 +841,7 @@ typedef struct _EVENT_DATA_SAS_PHY_LINK_STATUS #define MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE (0x03) #define MPI_EVENT_SAS_PLS_LR_RATE_1_5 (0x08) #define MPI_EVENT_SAS_PLS_LR_RATE_3_0 (0x09) +#define MPI_EVENT_SAS_PLS_LR_RATE_6_0 (0x0A) /* SAS Discovery Event data */ @@ -842,7 +857,7 @@ typedef struct _EVENT_DATA_SAS_DISCOVERY #define MPI_EVENT_SAS_DSCVRY_PHY_BITS_MASK (0xFFFF0000) #define MPI_EVENT_SAS_DSCVRY_PHY_BITS_SHIFT (16) -/* SAS Discovery Errror Event data */ +/* SAS Discovery Error Event data */ typedef struct _EVENT_DATA_DISCOVERY_ERROR { @@ -867,6 +882,7 @@ typedef struct _EVENT_DATA_DISCOVERY_ERROR #define MPI_EVENT_DSCVRY_ERR_DS_UNSUPPORTED_DEVICE (0x00000800) #define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000) #define MPI_EVENT_DSCVRY_ERR_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE (0x00004000) /* SAS SMP Error Event data */ @@ -902,6 +918,8 @@ typedef struct _EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE /* defines for the ReasonCode field of the SAS Initiator Device Status Change event */ #define MPI_EVENT_SAS_INIT_RC_ADDED (0x01) +#define MPI_EVENT_SAS_INIT_RC_REMOVED (0x02) +#define MPI_EVENT_SAS_INIT_RC_INACCESSIBLE (0x03) /* SAS Initiator Device Table Overflow Event data */ @@ -910,6 +928,7 @@ typedef struct _EVENT_DATA_SAS_INIT_TABLE_OVERFLOW U8 MaxInit; /* 00h */ U8 CurrentInit; /* 01h */ U16 Reserved1; /* 02h */ + U64 SASAddress; /* 04h */ } EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, MpiEventDataSasInitTableOverflow_t, diff --git a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h index 03253b53b78..f41fcb69b35 100644 --- a/drivers/message/fusion/lsi/mpi_lan.h +++ b/drivers/message/fusion/lsi/mpi_lan.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_lan.h diff --git a/drivers/message/fusion/lsi/mpi_log_fc.h b/drivers/message/fusion/lsi/mpi_log_fc.h index e4dafcefeec..03be8b21770 100644 --- a/drivers/message/fusion/lsi/mpi_log_fc.h +++ b/drivers/message/fusion/lsi/mpi_log_fc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 LSI Corporation. All rights reserved. + * Copyright (c) 2000-2008 LSI Corporation. All rights reserved. * * NAME: fc_log.h * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips @@ -38,8 +38,8 @@ typedef enum _MpiIocLogInfoFc { MPI_IOCLOGINFO_FC_INIT_BASE = 0x20000000, MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */ - MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primative */ - MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* Bad Rx Frame, bad end of frame primative */ + MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primitive */ + MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* Bad Rx Frame, bad end of frame primitive */ MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN = 0x20000004, /* Bad Rx Frame, overrun */ MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER = 0x20000005, /* Other errors caught by IOC which require retries */ MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD = 0x20000006, /* Main processor could not initialize sub-processor */ diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h index af9da03e95e..f62960b5d52 100644 --- a/drivers/message/fusion/lsi/mpi_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -1,6 +1,6 @@ /*************************************************************************** * * - * Copyright 2003 LSI Corporation. All rights reserved. * + * Copyright (c) 2000-2008 LSI Corporation. All rights reserved. * * * * Description * * ------------ * @@ -56,9 +56,9 @@ #define IOP_LOGINFO_CODE_FWUPLOAD_NO_FLASH_AVAILABLE (0x0003E000) /* Tried to upload from flash, but there is none */ #define IOP_LOGINFO_CODE_FWUPLOAD_UNKNOWN_IMAGE_TYPE (0x0003E001) /* ImageType field contents were invalid */ #define IOP_LOGINFO_CODE_FWUPLOAD_WRONG_IMAGE_SIZE (0x0003E002) /* ImageSize field in TCSGE was bad/offset in MfgPg 4 was wrong */ -#define IOP_LOGINFO_CODE_FWUPLOAD_ENTIRE_FLASH_UPLOAD_FAILED (0x0003E003) /* Error occured while attempting to upload the entire flash */ -#define IOP_LOGINFO_CODE_FWUPLOAD_REGION_UPLOAD_FAILED (0x0003E004) /* Error occured while attempting to upload single flash region */ -#define IOP_LOGINFO_CODE_FWUPLOAD_DMA_FAILURE (0x0003E005) /* Problem occured while DMAing FW to host memory */ +#define IOP_LOGINFO_CODE_FWUPLOAD_ENTIRE_FLASH_UPLOAD_FAILED (0x0003E003) /* Error occurred while attempting to upload the entire flash */ +#define IOP_LOGINFO_CODE_FWUPLOAD_REGION_UPLOAD_FAILED (0x0003E004) /* Error occurred while attempting to upload single flash region */ +#define IOP_LOGINFO_CODE_FWUPLOAD_DMA_FAILURE (0x0003E005) /* Problem occurred while DMAing FW to host memory */ #define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */ @@ -73,6 +73,8 @@ #define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004) #define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005) +#define IOP_LOGINFO_CODE_LOG_TIMESTAMP_EVENT (0x00080000) + /****************************************************************************/ /* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL */ /****************************************************************************/ @@ -92,7 +94,7 @@ #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP (0x0000000C) #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D (0x0000000D) #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL (0x0000000E) -#define PL_LOGINFO_SUB CODE_OPEN_FAIL_BAD_DEST (0x00000011) +#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BAD_DEST (0x00000011) #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP (0x00000012) #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP (0x00000013) #define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0 (0x00000014) @@ -159,10 +161,11 @@ #define PL_LOGINFO_SUB_CODE_INVALID_SGL (0x00000200) #define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00000300) -#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */ - /* Bit 0 is Status Bit 0: FrameXferErr */ - /* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */ - /* Bit 3 is Status Bit 18 WriteDataLengthGTDataLengthErr */ +#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) +/* Bits 0-3 encode Transport Status Register (offset 0x08) */ +/* Bit 0 is Status Bit 0: FrameXferErr */ +/* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */ +/* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */ #define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500) #define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600) @@ -177,10 +180,15 @@ #define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01) #define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00) #define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000) +#define PL_LOGINFO_SUB_CODE_BREAK_ON_SATA_CONNECTION (0x00002000) +/* not currently used in mainline */ +#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK (0x00003000) +#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK_AIP (0x00004000) +#define PL_LOGINFO_SUB_CODE_BREAK_ON_INCOMPLETE_BREAK_RCVD (0x00005000) #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occured on SMP Write */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occurred on SMP Read */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occurred on SMP Write */ #define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL (0x00200040) /* Encl Mgmt services not available for this WWID */ #define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED (0x00200050) /* Address Mode not suppored */ #define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM (0x00200060) /* Invalid Slot Number in SEP Msg */ @@ -199,8 +207,8 @@ #define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE (0x00200103) /* SEP NACK'd, it is busy */ #define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */ #define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM (0x00200105) /* SEP stopped or sent bad chksum in Hdr */ -#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transfering data */ -#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transfering sense data */ +#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transferring data */ +#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transferring sense data */ #define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1 (0x00200108) /* SEP returned unknown scsi status */ #define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2 (0x00200109) /* SEP returned unknown scsi status */ #define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP (0x0020010A) /* SEP returned bad chksum after STOP */ @@ -243,6 +251,8 @@ #define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED (0x00010014) /* Activation failed trying to import the volume */ #define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED (0x00010015) +/* Activation failed trying to import the volume */ +#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_PHYS_DISKS (0x00010016) /* Phys Disk failed, too many phys disks */ #define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS (0x00010020) @@ -258,7 +268,7 @@ /* Compatibility Error : IR Disabled */ #define IR_LOGINFO_COMPAT_ERROR_RAID_DISABLED (0x00010030) -/* Compatibility Error : Inquiry Comand failed */ +/* Compatibility Error : Inquiry Command failed */ #define IR_LOGINFO_COMPAT_ERROR_INQUIRY_FAILED (0x00010031) /* Compatibility Error : Device not direct access device */ #define IR_LOGINFO_COMPAT_ERROR_NOT_DIRECT_ACCESS (0x00010032) @@ -285,6 +295,21 @@ /* Compatibility Error : IME size limited to < 2TB */ #define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D) +/* Device Firmware Update: DFU can only be started once */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DFU_IN_PROGRESS (0x00010050) +/* Device Firmware Update: Volume must be Optimal/Active/non-Quiesced */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DEVICE_IN_INVALID_STATE (0x00010051) +/* Device Firmware Update: DFU Timeout cannot be zero */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_INVALID_TIMEOUT (0x00010052) +/* Device Firmware Update: CREATE TIMER FAILED */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_NO_TIMERS (0x00010053) +/* Device Firmware Update: Failed to read SAS_IO_UNIT_PG_1 */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_READING_CFG_PAGE (0x00010054) +/* Device Firmware Update: Invalid SAS_IO_UNIT_PG_1 value(s) */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_PORT_IO_TIMEOUTS_REQUIRED (0x00010055) +/* Device Firmware Update: Unable to allocate memory for page */ +#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ALLOC_CFG_PAGE (0x00010056) + /****************************************************************************/ /* Defines for convenience */ diff --git a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h index 2856108421d..add60cc85be 100644 --- a/drivers/message/fusion/lsi/mpi_raid.h +++ b/drivers/message/fusion/lsi/mpi_raid.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2001-2007 LSI Corporation. + * Copyright (c) 2001-2008 LSI Corporation. * * * Name: mpi_raid.h * Title: MPI RAID message and structures * Creation Date: February 27, 2001 * - * mpi_raid.h Version: 01.05.03 + * mpi_raid.h Version: 01.05.05 * * Version History * --------------- @@ -34,6 +34,9 @@ * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE. * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and * associated defines. + * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord + * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME. + * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME. * -------------------------------------------------------------------------- */ @@ -93,6 +96,7 @@ typedef struct _MSG_RAID_ACTION #define MPI_RAID_ACTION_SET_RESYNC_RATE (0x13) #define MPI_RAID_ACTION_SET_DATA_SCRUB_RATE (0x14) #define MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) +#define MPI_RAID_ACTION_SET_VOLUME_NAME (0x16) /* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */ #define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC (0x00000001) @@ -105,6 +109,9 @@ typedef struct _MSG_RAID_ACTION #define MPI_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) #define MPI_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000002) +/* ActionDataWord defines for use with MPI_RAID_ACTION_DISABLE_VOLUME action */ +#define MPI_RAID_ACTION_ADATA_DISABLE_FULL_REBUILD (0x00000001) + /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */ #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL (0x00000001) diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h index 33fca83cefc..ab410036bbf 100644 --- a/drivers/message/fusion/lsi/mpi_sas.h +++ b/drivers/message/fusion/lsi/mpi_sas.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2004-2006 LSI Corporation. + * Copyright (c) 2004-2008 LSI Corporation. * * * Name: mpi_sas.h * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: August 19, 2004 * - * mpi_sas.h Version: 01.05.04 + * mpi_sas.h Version: 01.05.05 * * Version History * --------------- @@ -23,6 +23,10 @@ * reply. * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO * Unit Control request. + * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER, + * including adding IOCParameter and IOCParameter value + * fields to SAS IO Unit Control Request. + * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define. * -------------------------------------------------------------------------- */ @@ -60,6 +64,8 @@ * Values for the SAS DeviceInfo field used in SAS Device Status Change Event * data and SAS IO Unit Configuration pages. */ +#define MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC (0xF0000000) + #define MPI_SAS_DEVICE_INFO_SEP (0x00004000) #define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) #define MPI_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) @@ -216,7 +222,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ U16 DevHandle; /* 04h */ - U8 Reserved3; /* 06h */ + U8 IOCParameter; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 TargetID; /* 0Ch */ @@ -225,7 +231,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST U8 PrimFlags; /* 0Fh */ U32 Primitive; /* 10h */ U64 SASAddress; /* 14h */ - U32 Reserved4; /* 1Ch */ + U32 IOCParameterValue; /* 1Ch */ } MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST, SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t; @@ -241,6 +247,8 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST #define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) #define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* obsolete name */ #define MPI_SAS_OP_REMOVE_DEVICE (0x0D) +#define MPI_SAS_OP_SET_IOC_PARAMETER (0x0E) +#define MPI_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) /* values for the PrimFlags field */ #define MPI_SAS_PRIMFLAGS_SINGLE (0x08) @@ -256,7 +264,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY U8 MsgLength; /* 02h */ U8 Function; /* 03h */ U16 DevHandle; /* 04h */ - U8 Reserved3; /* 06h */ + U8 IOCParameter; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U16 Reserved4; /* 0Ch */ diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h index ff8c37d3fdc..c3dea7f6909 100644 --- a/drivers/message/fusion/lsi/mpi_targ.h +++ b/drivers/message/fusion/lsi/mpi_targ.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 LSI Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_targ.h diff --git a/drivers/message/fusion/lsi/mpi_tool.h b/drivers/message/fusion/lsi/mpi_tool.h index 8834ae6ce0f..53cd715aa7e 100644 --- a/drivers/message/fusion/lsi/mpi_tool.h +++ b/drivers/message/fusion/lsi/mpi_tool.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2005 LSI Corporation. + * Copyright (c) 2001-2008 LSI Corporation. * * * Name: mpi_tool.h diff --git a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h index 08dad9c1e44..888b26dbc41 100644 --- a/drivers/message/fusion/lsi/mpi_type.h +++ b/drivers/message/fusion/lsi/mpi_type.h @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2004 LSI Corporation. + * Copyright (c) 2000-2008 LSI Corporation. * * * Name: mpi_type.h * Title: MPI Basic type definitions * Creation Date: June 6, 2000 * - * mpi_type.h Version: 01.05.01 + * mpi_type.h Version: 01.05.02 * * Version History * --------------- diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index c6be6eba7dc..ebc0af7d769 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5,7 +5,7 @@ * For use with LSI PCI chip/adapter(s) * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -50,6 +50,7 @@ #include <linux/module.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/pci.h> @@ -62,6 +63,8 @@ #ifdef CONFIG_MTRR #include <asm/mtrr.h> #endif +#include <linux/kthread.h> +#include <scsi/scsi_host.h> #include "mptbase.h" #include "lsi/mpi_log_fc.h" @@ -79,9 +82,21 @@ MODULE_VERSION(my_VERSION); /* * cmd line parameters */ -static int mpt_msi_enable; -module_param(mpt_msi_enable, int, 0); -MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)"); + +static int mpt_msi_enable_spi; +module_param(mpt_msi_enable_spi, int, 0); +MODULE_PARM_DESC(mpt_msi_enable_spi, + " Enable MSI Support for SPI controllers (default=0)"); + +static int mpt_msi_enable_fc; +module_param(mpt_msi_enable_fc, int, 0); +MODULE_PARM_DESC(mpt_msi_enable_fc, + " Enable MSI Support for FC controllers (default=0)"); + +static int mpt_msi_enable_sas; +module_param(mpt_msi_enable_sas, int, 0); +MODULE_PARM_DESC(mpt_msi_enable_sas, + " Enable MSI Support for SAS controllers (default=0)"); static int mpt_channel_mapping; module_param(mpt_channel_mapping, int, 0); @@ -91,7 +106,17 @@ static int mpt_debug_level; static int mpt_set_debug_level(const char *val, struct kernel_param *kp); module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, &mpt_debug_level, 0600); -MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)"); +MODULE_PARM_DESC(mpt_debug_level, + " debug level - refer to mptdebug.h - (default=0)"); + +int mpt_fwfault_debug; +EXPORT_SYMBOL(mpt_fwfault_debug); +module_param(mpt_fwfault_debug, int, 0600); +MODULE_PARM_DESC(mpt_fwfault_debug, + "Enable detection of Firmware fault and halt Firmware on fault - (default=0)"); + +static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS] + [MPT_MAX_CALLBACKNAME_LEN+1]; #ifdef MFCNT static int mfcounter = 0; @@ -103,8 +128,6 @@ static int mfcounter = 0; * Public data... */ -struct proc_dir_entry *mpt_proc_root_dir; - #define WHOINIT_UNKNOWN 0xAA /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -123,7 +146,9 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; -static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *mpt_proc_root_dir; +#endif /* * Driver Callback Index's @@ -136,7 +161,8 @@ static u8 last_drv_idx; * Forward protos... */ static irqreturn_t mpt_interrupt(int irq, void *bus_id); -static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); +static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, + MPT_FRAME_HDR *reply); static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag); @@ -167,29 +193,26 @@ static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); -static void mpt_timer_expired(unsigned long data); static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); -static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); +static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, + int sleepFlag); static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); #ifdef CONFIG_PROC_FS -static int procmpt_summary_read(char *buf, char **start, off_t offset, - int request, int *eof, void *data); -static int procmpt_version_read(char *buf, char **start, off_t offset, - int request, int *eof, void *data); -static int procmpt_iocinfo_read(char *buf, char **start, off_t offset, - int request, int *eof, void *data); +static const struct file_operations mpt_summary_proc_fops; +static const struct file_operations mpt_version_proc_fops; +static const struct file_operations mpt_iocinfo_proc_fops; #endif static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); -//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); -static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); +static int ProcessEventNotification(MPT_ADAPTER *ioc, + EventNotificationReply_t *evReply, int *evHandlers); static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); -static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info); +static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx); static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc); @@ -253,6 +276,170 @@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass) return 0; } +/** + * mpt_is_discovery_complete - determine if discovery has completed + * @ioc: per adatper instance + * + * Returns 1 when discovery completed, else zero. + */ +static int +mpt_is_discovery_complete(MPT_ADAPTER *ioc) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasIOUnitPage0_t *buffer; + dma_addr_t dma_handle; + int rc = 0; + + memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); + memset(&cfg, 0, sizeof(CONFIGPARMS)); + hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + cfg.cfghdr.ehdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if ((mpt_config(ioc, &cfg))) + goto out; + if (!hdr.ExtPageLength) + goto out; + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) + goto out; + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if ((mpt_config(ioc, &cfg))) + goto out_free_consistent; + + if (!(buffer->PhyData[0].PortFlags & + MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)) + rc = 1; + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return rc; +} + + +/** + * mpt_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 mpt_remove_dead_ioc_func(void *arg) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + struct pci_dev *pdev; + + if ((ioc == NULL)) + return -1; + + pdev = ioc->pcidev; + if ((pdev == NULL)) + return -1; + + pci_stop_and_remove_bus_device_locked(pdev); + return 0; +} + + + +/** + * mpt_fault_reset_work - work performed on workq after ioc fault + * @work: input argument, used to derive ioc + * +**/ +static void +mpt_fault_reset_work(struct work_struct *work) +{ + MPT_ADAPTER *ioc = + container_of(work, MPT_ADAPTER, fault_reset_work.work); + u32 ioc_raw_state; + int rc; + unsigned long flags; + MPT_SCSI_HOST *hd; + struct task_struct *p; + + if (ioc->ioc_reset_in_progress || !ioc->active) + goto out; + + + ioc_raw_state = mpt_GetIocState(ioc, 0); + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) { + printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n", + ioc->name, __func__); + + /* + * Call mptscsih_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. + */ + hd = shost_priv(ioc->sh); + ioc->schedule_dead_ioc_flush_running_cmds(hd); + + /*Remove the Dead Host */ + p = kthread_run(mpt_remove_dead_ioc_func, ioc, + "mpt_dead_ioc_%d", ioc->id); + if (IS_ERR(p)) { + printk(MYIOC_s_ERR_FMT + "%s: Running mpt_dead_ioc thread failed !\n", + ioc->name, __func__); + } else { + printk(MYIOC_s_WARN_FMT + "%s: Running mpt_dead_ioc thread success !\n", + ioc->name, __func__); + } + return; /* don't rearm timer */ + } + + if ((ioc_raw_state & MPI_IOC_STATE_MASK) + == MPI_IOC_STATE_FAULT) { + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", + ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); + printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", + ioc->name, __func__); + rc = mpt_HardResetHandler(ioc, CAN_SLEEP); + printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, + __func__, (rc == 0) ? "success" : "failed"); + ioc_raw_state = mpt_GetIocState(ioc, 0); + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) + printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " + "reset (%04xh)\n", ioc->name, ioc_raw_state & + MPI_DOORBELL_DATA_MASK); + } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) { + if ((mpt_is_discovery_complete(ioc))) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing " + "discovery_quiesce_io flag\n", ioc->name)); + ioc->sas_discovery_quiesce_io = 0; + } + } + + out: + /* + * Take turns polling alternate controller + */ + if (ioc->alt_ioc) + ioc = ioc->alt_ioc; + + /* rearm the timer */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->reset_work_q) + queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, + msecs_to_jiffies(MPT_POLLING_INTERVAL)); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +} + + /* * Process turbo (context) reply... */ @@ -307,7 +494,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || MptCallbacks[cb_idx] == NULL) { printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", - __FUNCTION__, ioc->name, cb_idx); + __func__, ioc->name, cb_idx); goto out; } @@ -361,7 +548,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) else if (ioc->bus_type == SPI) mpt_spi_log_info(ioc, log_info); else if (ioc->bus_type == SAS) - mpt_sas_log_info(ioc, log_info); + mpt_sas_log_info(ioc, log_info, cb_idx); } if (ioc_stat & MPI_IOCSTATUS_MASK) @@ -371,7 +558,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || MptCallbacks[cb_idx] == NULL) { printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", - __FUNCTION__, ioc->name, cb_idx); + __func__, ioc->name, cb_idx); freeme = 0; goto out; } @@ -429,9 +616,9 @@ mpt_interrupt(int irq, void *bus_id) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_base_reply - MPT base driver's callback routine + * mptbase_reply - MPT base driver's callback routine * @ioc: Pointer to MPT_ADAPTER structure - * @mf: Pointer to original MPT request frame + * @req: Pointer to original MPT request frame * @reply: Pointer to MPT reply frame (NULL if TurboReply) * * MPT base driver's callback routine; all base driver @@ -442,122 +629,49 @@ mpt_interrupt(int irq, void *bus_id) * should be freed, or 0 if it shouldn't. */ static int -mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) +mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { + EventNotificationReply_t *pEventReply; + u8 event; + int evHandlers; int freereq = 1; - u8 func; - - dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name)); -#ifdef CONFIG_FUSION_LOGGING - if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) && - !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { - dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n", - ioc->name, mf)); - DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf); - } -#endif - func = reply->u.hdr.Function; - dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n", - ioc->name, func)); - - if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { - EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply; - int evHandlers = 0; - int results; - - results = ProcessEventNotification(ioc, pEvReply, &evHandlers); - if (results != evHandlers) { - /* CHECKME! Any special handling needed here? */ - devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", - ioc->name, evHandlers, results)); - } - - /* - * Hmmm... It seems that EventNotificationReply is an exception - * to the rule of one reply per request. - */ - if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) { + switch (reply->u.hdr.Function) { + case MPI_FUNCTION_EVENT_NOTIFICATION: + pEventReply = (EventNotificationReply_t *)reply; + evHandlers = 0; + ProcessEventNotification(ioc, pEventReply, &evHandlers); + event = le32_to_cpu(pEventReply->Event) & 0xFF; + if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) freereq = 0; - } else { - devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n", - ioc->name, pEvReply)); - } - -#ifdef CONFIG_PROC_FS -// LogEvent(ioc, pEvReply); -#endif - - } else if (func == MPI_FUNCTION_EVENT_ACK) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n", - ioc->name)); - } else if (func == MPI_FUNCTION_CONFIG) { - CONFIGPARMS *pCfg; - unsigned long flags; - - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n", - ioc->name, mf, reply)); - - pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *))); - - if (pCfg) { - /* disable timer and remove from linked list */ - del_timer(&pCfg->timer); - - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_del(&pCfg->linkage); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - /* - * If IOC Status is SUCCESS, save the header - * and set the status code to GOOD. - */ - pCfg->status = MPT_CONFIG_ERROR; - if (reply) { - ConfigReply_t *pReply = (ConfigReply_t *)reply; - u16 status; - - status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; - dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n", - ioc->name, status, le32_to_cpu(pReply->IOCLogInfo))); - - pCfg->status = status; - if (status == MPI_IOCSTATUS_SUCCESS) { - if ((pReply->Header.PageType & - MPI_CONFIG_PAGETYPE_MASK) == - MPI_CONFIG_PAGETYPE_EXTENDED) { - pCfg->cfghdr.ehdr->ExtPageLength = - le16_to_cpu(pReply->ExtPageLength); - pCfg->cfghdr.ehdr->ExtPageType = - pReply->ExtPageType; - } - pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; - - /* If this is a regular header, save PageLength. */ - /* LMP Do this better so not using a reserved field! */ - pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; - pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; - pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; - } - } - - /* - * Wake up the original calling thread - */ - pCfg->wait_done = 1; - wake_up(&mpt_waitq); + if (event != MPI_EVENT_EVENT_CHANGE) + break; + case MPI_FUNCTION_CONFIG: + case MPI_FUNCTION_SAS_IO_UNIT_CONTROL: + ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + if (reply) { + ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->mptbase_cmds.reply, reply, + min(MPT_DEFAULT_FRAME_SIZE, + 4 * reply->u.reply.MsgLength)); } - } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) { - /* we should be always getting a reply frame */ - memcpy(ioc->persist_reply_frame, reply, - min(MPT_DEFAULT_FRAME_SIZE, - 4*reply->u.reply.MsgLength)); - del_timer(&ioc->persist_timer); - ioc->persist_wait_done = 1; - wake_up(&mpt_waitq); - } else { - printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n", - ioc->name, func); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->mptbase_cmds.done); + } else + freereq = 0; + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF) + freereq = 1; + break; + case MPI_FUNCTION_EVENT_ACK: + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "EventAck reply received\n", ioc->name)); + break; + default: + printk(MYIOC_s_ERR_FMT + "Unexpected msg function (=%02Xh) reply received!\n", + ioc->name, reply->u.hdr.Function); + break; } /* @@ -572,6 +686,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) * mpt_register - Register protocol-specific main callback handler. * @cbfunc: callback function pointer * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) + * @func_name: call function's name * * This routine is called by a protocol-specific driver (SCSI host, * LAN, SCSI target) to register its reply callback routine. Each @@ -588,7 +703,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) * considered an error by the caller. */ u8 -mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) +mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name) { u8 cb_idx; last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS; @@ -603,6 +718,8 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) MptDriverClass[cb_idx] = dclass; MptEvHandlers[cb_idx] = NULL; last_drv_idx = cb_idx; + strlcpy(MptCallbacksName[cb_idx], func_name, + MPT_MAX_CALLBACKNAME_LEN+1); break; } } @@ -903,7 +1020,6 @@ mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_free_msg_frame - Place MPT request frame back on FreeQ. - * @handle: Handle of registered MPT protocol driver * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * @@ -917,17 +1033,21 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) /* Put Request back on FreeQ! */ spin_lock_irqsave(&ioc->FreeQlock, flags); - mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */ - list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); + if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf) + goto out; + /* signature to know if this mf is freed */ + mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); + list_add(&mf->u.frame.linkage.list, &ioc->FreeQ); #ifdef MFCNT ioc->mfcnt--; #endif + out: spin_unlock_irqrestore(&ioc->FreeQlock, flags); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_add_sge - Place a simple SGE at address pAddr. + * mpt_add_sge - Place a simple 32 bit SGE at address pAddr. * @pAddr: virtual address for SGE * @flagslength: SGE flags and data transfer length * @dma_addr: Physical address @@ -935,23 +1055,116 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) * This routine places a MPT request frame back on the MPT adapter's * FreeQ. */ -void -mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) +static void +mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr) +{ + SGESimple32_t *pSge = (SGESimple32_t *) pAddr; + pSge->FlagsLength = cpu_to_le32(flagslength); + pSge->Address = cpu_to_le32(dma_addr); +} + +/** + * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr. + * @pAddr: virtual address for SGE + * @flagslength: SGE flags and data transfer length + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + **/ +static void +mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr) { - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + pSge->Address.Low = cpu_to_le32 + (lower_32_bits(dma_addr)); + pSge->Address.High = cpu_to_le32 + (upper_32_bits(dma_addr)); + pSge->FlagsLength = cpu_to_le32 + ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); +} + +/** + * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround). + * @pAddr: virtual address for SGE + * @flagslength: SGE flags and data transfer length + * @dma_addr: Physical address + * + * This routine places a MPT request frame back on the MPT adapter's + * FreeQ. + **/ +static void +mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr) +{ + SGESimple64_t *pSge = (SGESimple64_t *) pAddr; + u32 tmp; + + pSge->Address.Low = cpu_to_le32 + (lower_32_bits(dma_addr)); + tmp = (u32)(upper_32_bits(dma_addr)); + + /* + * 1078 errata workaround for the 36GB limitation + */ + if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) { + flagslength |= + MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS); + tmp |= (1<<31); + if (mpt_debug_level & MPT_DEBUG_36GB_MEM) + printk(KERN_DEBUG "1078 P0M2 addressing for " + "addr = 0x%llx len = %d\n", + (unsigned long long)dma_addr, + MPI_SGE_LENGTH(flagslength)); + } + + pSge->Address.High = cpu_to_le32(tmp); + pSge->FlagsLength = cpu_to_le32( + (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_add_chain - Place a 32 bit chain SGE at address pAddr. + * @pAddr: virtual address for SGE + * @next: nextChainOffset value (u32's) + * @length: length of next SGL segment + * @dma_addr: Physical address + * + */ +static void +mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) +{ + SGEChain32_t *pChain = (SGEChain32_t *) pAddr; + pChain->Length = cpu_to_le16(length); + pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; + pChain->NextChainOffset = next; + pChain->Address = cpu_to_le32(dma_addr); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr. + * @pAddr: virtual address for SGE + * @next: nextChainOffset value (u32's) + * @length: length of next SGL segment + * @dma_addr: Physical address + * + */ +static void +mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) +{ + SGEChain64_t *pChain = (SGEChain64_t *) pAddr; u32 tmp = dma_addr & 0xFFFFFFFF; - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pSge->Address.High = cpu_to_le32(tmp); + pChain->Length = cpu_to_le16(length); + pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING); - } else { - SGESimple32_t *pSge = (SGESimple32_t *) pAddr; - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address = cpu_to_le32(dma_addr); - } + pChain->NextChainOffset = next; + + pChain->Address.Low = cpu_to_le32(tmp); + tmp = (u32)(upper_32_bits(dma_addr)); + pChain->Address.High = cpu_to_le32(tmp); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1146,15 +1359,11 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) psge = (char *)&ioc_init->HostPageBufferSGE; flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_SYSTEM_ADDRESS | - MPI_SGE_FLAGS_32_BIT_ADDRESSING | MPI_SGE_FLAGS_HOST_TO_IOC | MPI_SGE_FLAGS_END_OF_BUFFER; - if (sizeof(dma_addr_t) == sizeof(u64)) { - flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING; - } flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; flags_length |= ioc->HostPageBuffer_sz; - mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma); + ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; return 0; @@ -1440,11 +1649,10 @@ mpt_mapresources(MPT_ADAPTER *ioc) { u8 __iomem *mem; int ii; - unsigned long mem_phys; + resource_size_t mem_phys; unsigned long port; u32 msize; u32 psize; - u8 revision; int r = -ENODEV; struct pci_dev *pdev; @@ -1458,26 +1666,45 @@ mpt_mapresources(MPT_ADAPTER *ioc) if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) { printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with " "MEM failed\n", ioc->name); - return r; - } - - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - - if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) - && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT - ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", - ioc->name)); - } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK) - && !pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT - ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", - ioc->name)); + goto out_pci_disable_device; + } + + if (sizeof(dma_addr_t) > 4) { + const uint64_t required_mask = dma_get_required_mask + (&pdev->dev); + if (required_mask > DMA_BIT_MASK(32) + && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) + && !pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(64))) { + ioc->dma_mask = DMA_BIT_MASK(64); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) + && !pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32))) { + ioc->dma_mask = DMA_BIT_MASK(32); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else { + printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", + ioc->name, pci_name(pdev)); + goto out_pci_release_region; + } } else { - printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", - ioc->name, pci_name(pdev)); - pci_release_selected_regions(pdev, ioc->bars); - return r; + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) + && !pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32))) { + ioc->dma_mask = DMA_BIT_MASK(32); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", + ioc->name)); + } else { + printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", + ioc->name, pci_name(pdev)); + goto out_pci_release_region; + } } mem_phys = msize = 0; @@ -1506,11 +1733,12 @@ mpt_mapresources(MPT_ADAPTER *ioc) if (mem == NULL) { printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter" " memory!\n", ioc->name); - return -EINVAL; + r = -EINVAL; + goto out_pci_release_region; } ioc->memmap = mem; - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", - ioc->name, mem, mem_phys)); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n", + ioc->name, mem, (unsigned long long)mem_phys)); ioc->mem_phys = mem_phys; ioc->chip = (SYSIF_REGS __iomem *)mem; @@ -1520,6 +1748,12 @@ mpt_mapresources(MPT_ADAPTER *ioc) ioc->pio_chip = (SYSIF_REGS __iomem *)port; return 0; + +out_pci_release_region: + pci_release_selected_regions(pdev, ioc->bars); +out_pci_disable_device: + pci_disable_device(pdev); + return r; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1546,11 +1780,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) MPT_ADAPTER *ioc; u8 cb_idx; int r = -ENODEV; - u8 revision; u8 pcixcmd; static int mpt_ids = 0; #ifdef CONFIG_PROC_FS - struct proc_dir_entry *dent, *ent; + struct proc_dir_entry *dent; #endif ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); @@ -1561,6 +1794,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->id = mpt_ids++; sprintf(ioc->name, "ioc%d", ioc->id); + dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n")); /* * set initial debug level @@ -1579,14 +1813,35 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) return r; } + /* + * Setting up proper handlers for scatter gather handling + */ + if (ioc->dma_mask == DMA_BIT_MASK(64)) { + if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) + ioc->add_sge = &mpt_add_sge_64bit_1078; + else + ioc->add_sge = &mpt_add_sge_64bit; + ioc->add_chain = &mpt_add_chain_64bit; + ioc->sg_addr_size = 8; + } else { + ioc->add_sge = &mpt_add_sge; + ioc->add_chain = &mpt_add_chain; + ioc->sg_addr_size = 4; + } + ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; + ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; - ioc->pcidev = pdev; - ioc->diagPending = 0; - spin_lock_init(&ioc->diagLock); - spin_lock_init(&ioc->initializing_hba_lock); + + spin_lock_init(&ioc->taskmgmt_lock); + mutex_init(&ioc->internal_cmds.mutex); + init_completion(&ioc->internal_cmds.done); + mutex_init(&ioc->mptbase_cmds.mutex); + init_completion(&ioc->mptbase_cmds.done); + mutex_init(&ioc->taskmgmt_cmds.mutex); + init_completion(&ioc->taskmgmt_cmds.done); /* Initialize the event logging. */ @@ -1599,16 +1854,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->mfcnt = 0; #endif + ioc->sh = NULL; ioc->cached_fw = NULL; - /* Initilize SCSI Config Data structure + /* Initialize SCSI Config Data structure */ memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); - /* Initialize the running configQ head. - */ - INIT_LIST_HEAD(&ioc->configQ); - /* Initialize the fc rport list head. */ INIT_LIST_HEAD(&ioc->fc_rports); @@ -1616,11 +1868,27 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) /* Find lookup slot. */ INIT_LIST_HEAD(&ioc->list); + + /* Initialize workqueue */ + INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); + + snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN, + "mpt_poll_%d", ioc->id); + ioc->reset_work_q = + create_singlethread_workqueue(ioc->reset_work_q_name); + if (!ioc->reset_work_q) { + printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", + ioc->name); + pci_release_selected_regions(pdev, ioc->bars); + kfree(ioc); + return -ENOMEM; + } + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", ioc->name, &ioc->facts, &ioc->pfacts[0])); - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name); + mpt_get_product_name(pdev->vendor, pdev->device, pdev->revision, + ioc->prod_name); switch (pdev->device) { @@ -1635,7 +1903,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) break; case MPI_MANUFACTPAGE_DEVICEID_FC929X: - if (revision < XL_929) { + if (pdev->revision < XL_929) { /* 929X Chip Fix. Set Split transactions level * for PCIX. Set MOST bits to zero. */ @@ -1666,7 +1934,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) /* 1030 Chip Fix. Disable Split transactions * for PCIX. Set MOST bits to zero if Rev < C0( = 8). */ - if (revision < C0_1030) { + if (pdev->revision < C0_1030) { pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); @@ -1679,13 +1947,38 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) case MPI_MANUFACTPAGE_DEVID_SAS1064: case MPI_MANUFACTPAGE_DEVID_SAS1068: ioc->errata_flag_1064 = 1; + ioc->bus_type = SAS; + break; case MPI_MANUFACTPAGE_DEVID_SAS1064E: case MPI_MANUFACTPAGE_DEVID_SAS1068E: case MPI_MANUFACTPAGE_DEVID_SAS1078: ioc->bus_type = SAS; + break; } + + switch (ioc->bus_type) { + + case SAS: + ioc->msi_enable = mpt_msi_enable_sas; + break; + + case SPI: + ioc->msi_enable = mpt_msi_enable_spi; + break; + + case FC: + ioc->msi_enable = mpt_msi_enable_fc; + break; + + default: + ioc->msi_enable = 0; + break; + } + + ioc->fw_events_off = 1; + if (ioc->errata_flag_1064) pci_disable_io_access(pdev); @@ -1706,6 +1999,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) */ mpt_detect_bound_ports(ioc, pdev); + INIT_LIST_HEAD(&ioc->fw_event_list); + spin_lock_init(&ioc->fw_event_lock); + snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id); + ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name); + if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0){ printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", @@ -1717,6 +2015,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) iounmap(ioc->memmap); if (r != -5) pci_release_selected_regions(pdev, ioc->bars); + + destroy_workqueue(ioc->reset_work_q); + ioc->reset_work_q = NULL; + kfree(ioc); pci_set_drvdata(pdev, NULL); return r; @@ -1736,19 +2038,15 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) */ dent = proc_mkdir(ioc->name, mpt_proc_root_dir); if (dent) { - ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent); - if (ent) { - ent->read_proc = procmpt_iocinfo_read; - ent->data = ioc; - } - ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent); - if (ent) { - ent->read_proc = procmpt_summary_read; - ent->data = ioc; - } + proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc); + proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc); } #endif + if (!ioc->alt_ioc) + queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, + msecs_to_jiffies(MPT_POLLING_INTERVAL)); + return 0; } @@ -1764,6 +2062,24 @@ mpt_detach(struct pci_dev *pdev) MPT_ADAPTER *ioc = pci_get_drvdata(pdev); char pname[32]; u8 cb_idx; + unsigned long flags; + struct workqueue_struct *wq; + + /* + * Stop polling ioc for fault condition + */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + wq = ioc->reset_work_q; + ioc->reset_work_q = NULL; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + cancel_delayed_work(&ioc->fault_reset_work); + destroy_workqueue(wq); + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + wq = ioc->fw_event_q; + ioc->fw_event_q = NULL; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + destroy_workqueue(wq); sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); remove_proc_entry(pname, NULL); @@ -1793,7 +2109,6 @@ mpt_detach(struct pci_dev *pdev) mpt_adapter_dispose(ioc); - pci_set_drvdata(pdev, NULL); } /************************************************************************** @@ -1831,7 +2146,7 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state) CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); free_irq(ioc->pci_irq, ioc); - if (mpt_msi_enable) + if (ioc->msi_enable) pci_disable_msi(ioc->pcidev); ioc->pci_irq = -1; pci_save_state(pdev); @@ -1866,6 +2181,21 @@ mpt_resume(struct pci_dev *pdev) if (err) return err; + if (ioc->dma_mask == DMA_BIT_MASK(64)) { + if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) + ioc->add_sge = &mpt_add_sge_64bit_1078; + else + ioc->add_sge = &mpt_add_sge_64bit; + ioc->add_chain = &mpt_add_chain_64bit; + ioc->sg_addr_size = 8; + } else { + + ioc->add_sge = &mpt_add_sge; + ioc->add_chain = &mpt_add_chain; + ioc->sg_addr_size = 4; + } + ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; + printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), CHIPREG_READ32(&ioc->chip->Doorbell)); @@ -1948,8 +2278,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) int hard; int rc=0; int ii; - u8 cb_idx; - int handlers; int ret = 0; int reset_alt_ioc_active = 0; int irq_allocated = 0; @@ -1963,12 +2291,16 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) ioc->active = 0; if (ioc->alt_ioc) { - if (ioc->alt_ioc->active) + if (ioc->alt_ioc->active || + reason == MPT_HOSTEVENT_IOC_RECOVER) { reset_alt_ioc_active = 1; - - /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */ - CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF); - ioc->alt_ioc->active = 0; + /* Disable alt-IOC's reply interrupts + * (and FreeQ) for a bit + **/ + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, + 0xFFFFFFFF); + ioc->alt_ioc->active = 0; + } } hard = 1; @@ -1989,9 +2321,11 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } } else { - printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name); + printk(MYIOC_s_WARN_FMT + "NOT READY WARNING!\n", ioc->name); } - return -1; + ret = -1; + goto out; } /* hard_reset_done = 0 if a soft reset was performed @@ -2001,7 +2335,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else - printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name); + printk(MYIOC_s_WARN_FMT + ": alt-ioc Not ready WARNING!\n", + ioc->alt_ioc->name); } for (ii=0; ii<5; ii++) { @@ -2022,7 +2358,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if (alt_ioc_ready) { if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); + "Initial Alt IocFacts failed rc=%x\n", + ioc->name, rc)); /* Retry - alt IOC was initialized once */ rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); @@ -2057,23 +2394,29 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { ioc->pci_irq = -1; if (ioc->pcidev->irq) { - if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev)) + if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev)) printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", ioc->name); + else + ioc->msi_enable = 0; rc = request_irq(ioc->pcidev->irq, mpt_interrupt, IRQF_SHARED, ioc->name, ioc); if (rc < 0) { printk(MYIOC_s_ERR_FMT "Unable to allocate " - "interrupt %d!\n", ioc->name, ioc->pcidev->irq); - if (mpt_msi_enable) + "interrupt %d!\n", + ioc->name, ioc->pcidev->irq); + if (ioc->msi_enable) pci_disable_msi(ioc->pcidev); - return -EBUSY; + ret = -EBUSY; + goto out; } irq_allocated = 1; ioc->pci_irq = ioc->pcidev->irq; pci_set_master(ioc->pcidev); /* ?? */ - dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt " - "%d\n", ioc->name, ioc->pcidev->irq)); + pci_set_drvdata(ioc->pcidev, ioc); + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "installed at interrupt %d\n", ioc->name, + ioc->pcidev->irq)); } } @@ -2082,17 +2425,22 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * init as upper addresses are needed for init. * If fails, continue with alt-ioc processing */ + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n", + ioc->name)); if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) ret = -3; /* May need to check/upload firmware & data here! * If fails, continue with alt-ioc processing */ + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n", + ioc->name)); if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) ret = -4; // NEW! if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { - printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n", + printk(MYIOC_s_WARN_FMT + ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", ioc->alt_ioc->name, rc); alt_ioc_ready = 0; reset_alt_ioc_active = 0; @@ -2102,8 +2450,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; reset_alt_ioc_active = 0; - printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n", - ioc->alt_ioc->name, rc); + printk(MYIOC_s_WARN_FMT + ": alt-ioc: (%d) init failure WARNING!\n", + ioc->alt_ioc->name, rc); } } @@ -2139,28 +2488,36 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } } + /* Enable MPT base driver management of EventNotification + * and EventAck handling. + */ + if ((ret == 0) && (!ioc->facts.EventState)) { + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "SendEventNotification\n", + ioc->name)); + ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */ + } + + if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) + rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag); + if (ret == 0) { /* Enable! (reply interrupt) */ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); ioc->active = 1; } - - if (reset_alt_ioc_active && ioc->alt_ioc) { - /* (re)Enable alt-IOC! (reply interrupt) */ - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n", - ioc->alt_ioc->name)); - CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); - ioc->alt_ioc->active = 1; + if (rc == 0) { /* alt ioc */ + if (reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt) */ + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc" + "reply irq re-enabled\n", + ioc->alt_ioc->name)); + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, + MPI_HIM_DIM); + ioc->alt_ioc->active = 1; + } } - /* Enable MPT base driver management of EventNotification - * and EventAck handling. - */ - if ((ret == 0) && (!ioc->facts.EventState)) - (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ - - if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) - (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */ /* Add additional "reason" check before call to GetLanConfigPages * (combined with GetIoUnitPage2 call). This prevents a somewhat @@ -2171,13 +2528,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { /* - * Initalize link list for inactive raid volumes. + * Initialize link list for inactive raid volumes. */ - init_MUTEX(&ioc->raid_data.inactive_list_mutex); + mutex_init(&ioc->raid_data.inactive_list_mutex); INIT_LIST_HEAD(&ioc->raid_data.inactive_list); - if (ioc->bus_type == SAS) { + switch (ioc->bus_type) { + case SAS: /* clear persistency table */ if(ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { @@ -2191,8 +2549,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) */ mpt_findImVolumes(ioc); - } else if (ioc->bus_type == FC) { - if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) && + /* Check, and possibly reset, the coalescing value + */ + mpt_read_ioc_pg_1(ioc); + + break; + + case FC: + if ((ioc->pfacts[0].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_LAN) && (ioc->lan_cnfg_page0.Header.PageLength == 0)) { /* * Pre-fetch the ports LAN MAC address! @@ -2201,11 +2566,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) (void) GetLanConfigPages(ioc); a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - ioc->name, a[5], a[4], a[3], a[2], a[1], a[0])); - + "LanAddr = %02X:%02X:%02X" + ":%02X:%02X:%02X\n", + ioc->name, a[5], a[4], + a[3], a[2], a[1], a[0])); } - } else { + break; + + case SPI: /* Get NVRAM and adapter maximums from SPP 0 and 2 */ mpt_GetScsiPortSettings(ioc, 0); @@ -2224,44 +2592,18 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) mpt_read_ioc_pg_1(ioc); mpt_read_ioc_pg_4(ioc); + + break; } GetIoUnitPage2(ioc); mpt_get_manufacturing_pg_0(ioc); } - /* - * Call each currently registered protocol IOC reset handler - * with post-reset indication. - * NOTE: If we're doing _IOC_BRINGUP, there can be no - * MptResetHandlers[] registered yet. - */ - if (hard_reset_done) { - rc = handlers = 0; - for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { - if ((ret == 0) && MptResetHandlers[cb_idx]) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling IOC post_reset handler #%d\n", - ioc->name, cb_idx)); - rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); - handlers++; - } - - if (alt_ioc_ready && MptResetHandlers[cb_idx]) { - drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling IOC post_reset handler #%d\n", - ioc->alt_ioc->name, cb_idx)); - rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET); - handlers++; - } - } - /* FIXME? Examine results here? */ - } - out: if ((ret != 0) && irq_allocated) { free_irq(ioc->pci_irq, ioc); - if (mpt_msi_enable) + if (ioc->msi_enable) pci_disable_msi(ioc->pcidev); } return ret; @@ -2305,16 +2647,20 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) if (_pcidev == peer) { /* Paranoia checks */ if (ioc->alt_ioc != NULL) { - printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", - ioc->name, ioc->alt_ioc->name); + printk(MYIOC_s_WARN_FMT + "Oops, already bound (%s <==> %s)!\n", + ioc->name, ioc->name, ioc->alt_ioc->name); break; } else if (ioc_srch->alt_ioc != NULL) { - printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n", - ioc_srch->name, ioc_srch->alt_ioc->name); + printk(MYIOC_s_WARN_FMT + "Oops, already bound (%s <==> %s)!\n", + ioc_srch->name, ioc_srch->name, + ioc_srch->alt_ioc->name); break; } - dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n", - ioc->name, ioc_srch->name)); + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "FOUND! binding %s <==> %s\n", + ioc->name, ioc->name, ioc_srch->name)); ioc_srch->alt_ioc = ioc; ioc->alt_ioc = ioc_srch; } @@ -2334,8 +2680,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) int ret; if (ioc->cached_fw != NULL) { - ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto " - "adapter\n", __FUNCTION__, ioc->name)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Pushing FW onto adapter\n", __func__, ioc->name)); if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) ioc->cached_fw, CAN_SLEEP)) < 0) { printk(MYIOC_s_WARN_FMT @@ -2344,11 +2690,30 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) } } + /* + * Put the controller into ready state (if its not already) + */ + if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) { + if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, + CAN_SLEEP)) { + if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) + printk(MYIOC_s_ERR_FMT "%s: IOC msg unit " + "reset failed to put ioc in ready state!\n", + ioc->name, __func__); + } else + printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " + "failed!\n", ioc->name, __func__); + } + + /* Disable adapter interrupts! */ + synchronize_irq(ioc->pcidev->irq); CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; + /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + CHIPREG_READ32(&ioc->chip->IntStatus); if (ioc->alloc != NULL) { sz = ioc->alloc_sz; @@ -2408,19 +2773,22 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) if((ret = mpt_host_page_access_control(ioc, MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { printk(MYIOC_s_ERR_FMT - "host page buffers free failed (%d)!\n", - ioc->name, ret); + ": %s: host page buffers free failed (%d)!\n", + ioc->name, __func__, ret); } - dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n", - ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); + dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "HostPageBuffer free @ %p, sz=%d bytes\n", + ioc->name, ioc->HostPageBuffer, + ioc->HostPageBuffer_sz)); pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, ioc->HostPageBuffer, ioc->HostPageBuffer_dma); ioc->HostPageBuffer = NULL; ioc->HostPageBuffer_sz = 0; ioc->alloc_total -= ioc->HostPageBuffer_sz; } -} + pci_set_drvdata(ioc->pcidev, NULL); +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_adapter_dispose - Free all resources associated with an MPT adapter @@ -2443,7 +2811,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) if (ioc->pci_irq != -1) { free_irq(ioc->pci_irq, ioc); - if (mpt_msi_enable) + if (ioc->msi_enable) pci_disable_msi(ioc->pcidev); ioc->pci_irq = -1; } @@ -2560,8 +2928,12 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) } /* Is it already READY? */ - if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) + if (!statefault && + ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) { + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT + "IOC is in READY state\n", ioc->name)); return 0; + } /* * Check to see if IOC is in FAULT state. @@ -2634,8 +3006,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) ii++; cntdn--; if (!cntdn) { - printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", - ioc->name, (int)((ii+5)/HZ)); + printk(MYIOC_s_ERR_FMT + "Wait IOC_READY state (0x%x) timeout(%d)!\n", + ioc->name, ioc_state, (int)((ii+5)/HZ)); return -ETIME; } @@ -2648,9 +3021,8 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) } if (statefault < 3) { - printk(MYIOC_s_INFO_FMT "Recovered from %s\n", - ioc->name, - statefault==1 ? "stuck handshake" : "IOC FAULT"); + printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name, + statefault == 1 ? "stuck handshake" : "IOC FAULT"); } return hard_reset_done; @@ -2703,8 +3075,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { - printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n", - ioc->name, ioc->last_state ); + printk(KERN_ERR MYNAM + ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", + ioc->name, ioc->last_state); return -44; } @@ -2766,7 +3139,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) * Old: u16{Major(4),Minor(4),SubMinor(8)} * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} */ - if (facts->MsgVersion < 0x0102) { + if (facts->MsgVersion < MPI_VERSION_01_02) { /* * Handle old FC f/w style, convert to new... */ @@ -2778,9 +3151,11 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); facts->ProductID = le16_to_cpu(facts->ProductID); + if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ioc->ir_firmware = 1; + facts->CurrentHostMfaHighAddr = le32_to_cpu(facts->CurrentHostMfaHighAddr); facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); @@ -2796,7 +3171,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) * to 14 in MPI-1.01.0x. */ if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 && - facts->MsgVersion > 0x0100) { + facts->MsgVersion > MPI_VERSION_01_00) { facts->FWImageSize = le32_to_cpu(facts->FWImageSize); } @@ -2978,6 +3353,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) ioc_init.MaxDevices = (U8)ioc->devices_per_bus; ioc_init.MaxBuses = (U8)ioc->number_of_buses; + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n", ioc->name, ioc->facts.MsgVersion)); if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { @@ -2992,7 +3368,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) } ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ - if (sizeof(dma_addr_t) == sizeof(u64)) { + if (ioc->sg_addr_size == sizeof(u64)) { /* Save the upper 32-bits of the request * (reply) and sense buffers. */ @@ -3119,7 +3495,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) * If memory has already been allocated, the same (cached) value * is returned. * - * Return 0 if successfull, or non-zero for failure + * Return 0 if successful, or non-zero for failure **/ int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) @@ -3195,11 +3571,10 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) FWUpload_t *prequest; FWUploadReply_t *preply; FWUploadTCSGE_t *ptcsge; - int sgeoffset; u32 flagsLength; int ii, sz, reply_sz; int cmdStatus; - + int request_size; /* If the image size is 0, we are done. */ if ((sz = ioc->facts.FWImageSize) == 0) @@ -3234,42 +3609,41 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) ptcsge->ImageSize = cpu_to_le32(sz); ptcsge++; - sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t); - flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; - mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); - - sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n", - ioc->name, prequest, sgeoffset)); + ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); + request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) + + ioc->SGE_size; + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload " + " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest, + ioc->facts.FWImageSize, request_size)); DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); - ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest, - reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); + ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest, + reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag); - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed " + "rc=%x \n", ioc->name, ii)); cmdStatus = -EFAULT; if (ii == 0) { /* Handshake transfer was complete and successful. * Check the Reply Frame. */ - int status, transfer_sz; - status = le16_to_cpu(preply->IOCStatus); - if (status == MPI_IOCSTATUS_SUCCESS) { - transfer_sz = le32_to_cpu(preply->ActualImageSize); - if (transfer_sz == sz) + int status; + status = le16_to_cpu(preply->IOCStatus) & + MPI_IOCSTATUS_MASK; + if (status == MPI_IOCSTATUS_SUCCESS && + ioc->facts.FWImageSize == + le32_to_cpu(preply->ActualImageSize)) cmdStatus = 0; - } } dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n", ioc->name, cmdStatus)); if (cmdStatus) { - - ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n", - ioc->name)); + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, " + "freeing image \n", ioc->name)); mpt_free_fw_memory(ioc); } kfree(prequest); @@ -3588,13 +3962,18 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) int count = 0; u32 diag1val = 0; MpiFwHeader_t *cached_fw; /* Pointer to FW */ + u8 cb_idx; /* Clear any existing interrupts */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { + + if (!ignore) + return 0; + drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " - "address=%p\n", ioc->name, __FUNCTION__, + "address=%p\n", ioc->name, __func__, &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); if (sleepFlag == CAN_SLEEP) @@ -3602,6 +3981,18 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) else mdelay(1); + /* + * Call each currently registered protocol IOC reset handler + * with pre-reset indication. + * NOTE: If we're doing _IOC_BRINGUP, there can be no + * MptResetHandlers[] registered yet. + */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + (*(MptResetHandlers[cb_idx]))(ioc, + MPT_IOC_PRE_RESET); + } + for (count = 0; count < 60; count ++) { doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell &= MPI_IOC_STATE_MASK; @@ -3610,6 +4001,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) "looking for READY STATE: doorbell=%x" " count=%d\n", ioc->name, doorbell, count)); + if (doorbell == MPI_IOC_STATE_READY) { return 1; } @@ -3697,25 +4089,15 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) * NOTE: If we're doing _IOC_BRINGUP, there can be no * MptResetHandlers[] registered yet. */ - { - u8 cb_idx; - int r = 0; - - for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { - if (MptResetHandlers[cb_idx]) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling IOC pre_reset handler #%d\n", - ioc->name, cb_idx)); - r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); - if (ioc->alt_ioc) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "Calling alt-%s pre_reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, cb_idx)); - r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET); - } + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, + ioc, MPT_IOC_PRE_RESET); + if (ioc->alt_ioc) { + mpt_signal_reset(cb_idx, + ioc->alt_ioc, MPT_IOC_PRE_RESET); } } - /* FIXME? Examine results here? */ } if (ioc->cached_fw) @@ -3760,6 +4142,10 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell &= MPI_IOC_STATE_MASK; + drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "looking for READY STATE: doorbell=%x" + " count=%d\n", ioc->name, doorbell, count)); + if (doorbell == MPI_IOC_STATE_READY) { break; } @@ -3771,6 +4157,11 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) mdelay (1000); } } + + if (doorbell != MPI_IOC_STATE_READY) + printk(MYIOC_s_ERR_FMT "Failed to come READY " + "after reset! IocState=%x", ioc->name, + doorbell); } } @@ -3889,8 +4280,9 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) if (sleepFlag != CAN_SLEEP) count *= 10; - printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", - ioc->name, (int)((count+5)/HZ)); + printk(MYIOC_s_ERR_FMT + "Wait IOC_READY state (0x%x) timeout(%d)!\n", + ioc->name, state, (int)((count+5)/HZ)); return -ETIME; } @@ -3960,24 +4352,29 @@ initChainBuffers(MPT_ADAPTER *ioc) * num_sge = num sge in request frame + last chain buffer * scale = num sge per chain buffer if no chain element */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) - num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + scale = ioc->req_sz / ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) + num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size; else - num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size; - if (sizeof(dma_addr_t) == sizeof(u64)) { + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { - numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + + scale + (ioc->req_sz - 64) / ioc->SGE_size; } dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n", ioc->name, num_sge, numSGE)); - if ( numSGE > MPT_SCSI_SG_DEPTH ) - numSGE = MPT_SCSI_SG_DEPTH; + if (ioc->bus_type == FC) { + if (numSGE > MPT_SCSI_FC_SG_DEPTH) + numSGE = MPT_SCSI_FC_SG_DEPTH; + } else { + if (numSGE > MPT_SCSI_SG_DEPTH) + numSGE = MPT_SCSI_SG_DEPTH; + } num_chain = 1; while (numSGE - num_sge > 0) { @@ -3991,6 +4388,8 @@ initChainBuffers(MPT_ADAPTER *ioc) if (ioc->bus_type == SPI) num_chain *= MPT_SCSI_CAN_QUEUE; + else if (ioc->bus_type == SAS) + num_chain *= MPT_SAS_CAN_QUEUE; else num_chain *= MPT_FC_CAN_QUEUE; @@ -4031,12 +4430,42 @@ PrimeIocFifos(MPT_ADAPTER *ioc) dma_addr_t alloc_dma; u8 *mem; int i, reply_sz, sz, total_size, num_chain; + u64 dma_mask; + + dma_mask = 0; /* Prime reply FIFO... */ if (ioc->reply_frames == NULL) { if ( (num_chain = initChainBuffers(ioc)) < 0) return -1; + /* + * 1078 errata workaround for the 36GB limitation + */ + if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 && + ioc->dma_mask > DMA_BIT_MASK(35)) { + if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32)) + && !pci_set_consistent_dma_mask(ioc->pcidev, + DMA_BIT_MASK(32))) { + dma_mask = DMA_BIT_MASK(35); + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "setting 35 bit addressing for " + "Request/Reply/Chain and Sense Buffers\n", + ioc->name)); + } else { + /*Reseting DMA mask to 64 bit*/ + pci_set_dma_mask(ioc->pcidev, + DMA_BIT_MASK(64)); + pci_set_consistent_dma_mask(ioc->pcidev, + DMA_BIT_MASK(64)); + + printk(MYIOC_s_ERR_FMT + "failed setting 35 bit addressing for " + "Request/Reply/Chain and Sense Buffers\n", + ioc->name); + return -1; + } + } total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", @@ -4175,9 +4604,16 @@ PrimeIocFifos(MPT_ADAPTER *ioc) alloc_dma += ioc->reply_sz; } + if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev, + ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev, + ioc->dma_mask)) + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "restoring 64 bit addressing\n", ioc->name)); + return 0; out_fail: + if (ioc->alloc != NULL) { sz = ioc->alloc_sz; pci_free_consistent(ioc->pcidev, @@ -4194,6 +4630,13 @@ out_fail: ioc->sense_buf_pool, ioc->sense_buf_pool_dma); ioc->sense_buf_pool = NULL; } + + if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev, + DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev, + DMA_BIT_MASK(64))) + d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "restoring 64 bit addressing\n", ioc->name)); + return -1; } @@ -4464,7 +4907,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) failcnt++; hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); /* don't overflow our IOC hs_reply[] buffer! */ - if (u16cnt < sizeof(ioc->hs_reply) / sizeof(ioc->hs_reply[0])) + if (u16cnt < ARRAY_SIZE(ioc->hs_reply)) hs_reply[u16cnt] = hword; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); } @@ -4629,7 +5072,14 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) SasIoUnitControlReply_t *sasIoUnitCntrReply; MPT_FRAME_HDR *mf = NULL; MPIHeader_t *mpi_hdr; + int ret = 0; + unsigned long timeleft; + mutex_lock(&ioc->mptbase_cmds.mutex); + + /* init the internal cmd struct */ + memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); + INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) /* insure garbage is not sent to fw */ switch(persist_opcode) { @@ -4639,17 +5089,19 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) break; default: - return -1; - break; + ret = -1; + goto out; } - printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode); + printk(KERN_DEBUG "%s: persist_opcode=%x\n", + __func__, persist_opcode); /* Get a MF for this command. */ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { - printk("%s: no msg frames!\n",__FUNCTION__); - return -1; + printk(KERN_DEBUG "%s: no msg frames!\n", __func__); + ret = -1; + goto out; } mpi_hdr = (MPIHeader_t *) mf; @@ -4659,27 +5111,43 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; sasIoUnitCntrReq->Operation = persist_opcode; - init_timer(&ioc->persist_timer); - ioc->persist_timer.data = (unsigned long) ioc; - ioc->persist_timer.function = mpt_timer_expired; - ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */; - ioc->persist_wait_done=0; - add_timer(&ioc->persist_timer); mpt_put_msg_frame(mpt_base_index, ioc, mf); - wait_event(mpt_waitq, ioc->persist_wait_done); + timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ); + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + printk(KERN_DEBUG "%s: failed\n", __func__); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!!, doorbell=0x%08x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0)); + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + goto out; + } + + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + ret = -1; + goto out; + } sasIoUnitCntrReply = - (SasIoUnitControlReply_t *)ioc->persist_reply_frame; + (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply; if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { - printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", - __FUNCTION__, - sasIoUnitCntrReply->IOCStatus, + printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", + __func__, sasIoUnitCntrReply->IOCStatus, sasIoUnitCntrReply->IOCLogInfo); - return -1; - } + printk(KERN_DEBUG "%s: failed\n", __func__); + ret = -1; + } else + printk(KERN_DEBUG "%s: success\n", __func__); + out: - printk("%s: success\n",__FUNCTION__); - return 0; + CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) + mutex_unlock(&ioc->mptbase_cmds.mutex); + return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5159,13 +5627,13 @@ mpt_inactive_raid_list_free(MPT_ADAPTER *ioc) if (list_empty(&ioc->raid_data.inactive_list)) return; - down(&ioc->raid_data.inactive_list_mutex); + mutex_lock(&ioc->raid_data.inactive_list_mutex); list_for_each_entry_safe(component_info, pNext, &ioc->raid_data.inactive_list, list) { list_del(&component_info->list); kfree(component_info); } - up(&ioc->raid_data.inactive_list_mutex); + mutex_unlock(&ioc->raid_data.inactive_list_mutex); } /** @@ -5224,7 +5692,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) if (!handle_inactive_volumes) goto out; - down(&ioc->raid_data.inactive_list_mutex); + mutex_lock(&ioc->raid_data.inactive_list_mutex); for (i = 0; i < buffer->NumPhysDisks; i++) { if(mpt_raid_phys_disk_pg0(ioc, buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) @@ -5244,7 +5712,7 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) list_add_tail(&component_info->list, &ioc->raid_data.inactive_list); } - up(&ioc->raid_data.inactive_list_mutex); + mutex_unlock(&ioc->raid_data.inactive_list_mutex); out: if (buffer) @@ -5264,17 +5732,20 @@ mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) * -ENOMEM if pci_alloc failed **/ int -mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk) +mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, + RaidPhysDiskPage0_t *phys_disk) { - CONFIGPARMS cfg; - ConfigPageHeader_t hdr; + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; dma_addr_t dma_handle; pRaidPhysDiskPage0_t buffer = NULL; int rc; memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t)); + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION; hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; @@ -5321,9 +5792,163 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t } /** + * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num + * @ioc: Pointer to a Adapter Structure + * @phys_disk_num: io unit unique phys disk num generated by the ioc + * + * Return: + * returns number paths + **/ +int +mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidPhysDiskPage1_t buffer = NULL; + int rc; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + hdr.PageNumber = 1; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) { + rc = 0; + goto out; + } + + if (!hdr.PageLength) { + rc = 0; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) { + rc = 0; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = phys_disk_num; + + if (mpt_config(ioc, &cfg) != 0) { + rc = 0; + goto out; + } + + rc = buffer->NumPhysDiskPaths; + out: + + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); + + return rc; +} +EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths); + +/** + * mpt_raid_phys_disk_pg1 - returns phys disk page 1 + * @ioc: Pointer to a Adapter Structure + * @phys_disk_num: io unit unique phys disk num generated by the ioc + * @phys_disk: requested payload data returned + * + * Return: + * 0 on success + * -EFAULT if read of config page header fails or data pointer not NULL + * -ENOMEM if pci_alloc failed + **/ +int +mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, + RaidPhysDiskPage1_t *phys_disk) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidPhysDiskPage1_t buffer = NULL; + int rc; + int i; + __le64 sas_address; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + rc = 0; + + hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; + hdr.PageNumber = 1; + cfg.cfghdr.hdr = &hdr; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + if (mpt_config(ioc, &cfg) != 0) { + rc = -EFAULT; + goto out; + } + + if (!hdr.PageLength) { + rc = -EFAULT; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) { + rc = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.pageAddr = phys_disk_num; + + if (mpt_config(ioc, &cfg) != 0) { + rc = -EFAULT; + goto out; + } + + phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths; + phys_disk->PhysDiskNum = phys_disk_num; + for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) { + phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID; + phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus; + phys_disk->Path[i].OwnerIdentifier = + buffer->Path[i].OwnerIdentifier; + phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags); + memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64)); + memcpy(&sas_address, + &buffer->Path[i].OwnerWWID, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + memcpy(&phys_disk->Path[i].OwnerWWID, + &sas_address, sizeof(__le64)); + } + + out: + + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); + + return rc; +} +EXPORT_SYMBOL(mpt_raid_phys_disk_pg1); + + +/** * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes * @ioc: Pointer to a Adapter Strucutre - * @portnum: IOC port number * * Return: * 0 on success @@ -5380,8 +6005,10 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) goto out; mem = kmalloc(iocpage2sz, GFP_KERNEL); - if (!mem) + if (!mem) { + rc = -ENOMEM; goto out; + } memcpy(mem, (u8 *)pIoc2, iocpage2sz); ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; @@ -5646,30 +6273,28 @@ mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc) * SendEventNotification - Send EventNotification (on or off) request to adapter * @ioc: Pointer to MPT_ADAPTER structure * @EvSwitch: Event switch flags + * @sleepFlag: Specifies whether the process can sleep */ static int -SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch) +SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag) { - EventNotification_t *evnp; + EventNotification_t evn; + MPIDefaultReply_t reply_buf; - evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc); - if (evnp == NULL) { - devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", - ioc->name)); - return 0; - } - memset(evnp, 0, sizeof(*evnp)); - - devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp)); + memset(&evn, 0, sizeof(EventNotification_t)); + memset(&reply_buf, 0, sizeof(MPIDefaultReply_t)); - evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; - evnp->ChainOffset = 0; - evnp->MsgFlags = 0; - evnp->Switch = EvSwitch; + evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION; + evn.Switch = EvSwitch; + evn.MsgContext = cpu_to_le32(mpt_base_index << 16); - mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Sending EventNotification (%d) request %p\n", + ioc->name, EvSwitch, &evn)); - return 0; + return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t), + (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30, + sleepFlag); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5685,7 +6310,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", - ioc->name,__FUNCTION__)); + ioc->name, __func__)); return -1; } @@ -5722,12 +6347,19 @@ int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) { Config_t *pReq; + ConfigReply_t *pReply; ConfigExtendedPageHeader_t *pExtHdr = NULL; MPT_FRAME_HDR *mf; - unsigned long flags; - int ii, rc; + int ii; int flagsLength; - int in_isr; + long timeout; + int ret; + u8 page_type = 0, extend_page; + unsigned long timeleft; + unsigned long flags; + int in_isr; + u8 issue_hard_reset = 0; + u8 retry_count = 0; /* Prevent calling wait_event() (below), if caller happens * to be in ISR context, because that is fatal! @@ -5737,15 +6369,43 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n", ioc->name)); return -EPERM; + } + + /* don't send a config page during diag reset */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: busy with host reset\n", ioc->name, __func__)); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + /* don't send if no chance of success */ + if (!ioc->active || + mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: ioc not operational, %d, %xh\n", + ioc->name, __func__, ioc->active, + mpt_GetIocState(ioc, 0))); + return -EFAULT; } + retry_config: + mutex_lock(&ioc->mptbase_cmds.mutex); + /* init the internal cmd struct */ + memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); + INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) + /* Get and Populate a free Frame */ if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { - dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n", - ioc->name)); - return -EAGAIN; + dcprintk(ioc, printk(MYIOC_s_WARN_FMT + "mpt_config: no msg frames!\n", ioc->name)); + ret = -EAGAIN; + goto out; } + pReq = (Config_t *)mf; pReq->Action = pCfg->action; pReq->Reserved = 0; @@ -5771,7 +6431,9 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) pReq->ExtPageType = pExtHdr->ExtPageType; pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; - /* Page Length must be treated as a reserved field for the extended header. */ + /* Page Length must be treated as a reserved field for the + * extended header. + */ pReq->Header.PageLength = 0; } @@ -5784,78 +6446,109 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) else flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { + if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == + MPI_CONFIG_PAGETYPE_EXTENDED) { flagsLength |= pExtHdr->ExtPageLength * 4; - - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n", - ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action)); - } - else { + page_type = pReq->ExtPageType; + extend_page = 1; + } else { flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; - - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n", - ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); + page_type = pReq->Header.PageType; + extend_page = 0; } - mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); - - /* Append pCfg pointer to end of mf - */ - *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; + dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Sending Config request type 0x%x, page 0x%x and action %d\n", + ioc->name, page_type, pReq->Header.PageNumber, pReq->Action)); - /* Initalize the timer - */ - init_timer(&pCfg->timer); - pCfg->timer.data = (unsigned long) ioc; - pCfg->timer.function = mpt_timer_expired; - pCfg->wait_done = 0; - - /* Set the timer; ensure 10 second minimum */ - if (pCfg->timeout < 10) - pCfg->timer.expires = jiffies + HZ*10; - else - pCfg->timer.expires = jiffies + HZ*pCfg->timeout; - - /* Add to end of Q, set timer and then issue this command */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_add_tail(&pCfg->linkage, &ioc->configQ); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - add_timer(&pCfg->timer); + ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); + timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout; mpt_put_msg_frame(mpt_base_index, ioc, mf); - wait_event(mpt_waitq, pCfg->wait_done); + timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, + timeout); + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Failed Sending Config request type 0x%x, page 0x%x," + " action %d, status %xh, time left %ld\n\n", + ioc->name, page_type, pReq->Header.PageNumber, + pReq->Action, ioc->mptbase_cmds.status, timeleft)); + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, + flags); + printk(MYIOC_s_INFO_FMT "%s: host reset in" + " progress mpt_config timed out.!!\n", + __func__, ioc->name); + mutex_unlock(&ioc->mptbase_cmds.mutex); + return -EFAULT; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + issue_hard_reset = 1; + } + goto out; + } - /* mf has been freed - do not access */ + if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + ret = -1; + goto out; + } + pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply; + ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + if (ret == MPI_IOCSTATUS_SUCCESS) { + if (extend_page) { + pCfg->cfghdr.ehdr->ExtPageLength = + le16_to_cpu(pReply->ExtPageLength); + pCfg->cfghdr.ehdr->ExtPageType = + pReply->ExtPageType; + } + pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; + pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; + pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; + pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; - rc = pCfg->status; + } - return rc; -} + if (retry_count) + printk(MYIOC_s_INFO_FMT "Retry completed " + "ret=0x%x timeleft=%ld\n", + ioc->name, ret, timeleft); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_timer_expired - Callback for timer process. - * Used only internal config functionality. - * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long - */ -static void -mpt_timer_expired(unsigned long data) -{ - MPT_ADAPTER *ioc = (MPT_ADAPTER *) data; + dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", + ret, le32_to_cpu(pReply->IOCLogInfo))); - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name)); +out: - /* Perform a FW reload */ - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) - printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); + CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) + mutex_unlock(&ioc->mptbase_cmds.mutex); + if (issue_hard_reset) { + issue_hard_reset = 0; + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!!, doorbell=0x%08x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0)); + if (retry_count == 0) { + if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0) + retry_count++; + } else + mpt_HardResetHandler(ioc, CAN_SLEEP); - /* No more processing. - * Hard reset clean-up will wake up - * process and free all resources. - */ - dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name)); + mpt_free_msg_frame(ioc, mf); + /* attempt one retry for a timed out command */ + if (retry_count < 2) { + printk(MYIOC_s_INFO_FMT + "Attempting Retry Config request" + " type 0x%x, page 0x%x," + " action %d\n", ioc->name, page_type, + pCfg->cfghdr.hdr->PageNumber, pCfg->action); + retry_count++; + goto retry_config; + } + } + return ret; - return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5869,41 +6562,34 @@ mpt_timer_expired(unsigned long data) static int mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - CONFIGPARMS *pCfg; - unsigned long flags; - - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT - ": IOC %s_reset routed to MPT base driver!\n", - ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - if (reset_phase == MPT_IOC_SETUP_RESET) { - ; - } else if (reset_phase == MPT_IOC_PRE_RESET) { - /* If the internal config Q is not empty - - * delete timer. MF resources will be freed when - * the FIFO's are primed. - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_for_each_entry(pCfg, &ioc->configQ, linkage) - del_timer(&pCfg->timer); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - } else { - CONFIGPARMS *pNext; - - /* Search the configQ for internal commands. - * Flush the Q, and wake up all suspended threads. - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) { - list_del(&pCfg->linkage); - - pCfg->status = MPT_CONFIG_ERROR; - pCfg->wait_done = 1; - wake_up(&mpt_waitq); + switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + ioc->taskmgmt_quiesce_io = 1; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); +/* wake up mptbase_cmds */ + if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->mptbase_cmds.status |= + MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->mptbase_cmds.done); } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); +/* wake up taskmgmt_cmds */ + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->taskmgmt_cmds.status |= + MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->taskmgmt_cmds.done); + } + break; + default: + break; } return 1; /* currently means nothing really */ @@ -5924,20 +6610,12 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) static int procmpt_create(void) { - struct proc_dir_entry *ent; - mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL); if (mpt_proc_root_dir == NULL) return -ENOTDIR; - ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir); - if (ent) - ent->read_proc = procmpt_summary_read; - - ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir); - if (ent) - ent->read_proc = procmpt_version_read; - + proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops); + proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops); return 0; } @@ -5956,71 +6634,47 @@ procmpt_destroy(void) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * procmpt_summary_read - Handle read request of a summary file - * @buf: Pointer to area to write information - * @start: Pointer to start pointer - * @offset: Offset to start writing - * @request: Amount of read data requested - * @eof: Pointer to EOF integer - * @data: Pointer - * +/* * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. - * Returns number of characters written to process performing the read. */ -static int -procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) -{ - MPT_ADAPTER *ioc; - char *out = buf; - int len; +static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan); - if (data) { - int more = 0; - - ioc = data; - mpt_print_ioc_summary(ioc, out, &more, 0, 1); +static int mpt_summary_proc_show(struct seq_file *m, void *v) +{ + MPT_ADAPTER *ioc = m->private; - out += more; + if (ioc) { + seq_mpt_print_ioc_summary(ioc, m, 1); } else { list_for_each_entry(ioc, &ioc_list, list) { - int more = 0; - - mpt_print_ioc_summary(ioc, out, &more, 0, 1); - - out += more; - if ((out-buf) >= request) - break; + seq_mpt_print_ioc_summary(ioc, m, 1); } } - len = out - buf; + return 0; +} - MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); +static int mpt_summary_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mpt_summary_proc_show, PDE_DATA(inode)); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * procmpt_version_read - Handle read request from /proc/mpt/version. - * @buf: Pointer to area to write information - * @start: Pointer to start pointer - * @offset: Offset to start writing - * @request: Amount of read data requested - * @eof: Pointer to EOF integer - * @data: Pointer - * - * Returns number of characters written to process performing the read. - */ -static int -procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) +static const struct file_operations mpt_summary_proc_fops = { + .owner = THIS_MODULE, + .open = mpt_summary_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int mpt_version_proc_show(struct seq_file *m, void *v) { u8 cb_idx; int scsi, fc, sas, lan, ctl, targ, dmp; char *drvname; - int len; - len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON); - len += sprintf(buf+len, " Fusion MPT base driver\n"); + seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON); + seq_printf(m, " Fusion MPT base driver\n"); scsi = fc = sas = lan = ctl = targ = dmp = 0; for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { @@ -6048,98 +6702,97 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo } if (drvname) - len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname); + seq_printf(m, " Fusion MPT %s driver\n", drvname); } } - MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); + return 0; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. - * @buf: Pointer to area to write information - * @start: Pointer to start pointer - * @offset: Offset to start writing - * @request: Amount of read data requested - * @eof: Pointer to EOF integer - * @data: Pointer - * - * Returns number of characters written to process performing the read. - */ -static int -procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) +static int mpt_version_proc_open(struct inode *inode, struct file *file) { - MPT_ADAPTER *ioc = data; - int len; + return single_open(file, mpt_version_proc_show, NULL); +} + +static const struct file_operations mpt_version_proc_fops = { + .owner = THIS_MODULE, + .open = mpt_version_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int mpt_iocinfo_proc_show(struct seq_file *m, void *v) +{ + MPT_ADAPTER *ioc = m->private; char expVer[32]; int sz; int p; mpt_get_fw_exp_ver(expVer, ioc); - len = sprintf(buf, "%s:", ioc->name); + seq_printf(m, "%s:", ioc->name); if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) - len += sprintf(buf+len, " (f/w download boot flag set)"); + seq_printf(m, " (f/w download boot flag set)"); // if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL) -// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!"); +// seq_printf(m, " CONFIG_CHECKSUM_FAIL!"); - len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n", + seq_printf(m, "\n ProductID = 0x%04x (%s)\n", ioc->facts.ProductID, ioc->prod_name); - len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer); + seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer); if (ioc->facts.FWImageSize) - len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize); - len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion); - len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit); - len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState); + seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize); + seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion); + seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit); + seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState); - len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n", + seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n", ioc->facts.CurrentHostMfaHighAddr); - len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n", + seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n", ioc->facts.CurrentSenseBufferHighAddr); - len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth); - len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); + seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth); + seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); - len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", + seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma); /* * Rounding UP to nearest 4-kB boundary here... */ sz = (ioc->req_sz * ioc->req_depth) + 128; sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; - len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", + seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz); - len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", + seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", 4*ioc->facts.RequestFrameSize, ioc->facts.GlobalCredits); - len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n", + seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n", (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma); sz = (ioc->reply_sz * ioc->reply_depth) + 128; - len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", + seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); - len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", + seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", ioc->facts.CurReplyFrameSize, ioc->facts.ReplyQueueDepth); - len += sprintf(buf+len, " MaxDevices = %d\n", + seq_printf(m, " MaxDevices = %d\n", (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices); - len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses); + seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses); /* per-port info */ for (p=0; p < ioc->facts.NumberOfPorts; p++) { - len += sprintf(buf+len, " PortNumber = %d (of %d)\n", + seq_printf(m, " PortNumber = %d (of %d)\n", p+1, ioc->facts.NumberOfPorts); if (ioc->bus_type == FC) { if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; - len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", a[5], a[4], a[3], a[2], a[1], a[0]); } - len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n", + seq_printf(m, " WWN = %08X%08X:%08X%08X\n", ioc->fc_port_page0[p].WWNN.High, ioc->fc_port_page0[p].WWNN.Low, ioc->fc_port_page0[p].WWPN.High, @@ -6147,9 +6800,21 @@ procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eo } } - MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); + return 0; } +static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mpt_iocinfo_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations mpt_iocinfo_proc_fops = { + .owner = THIS_MODULE, + .open = mpt_iocinfo_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif /* CONFIG_PROC_FS } */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -6216,6 +6881,284 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh *size = y; } +static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan) +{ + char expVer[32]; + + mpt_get_fw_exp_ver(expVer, ioc); + + /* + * Shorter summary of attached ioc's... + */ + seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d", + ioc->name, + ioc->prod_name, + MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */ + ioc->facts.FWVersion.Word, + expVer, + ioc->facts.NumberOfPorts, + ioc->req_depth); + + if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { + u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; + seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X", + a[5], a[4], a[3], a[2], a[1], a[0]); + } + + seq_printf(m, ", IRQ=%d", ioc->pci_irq); + + if (!ioc->active) + seq_printf(m, " (disabled)"); + + seq_putc(m, '\n'); +} + +/** + * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management + * @ioc: Pointer to MPT_ADAPTER structure + * + * Returns 0 for SUCCESS or -1 if FAILED. + * + * If -1 is return, then it was not possible to set the flags + **/ +int +mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress || + (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) { + retval = -1; + goto out; + } + retval = 0; + ioc->taskmgmt_in_progress = 1; + ioc->taskmgmt_quiesce_io = 1; + if (ioc->alt_ioc) { + ioc->alt_ioc->taskmgmt_in_progress = 1; + ioc->alt_ioc->taskmgmt_quiesce_io = 1; + } + out: + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return retval; +} +EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag); + +/** + * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +void +mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + ioc->taskmgmt_in_progress = 0; + ioc->taskmgmt_quiesce_io = 0; + if (ioc->alt_ioc) { + ioc->alt_ioc->taskmgmt_in_progress = 0; + ioc->alt_ioc->taskmgmt_quiesce_io = 0; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); +} +EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); + + +/** + * mpt_halt_firmware - Halts the firmware if it is operational and panic + * the kernel + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +void +mpt_halt_firmware(MPT_ADAPTER *ioc) +{ + u32 ioc_raw_state; + + ioc_raw_state = mpt_GetIocState(ioc, 0); + + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n", + ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); + panic("%s: IOC Fault (%04xh)!!!\n", ioc->name, + ioc_raw_state & MPI_DOORBELL_DATA_MASK); + } else { + CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00); + panic("%s: Firmware is halted due to command timeout\n", + ioc->name); + } +} +EXPORT_SYMBOL(mpt_halt_firmware); + +/** + * mpt_SoftResetHandler - Issues a less expensive reset + * @ioc: Pointer to MPT_ADAPTER structure + * @sleepFlag: Indicates if sleep or schedule must be called. + * + * Returns 0 for SUCCESS or -1 if FAILED. + * + * Message Unit Reset - instructs the IOC to reset the Reply Post and + * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded. + * All posted buffers are freed, and event notification is turned off. + * IOC doesn't reply to any outstanding request. This will transfer IOC + * to READY state. + **/ +int +mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag) +{ + int rc; + int ii; + u8 cb_idx; + unsigned long flags; + u32 ioc_state; + unsigned long time_count; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n", + ioc->name)); + + ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; + + if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); + + if (ioc_state == MPI_IOC_STATE_FAULT || + ioc_state == MPI_IOC_STATE_RESET) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "skipping, either in FAULT or RESET state!\n", ioc->name)); + return -1; + } + + if (ioc->bus_type == FC) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "skipping, because the bus type is FC!\n", ioc->name)); + return -1; + } + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return -1; + } + ioc->ioc_reset_in_progress = 1; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + rc = -1; + + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); + } + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->taskmgmt_in_progress) { + ioc->ioc_reset_in_progress = 0; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return -1; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + /* Disable reply interrupts (also blocks FreeQ) */ + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + ioc->active = 0; + time_count = jiffies; + + rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); + + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); + } + + if (rc) + goto out; + + ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; + if (ioc_state != MPI_IOC_STATE_READY) + goto out; + + for (ii = 0; ii < 5; ii++) { + /* Get IOC facts! Allow 5 retries */ + rc = GetIocFacts(ioc, sleepFlag, + MPT_HOSTEVENT_IOC_RECOVER); + if (rc == 0) + break; + if (sleepFlag == CAN_SLEEP) + msleep(100); + else + mdelay(100); + } + if (ii == 5) + goto out; + + rc = PrimeIocFifos(ioc); + if (rc != 0) + goto out; + + rc = SendIocInit(ioc, sleepFlag); + if (rc != 0) + goto out; + + rc = SendEventNotification(ioc, 1, sleepFlag); + if (rc != 0) + goto out; + + if (ioc->hard_resets < -1) + ioc->hard_resets++; + + /* + * At this point, we know soft reset succeeded. + */ + + ioc->active = 1; + CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); + + out: + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + ioc->ioc_reset_in_progress = 0; + ioc->taskmgmt_quiesce_io = 0; + ioc->taskmgmt_in_progress = 0; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + if (ioc->active) { /* otherwise, hard reset coming */ + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) + mpt_signal_reset(cb_idx, ioc, + MPT_IOC_POST_RESET); + } + } + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "SoftResetHandler: completed (%d seconds): %s\n", + ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, + ((rc == 0) ? "SUCCESS" : "FAILED"))); + + return rc; +} + +/** + * mpt_Soft_Hard_ResetHandler - Try less expensive reset + * @ioc: Pointer to MPT_ADAPTER structure + * @sleepFlag: Indicates if sleep or schedule must be called. + * + * Returns 0 for SUCCESS or -1 if FAILED. + * Try for softreset first, only if it fails go for expensive + * HardReset. + **/ +int +mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) { + int ret = -1; + + ret = mpt_SoftResetHandler(ioc, sleepFlag); + if (ret == 0) + return ret; + ret = mpt_HardResetHandler(ioc, sleepFlag); + return ret; +} +EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler); + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Reset Handling @@ -6240,76 +7183,111 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) { - int rc; + int rc; + u8 cb_idx; unsigned long flags; + unsigned long time_count; dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name)); #ifdef MFCNT printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); printk("MF count 0x%x !\n", ioc->mfcnt); #endif + if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); /* Reset the adapter. Prevent more than 1 call to * mpt_do_ioc_recovery at any instant in time. */ - spin_lock_irqsave(&ioc->diagLock, flags); - if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){ - spin_unlock_irqrestore(&ioc->diagLock, flags); - return 0; - } else { - ioc->diagPending = 1; + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + ioc->wait_on_reset_completion = 1; + do { + ssleep(1); + } while (ioc->ioc_reset_in_progress == 1); + ioc->wait_on_reset_completion = 0; + return ioc->reset_status; + } + if (ioc->wait_on_reset_completion) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + rc = 0; + time_count = jiffies; + goto exit; } - spin_unlock_irqrestore(&ioc->diagLock, flags); + ioc->ioc_reset_in_progress = 1; + if (ioc->alt_ioc) + ioc->alt_ioc->ioc_reset_in_progress = 1; + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - /* FIXME: If do_ioc_recovery fails, repeat.... - */ /* The SCSI driver needs to adjust timeouts on all current * commands prior to the diagnostic reset being issued. * Prevents timeouts occurring during a diagnostic reset...very bad. * For all other protocol drivers, this is a no-op. */ - { - u8 cb_idx; - int r = 0; - - for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { - if (MptResetHandlers[cb_idx]) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n", - ioc->name, cb_idx)); - r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); - if (ioc->alt_ioc) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, cb_idx)); - r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET); - } - } + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); + if (ioc->alt_ioc) + mpt_signal_reset(cb_idx, ioc->alt_ioc, + MPT_IOC_SETUP_RESET); } } - if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { - printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc); + time_count = jiffies; + rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag); + if (rc != 0) { + printk(KERN_WARNING MYNAM + ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n", + rc, ioc->name, mpt_GetIocState(ioc, 0)); + } else { + if (ioc->hard_resets < -1) + ioc->hard_resets++; } - ioc->reload_fw = 0; - if (ioc->alt_ioc) - ioc->alt_ioc->reload_fw = 0; - spin_lock_irqsave(&ioc->diagLock, flags); - ioc->diagPending = 0; - if (ioc->alt_ioc) - ioc->alt_ioc->diagPending = 0; - spin_unlock_irqrestore(&ioc->diagLock, flags); + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + ioc->ioc_reset_in_progress = 0; + ioc->taskmgmt_quiesce_io = 0; + ioc->taskmgmt_in_progress = 0; + ioc->reset_status = rc; + if (ioc->alt_ioc) { + ioc->alt_ioc->ioc_reset_in_progress = 0; + ioc->alt_ioc->taskmgmt_quiesce_io = 0; + ioc->alt_ioc->taskmgmt_in_progress = 0; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); + for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { + if (MptResetHandlers[cb_idx]) { + mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); + if (ioc->alt_ioc) + mpt_signal_reset(cb_idx, + ioc->alt_ioc, MPT_IOC_POST_RESET); + } + } +exit: + dtmprintk(ioc, + printk(MYIOC_s_DEBUG_FMT + "HardResetHandler: completed (%d seconds): %s\n", ioc->name, + jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ? + "SUCCESS" : "FAILED"))); return rc; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#ifdef CONFIG_FUSION_LOGGING static void -EventDescriptionStr(u8 event, u32 evData0, char *evStr) +mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) { char *ds = NULL; + u32 evData0; + int ii; + u8 event; + char *evStr = ioc->evStr; + + event = le32_to_cpu(pEventReply->Event) & 0xFF; + evData0 = le32_to_cpu(pEventReply->Data[0]); switch(event) { case MPI_EVENT_NONE: @@ -6343,9 +7321,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) ds = "Loop State(LIP) Change"; else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) - ds = "Loop State(LPE) Change"; /* ??? */ + ds = "Loop State(LPE) Change"; else - ds = "Loop State(LPB) Change"; /* ??? */ + ds = "Loop State(LPB) Change"; break; case MPI_EVENT_LOGOUT: ds = "Logout"; @@ -6524,7 +7502,12 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) case MPI_EVENT_SAS_PLS_LR_RATE_3_0: snprintf(evStr, EVENT_DESCR_STR_SZ, "SAS PHY Link Status: Phy=%d:" - " Rate 3.0 Gpbs",PhyNumber); + " Rate 3.0 Gbps", PhyNumber); + break; + case MPI_EVENT_SAS_PLS_LR_RATE_6_0: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" + " Rate 6.0 Gbps", PhyNumber); break; default: snprintf(evStr, EVENT_DESCR_STR_SZ, @@ -6545,28 +7528,65 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) } case MPI_EVENT_IR2: { + u8 id = (u8)(evData0); + u8 channel = (u8)(evData0 >> 8); + u8 phys_num = (u8)(evData0 >> 24); u8 ReasonCode = (u8)(evData0 >> 16); + switch (ReasonCode) { case MPI_EVENT_IR2_RC_LD_STATE_CHANGED: - ds = "IR2: LD State Changed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: LD State Changed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_STATE_CHANGED: - ds = "IR2: PD State Changed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD State Changed " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL: - ds = "IR2: Bad Block Table Full"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Bad Block Table Full: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_INSERTED: - ds = "IR2: PD Inserted"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD Inserted: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_PD_REMOVED: - ds = "IR2: PD Removed"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: PD Removed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: - ds = "IR2: Foreign CFG Detected"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Foreign CFG Detected: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR: - ds = "IR2: Rebuild Medium Error"; + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Rebuild Medium Error: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Dual Port Added: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR2: Dual Port Removed: " + "id=%d channel=%d phys_num=%d", + id, channel, phys_num); break; default: ds = "IR2"; @@ -6602,13 +7622,18 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: { u8 reason = (u8)(evData0); - u8 port_num = (u8)(evData0 >> 8); - u16 handle = le16_to_cpu(evData0 >> 16); - snprintf(evStr, EVENT_DESCR_STR_SZ, - "SAS Initiator Device Status Change: reason=0x%02x " - "port=%d handle=0x%04x", - reason, port_num, handle); + switch (reason) { + case MPI_EVENT_SAS_INIT_RC_ADDED: + ds = "SAS Initiator Status Change: Added"; + break; + case MPI_EVENT_SAS_INIT_RC_REMOVED: + ds = "SAS Initiator Status Change: Deleted"; + break; + default: + ds = "SAS Initiator Status Change"; + break; + } break; } @@ -6656,6 +7681,24 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) break; } + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + { + u8 reason = (u8)(evData0); + + switch (reason) { + case MPI_EVENT_SAS_EXP_RC_ADDED: + ds = "Expander Status Change: Added"; + break; + case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING: + ds = "Expander Status Change: Deleted"; + break; + default: + ds = "Expander Status Change"; + break; + } + break; + } + /* * MPT base "custom" events may be added here... */ @@ -6665,8 +7708,20 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr) } if (ds) strncpy(evStr, ds, EVENT_DESCR_STR_SZ); -} + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "MPT event:(%02Xh) : %s\n", + ioc->name, event, evStr)); + + devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM + ": Event data:\n")); + for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++) + devtverboseprintk(ioc, printk(" %08x", + le32_to_cpu(pEventReply->Data[ii]))); + devtverboseprintk(ioc, printk(KERN_DEBUG "\n")); +} +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * ProcessEventNotification - Route EventNotificationReply to all event handlers @@ -6683,37 +7738,24 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply { u16 evDataLen; u32 evData0 = 0; -// u32 evCtx; int ii; u8 cb_idx; int r = 0; int handlers = 0; - char evStr[EVENT_DESCR_STR_SZ]; u8 event; /* * Do platform normalization of values */ event = le32_to_cpu(pEventReply->Event) & 0xFF; -// evCtx = le32_to_cpu(pEventReply->EventContext); evDataLen = le16_to_cpu(pEventReply->EventDataLength); if (evDataLen) { evData0 = le32_to_cpu(pEventReply->Data[0]); } - EventDescriptionStr(event, evData0, evStr); - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n", - ioc->name, - event, - evStr)); - #ifdef CONFIG_FUSION_LOGGING - devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT - ": Event data:\n", ioc->name)); - for (ii = 0; ii < evDataLen; ii++) - devtverboseprintk(ioc, printk(" %08x", - le32_to_cpu(pEventReply->Data[ii]))); - devtverboseprintk(ioc, printk("\n")); + if (evDataLen) + mpt_display_event_info(ioc, pEventReply); #endif /* @@ -6768,8 +7810,9 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply */ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { if (MptEvHandlers[cb_idx]) { - devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n", - ioc->name, cb_idx)); + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Routing Event to event handler #%d\n", + ioc->name, cb_idx)); r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); handlers++; } @@ -6840,7 +7883,6 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) /** * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. * @ioc: Pointer to MPT_ADAPTER structure - * @mr: Pointer to MPT reply frame * @log_info: U32 LogInfo word from the IOC * * Refer to lsi/sp_log.h. @@ -6854,8 +7896,6 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) switch (info) { case 0x00010000: desc = "bug! MID not found"; - if (ioc->reload_fw == 0) - ioc->reload_fw++; break; case 0x00020000: @@ -6949,7 +7989,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) "Owner", /* 15h */ "Open Transmit DMA Abort", /* 16h */ "IO Device Missing Delay Retry", /* 17h */ - "IO Cancelled Due to Recieve Error", /* 18h */ + "IO Cancelled Due to Receive Error", /* 18h */ NULL, /* 19h */ NULL, /* 1Ah */ NULL, /* 1Bh */ @@ -7026,7 +8066,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) NULL, /* 2Eh */ NULL, /* 2Fh */ "Compatibility Error: IR Disabled", /* 30h */ - "Compatibility Error: Inquiry Comand Failed", /* 31h */ + "Compatibility Error: Inquiry Command Failed", /* 31h */ "Compatibility Error: Device not Direct Access " "Device ", /* 32h */ "Compatibility Error: Removable Device Found", /* 33h */ @@ -7055,11 +8095,12 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) * mpt_sas_log_info - Log information returned from SAS IOC. * @ioc: Pointer to MPT_ADAPTER structure * @log_info: U32 LogInfo reply word from the IOC + * @cb_idx: callback function's handle * * Refer to lsi/mpi_log_sas.h. **/ static void -mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info) +mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx) { union loginfo_type { u32 loginfo; @@ -7077,7 +8118,7 @@ union loginfo_type { sas_loginfo.loginfo = log_info; if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) && - (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*))) + (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str))) return; originator_desc = originator_str[sas_loginfo.dw.originator]; @@ -7086,22 +8127,22 @@ union loginfo_type { case 0: /* IOP */ if (sas_loginfo.dw.code < - sizeof(iop_code_str)/sizeof(char*)) + ARRAY_SIZE(iop_code_str)) code_desc = iop_code_str[sas_loginfo.dw.code]; break; case 1: /* PL */ if (sas_loginfo.dw.code < - sizeof(pl_code_str)/sizeof(char*)) + ARRAY_SIZE(pl_code_str)) code_desc = pl_code_str[sas_loginfo.dw.code]; break; case 2: /* IR */ if (sas_loginfo.dw.code >= - sizeof(ir_code_str)/sizeof(char*)) + ARRAY_SIZE(ir_code_str)) break; code_desc = ir_code_str[sas_loginfo.dw.code]; if (sas_loginfo.dw.subcode >= - sizeof(raid_sub_code_str)/sizeof(char*)) - break; + ARRAY_SIZE(raid_sub_code_str)) + break; if (sas_loginfo.dw.code == 0) sub_code_desc = raid_sub_code_str[sas_loginfo.dw.subcode]; @@ -7113,21 +8154,22 @@ union loginfo_type { if (sub_code_desc != NULL) printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): Originator={%s}, Code={%s}," - " SubCode={%s}\n", + " SubCode={%s} cb_idx %s\n", ioc->name, log_info, originator_desc, code_desc, - sub_code_desc); + sub_code_desc, MptCallbacksName[cb_idx]); else if (code_desc != NULL) printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): Originator={%s}, Code={%s}," - " SubCode(0x%04x)\n", + " SubCode(0x%04x) cb_idx %s\n", ioc->name, log_info, originator_desc, code_desc, - sas_loginfo.dw.subcode); + sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]); else printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x)," - " SubCode(0x%04x)\n", + " SubCode(0x%04x) cb_idx %s\n", ioc->name, log_info, originator_desc, - sas_loginfo.dw.code, sas_loginfo.dw.subcode); + sas_loginfo.dw.code, sas_loginfo.dw.subcode, + MptCallbacksName[cb_idx]); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -7444,7 +8486,6 @@ EXPORT_SYMBOL(mpt_resume); EXPORT_SYMBOL(mpt_suspend); #endif EXPORT_SYMBOL(ioc_list); -EXPORT_SYMBOL(mpt_proc_root_dir); EXPORT_SYMBOL(mpt_register); EXPORT_SYMBOL(mpt_deregister); EXPORT_SYMBOL(mpt_event_register); @@ -7457,7 +8498,6 @@ EXPORT_SYMBOL(mpt_get_msg_frame); EXPORT_SYMBOL(mpt_put_msg_frame); EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri); EXPORT_SYMBOL(mpt_free_msg_frame); -EXPORT_SYMBOL(mpt_add_sge); EXPORT_SYMBOL(mpt_send_handshake_request); EXPORT_SYMBOL(mpt_verify_adapter); EXPORT_SYMBOL(mpt_GetIocState); @@ -7494,7 +8534,8 @@ fusion_init(void) /* Register ourselves (mptbase) in order to facilitate * EventNotification handling. */ - mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER); + mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER, + "mptbase_reply"); /* Register for hard reset handling callbacks. */ diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index caadc68c300..76c05bc24cb 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -5,7 +5,7 @@ * LSIFC9xx/LSI409xx Fibre Channel * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -51,6 +51,7 @@ #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/mutex.h> #include "lsi/mpi_type.h" #include "lsi/mpi.h" /* Fusion MPI(nterface) basic defs */ @@ -72,11 +73,11 @@ #endif #ifndef COPYRIGHT -#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.06" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.06" +#define MPT_LINUX_VERSION_COMMON "3.04.20" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.20" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -88,6 +89,7 @@ */ #define MPT_MAX_ADAPTERS 18 #define MPT_MAX_PROTOCOL_DRIVERS 16 +#define MPT_MAX_CALLBACKNAME_LEN 49 #define MPT_MAX_BUS 1 /* Do not change */ #define MPT_MAX_FC_DEVICES 255 #define MPT_MAX_SCSI_DEVICES 16 @@ -103,6 +105,7 @@ #endif #define MPT_NAME_LENGTH 32 +#define MPT_KOBJ_NAME_LEN 20 #define MPT_PROCFS_MPTBASEDIR "mpt" /* chg it to "driver/fusion" ? */ @@ -133,6 +136,7 @@ #define MPT_COALESCING_TIMEOUT 0x10 + /* * SCSI transfer rate defines. */ @@ -154,16 +158,17 @@ /* * Try to keep these at 2^N-1 */ -#define MPT_FC_CAN_QUEUE 127 +#define MPT_FC_CAN_QUEUE 1024 #define MPT_SCSI_CAN_QUEUE 127 +#define MPT_SAS_CAN_QUEUE 127 /* * Set the MAX_SGE value based on user input. */ -#ifdef CONFIG_FUSION_MAX_SGE -#if CONFIG_FUSION_MAX_SGE < 16 +#ifdef CONFIG_FUSION_MAX_SGE +#if CONFIG_FUSION_MAX_SGE < 16 #define MPT_SCSI_SG_DEPTH 16 -#elif CONFIG_FUSION_MAX_SGE > 128 +#elif CONFIG_FUSION_MAX_SGE > 128 #define MPT_SCSI_SG_DEPTH 128 #else #define MPT_SCSI_SG_DEPTH CONFIG_FUSION_MAX_SGE @@ -172,9 +177,23 @@ #define MPT_SCSI_SG_DEPTH 40 #endif +#ifdef CONFIG_FUSION_MAX_FC_SGE +#if CONFIG_FUSION_MAX_FC_SGE < 16 +#define MPT_SCSI_FC_SG_DEPTH 16 +#elif CONFIG_FUSION_MAX_FC_SGE > 256 +#define MPT_SCSI_FC_SG_DEPTH 256 +#else +#define MPT_SCSI_FC_SG_DEPTH CONFIG_FUSION_MAX_FC_SGE +#endif +#else +#define MPT_SCSI_FC_SG_DEPTH 40 +#endif + /* debug print string length used for events and iocstatus */ # define EVENT_DESCR_STR_SZ 100 +#define MPT_POLLING_INTERVAL 1000 /* in milliseconds */ + #ifdef __KERNEL__ /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -378,6 +397,8 @@ typedef struct _VirtTarget { u8 raidVolume; /* set, if RAID Volume */ u8 type; /* byte 0 of Inquiry data */ u8 deleted; /* target in process of being removed */ + u8 inDMD; /* currently in the device + removal delay timer */ u32 num_luns; } VirtTarget; @@ -400,66 +421,39 @@ typedef struct _VirtDevice { #define MPT_TARGET_FLAGS_LED_ON 0x80 /* - * /proc/mpt interface - */ -typedef struct { - const char *name; - mode_t mode; - int pad; - read_proc_t *read_proc; - write_proc_t *write_proc; -} mpt_proc_entry_t; - -#define MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len) \ -do { \ - len -= offset; \ - if (len < request) { \ - *eof = 1; \ - if (len <= 0) \ - return 0; \ - } else \ - len = request; \ - *start = buf + offset; \ - return len; \ -} while (0) - - -/* * IOCTL structure and associated defines */ -#define MPT_IOCTL_STATUS_DID_IOCRESET 0x01 /* IOC Reset occurred on the current*/ -#define MPT_IOCTL_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ -#define MPT_IOCTL_STATUS_TIMER_ACTIVE 0x04 /* The timer is running */ -#define MPT_IOCTL_STATUS_SENSE_VALID 0x08 /* Sense data is valid */ -#define MPT_IOCTL_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ -#define MPT_IOCTL_STATUS_TMTIMER_ACTIVE 0x20 /* The TM timer is running */ -#define MPT_IOCTL_STATUS_TM_FAILED 0x40 /* User TM request failed */ - #define MPTCTL_RESET_OK 0x01 /* Issue Bus Reset */ -typedef struct _MPT_IOCTL { - struct _MPT_ADAPTER *ioc; - u8 ReplyFrame[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ - u8 sense[MPT_SENSE_BUFFER_ALLOC]; - int wait_done; /* wake-up value for this ioc */ - u8 rsvd; - u8 status; /* current command status */ - u8 reset; /* 1 if bus reset allowed */ - u8 id; /* target for reset */ - struct mutex ioctl_mutex; -} MPT_IOCTL; - -#define MPT_SAS_MGMT_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ -#define MPT_SAS_MGMT_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ -#define MPT_SAS_MGMT_STATUS_TM_FAILED 0x40 /* User TM request failed */ - -typedef struct _MPT_SAS_MGMT { +#define MPT_MGMT_STATUS_RF_VALID 0x01 /* The Reply Frame is VALID */ +#define MPT_MGMT_STATUS_COMMAND_GOOD 0x02 /* Command Status GOOD */ +#define MPT_MGMT_STATUS_PENDING 0x04 /* command is pending */ +#define MPT_MGMT_STATUS_DID_IOCRESET 0x08 /* IOC Reset occurred + on the current*/ +#define MPT_MGMT_STATUS_SENSE_VALID 0x10 /* valid sense info */ +#define MPT_MGMT_STATUS_TIMER_ACTIVE 0x20 /* obsolete */ +#define MPT_MGMT_STATUS_FREE_MF 0x40 /* free the mf from + complete routine */ + +#define INITIALIZE_MGMT_STATUS(status) \ + status = MPT_MGMT_STATUS_PENDING; +#define CLEAR_MGMT_STATUS(status) \ + status = 0; +#define CLEAR_MGMT_PENDING_STATUS(status) \ + status &= ~MPT_MGMT_STATUS_PENDING; +#define SET_MGMT_MSG_CONTEXT(msg_context, value) \ + msg_context = value; + +typedef struct _MPT_MGMT { struct mutex mutex; struct completion done; u8 reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ + u8 sense[MPT_SENSE_BUFFER_ALLOC]; u8 status; /* current command status */ -}MPT_SAS_MGMT; + int completion_code; + u32 msg_context; +} MPT_MGMT; /* * Event Structure and define @@ -531,7 +525,7 @@ struct inactive_raid_component_info { typedef struct _RaidCfgData { IOCPage2_t *pIocPg2; /* table of Raid Volumes */ IOCPage3_t *pIocPg3; /* table of physical disks */ - struct semaphore inactive_list_mutex; + struct mutex inactive_list_mutex; struct list_head inactive_list; /* link list for physical disk that belong in inactive volumes */ @@ -561,6 +555,48 @@ struct mptfc_rport_info u8 flags; }; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers + * Private to the driver. + */ + +#define MPT_HOST_BUS_UNKNOWN (0xFF) +#define MPT_HOST_TOO_MANY_TM (0x05) +#define MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) +#define MPT_HOST_NO_CHAIN (0xFFFFFFFF) +#define MPT_NVRAM_MASK_TIMEOUT (0x000000FF) +#define MPT_NVRAM_SYNC_MASK (0x0000FF00) +#define MPT_NVRAM_SYNC_SHIFT (8) +#define MPT_NVRAM_DISCONNECT_ENABLE (0x00010000) +#define MPT_NVRAM_ID_SCAN_ENABLE (0x00020000) +#define MPT_NVRAM_LUN_SCAN_ENABLE (0x00040000) +#define MPT_NVRAM_TAG_QUEUE_ENABLE (0x00080000) +#define MPT_NVRAM_WIDE_DISABLE (0x00100000) +#define MPT_NVRAM_BOOT_CHOICE (0x00200000) + +typedef enum { + FC, + SPI, + SAS +} BUS_TYPE; + +typedef struct _MPT_SCSI_HOST { + struct _MPT_ADAPTER *ioc; + ushort sel_timeout[MPT_MAX_FC_DEVICES]; + char *info_kbuf; + long last_queue_full; + u16 spi_pending; + struct list_head target_reset_list; +} MPT_SCSI_HOST; + +typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr); +typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length, + dma_addr_t dma_addr); +typedef void (*MPT_SCHEDULE_TARGET_RESET)(void *ioc); +typedef void (*MPT_FLUSH_RUNNING_CMDS)(MPT_SCSI_HOST *hd); + /* * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS */ @@ -570,6 +606,10 @@ typedef struct _MPT_ADAPTER int pci_irq; /* This irq */ char name[MPT_NAME_LENGTH]; /* "iocN" */ char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */ +#ifdef CONFIG_FUSION_LOGGING + /* used in mpt_display_event_info */ + char evStr[EVENT_DESCR_STR_SZ]; +#endif char board_name[16]; char board_assembly[16]; char board_tracer[16]; @@ -577,7 +617,7 @@ typedef struct _MPT_ADAPTER u16 nvdata_version_default; int debug_level; u8 io_missing_delay; - u8 device_missing_delay; + u16 device_missing_delay; SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */ SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */ u8 bus_type; @@ -597,6 +637,10 @@ typedef struct _MPT_ADAPTER int reply_depth; /* Num Allocated reply frames */ int reply_sz; /* Reply frame size */ int num_chain; /* Number of chain buffers */ + MPT_ADD_SGE add_sge; /* Pointer to add_sge + function */ + MPT_ADD_CHAIN add_chain; /* Pointer to add_chain + function */ /* Pool of buffers for chaining. ReqToChain * and ChainToChain track index of chain buffers. * ChainBuffer (DMA) virt/phys addresses. @@ -630,17 +674,15 @@ typedef struct _MPT_ADAPTER int mtrr_reg; struct pci_dev *pcidev; /* struct pci_dev pointer */ int bars; /* bitmask of BAR's that must be configured */ + int msi_enable; u8 __iomem *memmap; /* mmap address */ struct Scsi_Host *sh; /* Scsi Host pointer */ SpiCfgData spi_data; /* Scsi config. data */ RaidCfgData raid_data; /* Raid config. data */ SasCfgData sas_data; /* Sas config. data */ FcCfgData fc_data; /* Fc config. data */ - MPT_IOCTL *ioctl; /* ioctl data pointer */ struct proc_dir_entry *ioc_dentry; struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */ - spinlock_t diagLock; /* diagnostic reset lock */ - int diagPending; u32 biosVersion; /* BIOS version from IO Unit Page 2 */ int eventTypes; /* Event logging parameters */ int eventContext; /* Next event context */ @@ -648,7 +690,6 @@ typedef struct _MPT_ADAPTER struct _mpt_ioctl_events *events; /* pointer to event log */ u8 *cached_fw; /* Pointer to FW */ dma_addr_t cached_fw_dma; - struct list_head configQ; /* linked list of config. requests */ int hs_reply_idx; #ifndef MFCNT u32 pad0; @@ -661,9 +702,6 @@ typedef struct _MPT_ADAPTER IOCFactsReply_t facts; PortFactsReply_t pfacts[2]; FCPortPage0_t fc_port_page0[2]; - struct timer_list persist_timer; /* persist table timer */ - int persist_wait_done; /* persist completion flag */ - u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */ LANPage0_t lan_cnfg_page0; LANPage1_t lan_cnfg_page1; @@ -678,24 +716,48 @@ typedef struct _MPT_ADAPTER int aen_event_read_flag; /* flag to indicate event log was read*/ u8 FirstWhoInit; u8 upload_fw; /* If set, do a fw upload */ - u8 reload_fw; /* Force a FW Reload on next reset */ u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ u8 pad1[4]; u8 DoneCtx; u8 TaskCtx; u8 InternalCtx; - spinlock_t initializing_hba_lock; - int initializing_hba_lock_flag; struct list_head list; struct net_device *netdev; struct list_head sas_topology; struct mutex sas_topology_mutex; + + struct workqueue_struct *fw_event_q; + struct list_head fw_event_list; + spinlock_t fw_event_lock; + u8 fw_events_off; /* if '1', then ignore events */ + char fw_event_q_name[MPT_KOBJ_NAME_LEN]; + struct mutex sas_discovery_mutex; u8 sas_discovery_runtime; u8 sas_discovery_ignore_events; - u16 handle; + + /* port_info object for the host */ + struct mptsas_portinfo *hba_port_info; + u64 hba_port_sas_addr; + u16 hba_port_num_phy; + struct list_head sas_device_info_list; + struct mutex sas_device_info_mutex; + u8 old_sas_discovery_protocal; + u8 sas_discovery_quiesce_io; int sas_index; /* index refrencing */ - MPT_SAS_MGMT sas_mgmt; + MPT_MGMT sas_mgmt; + MPT_MGMT mptbase_cmds; /* for sending config pages */ + MPT_MGMT internal_cmds; + MPT_MGMT taskmgmt_cmds; + MPT_MGMT ioctl_cmds; + spinlock_t taskmgmt_lock; /* diagnostic reset lock */ + int taskmgmt_in_progress; + u8 taskmgmt_quiesce_io; + u8 ioc_reset_in_progress; + u8 reset_status; + u8 wait_on_reset_completion; + MPT_SCHEDULE_TARGET_RESET schedule_target_reset; + MPT_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; struct work_struct sas_persist_task; struct work_struct fc_setup_reset_work; @@ -704,10 +766,28 @@ typedef struct _MPT_ADAPTER u8 fc_link_speed[2]; spinlock_t fc_rescan_work_lock; struct work_struct fc_rescan_work; - char fc_rescan_work_q_name[KOBJ_NAME_LEN]; + char fc_rescan_work_q_name[MPT_KOBJ_NAME_LEN]; struct workqueue_struct *fc_rescan_work_q; + + /* driver forced bus resets count */ + unsigned long hard_resets; + /* fw/external bus resets count */ + unsigned long soft_resets; + /* cmd timeouts */ + unsigned long timeouts; + struct scsi_cmnd **ScsiLookup; spinlock_t scsi_lookup_lock; + u64 dma_mask; + u32 broadcast_aen_busy; + char reset_work_q_name[MPT_KOBJ_NAME_LEN]; + struct workqueue_struct *reset_work_q; + struct delayed_work fault_reset_work; + + u8 sg_addr_size; + u8 in_rescan; + u8 SGE_size; + } MPT_ADAPTER; /* @@ -744,13 +824,14 @@ typedef struct _mpt_sge { dma_addr_t Address; } MptSge_t; -#define mpt_addr_size() \ - ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \ - MPI_SGE_FLAGS_32_BIT_ADDRESSING) -#define mpt_msg_flags() \ - ((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ - MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32) +#define mpt_msg_flags(ioc) \ + (ioc->sg_addr_size == sizeof(u64)) ? \ + MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \ + MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 + +#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \ + (MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -790,19 +871,6 @@ typedef struct _MPT_LOCAL_REPLY { u32 pad; } MPT_LOCAL_REPLY; -#define MPT_HOST_BUS_UNKNOWN (0xFF) -#define MPT_HOST_TOO_MANY_TM (0x05) -#define MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) -#define MPT_HOST_NO_CHAIN (0xFFFFFFFF) -#define MPT_NVRAM_MASK_TIMEOUT (0x000000FF) -#define MPT_NVRAM_SYNC_MASK (0x0000FF00) -#define MPT_NVRAM_SYNC_SHIFT (8) -#define MPT_NVRAM_DISCONNECT_ENABLE (0x00010000) -#define MPT_NVRAM_ID_SCAN_ENABLE (0x00020000) -#define MPT_NVRAM_LUN_SCAN_ENABLE (0x00040000) -#define MPT_NVRAM_TAG_QUEUE_ENABLE (0x00080000) -#define MPT_NVRAM_WIDE_DISABLE (0x00100000) -#define MPT_NVRAM_BOOT_CHOICE (0x00200000) /* The TM_STATE variable is used to provide strict single threading of TM * requests as well as communicate TM error conditions. @@ -811,43 +879,6 @@ typedef struct _MPT_LOCAL_REPLY { #define TM_STATE_IN_PROGRESS (1) #define TM_STATE_ERROR (2) -typedef enum { - FC, - SPI, - SAS -} BUS_TYPE; - -typedef struct _MPT_SCSI_HOST { - MPT_ADAPTER *ioc; - int port; - u32 pad0; - MPT_LOCAL_REPLY *pLocal; /* used for internal commands */ - struct timer_list timer; - /* Pool of memory for holding SCpnts before doing - * OS callbacks. freeQ is the free pool. - */ - u8 tmPending; - u8 resetPending; - u8 negoNvram; /* DV disabled, nego NVRAM */ - u8 pad1; - u8 tmState; - u8 rsvd[2]; - MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */ - struct scsi_cmnd *abortSCpnt; - MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */ - unsigned long hard_resets; /* driver forced bus resets count */ - unsigned long soft_resets; /* fw/external bus resets count */ - unsigned long timeouts; /* cmd timeouts */ - ushort sel_timeout[MPT_MAX_FC_DEVICES]; - char *info_kbuf; - wait_queue_head_t scandv_waitq; - int scandv_wait_done; - long last_queue_full; - u16 tm_iocstatus; - u16 spi_pending; - struct list_head target_reset_list; -} MPT_SCSI_HOST; - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * More Dynamic Multi-Pathing stuff... @@ -861,21 +892,16 @@ struct scsi_cmnd; * Generic structure passed to the base mpt_config function. */ typedef struct _x_config_parms { - struct list_head linkage; /* linked list */ - struct timer_list timer; /* timer function for this request */ union { ConfigExtendedPageHeader_t *ehdr; ConfigPageHeader_t *hdr; } cfghdr; dma_addr_t physAddr; - int wait_done; /* wait for this request */ u32 pageAddr; /* properly formatted */ + u16 status; u8 action; u8 dir; u8 timeout; /* seconds */ - u8 pad1; - u16 status; - u16 pad2; } CONFIGPARMS; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -888,7 +914,8 @@ extern void mpt_detach(struct pci_dev *pdev); extern int mpt_suspend(struct pci_dev *pdev, pm_message_t state); extern int mpt_resume(struct pci_dev *pdev); #endif -extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass); +extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, + char *func_name); extern void mpt_deregister(u8 cb_idx); extern int mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc); extern void mpt_event_deregister(u8 cb_idx); @@ -900,25 +927,33 @@ extern MPT_FRAME_HDR *mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc); extern void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); extern void mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); extern void mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf); -extern void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr); extern int mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag); extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp); extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked); extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan); extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); +extern int mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag); extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); extern int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size); extern void mpt_free_fw_memory(MPT_ADAPTER *ioc); extern int mpt_findImVolumes(MPT_ADAPTER *ioc); extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk); +extern int mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, + pRaidPhysDiskPage1_t phys_disk); +extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, + u8 phys_disk_num); +extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); +extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc); +extern void mpt_halt_firmware(MPT_ADAPTER *ioc); + /* * Public data decl's... */ extern struct list_head ioc_list; -extern struct proc_dir_entry *mpt_proc_root_dir; +extern int mpt_fwfault_debug; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* } __KERNEL__ */ @@ -948,7 +983,6 @@ extern struct proc_dir_entry *mpt_proc_root_dir; #define MPT_SGE_FLAGS_END_OF_BUFFER (0x40000000) #define MPT_SGE_FLAGS_LOCAL_ADDRESS (0x08000000) #define MPT_SGE_FLAGS_DIRECTION (0x04000000) -#define MPT_SGE_FLAGS_ADDRESSING (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT) #define MPT_SGE_FLAGS_END_OF_LIST (0x01000000) #define MPT_SGE_FLAGS_TRANSACTION_ELEMENT (0x00000000) @@ -961,14 +995,12 @@ extern struct proc_dir_entry *mpt_proc_root_dir; MPT_SGE_FLAGS_END_OF_BUFFER | \ MPT_SGE_FLAGS_END_OF_LIST | \ MPT_SGE_FLAGS_SIMPLE_ELEMENT | \ - MPT_SGE_FLAGS_ADDRESSING | \ MPT_TRANSFER_IOC_TO_HOST) #define MPT_SGE_FLAGS_SSIMPLE_WRITE \ (MPT_SGE_FLAGS_LAST_ELEMENT | \ MPT_SGE_FLAGS_END_OF_BUFFER | \ MPT_SGE_FLAGS_END_OF_LIST | \ MPT_SGE_FLAGS_SIMPLE_ELEMENT | \ - MPT_SGE_FLAGS_ADDRESSING | \ MPT_TRANSFER_HOST_TO_IOC) /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index e630b50966e..8a050e88568 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -4,7 +4,7 @@ * For use with LSI PCI chip/adapters * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -54,7 +54,7 @@ #include <linux/pci.h> #include <linux/delay.h> /* for mdelay */ #include <linux/miscdevice.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compat.h> #include <asm/io.h> @@ -66,7 +66,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> -#define COPYRIGHT "Copyright (c) 1999-2007 LSI Corporation" +#define COPYRIGHT "Copyright (c) 1999-2008 LSI Corporation" #define MODULEAUTHOR "LSI Corporation" #include "mptbase.h" #include "mptctl.h" @@ -83,7 +83,9 @@ MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static DEFINE_MUTEX(mpctl_mutex); static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS; +static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS; static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait ); @@ -127,10 +129,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTER *ioc); -static void mptctl_timeout_expired (MPT_IOCTL *ioctl); -static int mptctl_bus_reset(MPT_IOCTL *ioctl); -static int mptctl_set_tm_flags(MPT_SCSI_HOST *hd); -static void mptctl_free_tm_flags(MPT_ADAPTER *ioc); /* * Reset Handler cleanup function @@ -183,10 +181,10 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) int rc = 0; if (nonblock) { - if (!mutex_trylock(&ioc->ioctl->ioctl_mutex)) + if (!mutex_trylock(&ioc->ioctl_cmds.mutex)) rc = -EAGAIN; } else { - if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex)) + if (mutex_lock_interruptible(&ioc->ioctl_cmds.mutex)) rc = -ERESTARTSYS; } return rc; @@ -202,266 +200,319 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock) static int mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { - char *sense_data; - int sz, req_index; - u16 iocStatus; - u8 cmd; + char *sense_data; + int req_index; + int sz; - if (req) - cmd = req->u.hdr.Function; - else - return 1; - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, " - "reply=%p\n", ioc->name, req->u.hdr.Function, req, reply)); - - if (ioc->ioctl) { - - if (reply==NULL) { + if (!req) + return 0; - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply " - "Function=%x!\n", ioc->name, cmd)); + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "completing mpi function " + "(0x%02X), req=%p, reply=%p\n", ioc->name, req->u.hdr.Function, + req, reply)); - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; - ioc->ioctl->reset &= ~MPTCTL_RESET_OK; + /* + * Handling continuation of the same reply. Processing the first + * reply, and eating the other replys that come later. + */ + if (ioc->ioctl_cmds.msg_context != req->u.hdr.MsgContext) + goto out_continuation; - /* We are done, issue wake up - */ - ioc->ioctl->wait_done = 1; - wake_up (&mptctl_wait); - return 1; + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; - } + if (!reply) + goto out; - /* Copy the reply frame (which much exist - * for non-SCSI I/O) to the IOC structure. - */ - memcpy(ioc->ioctl->ReplyFrame, reply, - min(ioc->reply_sz, 4*reply->u.reply.MsgLength)); - ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID; + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + sz = min(ioc->reply_sz, 4*reply->u.reply.MsgLength); + memcpy(ioc->ioctl_cmds.reply, reply, sz); - /* Set the command status to GOOD if IOC Status is GOOD - * OR if SCSI I/O cmd and data underrun or recovered error. - */ - iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK; - if (iocStatus == MPI_IOCSTATUS_SUCCESS) - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; - - if (iocStatus || reply->u.reply.IOCLogInfo) - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), " - "loginfo (0x%08X)\n", ioc->name, - iocStatus, - le32_to_cpu(reply->u.reply.IOCLogInfo))); - - if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || - (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { - - if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState) - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "\tscsi_status (0x%02x), scsi_state (0x%02x), " - "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name, - reply->u.sreply.SCSIStatus, - reply->u.sreply.SCSIState, - le16_to_cpu(reply->u.sreply.TaskTag), - le32_to_cpu(reply->u.sreply.TransferCount))); - - ioc->ioctl->reset &= ~MPTCTL_RESET_OK; - - if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) || - (iocStatus == MPI_IOCSTATUS_SCSI_RECOVERED_ERROR)) { - ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; - } - } - - /* Copy the sense data - if present - */ - if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) && - (reply->u.sreply.SCSIState & - MPI_SCSI_STATE_AUTOSENSE_VALID)){ + if (reply->u.reply.IOCStatus || reply->u.reply.IOCLogInfo) + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "iocstatus (0x%04X), loginfo (0x%08X)\n", ioc->name, + le16_to_cpu(reply->u.reply.IOCStatus), + le32_to_cpu(reply->u.reply.IOCLogInfo))); + + if ((req->u.hdr.Function == MPI_FUNCTION_SCSI_IO_REQUEST) || + (req->u.hdr.Function == + MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { + + if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState) + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "scsi_status (0x%02x), scsi_state (0x%02x), " + "tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name, + reply->u.sreply.SCSIStatus, + reply->u.sreply.SCSIState, + le16_to_cpu(reply->u.sreply.TaskTag), + le32_to_cpu(reply->u.sreply.TransferCount))); + + if (reply->u.sreply.SCSIState & + MPI_SCSI_STATE_AUTOSENSE_VALID) { sz = req->u.scsireq.SenseBufferLength; req_index = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); - sense_data = - ((u8 *)ioc->sense_buf_pool + + sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC)); - memcpy(ioc->ioctl->sense, sense_data, sz); - ioc->ioctl->status |= MPT_IOCTL_STATUS_SENSE_VALID; + memcpy(ioc->ioctl_cmds.sense, sense_data, sz); + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_SENSE_VALID; } + } - if (cmd == MPI_FUNCTION_SCSI_TASK_MGMT) - mptctl_free_tm_flags(ioc); - - /* We are done, issue wake up - */ - ioc->ioctl->wait_done = 1; - wake_up (&mptctl_wait); + out: + /* We are done, issue wake up + */ + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { + if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) { + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); + } else { + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + } } + + out_continuation: + if (reply && (reply->u.reply.MsgFlags & + MPI_MSGFLAGS_CONTINUATION_REPLY)) + return 0; return 1; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_timeout_expired - * - * Expecting an interrupt, however timed out. - * - */ -static void mptctl_timeout_expired (MPT_IOCTL *ioctl) + +static int +mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { - int rc = 1; + if (!mf) + return 0; - dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n", - ioctl->ioc->name, ioctl->ioc->id)); - if (ioctl == NULL) - return; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt completed (mf=%p, mr=%p)\n", + ioc->name, mf, mr)); - ioctl->wait_done = 0; - if (ioctl->reset & MPTCTL_RESET_OK) - rc = mptctl_bus_reset(ioctl); + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; - if (rc) { - /* Issue a reset for this device. - * The IOC is not responding. - */ - dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", - ioctl->ioc->name)); - mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP); - } - return; + if (!mr) + goto out; + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); + out: + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); + return 1; + } + return 0; } -/* mptctl_bus_reset - * - * Bus reset code. - * - */ -static int mptctl_bus_reset(MPT_IOCTL *ioctl) +static int +mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; - MPT_SCSI_HOST *hd; + SCSITaskMgmtReply_t *pScsiTmReply; int ii; - int retval=0; - + int retval; + unsigned long timeout; + unsigned long time_count; + u16 iocstatus; - ioctl->reset &= ~MPTCTL_RESET_OK; - if (ioctl->ioc->sh == NULL) - return -EPERM; - - hd = shost_priv(ioctl->ioc->sh); - if (hd == NULL) + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); return -EPERM; + } - /* Single threading .... - */ - if (mptctl_set_tm_flags(hd) != 0) - return -EPERM; + retval = 0; - /* Send request - */ - if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) { - dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n", - ioctl->ioc->name)); - - mptctl_free_tm_flags(ioctl->ioc); - return -ENOMEM; + mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc); + if (mf == NULL) { + dtmprintk(ioc, + printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n", + ioc->name)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + retval = -ENOMEM; + goto tm_done; } - dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", - ioctl->ioc->name, mf)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", + ioc->name, mf)); pScsiTm = (SCSITaskMgmt_t *) mf; - pScsiTm->TargetID = ioctl->id; - pScsiTm->Bus = hd->port; /* 0 */ - pScsiTm->ChainOffset = 0; + memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + pScsiTm->TaskType = tm_type; + if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && + (ioc->bus_type == FC)) + pScsiTm->MsgFlags = + MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; + pScsiTm->TargetID = target_id; + pScsiTm->Bus = bus_id; + pScsiTm->ChainOffset = 0; pScsiTm->Reserved = 0; - pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; pScsiTm->Reserved1 = 0; - pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; - + pScsiTm->TaskMsgContext = 0; for (ii= 0; ii < 8; ii++) pScsiTm->LUN[ii] = 0; - for (ii=0; ii < 7; ii++) pScsiTm->Reserved2[ii] = 0; - pScsiTm->TaskMsgContext = 0; - dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT - "mptctl_bus_reset: issued.\n", ioctl->ioc->name)); - - DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf); + switch (ioc->bus_type) { + case FC: + timeout = 40; + break; + case SAS: + timeout = 30; + break; + case SPI: + default: + timeout = 10; + break; + } - ioctl->wait_done=0; + dtmprintk(ioc, + printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n", + ioc->name, tm_type, timeout)); - if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && - (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05)) - mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf); + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + time_count = jiffies; + if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && + (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) + mpt_put_msg_frame_hi_pri(mptctl_taskmgmt_id, ioc, mf); else { - retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc, - sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); + retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc, + sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP); if (retval != 0) { - dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!" - " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd, - hd->ioc, mf)); - goto mptctl_bus_reset_done; + dfailprintk(ioc, + printk(MYIOC_s_ERR_FMT + "TaskMgmt send_handshake FAILED!" + " (ioc %p, mf %p, rc=%d) \n", ioc->name, + ioc, mf, retval)); + mpt_free_msg_frame(ioc, mf); + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto tm_done; } } /* Now wait for the command to complete */ - ii = wait_event_timeout(mptctl_wait, - ioctl->wait_done == 1, - HZ*5 /* 5 second timeout */); + ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ); - if(ii <=0 && (ioctl->wait_done != 1 )) { - mpt_free_msg_frame(hd->ioc, mf); - ioctl->wait_done = 0; - retval = -1; /* return failure */ + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + mpt_free_msg_frame(ioc, mf); + mpt_clear_taskmgmt_in_progress_flag(ioc); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + retval = 0; + else + retval = -1; /* return failure */ + goto tm_done; } -mptctl_bus_reset_done: - - mptctl_free_tm_flags(ioctl->ioc); - return retval; -} - -static int -mptctl_set_tm_flags(MPT_SCSI_HOST *hd) { - unsigned long flags; - - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - - if (hd->tmState == TM_STATE_NONE) { - hd->tmState = TM_STATE_IN_PROGRESS; - hd->tmPending = 1; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - } else { - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - return -EBUSY; + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + retval = -1; /* return failure */ + goto tm_done; + } + + pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, " + "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, " + "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus, + pScsiTmReply->TargetID, tm_type, + le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), + pScsiTmReply->ResponseCode, + le32_to_cpu(pScsiTmReply->TerminationCount))); + + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + + if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || + iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED || + iocstatus == MPI_IOCSTATUS_SUCCESS) + retval = 0; + else { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt failed\n", ioc->name)); + retval = -1; /* return failure */ } - return 0; + tm_done: + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + return retval; } +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptctl_timeout_expired + * + * Expecting an interrupt, however timed out. + * + */ static void -mptctl_free_tm_flags(MPT_ADAPTER *ioc) +mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { - MPT_SCSI_HOST * hd; unsigned long flags; + int ret_val = -1; + SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf; + u8 function = mf->u.hdr.Function; - hd = shost_priv(ioc->sh); - if (hd == NULL) + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n", + ioc->name, __func__)); + + if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) + mpt_free_msg_frame(ioc, mf); return; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmState = TM_STATE_NONE; - hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); + CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status) - return; + if (ioc->bus_type == SAS) { + if (function == MPI_FUNCTION_SCSI_IO_REQUEST) + ret_val = mptctl_do_taskmgmt(ioc, + MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, + scsi_req->Bus, scsi_req->TargetID); + else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) + ret_val = mptctl_do_taskmgmt(ioc, + MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + scsi_req->Bus, 0); + if (!ret_val) + return; + } else { + if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) || + (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) + ret_val = mptctl_do_taskmgmt(ioc, + MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + scsi_req->Bus, 0); + if (!ret_val) + return; + } + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n", + ioc->name)); + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); } + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* mptctl_ioc_reset * @@ -472,22 +523,23 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc) static int mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - MPT_IOCTL *ioctl = ioc->ioctl; - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name, - reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - if(ioctl == NULL) - return 1; - switch(reset_phase) { case MPT_IOC_SETUP_RESET: - ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); break; case MPT_IOC_POST_RESET: - ioctl->status &= ~MPT_IOCTL_STATUS_DID_IOCRESET; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->ioctl_cmds.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->ioctl_cmds.done); + } break; - case MPT_IOC_PRE_RESET: default: break; } @@ -505,7 +557,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) event = le32_to_cpu(pEvReply->Event) & 0xFF; dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n", - ioc->name, __FUNCTION__)); + ioc->name, __func__)); if(async_queue == NULL) return 1; @@ -548,17 +600,15 @@ static int mptctl_fasync(int fd, struct file *filep, int mode) { MPT_ADAPTER *ioc; + int ret; + mutex_lock(&mpctl_mutex); list_for_each_entry(ioc, &ioc_list, list) ioc->aen_event_read_flag=0; - return fasync_helper(fd, filep, mode, &async_queue); -} - -static int -mptctl_release(struct inode *inode, struct file *filep) -{ - return fasync_helper(-1, filep, 0, &async_queue); + ret = fasync_helper(fd, filep, mode, &async_queue); + mutex_unlock(&mpctl_mutex); + return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -591,11 +641,8 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) */ iocnumX = khdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || - (iocp == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnumX); + (iocp == NULL)) return -ENODEV; - } if (!iocp->active) { printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n", @@ -643,7 +690,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) else ret = -EINVAL; - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -652,9 +699,9 @@ static long mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&mpctl_mutex); ret = __mptctl_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&mpctl_mutex); return ret; } @@ -759,6 +806,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) int sge_offset = 0; u16 iocstat; pFWDownloadReply_t ReplyMsg = NULL; + unsigned long timeleft; if (mpt_verify_adapter(ioc, &iocp) < 0) { printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", @@ -842,8 +890,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) * 96 8 * 64 4 */ - maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t)) - / (sizeof(dma_addr_t) + sizeof(u32)); + maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - + sizeof(FWDownloadTCSGE_t)) + / iocp->SGE_size; if (numfrags > maxfrags) { ret = -EMLINK; goto fwdl_out; @@ -871,7 +920,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) if (nib == 0 || nib == 3) { ; } else if (sgIn->Address) { - mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); + iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address); n++; if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) { printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - " @@ -883,7 +932,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) } sgIn++; bl++; - sgOut += (sizeof(dma_addr_t) + sizeof(u32)); + sgOut += iocp->SGE_size; } DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags); @@ -892,16 +941,33 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) * Finally, perform firmware download. */ ReplyMsg = NULL; + SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, dlmsg->MsgContext); + INITIALIZE_MGMT_STATUS(iocp->ioctl_cmds.status) mpt_put_msg_frame(mptctl_id, iocp, mf); /* Now wait for the command to complete */ - ret = wait_event_timeout(mptctl_wait, - iocp->ioctl->wait_done == 1, - HZ*60); +retry_wait: + timeleft = wait_for_completion_timeout(&iocp->ioctl_cmds.done, HZ*60); + if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__); + if (iocp->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(iocp, mf); + goto fwdl_out; + } + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "FW download timeout, doorbell=0x%08x\n", + iocp->name, mpt_GetIocState(iocp, 0)); + mptctl_timeout_expired(iocp, mf); + } else + goto retry_wait; + goto fwdl_out; + } - if(ret <=0 && (iocp->ioctl->wait_done != 1 )) { - /* Now we need to reset the board */ - mptctl_timeout_expired(iocp->ioctl); + if (!(iocp->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + printk(MYIOC_s_WARN_FMT "%s: failed\n", iocp->name, __func__); + mpt_free_msg_frame(iocp, mf); ret = -ENODATA; goto fwdl_out; } @@ -909,10 +975,10 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) if (sgl) kfree_sgl(sgl, sgl_dma, buflist, iocp); - ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame; + ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply; iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; if (iocstat == MPI_IOCSTATUS_SUCCESS) { - printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name); + printk(MYIOC_s_INFO_FMT "F/W update successful!\n", iocp->name); return 0; } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n", @@ -933,6 +999,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) return 0; fwdl_out: + + CLEAR_MGMT_STATUS(iocp->ioctl_cmds.status); + SET_MGMT_MSG_CONTEXT(iocp->ioctl_cmds.msg_context, 0); kfree_sgl(sgl, sgl_dma, buflist, iocp); return ret; } @@ -1004,7 +1073,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, * */ sgl = sglbuf; - sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1; + sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1; while (bytes_allocd < bytes) { this_alloc = min(alloc_sz, bytes-bytes_allocd); buflist[buflist_ent].len = this_alloc; @@ -1025,8 +1094,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags, dma_addr_t dma_addr; bytes_allocd += this_alloc; - sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc); - dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir); + sgl->FlagsLength = (0x10000000|sgdir|this_alloc); + dma_addr = pci_map_single(ioc->pcidev, + buflist[buflist_ent].kptr, this_alloc, dir); sgl->Address = dma_addr; fragcnt++; @@ -1173,7 +1243,6 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) int iocnum; unsigned int port; int cim_rev; - u8 revision; struct scsi_device *sdev; VirtDevice *vdevice; @@ -1237,16 +1306,17 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) else karg->adapterType = MPT_IOCTL_INTERFACE_SCSI; - if (karg->hdr.port > 1) + if (karg->hdr.port > 1) { + kfree(karg); return -EINVAL; + } port = karg->hdr.port; karg->port = port; pdev = (struct pci_dev *) ioc->pcidev; karg->pciId = pdev->device; - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - karg->hwRev = revision; + karg->hwRev = pdev->revision; karg->subSystemDevice = pdev->subsystem_device; karg->subSystemVendor = pdev->subsystem_vendor; @@ -1271,6 +1341,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) if (ioc->sh) { shost_for_each_device(sdev, ioc->sh) { vdevice = sdev->hostdata; + if (vdevice == NULL || vdevice->vtarget == NULL) + continue; if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) continue; @@ -1392,6 +1464,8 @@ mptctl_gettargetinfo (unsigned long arg) if (!maxWordsLeft) continue; vdevice = sdev->hostdata; + if (vdevice == NULL || vdevice->vtarget == NULL) + continue; if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) continue; @@ -1772,7 +1846,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) int msgContext; u16 req_idx; ulong timeout; + unsigned long timeleft; struct scsi_device *sdev; + unsigned long flags; + u8 function; /* bufIn and bufOut are used for user to kernel space transfers */ @@ -1785,24 +1862,23 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) __FILE__, __LINE__, iocnum); return -ENODEV; } - if (!ioc->ioctl) { - printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " - "No memory available during driver init.\n", - __FILE__, __LINE__); - return -ENOMEM; - } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - " - "Busy with IOC Reset \n", __FILE__, __LINE__); + "Busy with diagnostic reset\n", __FILE__, __LINE__); return -EBUSY; } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); /* Verify that the final request frame will not be too large. */ sz = karg.dataSgeOffset * 4; if (karg.dataInSize > 0) - sz += sizeof(dma_addr_t) + sizeof(u32); + sz += ioc->SGE_size; if (karg.dataOutSize > 0) - sz += sizeof(dma_addr_t) + sizeof(u32); + sz += ioc->SGE_size; if (sz > ioc->req_sz) { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " @@ -1828,10 +1904,12 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to read MF from mpt_ioctl_command struct @ %p\n", ioc->name, __FILE__, __LINE__, mfPtr); + function = -1; rc = -EFAULT; goto done_free_mem; } hdr->MsgContext = cpu_to_le32(msgContext); + function = hdr->Function; /* Verify that this request is allowed. @@ -1839,7 +1917,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n", ioc->name, hdr->Function, mf)); - switch (hdr->Function) { + switch (function) { case MPI_FUNCTION_IOC_FACTS: case MPI_FUNCTION_PORT_FACTS: karg.dataOutSize = karg.dataInSize = 0; @@ -1894,7 +1972,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) } pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; - pScsiReq->MsgFlags |= mpt_msg_flags(); + pScsiReq->MsgFlags |= mpt_msg_flags(ioc); /* verify that app has not requested @@ -1916,6 +1994,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) struct scsi_target *starget = scsi_target(sdev); VirtTarget *vtarget = starget->hostdata; + if (vtarget == NULL) + continue; + if ((pScsiReq->TargetID == vtarget->id) && (pScsiReq->Bus == vtarget->channel) && (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) @@ -1936,8 +2017,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); - ioc->ioctl->reset = MPTCTL_RESET_OK; - ioc->ioctl->id = pScsiReq->TargetID; } else { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " @@ -1980,7 +2059,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) int dataSize; pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH; - pScsiReq->MsgFlags |= mpt_msg_flags(); + pScsiReq->MsgFlags |= mpt_msg_flags(ioc); /* verify that app has not requested @@ -2015,8 +2094,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); - ioc->ioctl->reset = MPTCTL_RESET_OK; - ioc->ioctl->id = pScsiReq->TargetID; } else { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", @@ -2027,20 +2104,17 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) break; case MPI_FUNCTION_SCSI_TASK_MGMT: - { - MPT_SCSI_HOST *hd = NULL; - if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) { - printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " - "SCSI driver not loaded or SCSI host not found. \n", - ioc->name, __FILE__, __LINE__); - rc = -EFAULT; - goto done_free_mem; - } else if (mptctl_set_tm_flags(hd) != 0) { - rc = -EPERM; - goto done_free_mem; - } - } + { + SCSITaskMgmt_t *pScsiTm; + pScsiTm = (SCSITaskMgmt_t *)mf; + dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "\tTaskType=0x%x MsgFlags=0x%x " + "TaskMsgContext=0x%x id=%d channel=%d\n", + ioc->name, pScsiTm->TaskType, le32_to_cpu + (pScsiTm->TaskMsgContext), pScsiTm->MsgFlags, + pScsiTm->TargetID, pScsiTm->Bus)); break; + } case MPI_FUNCTION_IOC_INIT: { @@ -2124,8 +2198,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) if (karg.dataInSize > 0) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_DIRECTION | - mpt_addr_size() ) + MPI_SGE_FLAGS_DIRECTION) << MPI_SGE_FLAGS_SHIFT; } else { flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; @@ -2142,8 +2215,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* Set up this SGE. * Copy to MF and to sglbuf */ - mpt_add_sge(psge, flagsLength, dma_addr_out); - psge += (sizeof(u32) + sizeof(dma_addr_t)); + ioc->add_sge(psge, flagsLength, dma_addr_out); + psge += ioc->SGE_size; /* Copy user data to kernel space. */ @@ -2176,18 +2249,25 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* Set up this SGE * Copy to MF and to sglbuf */ - mpt_add_sge(psge, flagsLength, dma_addr_in); + ioc->add_sge(psge, flagsLength, dma_addr_in); } } } else { /* Add a NULL SGE */ - mpt_add_sge(psge, flagsLength, (dma_addr_t) -1); + ioc->add_sge(psge, flagsLength, (dma_addr_t) -1); } - ioc->ioctl->wait_done = 0; + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, hdr->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + goto done_free_mem; + } + DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && @@ -2198,10 +2278,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); if (rc != 0) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "_send_handshake FAILED! (ioc %p, mf %p)\n", + "send_handshake FAILED! (ioc %p, mf %p)\n", ioc->name, ioc, mf)); - mptctl_free_tm_flags(ioc); + mpt_clear_taskmgmt_in_progress_flag(ioc); rc = -ENODATA; + mutex_unlock(&ioc->taskmgmt_cmds.mutex); goto done_free_mem; } } @@ -2211,36 +2292,51 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* Now wait for the command to complete */ timeout = (karg.timeout > 0) ? karg.timeout : MPT_IOCTL_DEFAULT_TIMEOUT; - timeout = wait_event_timeout(mptctl_wait, - ioc->ioctl->wait_done == 1, - HZ*timeout); - - if(timeout <=0 && (ioc->ioctl->wait_done != 1 )) { - /* Now we need to reset the board */ - - if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) - mptctl_free_tm_flags(ioc); - - mptctl_timeout_expired(ioc->ioctl); - rc = -ENODATA; +retry_wait: + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, + HZ*timeout); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + rc = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: TIMED OUT!\n", + ioc->name, __func__)); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + goto done_free_mem; + } + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "mpt cmd timeout, doorbell=0x%08x" + " function=0x%x\n", + ioc->name, mpt_GetIocState(ioc, 0), function); + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mptctl_timeout_expired(ioc, mf); + mf = NULL; + } else + goto retry_wait; goto done_free_mem; } + if (function == MPI_FUNCTION_SCSI_TASK_MGMT) + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + + mf = NULL; /* If a valid reply frame, copy to the user. * Offset 2: reply length in U32's */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) { + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) { if (karg.maxReplyBytes < ioc->reply_sz) { - sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]); + sz = min(karg.maxReplyBytes, + 4*ioc->ioctl_cmds.reply[2]); } else { - sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]); + sz = min(ioc->reply_sz, 4*ioc->ioctl_cmds.reply[2]); } - if (sz > 0) { if (copy_to_user(karg.replyFrameBufPtr, - &ioc->ioctl->ReplyFrame, sz)){ + ioc->ioctl_cmds.reply, sz)){ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write out reply frame %p\n", @@ -2253,10 +2349,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* If valid sense data, copy to user. */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_SENSE_VALID) { + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_SENSE_VALID) { sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE); if (sz > 0) { - if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) { + if (copy_to_user(karg.senseDataPtr, + ioc->ioctl_cmds.sense, sz)) { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - " "Unable to write sense data to user %p\n", ioc->name, __FILE__, __LINE__, @@ -2270,7 +2367,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) /* If the overall status is _GOOD and data in, copy data * to user. */ - if ((ioc->ioctl->status & MPT_IOCTL_STATUS_COMMAND_GOOD) && + if ((ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD) && (karg.dataInSize > 0) && (bufIn.kptr)) { if (copy_to_user(karg.dataInBufPtr, @@ -2285,9 +2382,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) done_free_mem: - ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_COMMAND_GOOD | - MPT_IOCTL_STATUS_SENSE_VALID | - MPT_IOCTL_STATUS_RF_VALID ); + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); /* Free the allocated memory. */ @@ -2302,7 +2398,7 @@ done_free_mem: } /* mf is null if command issued successfully - * otherwise, failure occured after mf acquired. + * otherwise, failure occurred after mf acquired. */ if (mf) mpt_free_msg_frame(ioc, mf); @@ -2336,7 +2432,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) int rc, cim_rev; ToolboxIstwiReadWriteRequest_t *IstwiRWRequest; MPT_FRAME_HDR *mf = NULL; - MPIHeader_t *mpi_hdr; + unsigned long timeleft; + int retval; + u32 msgcontext; /* Reset long to int. Should affect IA64 and SPARC only */ @@ -2467,9 +2565,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) MPT_SCSI_HOST *hd = shost_priv(ioc->sh); if (hd && (cim_rev == 1)) { - karg.hard_resets = hd->hard_resets; - karg.soft_resets = hd->soft_resets; - karg.timeouts = hd->timeouts; + karg.hard_resets = ioc->hard_resets; + karg.soft_resets = ioc->soft_resets; + karg.timeouts = ioc->timeouts; } } @@ -2477,17 +2575,17 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) * Gather ISTWI(Industry Standard Two Wire Interface) Data */ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", - ioc->name,__FUNCTION__)); + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT + "%s, no msg frames!!\n", ioc->name, __func__)); goto out; } IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf; - mpi_hdr = (MPIHeader_t *) mf; + msgcontext = IstwiRWRequest->MsgContext; memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t)); + IstwiRWRequest->MsgContext = msgcontext; IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX; IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL; - IstwiRWRequest->MsgContext = mpi_hdr->MsgContext; IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ; IstwiRWRequest->NumAddressBytes = 0x01; IstwiRWRequest->DataLength = cpu_to_le16(0x04); @@ -2499,22 +2597,32 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma); if (!pbuf) goto out; - mpt_add_sge((char *)&IstwiRWRequest->SGL, + ioc->add_sge((char *)&IstwiRWRequest->SGL, (MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma); - ioc->ioctl->wait_done = 0; + retval = 0; + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, + IstwiRWRequest->MsgContext); + INITIALIZE_MGMT_STATUS(ioc->ioctl_cmds.status) mpt_put_msg_frame(mptctl_id, ioc, mf); - rc = wait_event_timeout(mptctl_wait, - ioc->ioctl->wait_done == 1, - HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */); - - if(rc <=0 && (ioc->ioctl->wait_done != 1 )) { - /* - * Now we need to reset the board - */ - mpt_free_msg_frame(ioc, mf); - mptctl_timeout_expired(ioc->ioctl); +retry_wait: + timeleft = wait_for_completion_timeout(&ioc->ioctl_cmds.done, + HZ*MPT_IOCTL_DEFAULT_TIMEOUT); + if (!(ioc->ioctl_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = -ETIME; + printk(MYIOC_s_WARN_FMT "%s: failed\n", ioc->name, __func__); + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "HOST INFO command timeout, doorbell=0x%08x\n", + ioc->name, mpt_GetIocState(ioc, 0)); + mptctl_timeout_expired(ioc, mf); + } else + goto retry_wait; goto out; } @@ -2527,10 +2635,13 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) * bays have drives in them * pbuf[3] = Checksum (0x100 = (byte0 + byte2 + byte3) */ - if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) + if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_RF_VALID) karg.rsvd = *(u32 *)pbuf; out: + CLEAR_MGMT_STATUS(ioc->ioctl_cmds.status) + SET_MGMT_MSG_CONTEXT(ioc->ioctl_cmds.msg_context, 0); + if (pbuf) pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma); @@ -2702,7 +2813,6 @@ mptctl_hp_targetinfo(unsigned long arg) static const struct file_operations mptctl_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .release = mptctl_release, .fasync = mptctl_fasync, .unlocked_ioctl = mptctl_ioctl, #ifdef CONFIG_COMPAT @@ -2755,7 +2865,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd, ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -2809,7 +2919,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd, */ ret = mptctl_do_mpt_command (karg, &uarg->MF); - mutex_unlock(&iocp->ioctl->ioctl_mutex); + mutex_unlock(&iocp->ioctl_cmds.mutex); return ret; } @@ -2817,7 +2927,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd, static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&mpctl_mutex); switch (cmd) { case MPTIOCINFO: case MPTIOCINFO1: @@ -2842,7 +2952,7 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a ret = -ENOIOCTLCMD; break; } - unlock_kernel(); + mutex_unlock(&mpctl_mutex); return ret; } @@ -2861,21 +2971,10 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a static int mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - MPT_IOCTL *mem; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - /* - * Allocate and inite a MPT_IOCTL structure - */ - mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL); - if (!mem) { - mptctl_remove(pdev); - return -ENOMEM; - } - - ioc->ioctl = mem; - ioc->ioctl->ioc = ioc; - mutex_init(&ioc->ioctl->ioctl_mutex); + mutex_init(&ioc->ioctl_cmds.mutex); + init_completion(&ioc->ioctl_cmds.done); return 0; } @@ -2889,9 +2988,6 @@ mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id) static void mptctl_remove(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - - kfree ( ioc->ioctl ); } static struct mpt_pci_driver mptctl_driver = { @@ -2923,7 +3019,8 @@ static int __init mptctl_init(void) * Install our handler */ ++where; - mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER); + mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER, + "mptctl_reply"); if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) { printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); misc_deregister(&mptctl_miscdev); @@ -2931,6 +3028,16 @@ static int __init mptctl_init(void) goto out_fail; } + mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER, + "mptctl_taskmgmt_reply"); + if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) { + printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); + mpt_deregister(mptctl_id); + misc_deregister(&mptctl_miscdev); + err = -EBUSY; + goto out_fail; + } + mpt_reset_register(mptctl_id, mptctl_ioc_reset); mpt_event_register(mptctl_id, mptctl_event_process); @@ -2950,10 +3057,14 @@ static void mptctl_exit(void) printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n", mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor); + /* De-register event handler from base module */ + mpt_event_deregister(mptctl_id); + /* De-register reset handler from base module */ mpt_reset_deregister(mptctl_id); /* De-register callback handler from base module */ + mpt_deregister(mptctl_taskmgmt_id); mpt_deregister(mptctl_id); mpt_device_driver_deregister(MPTCTL_DRIVER); diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h index 2c1890127e1..d564cc9ada6 100644 --- a/drivers/message/fusion/mptctl.h +++ b/drivers/message/fusion/mptctl.h @@ -5,7 +5,7 @@ * LSIFC9xx/LSI409xx Fibre Channel * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ diff --git a/drivers/message/fusion/mptdebug.h b/drivers/message/fusion/mptdebug.h index ffdb0a6191b..28e47887928 100644 --- a/drivers/message/fusion/mptdebug.h +++ b/drivers/message/fusion/mptdebug.h @@ -3,7 +3,7 @@ * For use with LSI PCI chip/adapter(s) * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -58,6 +58,7 @@ #define MPT_DEBUG_FC 0x00080000 #define MPT_DEBUG_SAS 0x00100000 #define MPT_DEBUG_SAS_WIDE 0x00200000 +#define MPT_DEBUG_36GB_MEM 0x00400000 /* * CONFIG_FUSION_LOGGING - enabled in Kconfig @@ -135,6 +136,8 @@ #define dsaswideprintk(IOC, CMD) \ MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) +#define d36memprintk(IOC, CMD) \ + MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM) /* diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 3cdd4e96211..02a3eefd693 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -3,7 +3,7 @@ * For use with LSI PCI chip/adapter(s) * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -54,6 +54,7 @@ #include <linux/reboot.h> /* notifier code */ #include <linux/workqueue.h> #include <linux/sort.h> +#include <linux/slab.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -96,11 +97,10 @@ static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; static int mptfc_target_alloc(struct scsi_target *starget); static int mptfc_slave_alloc(struct scsi_device *sdev); -static int mptfc_qcmd(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)); +static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt); static void mptfc_target_destroy(struct scsi_target *starget); static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout); -static void __devexit mptfc_remove(struct pci_dev *pdev); +static void mptfc_remove(struct pci_dev *pdev); static int mptfc_abort(struct scsi_cmnd *SCpnt); static int mptfc_dev_reset(struct scsi_cmnd *SCpnt); static int mptfc_bus_reset(struct scsi_cmnd *SCpnt); @@ -109,7 +109,7 @@ static int mptfc_host_reset(struct scsi_cmnd *SCpnt); static struct scsi_host_template mptfc_driver_template = { .module = THIS_MODULE, .proc_name = "mptfc", - .proc_info = mptscsih_proc_info, + .show_info = mptscsih_show_info, .name = "MPT FC Host", .info = mptscsih_info, .queuecommand = mptfc_qcmd, @@ -195,29 +195,34 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt, unsigned long flags; int ready; MPT_ADAPTER *ioc; + int loops = 40; /* seconds */ hd = shost_priv(SCpnt->device->host); ioc = hd->ioc; spin_lock_irqsave(shost->host_lock, flags); - while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) { + while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY + || (loops > 0 && ioc->active == 0)) { spin_unlock_irqrestore(shost->host_lock, flags); dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "mptfc_block_error_handler.%d: %d:%d, port status is " - "DID_IMM_RETRY, deferring %s recovery.\n", + "%x, active flag %d, deferring %s recovery.\n", ioc->name, ioc->sh->host_no, - SCpnt->device->id, SCpnt->device->lun, caller)); + SCpnt->device->id, SCpnt->device->lun, + ready, ioc->active, caller)); msleep(1000); spin_lock_irqsave(shost->host_lock, flags); + loops --; } spin_unlock_irqrestore(shost->host_lock, flags); - if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) { + if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata + || ioc->active == 0) { dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT "%s.%d: %d:%d, failing recovery, " - "port state %d, vdevice %p.\n", caller, + "port state %x, active %d, vdevice %p.\n", caller, ioc->name, ioc->sh->host_no, SCpnt->device->id, SCpnt->device->lun, ready, - SCpnt->device->hostdata)); + ioc->active, SCpnt->device->hostdata)); return FAILED; } dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT @@ -231,28 +236,28 @@ static int mptfc_abort(struct scsi_cmnd *SCpnt) { return - mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__); + mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__); } static int mptfc_dev_reset(struct scsi_cmnd *SCpnt) { return - mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__); + mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__); } static int mptfc_bus_reset(struct scsi_cmnd *SCpnt) { return - mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__); + mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__); } static int mptfc_host_reset(struct scsi_cmnd *SCpnt) { return - mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__); + mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__); } static void @@ -476,6 +481,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) if (vtarget) { vtarget->id = pg0->CurrentTargetID; vtarget->channel = pg0->CurrentBus; + vtarget->deleted = 0; } } *((struct mptfc_rport_info **)rport->dd_data) = ri; @@ -643,7 +649,7 @@ mptfc_slave_alloc(struct scsi_device *sdev) } static int -mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) { struct mptfc_rport_info *ri; struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); @@ -652,14 +658,14 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) if (!vdevice || !vdevice->vtarget) { SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); + SCpnt->scsi_done(SCpnt); return 0; } err = fc_remote_port_chkready(rport); if (unlikely(err)) { SCpnt->result = err; - done(SCpnt); + SCpnt->scsi_done(SCpnt); return 0; } @@ -667,11 +673,11 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) ri = *((struct mptfc_rport_info **)rport->dd_data); if (unlikely(!ri)) { SCpnt->result = DID_IMM_RETRY << 16; - done(SCpnt); + SCpnt->scsi_done(SCpnt); return 0; } - return mptscsih_qcmd(SCpnt,done); + return mptscsih_qcmd(SCpnt); } /* @@ -1086,6 +1092,8 @@ mptfc_setup_reset(struct work_struct *work) container_of(work, MPT_ADAPTER, fc_setup_reset_work); u64 pn; struct mptfc_rport_info *ri; + struct scsi_target *starget; + VirtTarget *vtarget; /* reset about to happen, delete (block) all rports */ list_for_each_entry(ri, &ioc->fc_rports, list) { @@ -1093,6 +1101,12 @@ mptfc_setup_reset(struct work_struct *work) ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED; fc_remote_port_delete(ri->rport); /* won't sleep */ ri->rport = NULL; + starget = ri->starget; + if (starget) { + vtarget = starget->hostdata; + if (vtarget) + vtarget->deleted = 1; + } pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; @@ -1113,6 +1127,8 @@ mptfc_rescan_devices(struct work_struct *work) int ii; u64 pn; struct mptfc_rport_info *ri; + struct scsi_target *starget; + VirtTarget *vtarget; /* start by tagging all ports as missing */ list_for_each_entry(ri, &ioc->fc_rports, list) { @@ -1140,6 +1156,12 @@ mptfc_rescan_devices(struct work_struct *work) MPT_RPORT_INFO_FLAGS_MISSING); fc_remote_port_delete(ri->rport); /* won't sleep */ ri->rport = NULL; + starget = ri->starget; + if (starget) { + vtarget = starget->hostdata; + if (vtarget) + vtarget->deleted = 1; + } pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; @@ -1238,8 +1260,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) sh->max_id = ioc->pfacts->MaxDevices; sh->max_lun = max_lun; - sh->this_id = ioc->pfacts[0].PortSCSIID; - /* Required entry. */ sh->unique_id = ioc->id; @@ -1253,17 +1273,15 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } if (numSGE < sh->sg_tablesize) { @@ -1292,30 +1310,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; sh->transportt = mptfc_transport_template; @@ -1328,8 +1322,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* initialize workqueue */ - snprintf(ioc->fc_rescan_work_q_name, KOBJ_NAME_LEN, "mptfc_wq_%d", - sh->host_no); + snprintf(ioc->fc_rescan_work_q_name, sizeof(ioc->fc_rescan_work_q_name), + "mptfc_wq_%d", sh->host_no); ioc->fc_rescan_work_q = create_singlethread_workqueue(ioc->fc_rescan_work_q_name); if (!ioc->fc_rescan_work_q) @@ -1364,7 +1358,7 @@ static struct pci_driver mptfc_driver = { .name = "mptfc", .id_table = mptfc_pci_table, .probe = mptfc_probe, - .remove = __devexit_p(mptfc_remove), + .remove = mptfc_remove, .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, @@ -1380,6 +1374,9 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) unsigned long flags; int rc=1; + if (ioc->bus_type != FC) + return 0; + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", ioc->name, event)); @@ -1418,7 +1415,7 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) unsigned long flags; rc = mptscsih_ioc_reset(ioc,reset_phase); - if (rc == 0) + if ((ioc->bus_type != FC) || (!rc)) return rc; @@ -1474,9 +1471,12 @@ mptfc_init(void) if (!mptfc_transport_template) return -ENODEV; - mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER); - mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER); - mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER); + mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER, + "mptscsih_scandv_complete"); + mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER, + "mptscsih_scandv_complete"); + mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER, + "mptscsih_scandv_complete"); mpt_event_register(mptfcDoneCtx, mptfc_event_process); mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset); @@ -1494,8 +1494,7 @@ mptfc_init(void) * @pdev: Pointer to pci_dev structure * */ -static void __devexit -mptfc_remove(struct pci_dev *pdev) +static void mptfc_remove(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct mptfc_rport_info *p, *n; diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 7950fc678ed..cbe96072a6c 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -4,7 +4,7 @@ * For use with LSI Fibre Channel PCI chip/adapters * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 2000-2007 LSI Corporation + * Copyright (c) 2000-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -56,6 +56,8 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> +#include <linux/sched.h> +#include <linux/slab.h> #define my_VERSION MPT_LINUX_VERSION_COMMON #define MYNAM "mptlan" @@ -77,12 +79,6 @@ MODULE_VERSION(my_VERSION); * Fusion MPT LAN private structures */ -struct NAA_Hosed { - u16 NAA; - u8 ieee[FC_ALEN]; - struct NAA_Hosed *next; -}; - struct BufferControl { struct sk_buff *skb; dma_addr_t dma; @@ -112,7 +108,6 @@ struct mpt_lan_priv { u32 total_posted; u32 total_received; - struct net_device_stats stats; /* Per device statistics */ struct delayed_work post_buckets_task; struct net_device *dev; @@ -159,11 +154,6 @@ static u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS; static u32 max_buckets_out = 127; static u32 tx_max_out_p = 127 - 16; -#ifdef QLOGIC_NAA_WORKAROUND -static struct NAA_Hosed *mpt_bad_naa = NULL; -DEFINE_RWLOCK(bad_naa_lock); -#endif - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * lan_reply - Handle all data sent from the hardware. @@ -559,15 +549,6 @@ mpt_lan_close(struct net_device *dev) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static struct net_device_stats * -mpt_lan_get_stats(struct net_device *dev) -{ - struct mpt_lan_priv *priv = netdev_priv(dev); - - return (struct net_device_stats *) &priv->stats; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int mpt_lan_change_mtu(struct net_device *dev, int new_mtu) { @@ -605,12 +586,12 @@ mpt_lan_send_turbo(struct net_device *dev, u32 tmsg) ctx = GET_LAN_BUFFER_CONTEXT(tmsg); sent = priv->SendCtl[ctx].skb; - priv->stats.tx_packets++; - priv->stats.tx_bytes += sent->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += sent->len; dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", IOC_AND_NETDEV_NAMES_s_s(dev), - __FUNCTION__, sent)); + __func__, sent)); priv->SendCtl[ctx].skb = NULL; pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, @@ -647,7 +628,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) { case MPI_IOCSTATUS_SUCCESS: - priv->stats.tx_packets += count; + dev->stats.tx_packets += count; break; case MPI_IOCSTATUS_LAN_CANCELED: @@ -655,13 +636,13 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) break; case MPI_IOCSTATUS_INVALID_SGL: - priv->stats.tx_errors += count; + dev->stats.tx_errors += count; printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n", IOC_AND_NETDEV_NAMES_s_s(dev)); goto out; default: - priv->stats.tx_errors += count; + dev->stats.tx_errors += count; break; } @@ -672,11 +653,11 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext)); sent = priv->SendCtl[ctx].skb; - priv->stats.tx_bytes += sent->len; + dev->stats.tx_bytes += sent->len; dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", IOC_AND_NETDEV_NAMES_s_s(dev), - __FUNCTION__, sent)); + __func__, sent)); priv->SendCtl[ctx].skb = NULL; pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma, @@ -715,7 +696,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) u16 cur_naa = 0x1000; dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n", - __FUNCTION__, skb)); + __func__, skb)); spin_lock_irqsave(&priv->txfidx_lock, flags); if (priv->mpt_txfidx_tail < 0) { @@ -723,8 +704,8 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->txfidx_lock, flags); printk (KERN_ERR "%s: no tx context available: %u\n", - __FUNCTION__, priv->mpt_txfidx_tail); - return 1; + __func__, priv->mpt_txfidx_tail); + return NETDEV_TX_BUSY; } mf = mpt_get_msg_frame(LanCtx, mpt_dev); @@ -733,8 +714,8 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->txfidx_lock, flags); printk (KERN_ERR "%s: Unable to alloc request frame\n", - __FUNCTION__); - return 1; + __func__); + return NETDEV_TX_BUSY; } ctx = priv->mpt_txfidx[priv->mpt_txfidx_tail--]; @@ -780,30 +761,6 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) // ctx, skb, skb->data)); mac = skb_mac_header(skb); -#ifdef QLOGIC_NAA_WORKAROUND -{ - struct NAA_Hosed *nh; - - /* Munge the NAA for Tx packets to QLogic boards, which don't follow - RFC 2625. The longer I look at this, the more my opinion of Qlogic - drops. */ - read_lock_irq(&bad_naa_lock); - for (nh = mpt_bad_naa; nh != NULL; nh=nh->next) { - if ((nh->ieee[0] == mac[0]) && - (nh->ieee[1] == mac[1]) && - (nh->ieee[2] == mac[2]) && - (nh->ieee[3] == mac[3]) && - (nh->ieee[4] == mac[4]) && - (nh->ieee[5] == mac[5])) { - cur_naa = nh->NAA; - dlprintk ((KERN_INFO "mptlan/sdu_send: using NAA value " - "= %04x.\n", cur_naa)); - break; - } - } - read_unlock_irq(&bad_naa_lock); -} -#endif pTrans->TransactionDetails[0] = cpu_to_le32((cur_naa << 16) | (mac[0] << 8) | @@ -840,7 +797,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) IOC_AND_NETDEV_NAMES_s_s(dev), le32_to_cpu(pSimple->FlagsLength))); - return 0; + return NETDEV_TX_OK; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -850,7 +807,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue */ { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { if (priority) { @@ -869,7 +826,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) static int mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); skb->protocol = mpt_lan_type_trans(skb, dev); @@ -877,8 +834,8 @@ mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) "delivered to upper level.\n", IOC_AND_NETDEV_NAMES_s_s(dev), skb->len)); - priv->stats.rx_bytes += skb->len; - priv->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; skb->dev = dev; netif_rx(skb); @@ -901,7 +858,7 @@ mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *skb, *old_skb; unsigned long flags; @@ -956,7 +913,7 @@ static int mpt_lan_receive_post_free(struct net_device *dev, LANReceivePostReply_t *pRecvRep) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; unsigned long flags; struct sk_buff *skb; @@ -1011,7 +968,7 @@ static int mpt_lan_receive_post_reply(struct net_device *dev, LANReceivePostReply_t *pRecvRep) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *skb, *old_skb; unsigned long flags; @@ -1208,7 +1165,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n", IOC_AND_NETDEV_NAMES_s_s(dev), - __FUNCTION__, buckets, curr)); + __func__, buckets, curr)); max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) / (MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t)); @@ -1217,9 +1174,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) mf = mpt_get_msg_frame(LanCtx, mpt_dev); if (mf == NULL) { printk (KERN_ERR "%s: Unable to alloc request frame\n", - __FUNCTION__); + __func__); dioprintk((KERN_ERR "%s: %u buckets remaining\n", - __FUNCTION__, buckets)); + __func__, buckets)); goto out; } pRecvReq = (LANReceivePostRequest_t *) mf; @@ -1244,7 +1201,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) spin_lock_irqsave(&priv->rxfidx_lock, flags); if (priv->mpt_rxfidx_tail < 0) { printk (KERN_ERR "%s: Can't alloc context\n", - __FUNCTION__); + __func__); spin_unlock_irqrestore(&priv->rxfidx_lock, flags); break; @@ -1267,7 +1224,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) if (skb == NULL) { printk (KERN_WARNING MYNAM "/%s: Can't alloc skb\n", - __FUNCTION__); + __func__); priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; spin_unlock_irqrestore(&priv->rxfidx_lock, flags); break; @@ -1305,7 +1262,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) if (pSimple == NULL) { /**/ printk (KERN_WARNING MYNAM "/%s: No buckets posted\n", -/**/ __FUNCTION__); +/**/ __func__); mpt_free_msg_frame(mpt_dev, mf); goto out; } @@ -1329,9 +1286,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv) out: dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n", - __FUNCTION__, buckets, atomic_read(&priv->buckets_out))); + __func__, buckets, atomic_read(&priv->buckets_out))); dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n", - __FUNCTION__, priv->total_posted, priv->total_received)); + __func__, priv->total_posted, priv->total_received)); clear_bit(0, &priv->post_buckets_active); } @@ -1343,6 +1300,14 @@ mpt_lan_post_receive_buckets_work(struct work_struct *work) post_buckets_task.work)); } +static const struct net_device_ops mpt_netdev_ops = { + .ndo_open = mpt_lan_open, + .ndo_stop = mpt_lan_close, + .ndo_start_xmit = mpt_lan_sdu_send, + .ndo_change_mtu = mpt_lan_change_mtu, + .ndo_tx_timeout = mpt_lan_tx_timeout, +}; + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static struct net_device * mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) @@ -1407,15 +1372,7 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ? tx_max_out_p : MPT_TX_MAX_OUT_LIM; - dev->open = mpt_lan_open; - dev->stop = mpt_lan_close; - dev->get_stats = mpt_lan_get_stats; - dev->set_multicast_list = NULL; - dev->change_mtu = mpt_lan_change_mtu; - dev->hard_start_xmit = mpt_lan_sdu_send; - -/* Not in 2.3.42. Need 2.3.45+ */ - dev->tx_timeout = mpt_lan_tx_timeout; + dev->netdev_ops = &mpt_netdev_ops; dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT; dlprintk((KERN_INFO MYNAM ": Finished registering dev " @@ -1462,11 +1419,9 @@ mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device " "registered as '%s'\n", ioc->name, dev->name); printk(KERN_INFO MYNAM ": %s/%s: " - "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + "LanAddr = %pM\n", IOC_AND_NETDEV_NAMES_s_s(dev), - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + dev->dev_addr); ioc->netdev = dev; @@ -1497,7 +1452,9 @@ static int __init mpt_lan_init (void) { show_mptmod_ver(LANAME, LANVER); - if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) { + LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER, + "lan_reply"); + if (LanCtx <= 0) { printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); return -EBUSY; } @@ -1551,9 +1508,8 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n", NETDEV_PTR_TO_IOC_NAME_s(dev)); - printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", - fch->saddr[0], fch->saddr[1], fch->saddr[2], - fch->saddr[3], fch->saddr[4], fch->saddr[5]); + printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %pM\n", + fch->saddr); } if (*fch->daddr & 1) { @@ -1572,80 +1528,6 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) fcllc = (struct fcllc *)skb->data; -#ifdef QLOGIC_NAA_WORKAROUND -{ - u16 source_naa = fch->stype, found = 0; - - /* Workaround for QLogic not following RFC 2625 in regards to the NAA - value. */ - - if ((source_naa & 0xF000) == 0) - source_naa = swab16(source_naa); - - if (fcllc->ethertype == htons(ETH_P_ARP)) - dlprintk ((KERN_INFO "mptlan/type_trans: got arp req/rep w/ naa of " - "%04x.\n", source_naa)); - - if ((fcllc->ethertype == htons(ETH_P_ARP)) && - ((source_naa >> 12) != MPT_LAN_NAA_RFC2625)){ - struct NAA_Hosed *nh, *prevnh; - int i; - - dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep from " - "system with non-RFC 2625 NAA value (%04x).\n", - source_naa)); - - write_lock_irq(&bad_naa_lock); - for (prevnh = nh = mpt_bad_naa; nh != NULL; - prevnh=nh, nh=nh->next) { - if ((nh->ieee[0] == fch->saddr[0]) && - (nh->ieee[1] == fch->saddr[1]) && - (nh->ieee[2] == fch->saddr[2]) && - (nh->ieee[3] == fch->saddr[3]) && - (nh->ieee[4] == fch->saddr[4]) && - (nh->ieee[5] == fch->saddr[5])) { - found = 1; - dlprintk ((KERN_INFO "mptlan/type_trans: ARP Re" - "q/Rep w/ bad NAA from system already" - " in DB.\n")); - break; - } - } - - if ((!found) && (nh == NULL)) { - - nh = kmalloc(sizeof(struct NAA_Hosed), GFP_KERNEL); - dlprintk ((KERN_INFO "mptlan/type_trans: ARP Req/Rep w/" - " bad NAA from system not yet in DB.\n")); - - if (nh != NULL) { - nh->next = NULL; - if (!mpt_bad_naa) - mpt_bad_naa = nh; - if (prevnh) - prevnh->next = nh; - - nh->NAA = source_naa; /* Set the S_NAA value. */ - for (i = 0; i < FC_ALEN; i++) - nh->ieee[i] = fch->saddr[i]; - dlprintk ((KERN_INFO "Got ARP from %02x:%02x:%02x:%02x:" - "%02x:%02x with non-compliant S_NAA value.\n", - fch->saddr[0], fch->saddr[1], fch->saddr[2], - fch->saddr[3], fch->saddr[4],fch->saddr[5])); - } else { - printk (KERN_ERR "mptlan/type_trans: Unable to" - " kmalloc a NAA_Hosed struct.\n"); - } - } else if (!found) { - printk (KERN_ERR "mptlan/type_trans: found not" - " set, but nh isn't null. Evil " - "funkiness abounds.\n"); - } - write_unlock_irq(&bad_naa_lock); - } -} -#endif - /* Strip the SNAP header from ARP packets since we don't * pass them through to the 802.2/SNAP layers. */ diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index bafb67fc818..69e9d546356 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -4,7 +4,7 @@ * For use with LSI Fibre Channel PCI chip/adapters * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 2000-2007 LSI Corporation + * Copyright (c) 2000-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -69,7 +69,6 @@ #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/delay.h> -// #include <linux/trdevice.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -122,7 +121,7 @@ MODULE_DESCRIPTION(LANAME); #define dlprintk(x) #endif -#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)(d)->priv) +#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)netdev_priv(d)) #define NETDEV_PTR_TO_IOC_NAME_s(d) (NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name) #define IOC_AND_NETDEV_NAMES_s_s(d) NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 78734e25edd..711fcb5cec8 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -3,7 +3,7 @@ * For use with LSI PCI chip/adapter(s) * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -45,6 +45,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/jiffies.h> @@ -56,6 +57,7 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport_sas.h> +#include <scsi/scsi_transport.h> #include <scsi/scsi_dbg.h> #include "mptbase.h" @@ -72,6 +74,7 @@ */ #define MPTSAS_RAID_CHANNEL 1 +#define SAS_CONFIG_PAGE_TIMEOUT 30 MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); @@ -89,12 +92,47 @@ static int max_lun = MPTSAS_MAX_LUN; module_param(max_lun, int, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); +static int mpt_loadtime_max_sectors = 8192; +module_param(mpt_loadtime_max_sectors, int, 0); +MODULE_PARM_DESC(mpt_loadtime_max_sectors, + " Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192"); + static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; - -static void mptsas_hotplug_work(struct work_struct *work); +static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; + +static void mptsas_firmware_event_work(struct work_struct *work); +static void mptsas_send_sas_event(struct fw_event_work *fw_event); +static void mptsas_send_raid_event(struct fw_event_work *fw_event); +static void mptsas_send_ir2_event(struct fw_event_work *fw_event); +static void mptsas_parse_device_info(struct sas_identify *identify, + struct mptsas_devinfo *device_info); +static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, + struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); +static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address + (MPT_ADAPTER *ioc, u64 sas_address); +static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, + struct mptsas_devinfo *device_info, u32 form, u32 form_specific); +static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, + struct mptsas_enclosure *enclosure, u32 form, u32 form_specific); +static int mptsas_add_end_device(MPT_ADAPTER *ioc, + struct mptsas_phyinfo *phy_info); +static void mptsas_del_end_device(MPT_ADAPTER *ioc, + struct mptsas_phyinfo *phy_info); +static void mptsas_send_link_status_event(struct fw_event_work *fw_event); +static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address + (MPT_ADAPTER *ioc, u64 sas_address); +static void mptsas_expander_delete(MPT_ADAPTER *ioc, + struct mptsas_portinfo *port_info, u8 force); +static void mptsas_send_expander_event(struct fw_event_work *fw_event); +static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); +static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); +static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event); +static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); +static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); +void mptsas_schedule_target_reset(void *ioc); static void mptsas_print_phy_data(MPT_ADAPTER *ioc, MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) @@ -218,6 +256,111 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) le16_to_cpu(pg1->AttachedDevHandle))); } +/* inhibit sas firmware event handling */ +static void +mptsas_fw_event_off(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + ioc->fw_events_off = 1; + ioc->sas_discovery_quiesce_io = 0; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + +} + +/* enable sas firmware event handling */ +static void +mptsas_fw_event_on(MPT_ADAPTER *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + ioc->fw_events_off = 0; + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* queue a sas firmware event */ +static void +mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + unsigned long delay) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + list_add_tail(&fw_event->list, &ioc->fw_event_list); + INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)" + "on cpuid %d\n", ioc->name, __func__, + fw_event, smp_processor_id())); + queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, + &fw_event->work, delay); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* requeue a sas firmware event */ +static void +mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + unsigned long delay) +{ + unsigned long flags; + spin_lock_irqsave(&ioc->fw_event_lock, flags); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " + "(fw_event=0x%p)on cpuid %d\n", ioc->name, __func__, + fw_event, smp_processor_id())); + fw_event->retries++; + queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, + &fw_event->work, msecs_to_jiffies(delay)); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* free memory associated to a sas firmware event */ +static void +mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n", + ioc->name, __func__, fw_event)); + list_del(&fw_event->list); + kfree(fw_event); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} + +/* walk the firmware event queue, and either stop or wait for + * outstanding events to complete */ +static void +mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) +{ + struct fw_event_work *fw_event, *next; + struct mptsas_target_reset_event *target_reset_list, *n; + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); + + /* flush the target_reset_list */ + if (!list_empty(&hd->target_reset_list)) { + list_for_each_entry_safe(target_reset_list, n, + &hd->target_reset_list, list) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: removing target reset for id=%d\n", + ioc->name, __func__, + target_reset_list->sas_event_data.TargetID)); + list_del(&target_reset_list->list); + kfree(target_reset_list); + } + } + + if (list_empty(&ioc->fw_event_list) || + !ioc->fw_event_q || in_interrupt()) + return; + + list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { + if (cancel_delayed_work(&fw_event->work)) + mptsas_free_fw_event(ioc, fw_event); + } +} + + static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) { struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); @@ -251,6 +394,38 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) return rc; } +/** + * mptsas_find_portinfo_by_sas_address - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: + * + * This function should be called with the sas_topology_mutex already held + * + **/ +static struct mptsas_portinfo * +mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) +{ + struct mptsas_portinfo *port_info, *rc = NULL; + int i; + + if (sas_address >= ioc->hba_port_sas_addr && + sas_address < (ioc->hba_port_sas_addr + + ioc->hba_port_num_phy)) + return ioc->hba_port_info; + + mutex_lock(&ioc->sas_topology_mutex); + list_for_each_entry(port_info, &ioc->sas_topology, list) + for (i = 0; i < port_info->num_phys; i++) + if (port_info->phy_info[i].identify.sas_address == + sas_address) { + rc = port_info; + goto out; + } + out: + mutex_unlock(&ioc->sas_topology_mutex); + return rc; +} + /* * Returns true if there is a scsi end device */ @@ -286,7 +461,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai phy_info = port_info->phy_info; dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " - "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details, + "bitmask=0x%016llX\n", ioc->name, __func__, port_details, port_details->num_phys, (unsigned long long) port_details->phy_bitmask)); @@ -294,6 +469,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai if(phy_info->port_details != port_details) continue; memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); + mptsas_set_rphy(ioc, phy_info, NULL); phy_info->port_details = NULL; } kfree(port_details); @@ -365,6 +541,285 @@ starget) phy_info->port_details->starget = starget; } +/** + * mptsas_add_device_component - + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: fw mapped id's + * @id: + * @sas_address: + * @device_info: + * + **/ +static void +mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, + u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) +{ + struct mptsas_device_info *sas_info, *next; + struct scsi_device *sdev; + struct scsi_target *starget; + struct sas_rphy *rphy; + + /* + * Delete all matching devices out of the list + */ + mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (!sas_info->is_logical_volume && + (sas_info->sas_address == sas_address || + (sas_info->fw.channel == channel && + sas_info->fw.id == id))) { + list_del(&sas_info->list); + kfree(sas_info); + } + } + + sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); + if (!sas_info) + goto out; + + /* + * Set Firmware mapping + */ + sas_info->fw.id = id; + sas_info->fw.channel = channel; + + sas_info->sas_address = sas_address; + sas_info->device_info = device_info; + sas_info->slot = slot; + sas_info->enclosure_logical_id = enclosure_logical_id; + INIT_LIST_HEAD(&sas_info->list); + list_add_tail(&sas_info->list, &ioc->sas_device_info_list); + + /* + * Set OS mapping + */ + shost_for_each_device(sdev, ioc->sh) { + starget = scsi_target(sdev); + rphy = dev_to_rphy(starget->dev.parent); + if (rphy->identify.sas_address == sas_address) { + sas_info->os.id = starget->id; + sas_info->os.channel = starget->channel; + } + } + + out: + mutex_unlock(&ioc->sas_device_info_mutex); + return; +} + +/** + * mptsas_add_device_component_by_fw - + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: fw mapped id's + * @id: + * + **/ +static void +mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct mptsas_devinfo sas_device; + struct mptsas_enclosure enclosure_info; + int rc; + + rc = mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (channel << 8) + id); + if (rc) + return; + + memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); + mptsas_sas_enclosure_pg0(ioc, &enclosure_info, + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << + MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), + sas_device.handle_enclosure); + + mptsas_add_device_component(ioc, sas_device.channel, + sas_device.id, sas_device.sas_address, sas_device.device_info, + sas_device.slot, enclosure_info.enclosure_logical_id); +} + +/** + * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: fw mapped id's + * @id: + * + **/ +static void +mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, + struct scsi_target *starget) +{ + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + dma_addr_t dma_handle; + pRaidVolumePage0_t buffer = NULL; + int i; + RaidPhysDiskPage0_t phys_disk; + struct mptsas_device_info *sas_info, *next; + + memset(&cfg, 0 , sizeof(CONFIGPARMS)); + memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); + hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; + /* assumption that all volumes on channel = 0 */ + cfg.pageAddr = starget->id; + cfg.cfghdr.hdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!hdr.PageLength) + goto out; + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, + &dma_handle); + + if (!buffer) + goto out; + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + if (mpt_config(ioc, &cfg) != 0) + goto out; + + if (!buffer->NumPhysDisks) + goto out; + + /* + * Adding entry for hidden components + */ + for (i = 0; i < buffer->NumPhysDisks; i++) { + + if (mpt_raid_phys_disk_pg0(ioc, + buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) + continue; + + mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus, + phys_disk.PhysDiskID); + + mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (!sas_info->is_logical_volume && + (sas_info->fw.channel == phys_disk.PhysDiskBus && + sas_info->fw.id == phys_disk.PhysDiskID)) { + sas_info->is_hidden_raid_component = 1; + sas_info->volume_id = starget->id; + } + } + mutex_unlock(&ioc->sas_device_info_mutex); + + } + + /* + * Delete all matching devices out of the list + */ + mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (sas_info->is_logical_volume && sas_info->fw.id == + starget->id) { + list_del(&sas_info->list); + kfree(sas_info); + } + } + + sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL); + if (sas_info) { + sas_info->fw.id = starget->id; + sas_info->os.id = starget->id; + sas_info->os.channel = starget->channel; + sas_info->is_logical_volume = 1; + INIT_LIST_HEAD(&sas_info->list); + list_add_tail(&sas_info->list, &ioc->sas_device_info_list); + } + mutex_unlock(&ioc->sas_device_info_mutex); + + out: + if (buffer) + pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer, + dma_handle); +} + +/** + * mptsas_add_device_component_starget - + * @ioc: Pointer to MPT_ADAPTER structure + * @starget: + * + **/ +static void +mptsas_add_device_component_starget(MPT_ADAPTER *ioc, + struct scsi_target *starget) +{ + VirtTarget *vtarget; + struct sas_rphy *rphy; + struct mptsas_phyinfo *phy_info = NULL; + struct mptsas_enclosure enclosure_info; + + rphy = dev_to_rphy(starget->dev.parent); + vtarget = starget->hostdata; + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + rphy->identify.sas_address); + if (!phy_info) + return; + + memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); + mptsas_sas_enclosure_pg0(ioc, &enclosure_info, + (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << + MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), + phy_info->attached.handle_enclosure); + + mptsas_add_device_component(ioc, phy_info->attached.channel, + phy_info->attached.id, phy_info->attached.sas_address, + phy_info->attached.device_info, + phy_info->attached.slot, enclosure_info.enclosure_logical_id); +} + +/** + * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached + * @ioc: Pointer to MPT_ADAPTER structure + * @channel: os mapped id's + * @id: + * + **/ +static void +mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) +{ + struct mptsas_device_info *sas_info, *next; + + /* + * Set is_cached flag + */ + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + if (sas_info->os.channel == channel && sas_info->os.id == id) + sas_info->is_cached = 1; + } +} + +/** + * mptsas_del_device_components - Cleaning the list + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +static void +mptsas_del_device_components(MPT_ADAPTER *ioc) +{ + struct mptsas_device_info *sas_info, *next; + + mutex_lock(&ioc->sas_device_info_mutex); + list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, + list) { + list_del(&sas_info->list); + kfree(sas_info); + } + mutex_unlock(&ioc->sas_device_info_mutex); +} + /* * mptsas_setup_wide_ports @@ -397,11 +852,17 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) */ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: deleting phy = %d\n", - ioc->name, __FUNCTION__, port_details, i)); + ioc->name, __func__, port_details, i)); port_details->num_phys--; port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); - sas_port_delete_phy(port_details->port, phy_info->phy); + if (phy_info->phy) { + devtprintk(ioc, dev_printk(KERN_DEBUG, + &phy_info->phy->dev, MYIOC_s_FMT + "delete phy %d, phy-obj (0x%p)\n", ioc->name, + phy_info->phy_id, phy_info->phy)); + sas_port_delete_phy(port_details->port, phy_info->phy); + } phy_info->port_details = NULL; } @@ -420,8 +881,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) * Forming a port */ if (!port_details) { - port_details = kzalloc(sizeof(*port_details), - GFP_KERNEL); + port_details = kzalloc(sizeof(struct + mptsas_portinfo_details), GFP_KERNEL); if (!port_details) goto out; port_details->num_phys = 1; @@ -483,7 +944,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) continue; dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: phy_id=%02d num_phys=%02d " - "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, + "bitmask=0x%016llX\n", ioc->name, __func__, port_details, i, port_details->num_phys, (unsigned long long)port_details->phy_bitmask)); dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n", @@ -509,15 +970,62 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) VirtTarget *vtarget = NULL; shost_for_each_device(sdev, ioc->sh) { - if ((vdevice = sdev->hostdata) == NULL) + vdevice = sdev->hostdata; + if ((vdevice == NULL) || + (vdevice->vtarget == NULL)) + continue; + if ((vdevice->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT || + vdevice->vtarget->raidVolume)) continue; if (vdevice->vtarget->id == id && - vdevice->vtarget->channel == channel) + vdevice->vtarget->channel == channel) vtarget = vdevice->vtarget; } return vtarget; } +static void +mptsas_queue_device_delete(MPT_ADAPTER *ioc, + MpiEventDataSasDeviceStatusChange_t *sas_event_data) +{ + struct fw_event_work *fw_event; + int sz; + + sz = offsetof(struct fw_event_work, event_data) + + sizeof(MpiEventDataSasDeviceStatusChange_t); + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", + ioc->name, __func__, __LINE__); + return; + } + memcpy(fw_event->event_data, sas_event_data, + sizeof(MpiEventDataSasDeviceStatusChange_t)); + fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); +} + +static void +mptsas_queue_rescan(MPT_ADAPTER *ioc) +{ + struct fw_event_work *fw_event; + int sz; + + sz = offsetof(struct fw_event_work, event_data); + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", + ioc->name, __func__, __LINE__); + return; + } + fw_event->event = -1; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1)); +} + + /** * mptsas_target_reset * @@ -536,13 +1044,21 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; - - if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n", - ioc->name,__FUNCTION__, __LINE__)); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) return 0; + + + mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); + if (mf == NULL) { + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT + "%s, no msg frames @%d!!\n", ioc->name, + __func__, __LINE__)); + goto out_fail; } + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", + ioc->name, mf)); + /* Format the Request */ pScsiTm = (SCSITaskMgmt_t *) mf; @@ -555,15 +1071,37 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); - mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n", + ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); + + mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); return 1; + + out_fail: + + mpt_clear_taskmgmt_in_progress_flag(ioc); + return 0; +} + +static void +mptsas_block_io_sdev(struct scsi_device *sdev, void *data) +{ + scsi_device_set_state(sdev, SDEV_BLOCK); +} + +static void +mptsas_block_io_starget(struct scsi_target *starget) +{ + if (starget) + starget_for_each_device(starget, NULL, mptsas_block_io_sdev); } /** * mptsas_target_reset_queue * - * Receive request for TARGET_RESET after recieving an firmware + * Receive request for TARGET_RESET after receiving an firmware * event NOT_RESPONDING_EVENT, then put command in link list * and queue if task_queue already in use. * @@ -583,16 +1121,18 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, id = sas_event_data->TargetID; channel = sas_event_data->Bus; - if (!(vtarget = mptsas_find_vtarget(ioc, channel, id))) - return; - - vtarget->deleted = 1; /* block IO */ + vtarget = mptsas_find_vtarget(ioc, channel, id); + if (vtarget) { + mptsas_block_io_starget(vtarget->starget); + vtarget->deleted = 1; /* block IO */ + } - target_reset_list = kzalloc(sizeof(*target_reset_list), + target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event), GFP_ATOMIC); if (!target_reset_list) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", - ioc->name,__FUNCTION__, __LINE__)); + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT + "%s, failed to allocate mem @%d..!!\n", + ioc->name, __func__, __LINE__)); return; } @@ -600,119 +1140,143 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, sizeof(*sas_event_data)); list_add_tail(&target_reset_list->list, &hd->target_reset_list); - if (hd->resetPending) - return; + target_reset_list->time_count = jiffies; if (mptsas_target_reset(ioc, channel, id)) { target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; } } /** - * mptsas_dev_reset_complete - * - * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, - * enable work queue to finish off removing device from upper layers. - * then send next TARGET_RESET in the queue. + * mptsas_schedule_target_reset- send pending target reset + * @iocp: per adapter object * - * @ioc + * This function will delete scheduled target reset from the list and + * try to send next target reset. This will be called from completion + * context of any Task management command. + */ + +void +mptsas_schedule_target_reset(void *iocp) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp); + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); + struct list_head *head = &hd->target_reset_list; + struct mptsas_target_reset_event *target_reset_list; + u8 id, channel; + /* + * issue target reset to next device in the queue + */ + + head = &hd->target_reset_list; + if (list_empty(head)) + return; + + target_reset_list = list_entry(head->next, + struct mptsas_target_reset_event, list); + + id = target_reset_list->sas_event_data.TargetID; + channel = target_reset_list->sas_event_data.Bus; + target_reset_list->time_count = jiffies; + + if (mptsas_target_reset(ioc, channel, id)) + target_reset_list->target_reset_issued = 1; + return; +} + + +/** + * mptsas_taskmgmt_complete - complete SAS task management function + * @ioc: Pointer to MPT_ADAPTER structure * + * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work + * queue to finish off removing device from upper layers. then send next + * TARGET_RESET in the queue. **/ -static void -mptsas_dev_reset_complete(MPT_ADAPTER *ioc) +static int +mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) { MPT_SCSI_HOST *hd = shost_priv(ioc->sh); struct list_head *head = &hd->target_reset_list; - struct mptsas_target_reset_event *target_reset_list; - struct mptsas_hotplug_event *ev; - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; u8 id, channel; - __le64 sas_address; + struct mptsas_target_reset_event *target_reset_list; + SCSITaskMgmtReply_t *pScsiTmReply; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " + "(mf = %p, mr = %p)\n", ioc->name, mf, mr)); + + pScsiTmReply = (SCSITaskMgmtReply_t *)mr; + if (pScsiTmReply) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" + "\ttask_type = 0x%02X, iocstatus = 0x%04X " + "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " + "term_cmnds = %d\n", ioc->name, + pScsiTmReply->Bus, pScsiTmReply->TargetID, + pScsiTmReply->TaskType, + le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), + pScsiTmReply->ResponseCode, + le32_to_cpu(pScsiTmReply->TerminationCount))); + + if (pScsiTmReply->ResponseCode) + mptscsih_taskmgmt_response_code(ioc, + pScsiTmReply->ResponseCode); + } + + if (pScsiTmReply && (pScsiTmReply->TaskType == + MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == + MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) { + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + return 1; + } + return 0; + } + + mpt_clear_taskmgmt_in_progress_flag(ioc); if (list_empty(head)) - return; + return 1; - target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list); + target_reset_list = list_entry(head->next, + struct mptsas_target_reset_event, list); - sas_event_data = &target_reset_list->sas_event_data; - id = sas_event_data->TargetID; - channel = sas_event_data->Bus; - hd->resetPending = 0; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt: completed (%d seconds)\n", + ioc->name, jiffies_to_msecs(jiffies - + target_reset_list->time_count)/1000)); + + id = pScsiTmReply->TargetID; + channel = pScsiTmReply->Bus; + target_reset_list->time_count = jiffies; /* * retry target reset */ if (!target_reset_list->target_reset_issued) { - if (mptsas_target_reset(ioc, channel, id)) { + if (mptsas_target_reset(ioc, channel, id)) target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; - } - return; + return 1; } /* * enable work queue to remove device from upper layers */ list_del(&target_reset_list->list); + if (!ioc->fw_events_off) + mptsas_queue_device_delete(ioc, + &target_reset_list->sas_event_data); - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n", - ioc->name,__FUNCTION__, __LINE__)); - return; - } - - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->handle = le16_to_cpu(sas_event_data->DevHandle); - ev->parent_handle = - le16_to_cpu(sas_event_data->ParentDevHandle); - ev->channel = channel; - ev->id =id; - ev->phy_id = sas_event_data->PhyNum; - memcpy(&sas_address, &sas_event_data->SASAddress, - sizeof(__le64)); - ev->sas_address = le64_to_cpu(sas_address); - ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo); - ev->event_type = MPTSAS_DEL_DEVICE; - schedule_work(&ev->work); - kfree(target_reset_list); - - /* - * issue target reset to next device in the queue - */ - - head = &hd->target_reset_list; - if (list_empty(head)) - return; - - target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, - list); - - sas_event_data = &target_reset_list->sas_event_data; - id = sas_event_data->TargetID; - channel = sas_event_data->Bus; - if (mptsas_target_reset(ioc, channel, id)) { - target_reset_list->target_reset_issued = 1; - hd->resetPending = 1; - } -} + ioc->schedule_target_reset(ioc); -/** - * mptsas_taskmgmt_complete - * - * @ioc - * @mf - * @mr - * - **/ -static int -mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) -{ - mptsas_dev_reset_complete(ioc); - return mptscsih_taskmgmt_complete(ioc, mf, mr); + return 1; } /** @@ -726,37 +1290,58 @@ static int mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { MPT_SCSI_HOST *hd; - struct mptsas_target_reset_event *target_reset_list, *n; int rc; rc = mptscsih_ioc_reset(ioc, reset_phase); + if ((ioc->bus_type != SAS) || (!rc)) + return rc; - if (ioc->bus_type != SAS) - goto out; - - if (reset_phase != MPT_IOC_POST_RESET) - goto out; - - if (!ioc->sh || !ioc->sh->hostdata) - goto out; hd = shost_priv(ioc->sh); if (!hd->ioc) goto out; - if (list_empty(&hd->target_reset_list)) - goto out; - - /* flush the target_reset_list */ - list_for_each_entry_safe(target_reset_list, n, - &hd->target_reset_list, list) { - list_del(&target_reset_list->list); - kfree(target_reset_list); + switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + mptsas_fw_event_off(ioc); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->sas_mgmt.done); + } + mptsas_cleanup_fw_event_q(ioc); + mptsas_queue_rescan(ioc); + break; + default: + break; } out: return rc; } + +/** + * enum device_state - + * @DEVICE_RETRY: need to retry the TUR + * @DEVICE_ERROR: TUR return error, don't add device + * @DEVICE_READY: device can be added + * + */ +enum device_state{ + DEVICE_RETRY, + DEVICE_ERROR, + DEVICE_READY, +}; + static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, u32 form, u32 form_specific) @@ -779,7 +1364,7 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -822,15 +1407,309 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, return error; } +/** + * mptsas_add_end_device - report a new end device to sas transport layer + * @ioc: Pointer to MPT_ADAPTER structure + * @phy_info: describes attached device + * + * return (0) success (1) failure + * + **/ +static int +mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) +{ + struct sas_rphy *rphy; + struct sas_port *port; + struct sas_identify identify; + char *ds = NULL; + u8 fw_id; + + if (!phy_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __func__, __LINE__)); + return 1; + } + + fw_id = phy_info->attached.id; + + if (mptsas_get_rphy(phy_info)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return 2; + } + + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return 3; + } + + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) + ds = "ssp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) + ds = "stp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "sata"; + + printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," + " phy %d, sas_addr 0x%llx\n", ioc->name, ds, + phy_info->attached.channel, phy_info->attached.id, + phy_info->attached.phy_id, (unsigned long long) + phy_info->attached.sas_address); + + mptsas_parse_device_info(&identify, &phy_info->attached); + rphy = sas_end_device_alloc(port); + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return 5; /* non-fatal: an rphy can be added later */ + } + + rphy->identify = identify; + if (sas_rphy_add(rphy)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + sas_rphy_free(rphy); + return 6; + } + mptsas_set_rphy(ioc, phy_info, rphy); + return 0; +} + +/** + * mptsas_del_end_device - report a deleted end device to sas transport layer + * @ioc: Pointer to MPT_ADAPTER structure + * @phy_info: describes attached device + * + **/ +static void +mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) +{ + struct sas_rphy *rphy; + struct sas_port *port; + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info_parent; + int i; + char *ds = NULL; + u8 fw_id; + u64 sas_address; + + if (!phy_info) + return; + + fw_id = phy_info->attached.id; + sas_address = phy_info->attached.sas_address; + + if (!phy_info->port_details) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return; + } + rphy = mptsas_get_rphy(phy_info); + if (!rphy) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return; + } + + if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR + || phy_info->attached.device_info + & MPI_SAS_DEVICE_INFO_SMP_INITIATOR + || phy_info->attached.device_info + & MPI_SAS_DEVICE_INFO_STP_INITIATOR) + ds = "initiator"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SSP_TARGET) + ds = "ssp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_STP_TARGET) + ds = "stp"; + if (phy_info->attached.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE) + ds = "sata"; + + dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT + "removing %s device: fw_channel %d, fw_id %d, phy %d," + "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel, + phy_info->attached.id, phy_info->attached.phy_id, + (unsigned long long) sas_address); + + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, fw_id, __LINE__)); + return; + } + port_info = phy_info->portinfo; + phy_info_parent = port_info->phy_info; + for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { + if (!phy_info_parent->phy) + continue; + if (phy_info_parent->attached.sas_address != + sas_address) + continue; + dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, + MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", + ioc->name, phy_info_parent->phy_id, + phy_info_parent->phy); + sas_port_delete_phy(port, phy_info_parent->phy); + } + + dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT + "delete port %d, sas_addr (0x%llx)\n", ioc->name, + port->port_identifier, (unsigned long long)sas_address); + sas_port_delete(port); + mptsas_set_port(ioc, phy_info, NULL); + mptsas_port_delete(ioc, phy_info->port_details); +} + +struct mptsas_phyinfo * +mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, + struct mptsas_devinfo *sas_device) +{ + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo *port_info; + int i; + + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device->sas_address); + if (!phy_info) + goto out; + port_info = phy_info->portinfo; + if (!port_info) + goto out; + mutex_lock(&ioc->sas_topology_mutex); + for (i = 0; i < port_info->num_phys; i++) { + if (port_info->phy_info[i].attached.sas_address != + sas_device->sas_address) + continue; + port_info->phy_info[i].attached.channel = sas_device->channel; + port_info->phy_info[i].attached.id = sas_device->id; + port_info->phy_info[i].attached.sas_address = + sas_device->sas_address; + port_info->phy_info[i].attached.handle = sas_device->handle; + port_info->phy_info[i].attached.handle_parent = + sas_device->handle_parent; + port_info->phy_info[i].attached.handle_enclosure = + sas_device->handle_enclosure; + } + mutex_unlock(&ioc->sas_topology_mutex); + out: + return phy_info; +} + +/** + * mptsas_firmware_event_work - work thread for processing fw events + * @work: work queue payload containing info describing the event + * Context: user + * + */ +static void +mptsas_firmware_event_work(struct work_struct *work) +{ + struct fw_event_work *fw_event = + container_of(work, struct fw_event_work, work.work); + MPT_ADAPTER *ioc = fw_event->ioc; + + /* special rescan topology handling */ + if (fw_event->event == -1) { + if (ioc->in_rescan) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: rescan ignored as it is in progress\n", + ioc->name, __func__)); + return; + } + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after " + "reset\n", ioc->name, __func__)); + ioc->in_rescan = 1; + mptsas_not_responding_devices(ioc); + mptsas_scan_sas_topology(ioc); + ioc->in_rescan = 0; + mptsas_free_fw_event(ioc, fw_event); + mptsas_fw_event_on(ioc); + return; + } + + /* events handling turned off during host reset */ + if (ioc->fw_events_off) { + mptsas_free_fw_event(ioc, fw_event); + return; + } + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), " + "event = (0x%02x)\n", ioc->name, __func__, fw_event, + (fw_event->event & 0xFF))); + + switch (fw_event->event) { + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + mptsas_send_sas_event(fw_event); + break; + case MPI_EVENT_INTEGRATED_RAID: + mptsas_send_raid_event(fw_event); + break; + case MPI_EVENT_IR2: + mptsas_send_ir2_event(fw_event); + break; + case MPI_EVENT_PERSISTENT_TABLE_FULL: + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); + break; + case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: + mptsas_broadcast_primative_work(fw_event); + break; + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + mptsas_send_expander_event(fw_event); + break; + case MPI_EVENT_SAS_PHY_LINK_STATUS: + mptsas_send_link_status_event(fw_event); + break; + case MPI_EVENT_QUEUE_FULL: + mptsas_handle_queue_full_event(fw_event); + break; + } +} + + + static int mptsas_slave_configure(struct scsi_device *sdev) { + struct Scsi_Host *host = sdev->host; + MPT_SCSI_HOST *hd = shost_priv(host); + MPT_ADAPTER *ioc = hd->ioc; + VirtDevice *vdevice = sdev->hostdata; - if (sdev->channel == MPTSAS_RAID_CHANNEL) + if (vdevice->vtarget->deleted) { + sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n"); + vdevice->vtarget->deleted = 0; + } + + /* + * RAID volumes placed beyond the last expected port. + * Ignore sending sas mode pages in that case.. + */ + if (sdev->channel == MPTSAS_RAID_CHANNEL) { + mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev)); goto out; + } sas_read_port_mode_page(sdev); + mptsas_add_device_component_starget(ioc, scsi_target(sdev)); + out: return mptscsih_slave_configure(sdev); } @@ -861,9 +1740,18 @@ mptsas_target_alloc(struct scsi_target *starget) * RAID volumes placed beyond the last expected port. */ if (starget->channel == MPTSAS_RAID_CHANNEL) { - for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) - if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID) - channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus; + if (!ioc->raid_data.pIocPg2) { + kfree(vtarget); + return -ENXIO; + } + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (id == ioc->raid_data.pIocPg2-> + RaidVolume[i].VolumeID) { + channel = ioc->raid_data.pIocPg2-> + RaidVolume[i].VolumeBus; + } + } + vtarget->raidVolume = 1; goto out; } @@ -912,11 +1800,18 @@ mptsas_target_destroy(struct scsi_target *starget) struct sas_rphy *rphy; struct mptsas_portinfo *p; int i; - MPT_ADAPTER *ioc = hd->ioc; + MPT_ADAPTER *ioc = hd->ioc; + VirtTarget *vtarget; if (!starget->hostdata) return; + vtarget = starget->hostdata; + + mptsas_del_device_component_by_os(ioc, starget->channel, + starget->id); + + if (starget->channel == MPTSAS_RAID_CHANNEL) goto out; @@ -926,12 +1821,21 @@ mptsas_target_destroy(struct scsi_target *starget) if (p->phy_info[i].attached.sas_address != rphy->identify.sas_address) continue; + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT + "delete device: fw_channel %d, fw_id %d, phy %d, " + "sas_addr 0x%llx\n", ioc->name, + p->phy_info[i].attached.channel, + p->phy_info[i].attached.id, + p->phy_info[i].attached.phy_id, (unsigned long long) + p->phy_info[i].attached.sas_address); + mptsas_set_starget(&p->phy_info[i], NULL); - goto out; } } out: + vtarget->starget = NULL; kfree(starget->hostdata); starget->hostdata = NULL; } @@ -992,27 +1896,87 @@ mptsas_slave_alloc(struct scsi_device *sdev) } static int -mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) { + MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; VirtDevice *vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); + SCpnt->scsi_done(SCpnt); return 0; } -// scsi_print_command(SCpnt); + hd = shost_priv(shost); + ioc = hd->ioc; + + if (ioc->sas_discovery_quiesce_io) + return SCSI_MLQUEUE_HOST_BUSY; + + if (ioc->debug_level & MPT_DEBUG_SCSI) + scsi_print_command(SCpnt); + + return mptscsih_qcmd(SCpnt); +} + +/** + * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout + * if the device under question is currently in the + * device removal delay. + * @sc: scsi command that the midlayer is about to time out + * + **/ +static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) +{ + MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; + VirtDevice *vdevice; + enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; + + hd = shost_priv(sc->device->host); + if (hd == NULL) { + printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n", + __func__, sc); + goto done; + } + + ioc = hd->ioc; + if (ioc->bus_type != SAS) { + printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n", + __func__, sc); + goto done; + } + + /* In case if IOC is in reset from internal context. + * Do not execute EEH for the same IOC. SML should to reset timer. + */ + if (ioc->ioc_reset_in_progress) { + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset," + "SML need to reset the timer (sc=%p)\n", + ioc->name, __func__, sc)); + rc = BLK_EH_RESET_TIMER; + } + vdevice = sc->device->hostdata; + if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD + || vdevice->vtarget->deleted)) { + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed " + "or in device removal delay (sc=%p)\n", + ioc->name, __func__, sc)); + rc = BLK_EH_RESET_TIMER; + goto done; + } - return mptscsih_qcmd(SCpnt,done); +done: + return rc; } static struct scsi_host_template mptsas_driver_template = { .module = THIS_MODULE, .proc_name = "mptsas", - .proc_info = mptscsih_proc_info, - .name = "MPT SPI Host", + .show_info = mptscsih_show_info, + .name = "MPT SAS Host", .info = mptscsih_info, .queuecommand = mptsas_qcmd, .target_alloc = mptsas_target_alloc, @@ -1023,10 +1987,9 @@ static struct scsi_host_template mptsas_driver_template = { .change_queue_depth = mptscsih_change_queue_depth, .eh_abort_handler = mptscsih_abort, .eh_device_reset_handler = mptscsih_dev_reset, - .eh_bus_reset_handler = mptscsih_bus_reset, .eh_host_reset_handler = mptscsih_host_reset, .bios_param = mptscsih_bios_param, - .can_queue = MPT_FC_CAN_QUEUE, + .can_queue = MPT_SAS_CAN_QUEUE, .this_id = -1, .sg_tablesize = MPT_SCSI_SG_DEPTH, .max_sectors = 8192, @@ -1061,7 +2024,7 @@ static int mptsas_get_linkerrors(struct sas_phy *phy) cfg.pageAddr = phy->identify.phy_identifier; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -1100,14 +2063,19 @@ static int mptsas_get_linkerrors(struct sas_phy *phy) static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) { - ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD; + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; if (reply != NULL) { - ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID; + ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; memcpy(ioc->sas_mgmt.reply, reply, min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); } - complete(&ioc->sas_mgmt.done); - return 1; + + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { + ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->sas_mgmt.done); + return 1; + } + return 0; } static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) @@ -1146,21 +2114,24 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; req->PhyNum = phy->identify.phy_identifier; + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); - if (!timeleft) { - /* On timeout reset the board */ + if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + error = -ETIME; mpt_free_msg_frame(ioc, mf); - mpt_HardResetHandler(ioc, CAN_SLEEP); - error = -ETIMEDOUT; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out_unlock; + if (!timeleft) + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); goto out_unlock; } /* a reply frame is expected */ if ((ioc->sas_mgmt.status & - MPT_IOCTL_STATUS_RF_VALID) == 0) { + MPT_MGMT_STATUS_RF_VALID) == 0) { error = -ENXIO; goto out_unlock; } @@ -1169,7 +2140,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", - ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo); + ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo); error = -ENXIO; goto out_unlock; } @@ -1177,6 +2148,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) error = 0; out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) mutex_unlock(&ioc->sas_mgmt.mutex); out: return error; @@ -1256,15 +2228,15 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, if (!rsp) { printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n", - ioc->name, __FUNCTION__); + ioc->name, __func__); return -EINVAL; } /* do we need to support multiple segments? */ - if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { - printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", - ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len, - rsp->bio->bi_vcnt, rsp->data_len); + if (bio_multiple_segments(req->bio) || + bio_multiple_segments(rsp->bio)) { + printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n", + ioc->name, __func__, blk_rq_bytes(req), blk_rq_bytes(rsp)); return -EINVAL; } @@ -1281,7 +2253,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, smpreq = (SmpPassthroughRequest_t *)mf; memset(smpreq, 0, sizeof(*smpreq)); - smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4); + smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; if (rphy) @@ -1290,7 +2262,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, struct mptsas_portinfo *port_info; mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle); + port_info = ioc->hba_port_info; if (port_info && port_info->phy_info) sas_address = port_info->phy_info[0].phy->identify.sas_address; @@ -1305,62 +2277,73 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* request */ flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_DIRECTION | - mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT; - flagsLength |= (req->data_len - 4); + MPI_SGE_FLAGS_DIRECTION) + << MPI_SGE_FLAGS_SHIFT; + flagsLength |= (blk_rq_bytes(req) - 4); dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), - req->data_len, PCI_DMA_BIDIRECTIONAL); + blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_out) goto put_mf; - mpt_add_sge(psge, flagsLength, dma_addr_out); - psge += (sizeof(u32) + sizeof(dma_addr_t)); + ioc->add_sge(psge, flagsLength, dma_addr_out); + psge += ioc->SGE_size; /* response */ - flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - flagsLength |= rsp->data_len + 4; + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_IOC_TO_HOST | + MPI_SGE_FLAGS_END_OF_BUFFER; + + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= blk_rq_bytes(rsp) + 4; dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), - rsp->data_len, PCI_DMA_BIDIRECTIONAL); + blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) goto unmap; - mpt_add_sge(psge, flagsLength, dma_addr_in); + ioc->add_sge(psge, flagsLength, dma_addr_in); + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); - if (!timeleft) { - printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__); - /* On timeout reset the board */ - mpt_HardResetHandler(ioc, CAN_SLEEP); - ret = -ETIMEDOUT; + if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + mpt_free_msg_frame(ioc, mf); + mf = NULL; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto unmap; + if (!timeleft) + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); goto unmap; } mf = NULL; - if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) { + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { SmpPassthroughReply_t *smprep; smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; memcpy(req->sense, smprep, sizeof(*smprep)); req->sense_len = sizeof(*smprep); - req->data_len = 0; - rsp->data_len -= smprep->ResponseDataLength; + req->resid_len = 0; + rsp->resid_len -= smprep->ResponseDataLength; } else { - printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", - ioc->name, __FUNCTION__); + printk(MYIOC_s_ERR_FMT + "%s: smp passthru reply failed to be returned\n", + ioc->name, __func__); ret = -ENXIO; } unmap: if (dma_addr_out) - pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len, + pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); if (dma_addr_in) - pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len, + pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); put_mf: if (mf) mpt_free_msg_frame(ioc, mf); out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) mutex_unlock(&ioc->sas_mgmt.mutex); out: return ret; @@ -1398,7 +2381,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -1424,7 +2407,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) port_info->num_phys = buffer->NumPhys; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(*port_info->phy_info),GFP_KERNEL); + sizeof(struct mptsas_phyinfo), GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; @@ -1462,14 +2445,14 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) SasIOUnitPage1_t *buffer; dma_addr_t dma_handle; int error; - u16 device_missing_delay; + u8 device_missing_delay; memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); memset(&cfg, 0, sizeof(CONFIGPARMS)); cfg.cfghdr.ehdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED; cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION; @@ -1499,7 +2482,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) ioc->io_missing_delay = le16_to_cpu(buffer->IODeviceMissingDelay); - device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay); + device_missing_delay = buffer->ReportDeviceMissingDelay; ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ? (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 : device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK; @@ -1531,7 +2514,7 @@ mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, cfg.cfghdr.ehdr = &hdr; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; /* Get Phy Pg 0 for each Phy. */ cfg.physAddr = -1; @@ -1586,10 +2569,6 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, __le64 sas_address; int error=0; - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(device_info)) - goto out; - hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 0; @@ -1603,7 +2582,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; memset(device_info, 0, sizeof(struct mptsas_devinfo)); error = mpt_config(ioc, &cfg); @@ -1625,11 +2604,18 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; error = mpt_config(ioc, &cfg); + + if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { + error = -ENODEV; + goto out_free_consistent; + } + if (error) goto out_free_consistent; mptsas_print_device_pg0(ioc, buffer); + memset(device_info, 0, sizeof(struct mptsas_devinfo)); device_info->handle = le16_to_cpu(buffer->DevHandle); device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); device_info->handle_enclosure = @@ -1644,6 +2630,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, device_info->sas_address = le64_to_cpu(sas_address); device_info->device_info = le32_to_cpu(buffer->DeviceInfo); + device_info->flags = le16_to_cpu(buffer->Flags); out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, @@ -1661,7 +2648,9 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, SasExpanderPage0_t *buffer; dma_addr_t dma_handle; int i, error; + __le64 sas_address; + memset(port_info, 0, sizeof(struct mptsas_portinfo)); hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 0; @@ -1675,7 +2664,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; memset(port_info, 0, sizeof(struct mptsas_portinfo)); error = mpt_config(ioc, &cfg); @@ -1698,27 +2687,32 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; error = mpt_config(ioc, &cfg); - if (error) - goto out_free_consistent; - - if (!buffer->NumPhys) { + if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { error = -ENODEV; goto out_free_consistent; } + if (error) + goto out_free_consistent; + /* save config data */ - port_info->num_phys = buffer->NumPhys; + port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(*port_info->phy_info),GFP_KERNEL); + sizeof(struct mptsas_phyinfo), GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; } + memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); for (i = 0; i < port_info->num_phys; i++) { port_info->phy_info[i].portinfo = port_info; port_info->phy_info[i].handle = le16_to_cpu(buffer->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(buffer->ParentDevHandle); } out_free_consistent: @@ -1738,11 +2732,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, dma_addr_t dma_handle; int error=0; - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(&phy_info->attached)) - goto out; - - hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; + hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 1; hdr.Reserved1 = 0; @@ -1755,7 +2745,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ - cfg.timeout = 10; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; error = mpt_config(ioc, &cfg); if (error) @@ -1777,6 +2767,12 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; error = mpt_config(ioc, &cfg); + + if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { + error = -ENODEV; + goto out_free_consistent; + } + if (error) goto out_free_consistent; @@ -1799,6 +2795,187 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, return error; } +struct rep_manu_request{ + u8 smp_frame_type; + u8 function; + u8 reserved; + u8 request_length; +}; + +struct rep_manu_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x01 */ + u8 function_result; + u8 response_length; + u16 expander_change_count; + u8 reserved0[2]; + u8 sas_format:1; + u8 reserved1:7; + u8 reserved2[3]; + u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; + u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; + u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; + u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; + u16 component_id; + u8 component_revision_id; + u8 reserved3; + u8 vendor_specific[8]; +}; + +/** + * mptsas_exp_repmanufacture_info - + * @ioc: per adapter object + * @sas_address: expander sas address + * @edev: the sas_expander_device object + * + * Fills in the sas_expander_device object when SMP port is created. + * + * Returns 0 for success, non-zero for failure. + */ +static int +mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, + u64 sas_address, struct sas_expander_device *edev) +{ + MPT_FRAME_HDR *mf; + SmpPassthroughRequest_t *smpreq; + SmpPassthroughReply_t *smprep; + struct rep_manu_reply *manufacture_reply; + struct rep_manu_request *manufacture_request; + int ret; + int flagsLength; + unsigned long timeleft; + char *psge; + unsigned long flags; + void *data_out = NULL; + dma_addr_t data_out_dma = 0; + u32 sz; + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); + if (ret) + goto out; + + mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); + if (!mf) { + ret = -ENOMEM; + goto out_unlock; + } + + smpreq = (SmpPassthroughRequest_t *)mf; + memset(smpreq, 0, sizeof(*smpreq)); + + sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); + + data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma); + if (!data_out) { + printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + ret = -ENOMEM; + goto put_mf; + } + + manufacture_request = data_out; + manufacture_request->smp_frame_type = 0x40; + manufacture_request->function = 1; + manufacture_request->reserved = 0; + manufacture_request->request_length = 0; + + smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; + smpreq->PhysicalPort = 0xFF; + *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); + smpreq->RequestDataLength = sizeof(struct rep_manu_request); + + psge = (char *) + (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); + + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_END_OF_BUFFER; + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= sizeof(struct rep_manu_request); + + ioc->add_sge(psge, flagsLength, data_out_dma); + psge += ioc->SGE_size; + + flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_IOC_TO_HOST | + MPI_SGE_FLAGS_END_OF_BUFFER; + flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; + flagsLength |= sizeof(struct rep_manu_reply); + ioc->add_sge(psge, flagsLength, data_out_dma + + sizeof(struct rep_manu_request)); + + INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) + mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); + + timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); + if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + mpt_free_msg_frame(ioc, mf); + mf = NULL; + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out_free; + if (!timeleft) + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); + goto out_free; + } + + mf = NULL; + + if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { + u8 *tmp; + + smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; + if (le16_to_cpu(smprep->ResponseDataLength) != + sizeof(struct rep_manu_reply)) + goto out_free; + + manufacture_reply = data_out + sizeof(struct rep_manu_request); + strncpy(edev->vendor_id, manufacture_reply->vendor_id, + SAS_EXPANDER_VENDOR_ID_LEN); + strncpy(edev->product_id, manufacture_reply->product_id, + SAS_EXPANDER_PRODUCT_ID_LEN); + strncpy(edev->product_rev, manufacture_reply->product_rev, + SAS_EXPANDER_PRODUCT_REV_LEN); + edev->level = manufacture_reply->sas_format; + if (manufacture_reply->sas_format) { + strncpy(edev->component_vendor_id, + manufacture_reply->component_vendor_id, + SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); + tmp = (u8 *)&manufacture_reply->component_id; + edev->component_id = tmp[0] << 8 | tmp[1]; + edev->component_revision_id = + manufacture_reply->component_revision_id; + } + } else { + printk(MYIOC_s_ERR_FMT + "%s: smp passthru reply failed to be returned\n", + ioc->name, __func__); + ret = -ENXIO; + } +out_free: + if (data_out_dma) + pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma); +put_mf: + if (mf) + mpt_free_msg_frame(ioc, mf); +out_unlock: + CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) + mutex_unlock(&ioc->sas_mgmt.mutex); +out: + return ret; + } + static void mptsas_parse_device_info(struct sas_identify *identify, struct mptsas_devinfo *device_info) @@ -1865,6 +3042,7 @@ static int mptsas_probe_one_phy(struct device *dev, struct sas_phy *phy; struct sas_port *port; int error = 0; + VirtTarget *vtarget; if (!dev) { error = -ENODEV; @@ -1898,6 +3076,9 @@ static int mptsas_probe_one_phy(struct device *dev, case MPI_SAS_IOUNIT0_RATE_3_0: phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; break; + case MPI_SAS_IOUNIT0_RATE_6_0: + phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; + break; case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: case MPI_SAS_IOUNIT0_RATE_UNKNOWN: default: @@ -1992,20 +3173,25 @@ static int mptsas_probe_one_phy(struct device *dev, if (error) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + __func__, __LINE__)); goto out; } mptsas_set_port(ioc, phy_info, port); - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "sas_port_alloc: port=%p dev=%p port_id=%d\n", - ioc->name, port, dev, port->port_identifier)); + devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, + MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n", + ioc->name, port->port_identifier, + (unsigned long long)phy_info-> + attached.sas_address)); } - dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n", - ioc->name, phy_info->phy_id)); + dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "sas_port_add_phy: phy_id=%d\n", + ioc->name, phy_info->phy_id)); sas_port_add_phy(port, phy_info->phy); phy_info->sas_port_add_phy = 0; + devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, + MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name, + phy_info->phy_id, phy_info->phy)); } - if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { struct sas_rphy *rphy; @@ -2018,19 +3204,17 @@ static int mptsas_probe_one_phy(struct device *dev, * the adding/removing of devices that occur * after start of day. */ - if (ioc->sas_discovery_runtime && - mptsas_is_end_device(&phy_info->attached)) - goto out; + if (mptsas_is_end_device(&phy_info->attached) && + phy_info->attached.handle_parent) { + goto out; + } mptsas_parse_device_info(&identify, &phy_info->attached); if (scsi_is_host_device(parent)) { struct mptsas_portinfo *port_info; int i; - mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_find_portinfo_by_handle(ioc, - ioc->handle); - mutex_unlock(&ioc->sas_topology_mutex); + port_info = ioc->hba_port_info; for (i = 0; i < port_info->num_phys; i++) if (port_info->phy_info[i].identify.sas_address == @@ -2063,7 +3247,7 @@ static int mptsas_probe_one_phy(struct device *dev, if (!rphy) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + __func__, __LINE__)); goto out; } @@ -2072,11 +3256,26 @@ static int mptsas_probe_one_phy(struct device *dev, if (error) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + __func__, __LINE__)); sas_rphy_free(rphy); goto out; } mptsas_set_rphy(ioc, phy_info, rphy); + if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || + identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) + mptsas_exp_repmanufacture_info(ioc, + identify.sas_address, + rphy_to_expander_device(rphy)); + } + + /* If the device exists,verify it wasn't previously flagged + as a missing device. If so, clear it */ + vtarget = mptsas_find_vtarget(ioc, + phy_info->attached.channel, + phy_info->attached.id); + if (vtarget && vtarget->inDMD) { + printk(KERN_INFO "Device returned, unsetting inDMD\n"); + vtarget->inDMD = 0; } out: @@ -2089,7 +3288,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) struct mptsas_portinfo *port_info, *hba; int error = -ENOMEM, i; - hba = kzalloc(sizeof(*port_info), GFP_KERNEL); + hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); if (! hba) goto out; @@ -2099,10 +3298,10 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) mptsas_sas_io_unit_pg1(ioc); mutex_lock(&ioc->sas_topology_mutex); - ioc->handle = hba->phy_info[0].handle; - port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle); + port_info = ioc->hba_port_info; if (!port_info) { - port_info = hba; + ioc->hba_port_info = port_info = hba; + ioc->hba_port_num_phy = port_info->num_phys; list_add_tail(&port_info->list, &ioc->sas_topology); } else { for (i = 0; i < hba->num_phys; i++) { @@ -2118,15 +3317,22 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) hba = NULL; } mutex_unlock(&ioc->sas_topology_mutex); +#if defined(CPQ_CIM) + ioc->num_ports = port_info->num_phys; +#endif for (i = 0; i < port_info->num_phys; i++) { mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << MPI_SAS_PHY_PGAD_FORM_SHIFT), i); - + port_info->phy_info[i].identify.handle = + port_info->phy_info[i].handle; mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].handle); + port_info->phy_info[i].identify.handle); + if (!ioc->hba_port_sas_addr) + ioc->hba_port_sas_addr = + port_info->phy_info[i].identify.sas_address; port_info->phy_info[i].identify.phy_id = port_info->phy_info[i].phy_id = i; if (port_info->phy_info[i].attached.handle) @@ -2151,249 +3357,763 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) return error; } -static int -mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) +static void +mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) { - struct mptsas_portinfo *port_info, *p, *ex; - struct device *parent; - struct sas_rphy *rphy; - int error = -ENOMEM, i, j; - - ex = kzalloc(sizeof(*port_info), GFP_KERNEL); - if (!ex) - goto out; - - error = mptsas_sas_expander_pg0(ioc, ex, - (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); - if (error) - goto out_free_port_info; - - *handle = ex->phy_info[0].handle; - - mutex_lock(&ioc->sas_topology_mutex); - port_info = mptsas_find_portinfo_by_handle(ioc, *handle); - if (!port_info) { - port_info = ex; - list_add_tail(&port_info->list, &ioc->sas_topology); - } else { - for (i = 0; i < ex->num_phys; i++) { - port_info->phy_info[i].handle = - ex->phy_info[i].handle; - port_info->phy_info[i].port_id = - ex->phy_info[i].port_id; - } - kfree(ex->phy_info); - kfree(ex); - ex = NULL; - } - mutex_unlock(&ioc->sas_topology_mutex); - + struct mptsas_portinfo *parent; + struct device *parent_dev; + struct sas_rphy *rphy; + int i; + u64 sas_address; /* expander sas address */ + u32 handle; + + handle = port_info->phy_info[0].handle; + sas_address = port_info->phy_info[0].identify.sas_address; for (i = 0; i < port_info->num_phys; i++) { mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); - - if (port_info->phy_info[i].identify.handle) { - mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].identify, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].identify.handle); - port_info->phy_info[i].identify.phy_id = - port_info->phy_info[i].phy_id; - } + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle); + + mptsas_sas_device_pg0(ioc, + &port_info->phy_info[i].identify, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].identify.handle); + port_info->phy_info[i].identify.phy_id = + port_info->phy_info[i].phy_id; if (port_info->phy_info[i].attached.handle) { mptsas_sas_device_pg0(ioc, - &port_info->phy_info[i].attached, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - port_info->phy_info[i].attached.handle); + &port_info->phy_info[i].attached, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].attached.handle); port_info->phy_info[i].attached.phy_id = port_info->phy_info[i].phy_id; } } - parent = &ioc->sh->shost_gendev; - for (i = 0; i < port_info->num_phys; i++) { - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(p, &ioc->sas_topology, list) { - for (j = 0; j < p->num_phys; j++) { - if (port_info->phy_info[i].identify.handle != - p->phy_info[j].attached.handle) - continue; - rphy = mptsas_get_rphy(&p->phy_info[j]); - parent = &rphy->dev; - } - } + mutex_lock(&ioc->sas_topology_mutex); + parent = mptsas_find_portinfo_by_handle(ioc, + port_info->phy_info[0].identify.handle_parent); + if (!parent) { mutex_unlock(&ioc->sas_topology_mutex); + return; } + for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; + i++) { + if (parent->phy_info[i].attached.sas_address == sas_address) { + rphy = mptsas_get_rphy(&parent->phy_info[i]); + parent_dev = &rphy->dev; + } + } + mutex_unlock(&ioc->sas_topology_mutex); mptsas_setup_wide_ports(ioc, port_info); - for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) - mptsas_probe_one_phy(parent, &port_info->phy_info[i], + mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i], ioc->sas_index, 0); +} - return 0; +static void +mptsas_expander_event_add(MPT_ADAPTER *ioc, + MpiEventDataSasExpanderStatusChange_t *expander_data) +{ + struct mptsas_portinfo *port_info; + int i; + __le64 sas_address; - out_free_port_info: - if (ex) { - kfree(ex->phy_info); - kfree(ex); + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); + if (!port_info) + BUG(); + port_info->num_phys = (expander_data->NumPhys) ? + expander_data->NumPhys : 1; + port_info->phy_info = kcalloc(port_info->num_phys, + sizeof(struct mptsas_phyinfo), GFP_KERNEL); + if (!port_info->phy_info) + BUG(); + memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); + for (i = 0; i < port_info->num_phys; i++) { + port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(expander_data->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(expander_data->ParentDevHandle); + } + + mutex_lock(&ioc->sas_topology_mutex); + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); + + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)sas_address); + + mptsas_expander_refresh(ioc, port_info); +} + +/** + * mptsas_delete_expander_siblings - remove siblings attached to expander + * @ioc: Pointer to MPT_ADAPTER structure + * @parent: the parent port_info object + * @expander: the expander port_info object + **/ +static void +mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo + *parent, struct mptsas_portinfo *expander) +{ + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo *port_info; + struct sas_rphy *rphy; + int i; + + phy_info = expander->phy_info; + for (i = 0; i < expander->num_phys; i++, phy_info++) { + rphy = mptsas_get_rphy(phy_info); + if (!rphy) + continue; + if (rphy->identify.device_type == SAS_END_DEVICE) + mptsas_del_end_device(ioc, phy_info); + } + + phy_info = expander->phy_info; + for (i = 0; i < expander->num_phys; i++, phy_info++) { + rphy = mptsas_get_rphy(phy_info); + if (!rphy) + continue; + if (rphy->identify.device_type == + MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || + rphy->identify.device_type == + MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { + port_info = mptsas_find_portinfo_by_sas_address(ioc, + rphy->identify.sas_address); + if (!port_info) + continue; + if (port_info == parent) /* backlink rphy */ + continue; + /* + Delete this expander even if the expdevpage is exists + because the parent expander is already deleted + */ + mptsas_expander_delete(ioc, port_info, 1); + } + } +} + + +/** + * mptsas_expander_delete - remove this expander + * @ioc: Pointer to MPT_ADAPTER structure + * @port_info: expander port_info struct + * @force: Flag to forcefully delete the expander + * + **/ + +static void mptsas_expander_delete(MPT_ADAPTER *ioc, + struct mptsas_portinfo *port_info, u8 force) +{ + + struct mptsas_portinfo *parent; + int i; + u64 expander_sas_address; + struct mptsas_phyinfo *phy_info; + struct mptsas_portinfo buffer; + struct mptsas_portinfo_details *port_details; + struct sas_port *port; + + if (!port_info) + return; + + /* see if expander is still there before deleting */ + mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), + port_info->phy_info[0].identify.handle); + + if (buffer.num_phys) { + kfree(buffer.phy_info); + if (!force) + return; + } + + + /* + * Obtain the port_info instance to the parent port + */ + port_details = NULL; + expander_sas_address = + port_info->phy_info[0].identify.sas_address; + parent = mptsas_find_portinfo_by_handle(ioc, + port_info->phy_info[0].identify.handle_parent); + mptsas_delete_expander_siblings(ioc, parent, port_info); + if (!parent) + goto out; + + /* + * Delete rphys in the parent that point + * to this expander. + */ + phy_info = parent->phy_info; + port = NULL; + for (i = 0; i < parent->num_phys; i++, phy_info++) { + if (!phy_info->phy) + continue; + if (phy_info->attached.sas_address != + expander_sas_address) + continue; + if (!port) { + port = mptsas_get_port(phy_info); + port_details = phy_info->port_details; + } + dev_printk(KERN_DEBUG, &phy_info->phy->dev, + MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name, + phy_info->phy_id, phy_info->phy); + sas_port_delete_phy(port, phy_info->phy); + } + if (port) { + dev_printk(KERN_DEBUG, &port->dev, + MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n", + ioc->name, port->port_identifier, + (unsigned long long)expander_sas_address); + sas_port_delete(port); + mptsas_port_delete(ioc, port_details); } out: - return error; + + printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)expander_sas_address); + + /* + * free link + */ + list_del(&port_info->list); + kfree(port_info->phy_info); + kfree(port_info); } -/* - * mptsas_delete_expander_phys + +/** + * mptsas_send_expander_event - expanders events + * @ioc: Pointer to MPT_ADAPTER structure + * @expander_data: event data * * - * This will traverse topology, and remove expanders - * that are no longer present + * This function handles adding, removing, and refreshing + * device handles within the expander objects. */ static void -mptsas_delete_expander_phys(MPT_ADAPTER *ioc) +mptsas_send_expander_event(struct fw_event_work *fw_event) { - struct mptsas_portinfo buffer; - struct mptsas_portinfo *port_info, *n, *parent; - struct mptsas_phyinfo *phy_info; - struct sas_port * port; + MPT_ADAPTER *ioc; + MpiEventDataSasExpanderStatusChange_t *expander_data; + struct mptsas_portinfo *port_info; + __le64 sas_address; int i; - u64 expander_sas_address; + ioc = fw_event->ioc; + expander_data = (MpiEventDataSasExpanderStatusChange_t *) + fw_event->event_data; + memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); + + if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { + if (port_info) { + for (i = 0; i < port_info->num_phys; i++) { + port_info->phy_info[i].portinfo = port_info; + port_info->phy_info[i].handle = + le16_to_cpu(expander_data->DevHandle); + port_info->phy_info[i].identify.sas_address = + le64_to_cpu(sas_address); + port_info->phy_info[i].identify.handle_parent = + le16_to_cpu(expander_data->ParentDevHandle); + } + mptsas_expander_refresh(ioc, port_info); + } else if (!port_info && expander_data->NumPhys) + mptsas_expander_event_add(ioc, expander_data); + } else if (expander_data->ReasonCode == + MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) + mptsas_expander_delete(ioc, port_info, 0); + + mptsas_free_fw_event(ioc, fw_event); +} + + +/** + * mptsas_expander_add - + * @ioc: Pointer to MPT_ADAPTER structure + * @handle: + * + */ +struct mptsas_portinfo * +mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) +{ + struct mptsas_portinfo buffer, *port_info; + int i; + + if ((mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle))) + return NULL; + + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC); + if (!port_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __func__, __LINE__)); + return NULL; + } + port_info->num_phys = buffer.num_phys; + port_info->phy_info = buffer.phy_info; + for (i = 0; i < port_info->num_phys; i++) + port_info->phy_info[i].portinfo = port_info; mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)buffer.phy_info[0].identify.sas_address); + mptsas_expander_refresh(ioc, port_info); + return port_info; +} - if (port_info->phy_info && - (!(port_info->phy_info[0].identify.device_info & - MPI_SAS_DEVICE_INFO_SMP_TARGET))) +static void +mptsas_send_link_status_event(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc; + MpiEventDataSasPhyLinkStatus_t *link_data; + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info = NULL; + __le64 sas_address; + u8 phy_num; + u8 link_rate; + + ioc = fw_event->ioc; + link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; + + memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); + sas_address = le64_to_cpu(sas_address); + link_rate = link_data->LinkRates >> 4; + phy_num = link_data->PhyNum; + + port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); + if (port_info) { + phy_info = &port_info->phy_info[phy_num]; + if (phy_info) + phy_info->negotiated_link_rate = link_rate; + } + + if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || + link_rate == MPI_SAS_IOUNIT0_RATE_3_0 || + link_rate == MPI_SAS_IOUNIT0_RATE_6_0) { + + if (!port_info) { + if (ioc->old_sas_discovery_protocal) { + port_info = mptsas_expander_add(ioc, + le16_to_cpu(link_data->DevHandle)); + if (port_info) + goto out; + } + goto out; + } + + if (port_info == ioc->hba_port_info) + mptsas_probe_hba_phys(ioc); + else + mptsas_expander_refresh(ioc, port_info); + } else if (phy_info && phy_info->phy) { + if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) + phy_info->phy->negotiated_linkrate = + SAS_PHY_DISABLED; + else if (link_rate == + MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) + phy_info->phy->negotiated_linkrate = + SAS_LINK_RATE_FAILED; + else { + phy_info->phy->negotiated_linkrate = + SAS_LINK_RATE_UNKNOWN; + if (ioc->device_missing_delay && + mptsas_is_end_device(&phy_info->attached)) { + struct scsi_device *sdev; + VirtDevice *vdevice; + u8 channel, id; + id = phy_info->attached.id; + channel = phy_info->attached.channel; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Link down for fw_id %d:fw_channel %d\n", + ioc->name, phy_info->attached.id, + phy_info->attached.channel)); + + shost_for_each_device(sdev, ioc->sh) { + vdevice = sdev->hostdata; + if ((vdevice == NULL) || + (vdevice->vtarget == NULL)) + continue; + if ((vdevice->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT || + vdevice->vtarget->raidVolume)) + continue; + if (vdevice->vtarget->id == id && + vdevice->vtarget->channel == + channel) + devtprintk(ioc, + printk(MYIOC_s_DEBUG_FMT + "SDEV OUTSTANDING CMDS" + "%d\n", ioc->name, + sdev->device_busy)); + } + + } + } + } + out: + mptsas_free_fw_event(ioc, fw_event); +} + +static void +mptsas_not_responding_devices(MPT_ADAPTER *ioc) +{ + struct mptsas_portinfo buffer, *port_info; + struct mptsas_device_info *sas_info; + struct mptsas_devinfo sas_device; + u32 handle; + VirtTarget *vtarget = NULL; + struct mptsas_phyinfo *phy_info; + u8 found_expander; + int retval, retry_count; + unsigned long flags; + + mpt_findImVolumes(ioc); + + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: exiting due to a parallel reset \n", ioc->name, + __func__)); + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + return; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + + /* devices, logical volumes */ + mutex_lock(&ioc->sas_device_info_mutex); + redo_device_scan: + list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { + if (sas_info->is_cached) continue; + if (!sas_info->is_logical_volume) { + sas_device.handle = 0; + retry_count = 0; +retry_page: + retval = mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID + << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (sas_info->fw.channel << 8) + + sas_info->fw.id); + + if (sas_device.handle) + continue; + if (retval == -EBUSY) { + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + dfailprintk(ioc, + printk(MYIOC_s_DEBUG_FMT + "%s: exiting due to reset\n", + ioc->name, __func__)); + spin_unlock_irqrestore + (&ioc->taskmgmt_lock, flags); + mutex_unlock(&ioc-> + sas_device_info_mutex); + return; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, + flags); + } - if (mptsas_sas_expander_pg0(ioc, &buffer, - (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << - MPI_SAS_EXPAND_PGAD_FORM_SHIFT), - port_info->phy_info[0].handle)) { + if (retval && (retval != -ENODEV)) { + if (retry_count < 10) { + retry_count++; + goto retry_page; + } else { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Config page retry exceeded retry " + "count deleting device 0x%llx\n", + ioc->name, __func__, + sas_info->sas_address)); + } + } - /* - * Obtain the port_info instance to the parent port - */ - parent = mptsas_find_portinfo_by_handle(ioc, - port_info->phy_info[0].identify.handle_parent); + /* delete device */ + vtarget = mptsas_find_vtarget(ioc, + sas_info->fw.channel, sas_info->fw.id); - if (!parent) - goto next_port; + if (vtarget) + vtarget->deleted = 1; - expander_sas_address = - port_info->phy_info[0].identify.sas_address; + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_info->sas_address); - /* - * Delete rphys in the parent that point - * to this expander. The transport layer will - * cleanup all the children. - */ - phy_info = parent->phy_info; - for (i = 0; i < parent->num_phys; i++, phy_info++) { - port = mptsas_get_port(phy_info); - if (!port) - continue; - if (phy_info->attached.sas_address != - expander_sas_address) - continue; - dsaswideprintk(ioc, - dev_printk(KERN_DEBUG, &port->dev, - MYIOC_s_FMT "delete port (%d)\n", ioc->name, - port->port_identifier)); - sas_port_delete(port); - mptsas_port_delete(ioc, phy_info->port_details); + if (phy_info) { + mptsas_del_end_device(ioc, phy_info); + goto redo_device_scan; } - next_port: + } else + mptsas_volume_delete(ioc, sas_info->fw.id); + } + mutex_unlock(&ioc->sas_device_info_mutex); - phy_info = port_info->phy_info; - for (i = 0; i < port_info->num_phys; i++, phy_info++) - mptsas_port_delete(ioc, phy_info->port_details); + /* expanders */ + mutex_lock(&ioc->sas_topology_mutex); + redo_expander_scan: + list_for_each_entry(port_info, &ioc->sas_topology, list) { - list_del(&port_info->list); - kfree(port_info->phy_info); - kfree(port_info); + if (port_info->phy_info && + (!(port_info->phy_info[0].identify.device_info & + MPI_SAS_DEVICE_INFO_SMP_TARGET))) + continue; + found_expander = 0; + handle = 0xFFFF; + while (!mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) && + !found_expander) { + + handle = buffer.phy_info[0].handle; + if (buffer.phy_info[0].identify.sas_address == + port_info->phy_info[0].identify.sas_address) { + found_expander = 1; + } + kfree(buffer.phy_info); + } + + if (!found_expander) { + mptsas_expander_delete(ioc, port_info, 0); + goto redo_expander_scan; } - /* - * Free this memory allocated from inside - * mptsas_sas_expander_pg0 - */ - kfree(buffer.phy_info); } mutex_unlock(&ioc->sas_topology_mutex); } -/* - * Start of day discovery - */ +/** + * mptsas_probe_expanders - adding expanders + * @ioc: Pointer to MPT_ADAPTER structure + * + **/ +static void +mptsas_probe_expanders(MPT_ADAPTER *ioc) +{ + struct mptsas_portinfo buffer, *port_info; + u32 handle; + int i; + + handle = 0xFFFF; + while (!mptsas_sas_expander_pg0(ioc, &buffer, + (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) { + + handle = buffer.phy_info[0].handle; + port_info = mptsas_find_portinfo_by_sas_address(ioc, + buffer.phy_info[0].identify.sas_address); + + if (port_info) { + /* refreshing handles */ + for (i = 0; i < buffer.num_phys; i++) { + port_info->phy_info[i].handle = handle; + port_info->phy_info[i].identify.handle_parent = + buffer.phy_info[0].identify.handle_parent; + } + mptsas_expander_refresh(ioc, port_info); + kfree(buffer.phy_info); + continue; + } + + port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL); + if (!port_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __func__, __LINE__)); + return; + } + port_info->num_phys = buffer.num_phys; + port_info->phy_info = buffer.phy_info; + for (i = 0; i < port_info->num_phys; i++) + port_info->phy_info[i].portinfo = port_info; + mutex_lock(&ioc->sas_topology_mutex); + list_add_tail(&port_info->list, &ioc->sas_topology); + mutex_unlock(&ioc->sas_topology_mutex); + printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " + "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys, + (unsigned long long)buffer.phy_info[0].identify.sas_address); + mptsas_expander_refresh(ioc, port_info); + } +} + +static void +mptsas_probe_devices(MPT_ADAPTER *ioc) +{ + u16 handle; + struct mptsas_devinfo sas_device; + struct mptsas_phyinfo *phy_info; + + handle = 0xFFFF; + while (!(mptsas_sas_device_pg0(ioc, &sas_device, + MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + + handle = sas_device.handle; + + if ((sas_device.device_info & + (MPI_SAS_DEVICE_INFO_SSP_TARGET | + MPI_SAS_DEVICE_INFO_STP_TARGET | + MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) + continue; + + /* If there is no FW B_T mapping for this device then continue + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + continue; + + phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); + if (!phy_info) + continue; + + if (mptsas_get_rphy(phy_info)) + continue; + + mptsas_add_end_device(ioc, phy_info); + } +} + +/** + * mptsas_scan_sas_topology - + * @ioc: Pointer to MPT_ADAPTER structure + * @sas_address: + * + **/ static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc) { - u32 handle = 0xFFFF; + struct scsi_device *sdev; int i; - mutex_lock(&ioc->sas_discovery_mutex); mptsas_probe_hba_phys(ioc); - while (!mptsas_probe_expander_phys(ioc, &handle)) - ; + mptsas_probe_expanders(ioc); + mptsas_probe_devices(ioc); + /* Reporting RAID volumes. */ - if (!ioc->ir_firmware) - goto out; - if (!ioc->raid_data.pIocPg2) - goto out; - if (!ioc->raid_data.pIocPg2->NumActiveVolumes) - goto out; + if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || + !ioc->raid_data.pIocPg2->NumActiveVolumes) + return; for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); + if (sdev) { + scsi_device_put(sdev); + continue; + } + printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); } - out: - mutex_unlock(&ioc->sas_discovery_mutex); } -/* - * Work queue thread to handle Runtime discovery - * Mere purpose is the hot add/delete of expanders - *(Mutex UNLOCKED) - */ + static void -__mptsas_discovery_work(MPT_ADAPTER *ioc) +mptsas_handle_queue_full_event(struct fw_event_work *fw_event) { - u32 handle = 0xFFFF; + MPT_ADAPTER *ioc; + EventDataQueueFull_t *qfull_data; + struct mptsas_device_info *sas_info; + struct scsi_device *sdev; + int depth; + int id = -1; + int channel = -1; + int fw_id, fw_channel; + u16 current_depth; + + + ioc = fw_event->ioc; + qfull_data = (EventDataQueueFull_t *)fw_event->event_data; + fw_id = qfull_data->TargetID; + fw_channel = qfull_data->Bus; + current_depth = le16_to_cpu(qfull_data->CurrentDepth); + + /* if hidden raid component, look for the volume id */ + mutex_lock(&ioc->sas_device_info_mutex); + if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) { + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (sas_info->is_cached || + sas_info->is_logical_volume) + continue; + if (sas_info->is_hidden_raid_component && + (sas_info->fw.channel == fw_channel && + sas_info->fw.id == fw_id)) { + id = sas_info->volume_id; + channel = MPTSAS_RAID_CHANNEL; + goto out; + } + } + } else { + list_for_each_entry(sas_info, &ioc->sas_device_info_list, + list) { + if (sas_info->is_cached || + sas_info->is_hidden_raid_component || + sas_info->is_logical_volume) + continue; + if (sas_info->fw.channel == fw_channel && + sas_info->fw.id == fw_id) { + id = sas_info->os.id; + channel = sas_info->os.channel; + goto out; + } + } - ioc->sas_discovery_runtime=1; - mptsas_delete_expander_phys(ioc); - mptsas_probe_hba_phys(ioc); - while (!mptsas_probe_expander_phys(ioc, &handle)) - ; - ioc->sas_discovery_runtime=0; -} + } -/* - * Work queue thread to handle Runtime discovery - * Mere purpose is the hot add/delete of expanders - *(Mutex LOCKED) - */ -static void -mptsas_discovery_work(struct work_struct *work) -{ - struct mptsas_discovery_event *ev = - container_of(work, struct mptsas_discovery_event, work); - MPT_ADAPTER *ioc = ev->ioc; + out: + mutex_unlock(&ioc->sas_device_info_mutex); + + if (id != -1) { + shost_for_each_device(sdev, ioc->sh) { + if (sdev->id == id && sdev->channel == channel) { + if (current_depth > sdev->queue_depth) { + sdev_printk(KERN_INFO, sdev, + "strange observation, the queue " + "depth is (%d) meanwhile fw queue " + "depth (%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) + sdev_printk(KERN_INFO, sdev, + "Queue depth not changed yet\n"); + } + } + } - mutex_lock(&ioc->sas_discovery_mutex); - __mptsas_discovery_work(ioc); - mutex_unlock(&ioc->sas_discovery_mutex); - kfree(ev); + mptsas_free_fw_event(ioc, fw_event); } + static struct mptsas_phyinfo * mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) { @@ -2418,69 +4138,80 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) return phy_info; } +/** + * mptsas_find_phyinfo_by_phys_disk_num - + * @ioc: Pointer to MPT_ADAPTER structure + * @phys_disk_num: + * @channel: + * @id: + * + **/ static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id) +mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, + u8 channel, u8 id) { - struct mptsas_portinfo *port_info; struct mptsas_phyinfo *phy_info = NULL; + struct mptsas_portinfo *port_info; + RaidPhysDiskPage1_t *phys_disk = NULL; + int num_paths; + u64 sas_address = 0; int i; - mutex_lock(&ioc->sas_topology_mutex); - list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) { - if (!mptsas_is_end_device( - &port_info->phy_info[i].attached)) - continue; - if (port_info->phy_info[i].attached.id != id) - continue; - if (port_info->phy_info[i].attached.channel != channel) - continue; - phy_info = &port_info->phy_info[i]; - break; + phy_info = NULL; + if (!ioc->raid_data.pIocPg3) + return NULL; + /* dual port support */ + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); + if (!num_paths) + goto out; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + goto out; + mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); + for (i = 0; i < num_paths; i++) { + if ((phys_disk->Path[i].Flags & 1) != 0) + /* entry no longer valid */ + continue; + if ((id == phys_disk->Path[i].PhysDiskID) && + (channel == phys_disk->Path[i].PhysDiskBus)) { + memcpy(&sas_address, &phys_disk->Path[i].WWID, + sizeof(u64)); + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_address); + goto out; } } - mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; -} -static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) -{ - struct mptsas_portinfo *port_info; - struct mptsas_phyinfo *phy_info = NULL; - int i; + out: + kfree(phys_disk); + if (phy_info) + return phy_info; + /* + * Extra code to handle RAID0 case, where the sas_address is not updated + * in phys_disk_page_1 when hotswapped + */ mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) { + for (i = 0; i < port_info->num_phys && !phy_info; i++) { if (!mptsas_is_end_device( &port_info->phy_info[i].attached)) continue; if (port_info->phy_info[i].attached.phys_disk_num == ~0) continue; - if (port_info->phy_info[i].attached.phys_disk_num != id) - continue; - if (port_info->phy_info[i].attached.channel != channel) - continue; - phy_info = &port_info->phy_info[i]; - break; + if ((port_info->phy_info[i].attached.phys_disk_num == + phys_disk_num) && + (port_info->phy_info[i].attached.id == id) && + (port_info->phy_info[i].attached.channel == + channel)) + phy_info = &port_info->phy_info[i]; } } mutex_unlock(&ioc->sas_topology_mutex); return phy_info; } -/* - * Work queue thread to clear the persitency table - */ -static void -mptsas_persist_clear_table(struct work_struct *work) -{ - MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task); - - mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); -} - static void mptsas_reprobe_lun(struct scsi_device *sdev, void *data) { @@ -2506,7 +4237,8 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) pRaidVolumePage0_t buffer = NULL; RaidPhysDiskPage0_t phys_disk; int i; - struct mptsas_hotplug_event *ev; + struct mptsas_phyinfo *phy_info; + struct mptsas_devinfo sas_device; memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); @@ -2514,6 +4246,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) cfg.pageAddr = (channel << 8) + id; cfg.cfghdr.hdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; if (mpt_config(ioc, &cfg) != 0) goto out; @@ -2546,20 +4279,24 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) continue; - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name); - goto out; - } + if (mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (phys_disk.PhysDiskBus << 8) + + phys_disk.PhysDiskID)) + continue; + + /* If there is no FW B_T mapping for this device then continue + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + continue; + - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->id = phys_disk.PhysDiskID; - ev->channel = phys_disk.PhysDiskBus; - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = phys_disk.PhysDiskNum; - ev->event_type = MPTSAS_ADD_DEVICE; - schedule_work(&ev->work); + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device.sas_address); + mptsas_add_end_device(ioc, phy_info); } out: @@ -2571,417 +4308,436 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) * Work queue thread to handle SAS hotplug events */ static void -mptsas_hotplug_work(struct work_struct *work) +mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, + struct mptsas_hotplug_event *hot_plug_info) { - struct mptsas_hotplug_event *ev = - container_of(work, struct mptsas_hotplug_event, work); - - MPT_ADAPTER *ioc = ev->ioc; struct mptsas_phyinfo *phy_info; - struct sas_rphy *rphy; - struct sas_port *port; - struct scsi_device *sdev; struct scsi_target * starget; - struct sas_identify identify; - char *ds = NULL; struct mptsas_devinfo sas_device; VirtTarget *vtarget; - VirtDevice *vdevice; - - mutex_lock(&ioc->sas_discovery_mutex); - switch (ev->event_type) { - case MPTSAS_DEL_DEVICE: + int i; + struct mptsas_portinfo *port_info; - phy_info = NULL; - if (ev->phys_disk_num_valid) { - if (ev->hidden_raid_component){ - if (mptsas_sas_device_pg0(ioc, &sas_device, - (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (ev->channel << 8) + ev->id)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; - } - phy_info = mptsas_find_phyinfo_by_sas_address( - ioc, sas_device.sas_address); - }else - phy_info = mptsas_find_phyinfo_by_phys_disk_num( - ioc, ev->channel, ev->phys_disk_num); - } + switch (hot_plug_info->event_type) { - if (!phy_info) - phy_info = mptsas_find_phyinfo_by_target(ioc, - ev->channel, ev->id); + case MPTSAS_ADD_PHYSDISK: - /* - * Sanity checks, for non-existing phys and remote rphys. - */ - if (!phy_info){ - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; - } - if (!phy_info->port_details) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; - } - rphy = mptsas_get_rphy(phy_info); - if (!rphy) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + if (!ioc->raid_data.pIocPg2) break; + + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { + if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == + hot_plug_info->id) { + printk(MYIOC_s_WARN_FMT "firmware bug: unable " + "to add hidden disk - target_id matchs " + "volume_id\n", ioc->name); + mptsas_free_fw_event(ioc, fw_event); + return; + } } + mpt_findImVolumes(ioc); - port = mptsas_get_port(phy_info); - if (!port) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + case MPTSAS_ADD_DEVICE: + memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); + mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (hot_plug_info->channel << 8) + + hot_plug_info->id); + + /* If there is no FW B_T mapping for this device then break + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) break; - } - starget = mptsas_get_starget(phy_info); - if (starget) { - vtarget = starget->hostdata; + if (!sas_device.handle) + return; + + phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); + /* Only For SATA Device ADD */ + if (!phy_info && (sas_device.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE)) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s %d SATA HOT PLUG: " + "parent handle of device %x\n", ioc->name, + __func__, __LINE__, sas_device.handle_parent)); + port_info = mptsas_find_portinfo_by_handle(ioc, + sas_device.handle_parent); - if (!vtarget) { + if (port_info == ioc->hba_port_info) + mptsas_probe_hba_phys(ioc); + else if (port_info) + mptsas_expander_refresh(ioc, port_info); + else { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + "%s %d port info is NULL\n", + ioc->name, __func__, __LINE__)); break; } + phy_info = mptsas_refreshing_device_handles + (ioc, &sas_device); + } - /* - * Handling RAID components - */ - if (ev->phys_disk_num_valid && - ev->hidden_raid_component) { - printk(MYIOC_s_INFO_FMT - "RAID Hidding: channel=%d, id=%d, " - "physdsk %d \n", ioc->name, ev->channel, - ev->id, ev->phys_disk_num); - vtarget->id = ev->phys_disk_num; - vtarget->tflags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - mptsas_reprobe_target(starget, 1); - phy_info->attached.phys_disk_num = - ev->phys_disk_num; + if (!phy_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s %d phy info is NULL\n", + ioc->name, __func__, __LINE__)); break; - } } - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) - ds = "ssp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) - ds = "stp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "sata"; - - printk(MYIOC_s_INFO_FMT - "removing %s device, channel %d, id %d, phy %d\n", - ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); - dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT - "delete port (%d)\n", ioc->name, port->port_identifier); - sas_port_delete(port); - mptsas_port_delete(ioc, phy_info->port_details); + if (mptsas_get_rphy(phy_info)) + break; + + mptsas_add_end_device(ioc, phy_info); break; - case MPTSAS_ADD_DEVICE: - if (ev->phys_disk_num_valid) - mpt_findImVolumes(ioc); + case MPTSAS_DEL_DEVICE: + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + hot_plug_info->sas_address); + mptsas_del_end_device(ioc, phy_info); + break; + + case MPTSAS_DEL_PHYSDISK: + + mpt_findImVolumes(ioc); + + phy_info = mptsas_find_phyinfo_by_phys_disk_num( + ioc, hot_plug_info->phys_disk_num, + hot_plug_info->channel, + hot_plug_info->id); + mptsas_del_end_device(ioc, phy_info); + break; + + case MPTSAS_ADD_PHYSDISK_REPROBE: - /* - * Refresh sas device pg0 data - */ if (mptsas_sas_device_pg0(ioc, &sas_device, (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - (ev->channel << 8) + ev->id)) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + (hot_plug_info->channel << 8) + hot_plug_info->id)) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } - __mptsas_discovery_work(ioc); + /* If there is no FW B_T mapping for this device then break + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + break; - phy_info = mptsas_find_phyinfo_by_sas_address(ioc, - sas_device.sas_address); + phy_info = mptsas_find_phyinfo_by_sas_address( + ioc, sas_device.sas_address); - if (!phy_info || !phy_info->port_details) { + if (!phy_info) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } starget = mptsas_get_starget(phy_info); - if (starget && (!ev->hidden_raid_component)){ + if (!starget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); + break; + } + + vtarget = starget->hostdata; + if (!vtarget) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); + break; + } - vtarget = starget->hostdata; + mpt_findImVolumes(ioc); + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " + "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", + ioc->name, hot_plug_info->channel, hot_plug_info->id, + hot_plug_info->phys_disk_num, (unsigned long long) + sas_device.sas_address); + + vtarget->id = hot_plug_info->phys_disk_num; + vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; + phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; + mptsas_reprobe_target(starget, 1); + break; - if (!vtarget) { + case MPTSAS_DEL_PHYSDISK_REPROBE: + + if (mptsas_sas_device_pg0(ioc, &sas_device, + (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + (hot_plug_info->channel << 8) + hot_plug_info->id)) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; - } - /* - * Handling RAID components - */ - if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - printk(MYIOC_s_INFO_FMT - "RAID Exposing: channel=%d, id=%d, " - "physdsk %d \n", ioc->name, ev->channel, - ev->id, ev->phys_disk_num); - vtarget->tflags &= - ~MPT_TARGET_FLAGS_RAID_COMPONENT; - vtarget->id = ev->id; - mptsas_reprobe_target(starget, 0); - phy_info->attached.phys_disk_num = ~0; - } + "%s: fw_id=%d exit at line=%d\n", + ioc->name, __func__, + hot_plug_info->id, __LINE__)); break; } - if (mptsas_get_rphy(phy_info)) { + /* If there is no FW B_T mapping for this device then break + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + break; + + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device.sas_address); + if (!phy_info) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - if (ev->channel) printk("%d\n", __LINE__); + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } - port = mptsas_get_port(phy_info); - if (!port) { + starget = mptsas_get_starget(phy_info); + if (!starget) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } - memcpy(&phy_info->attached, &sas_device, - sizeof(struct mptsas_devinfo)); - - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SSP_TARGET) - ds = "ssp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_STP_TARGET) - ds = "stp"; - if (phy_info->attached.device_info & - MPI_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "sata"; - - printk(MYIOC_s_INFO_FMT - "attaching %s device, channel %d, id %d, phy %d\n", - ioc->name, ds, ev->channel, ev->id, ev->phy_id); - mptsas_parse_device_info(&identify, &phy_info->attached); - rphy = sas_end_device_alloc(port); - if (!rphy) { + vtarget = starget->hostdata; + if (!vtarget) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - break; /* non-fatal: an rphy can be added later */ + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); + break; } - rphy->identify = identify; - if (sas_rphy_add(rphy)) { + if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT - "%s: exit at line=%d\n", ioc->name, - __FUNCTION__, __LINE__)); - sas_rphy_free(rphy); + "%s: fw_id=%d exit at line=%d\n", ioc->name, + __func__, hot_plug_info->id, __LINE__)); break; } - mptsas_set_rphy(ioc, phy_info, rphy); + + mpt_findImVolumes(ioc); + + starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" + " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n", + ioc->name, hot_plug_info->channel, hot_plug_info->id, + hot_plug_info->phys_disk_num, (unsigned long long) + sas_device.sas_address); + + vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; + vtarget->id = hot_plug_info->id; + phy_info->attached.phys_disk_num = ~0; + mptsas_reprobe_target(starget, 0); + mptsas_add_device_component_by_fw(ioc, + hot_plug_info->channel, hot_plug_info->id); break; + case MPTSAS_ADD_RAID: - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - ev->id, 0); - if (sdev) { - scsi_device_put(sdev); - break; - } - printk(MYIOC_s_INFO_FMT - "attaching raid volume, channel %d, id %d\n", - ioc->name, MPTSAS_RAID_CHANNEL, ev->id); - scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0); + mpt_findImVolumes(ioc); + printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + hot_plug_info->id); + scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, + hot_plug_info->id, 0); break; + case MPTSAS_DEL_RAID: - sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, - ev->id, 0); - if (!sdev) - break; - printk(MYIOC_s_INFO_FMT - "removing raid volume, channel %d, id %d\n", - ioc->name, MPTSAS_RAID_CHANNEL, ev->id); - vdevice = sdev->hostdata; - scsi_remove_device(sdev); - scsi_device_put(sdev); + mpt_findImVolumes(ioc); + printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, + hot_plug_info->id); + scsi_remove_device(hot_plug_info->sdev); + scsi_device_put(hot_plug_info->sdev); break; + case MPTSAS_ADD_INACTIVE_VOLUME: + + mpt_findImVolumes(ioc); mptsas_adding_inactive_raid_components(ioc, - ev->channel, ev->id); + hot_plug_info->channel, hot_plug_info->id); break; - case MPTSAS_IGNORE_EVENT: + default: break; } - mutex_unlock(&ioc->sas_discovery_mutex); - kfree(ev); + mptsas_free_fw_event(ioc, fw_event); } static void -mptsas_send_sas_event(MPT_ADAPTER *ioc, - EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) +mptsas_send_sas_event(struct fw_event_work *fw_event) { - struct mptsas_hotplug_event *ev; - u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); - __le64 sas_address; + MPT_ADAPTER *ioc; + struct mptsas_hotplug_event hot_plug_info; + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; + u32 device_info; + u64 sas_address; + + ioc = fw_event->ioc; + sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) + fw_event->event_data; + device_info = le32_to_cpu(sas_event_data->DeviceInfo); if ((device_info & - (MPI_SAS_DEVICE_INFO_SSP_TARGET | - MPI_SAS_DEVICE_INFO_STP_TARGET | - MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) + (MPI_SAS_DEVICE_INFO_SSP_TARGET | + MPI_SAS_DEVICE_INFO_STP_TARGET | + MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { + mptsas_free_fw_event(ioc, fw_event); return; + } + + if (sas_event_data->ReasonCode == + MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); + return; + } switch (sas_event_data->ReasonCode) { case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: - - mptsas_target_reset_queue(ioc, sas_event_data); - break; - case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); - break; - } - - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->handle = le16_to_cpu(sas_event_data->DevHandle); - ev->parent_handle = - le16_to_cpu(sas_event_data->ParentDevHandle); - ev->channel = sas_event_data->Bus; - ev->id = sas_event_data->TargetID; - ev->phy_id = sas_event_data->PhyNum; + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); + hot_plug_info.channel = sas_event_data->Bus; + hot_plug_info.id = sas_event_data->TargetID; + hot_plug_info.phy_id = sas_event_data->PhyNum; memcpy(&sas_address, &sas_event_data->SASAddress, - sizeof(__le64)); - ev->sas_address = le64_to_cpu(sas_address); - ev->device_info = device_info; - + sizeof(u64)); + hot_plug_info.sas_address = le64_to_cpu(sas_address); + hot_plug_info.device_info = device_info; if (sas_event_data->ReasonCode & MPI_EVENT_SAS_DEV_STAT_RC_ADDED) - ev->event_type = MPTSAS_ADD_DEVICE; + hot_plug_info.event_type = MPTSAS_ADD_DEVICE; else - ev->event_type = MPTSAS_DEL_DEVICE; - schedule_work(&ev->work); + hot_plug_info.event_type = MPTSAS_DEL_DEVICE; + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); break; + case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: - /* - * Persistent table is full. - */ - INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table); - schedule_work(&ioc->sas_persist_task); + mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + mptsas_free_fw_event(ioc, fw_event); break; - /* - * TODO, handle other events - */ + case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: + /* TODO */ case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: - case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: - case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: + /* TODO */ default: + mptsas_free_fw_event(ioc, fw_event); break; } } + static void -mptsas_send_raid_event(MPT_ADAPTER *ioc, - EVENT_DATA_RAID *raid_event_data) +mptsas_send_raid_event(struct fw_event_work *fw_event) { - struct mptsas_hotplug_event *ev; - int status = le32_to_cpu(raid_event_data->SettingsStatus); - int state = (status >> 8) & 0xff; - - if (ioc->bus_type != SAS) - return; - - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); - return; + MPT_ADAPTER *ioc; + EVENT_DATA_RAID *raid_event_data; + struct mptsas_hotplug_event hot_plug_info; + int status; + int state; + struct scsi_device *sdev = NULL; + VirtDevice *vdevice = NULL; + RaidPhysDiskPage0_t phys_disk; + + ioc = fw_event->ioc; + raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; + status = le32_to_cpu(raid_event_data->SettingsStatus); + state = (status >> 8) & 0xff; + + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.id = raid_event_data->VolumeID; + hot_plug_info.channel = raid_event_data->VolumeBus; + hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; + + if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || + raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || + raid_event_data->ReasonCode == + MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { + sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, + hot_plug_info.id, 0); + hot_plug_info.sdev = sdev; + if (sdev) + vdevice = sdev->hostdata; } - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->id = raid_event_data->VolumeID; - ev->channel = raid_event_data->VolumeBus; - ev->event_type = MPTSAS_IGNORE_EVENT; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " + "ReasonCode=%02x\n", ioc->name, __func__, + raid_event_data->ReasonCode)); switch (raid_event_data->ReasonCode) { case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->event_type = MPTSAS_ADD_DEVICE; + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; break; case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->hidden_raid_component = 1; - ev->event_type = MPTSAS_DEL_DEVICE; + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; break; case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: switch (state) { case MPI_PD_STATE_ONLINE: case MPI_PD_STATE_NOT_COMPATIBLE: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->hidden_raid_component = 1; - ev->event_type = MPTSAS_ADD_DEVICE; + mpt_raid_phys_disk_pg0(ioc, + raid_event_data->PhysDiskNum, &phys_disk); + hot_plug_info.id = phys_disk.PhysDiskID; + hot_plug_info.channel = phys_disk.PhysDiskBus; + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; break; + case MPI_PD_STATE_FAILED: case MPI_PD_STATE_MISSING: case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: - ev->phys_disk_num_valid = 1; - ev->phys_disk_num = raid_event_data->PhysDiskNum; - ev->event_type = MPTSAS_DEL_DEVICE; + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; break; default: break; } break; case MPI_EVENT_RAID_RC_VOLUME_DELETED: - ev->event_type = MPTSAS_DEL_RAID; + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; break; case MPI_EVENT_RAID_RC_VOLUME_CREATED: - ev->event_type = MPTSAS_ADD_RAID; + if (sdev) { + scsi_device_put(sdev); + break; + } + hot_plug_info.event_type = MPTSAS_ADD_RAID; break; case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: + if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; + break; + } switch (state) { case MPI_RAIDVOL0_STATUS_STATE_FAILED: case MPI_RAIDVOL0_STATUS_STATE_MISSING: - ev->event_type = MPTSAS_DEL_RAID; + if (!sdev) + break; + vdevice->vtarget->deleted = 1; /* block IO */ + hot_plug_info.event_type = MPTSAS_DEL_RAID; break; case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: - ev->event_type = MPTSAS_ADD_RAID; + if (sdev) { + scsi_device_put(sdev); + break; + } + hot_plug_info.event_type = MPTSAS_ADD_RAID; break; default: break; @@ -2990,32 +4746,189 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, default: break; } - schedule_work(&ev->work); + + if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); + else + mptsas_free_fw_event(ioc, fw_event); } -static void -mptsas_send_discovery_event(MPT_ADAPTER *ioc, - EVENT_DATA_SAS_DISCOVERY *discovery_data) +/** + * mptsas_issue_tm - send mptsas internal tm request + * @ioc: Pointer to MPT_ADAPTER structure + * @type: Task Management type + * @channel: channel number for task management + * @id: Logical Target ID for reset (if appropriate) + * @lun: Logical unit for reset (if appropriate) + * @task_context: Context for the task to be aborted + * @timeout: timeout for task management control + * + * return 0 on success and -1 on failure: + * + */ +static int +mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, + int task_context, ulong timeout, u8 *issue_reset) { - struct mptsas_discovery_event *ev; + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + int retval; + unsigned long timeleft; + + *issue_reset = 0; + mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); + if (mf == NULL) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " + "msg frames!!\n", ioc->name)); + goto out; + } - /* - * DiscoveryStatus - * - * This flag will be non-zero when firmware - * kicks off discovery, and return to zero - * once its completed. - */ - if (discovery_data->DiscoveryStatus) - return; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " + "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " + "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, + type, timeout, channel, id, (unsigned long long)lun, + task_context)); - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) + pScsiTm = (SCSITaskMgmt_t *) mf; + memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); + pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; + pScsiTm->TaskType = type; + pScsiTm->MsgFlags = 0; + pScsiTm->TargetID = id; + pScsiTm->Bus = channel; + pScsiTm->ChainOffset = 0; + pScsiTm->Reserved = 0; + pScsiTm->Reserved1 = 0; + pScsiTm->TaskMsgContext = task_context; + int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); + + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + retval = 0; + mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); + + /* Now wait for the command to complete */ + timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, + timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); + mpt_free_msg_frame(ioc, mf); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + *issue_reset = 1; + goto out; + } + + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + retval = -1; /* return failure */ + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt request: failed with no reply\n", ioc->name)); + goto out; + } + + out: + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + return retval; +} + +/** + * mptsas_broadcast_primative_work - Handle broadcast primitives + * @work: work queue payload containing info describing the event + * + * this will be handled in workqueue context. + */ +static void +mptsas_broadcast_primative_work(struct fw_event_work *fw_event) +{ + MPT_ADAPTER *ioc = fw_event->ioc; + MPT_FRAME_HDR *mf; + VirtDevice *vdevice; + int ii; + struct scsi_cmnd *sc; + SCSITaskMgmtReply_t *pScsiTmReply; + u8 issue_reset; + int task_context; + u8 channel, id; + int lun; + u32 termination_count; + u32 query_count; + + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s - enter\n", ioc->name, __func__)); + + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + mptsas_requeue_fw_event(ioc, fw_event, 1000); return; - INIT_WORK(&ev->work, mptsas_discovery_work); - ev->ioc = ioc; - schedule_work(&ev->work); -}; + } + + issue_reset = 0; + termination_count = 0; + query_count = 0; + mpt_findImVolumes(ioc); + pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; + + for (ii = 0; ii < ioc->req_depth; ii++) { + if (ioc->fw_events_off) + goto out; + sc = mptscsih_get_scsi_lookup(ioc, ii); + if (!sc) + continue; + mf = MPT_INDEX_2_MFPTR(ioc, ii); + if (!mf) + continue; + task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; + vdevice = sc->device->hostdata; + if (!vdevice || !vdevice->vtarget) + continue; + if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) + continue; /* skip hidden raid components */ + if (vdevice->vtarget->raidVolume) + continue; /* skip hidden raid components */ + channel = vdevice->vtarget->channel; + id = vdevice->vtarget->id; + lun = vdevice->lun; + if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, + channel, id, (u64)lun, task_context, 30, &issue_reset)) + goto out; + query_count++; + termination_count += + le32_to_cpu(pScsiTmReply->TerminationCount); + if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && + (pScsiTmReply->ResponseCode == + MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || + pScsiTmReply->ResponseCode == + MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) + continue; + if (mptsas_issue_tm(ioc, + MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, + channel, id, (u64)lun, 0, 30, &issue_reset)) + goto out; + termination_count += + le32_to_cpu(pScsiTmReply->TerminationCount); + } + + out: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s - exit, query_count = %d termination_count = %d\n", + ioc->name, __func__, query_count, termination_count)); + + ioc->broadcast_aen_busy = 0; + mpt_clear_taskmgmt_in_progress_flag(ioc); + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + + if (issue_reset) { + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!! doorbell=0x%08x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0)); + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); + } + mptsas_free_fw_event(ioc, fw_event); +} /* * mptsas_send_ir2_event - handle exposing hidden disk when @@ -3026,76 +4939,197 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc, * */ static void -mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data) +mptsas_send_ir2_event(struct fw_event_work *fw_event) { - struct mptsas_hotplug_event *ev; - - if (ir2_data->ReasonCode != - MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED) - return; - - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) + MPT_ADAPTER *ioc; + struct mptsas_hotplug_event hot_plug_info; + MPI_EVENT_DATA_IR2 *ir2_data; + u8 reasonCode; + RaidPhysDiskPage0_t phys_disk; + + ioc = fw_event->ioc; + ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; + reasonCode = ir2_data->ReasonCode; + + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " + "ReasonCode=%02x\n", ioc->name, __func__, reasonCode)); + + memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); + hot_plug_info.id = ir2_data->TargetID; + hot_plug_info.channel = ir2_data->Bus; + switch (reasonCode) { + case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: + hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: + hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; + hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; + break; + case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: + hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; + mpt_raid_phys_disk_pg0(ioc, + ir2_data->PhysDiskNum, &phys_disk); + hot_plug_info.id = phys_disk.PhysDiskID; + hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; + break; + default: + mptsas_free_fw_event(ioc, fw_event); return; - - INIT_WORK(&ev->work, mptsas_hotplug_work); - ev->ioc = ioc; - ev->id = ir2_data->TargetID; - ev->channel = ir2_data->Bus; - ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME; - - schedule_work(&ev->work); -}; + } + mptsas_hotplug_work(ioc, fw_event, &hot_plug_info); +} static int mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) { - int rc=1; - u8 event = le32_to_cpu(reply->Event) & 0xFF; + u32 event = le32_to_cpu(reply->Event); + int sz, event_data_sz; + struct fw_event_work *fw_event; + unsigned long delay; - if (!ioc->sh) - goto out; + if (ioc->bus_type != SAS) + return 0; - /* - * sas_discovery_ignore_events - * - * This flag is to prevent anymore processing of - * sas events once mptsas_remove function is called. - */ - if (ioc->sas_discovery_ignore_events) { - rc = mptscsih_event_process(ioc, reply); - goto out; - } + /* events turned off due to host reset or driver unloading */ + if (ioc->fw_events_off) + return 0; + delay = msecs_to_jiffies(1); switch (event) { + case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: + { + EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = + (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; + if (broadcast_event_data->Primitive != + MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) + return 0; + if (ioc->broadcast_aen_busy) + return 0; + ioc->broadcast_aen_busy = 1; + break; + } case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: - mptsas_send_sas_event(ioc, - (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); + { + EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = + (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; + u16 ioc_stat; + ioc_stat = le16_to_cpu(reply->IOCStatus); + + if (sas_event_data->ReasonCode == + MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { + mptsas_target_reset_queue(ioc, sas_event_data); + return 0; + } + if (sas_event_data->ReasonCode == + MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && + ioc->device_missing_delay && + (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) { + VirtTarget *vtarget = NULL; + u8 id, channel; + + id = sas_event_data->TargetID; + channel = sas_event_data->Bus; + + vtarget = mptsas_find_vtarget(ioc, channel, id); + if (vtarget) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "LogInfo (0x%x) available for " + "INTERNAL_DEVICE_RESET" + "fw_id %d fw_channel %d\n", ioc->name, + le32_to_cpu(reply->IOCLogInfo), + id, channel)); + if (vtarget->raidVolume) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Skipping Raid Volume for inDMD\n", + ioc->name)); + } else { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Setting device flag inDMD\n", + ioc->name)); + vtarget->inDMD = 1; + } + + } + + } + break; - case MPI_EVENT_INTEGRATED_RAID: - mptsas_send_raid_event(ioc, - (EVENT_DATA_RAID *)reply->Data); + } + case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: + { + MpiEventDataSasExpanderStatusChange_t *expander_data = + (MpiEventDataSasExpanderStatusChange_t *)reply->Data; + + if (ioc->old_sas_discovery_protocal) + return 0; + + if (expander_data->ReasonCode == + MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && + ioc->device_missing_delay) + delay = HZ * ioc->device_missing_delay; break; + } + case MPI_EVENT_SAS_DISCOVERY: + { + u32 discovery_status; + EventDataSasDiscovery_t *discovery_data = + (EventDataSasDiscovery_t *)reply->Data; + + discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); + ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; + if (ioc->old_sas_discovery_protocal && !discovery_status) + mptsas_queue_rescan(ioc); + return 0; + } + case MPI_EVENT_INTEGRATED_RAID: case MPI_EVENT_PERSISTENT_TABLE_FULL: - INIT_WORK(&ioc->sas_persist_task, - mptsas_persist_clear_table); - schedule_work(&ioc->sas_persist_task); - break; - case MPI_EVENT_SAS_DISCOVERY: - mptsas_send_discovery_event(ioc, - (EVENT_DATA_SAS_DISCOVERY *)reply->Data); - break; case MPI_EVENT_IR2: - mptsas_send_ir2_event(ioc, - (PTR_MPI_EVENT_DATA_IR2)reply->Data); + case MPI_EVENT_SAS_PHY_LINK_STATUS: + case MPI_EVENT_QUEUE_FULL: break; default: - rc = mptscsih_event_process(ioc, reply); - break; + return 0; } - out: - return rc; + event_data_sz = ((reply->MsgLength * 4) - + offsetof(EventNotificationReply_t, Data)); + sz = offsetof(struct fw_event_work, event_data) + event_data_sz; + fw_event = kzalloc(sz, GFP_ATOMIC); + if (!fw_event) { + printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name, + __func__, __LINE__); + return 0; + } + memcpy(fw_event->event_data, reply->Data, event_data_sz); + fw_event->event = event; + fw_event->ioc = ioc; + mptsas_add_fw_event(ioc, fw_event, delay); + return 0; +} + +/* Delete a volume when no longer listed in ioc pg2 + */ +static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) +{ + struct scsi_device *sdev; + int i; + + sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); + if (!sdev) + return; + if (!ioc->raid_data.pIocPg2) + goto out; + if (!ioc->raid_data.pIocPg2->NumActiveVolumes) + goto out; + for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) + if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) + goto release_sdev; + out: + printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " + "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id); + scsi_remove_device(sdev); + release_sdev: + scsi_device_put(sdev); } static int @@ -3117,10 +5151,13 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) return r; ioc = pci_get_drvdata(pdev); + mptsas_fw_event_off(ioc); ioc->DoneCtx = mptsasDoneCtx; ioc->TaskCtx = mptsasTaskCtx; ioc->InternalCtx = mptsasInternalCtx; - + ioc->schedule_target_reset = &mptsas_schedule_target_reset; + ioc->schedule_dead_ioc_flush_running_cmds = + &mptscsih_flush_running_cmds; /* Added sanity check on readiness of the MPT adapter. */ if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { @@ -3175,14 +5212,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* set 16 byte cdb's */ sh->max_cmd_len = 16; - - sh->max_id = ioc->pfacts[0].PortSCSIID; + sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue); + sh->max_id = -1; sh->max_lun = max_lun; - sh->transportt = mptsas_transport_template; - sh->this_id = ioc->pfacts[0].PortSCSIID; - /* Required entry. */ sh->unique_id = ioc->id; @@ -3202,17 +5236,15 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } if (numSGE < sh->sg_tablesize) { @@ -3223,6 +5255,21 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) sh->sg_tablesize = numSGE; } + if (mpt_loadtime_max_sectors) { + if (mpt_loadtime_max_sectors < 64 || + mpt_loadtime_max_sectors > 8192) { + printk(MYIOC_s_INFO_FMT "Invalid value passed for" + "mpt_loadtime_max_sectors %d." + "Range from 64 to 8192\n", ioc->name, + mpt_loadtime_max_sectors); + } + mpt_loadtime_max_sectors &= 0xFFFFFFFE; + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Resetting max sector to %d from %d\n", + ioc->name, mpt_loadtime_max_sectors, sh->max_sectors)); + sh->max_sectors = mpt_loadtime_max_sectors; + } + hd = shost_priv(sh); hd->ioc = ioc; @@ -3240,34 +5287,13 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - ioc->sas_data.ptClear = mpt_pt_clear; - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; INIT_LIST_HEAD(&hd->target_reset_list); + INIT_LIST_HEAD(&ioc->sas_device_info_list); + mutex_init(&ioc->sas_device_info_mutex); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); if (ioc->sas_data.ptClear==1) { @@ -3282,8 +5308,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_mptsas_probe; } + /* older firmware doesn't support expander events */ + if ((ioc->facts.HeaderVersion >> 8) < 0xE) + ioc->old_sas_discovery_protocal = 1; mptsas_scan_sas_topology(ioc); - + mptsas_fw_event_on(ioc); return 0; out_mptsas_probe: @@ -3292,12 +5321,31 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) return error; } -static void __devexit mptsas_remove(struct pci_dev *pdev) +void +mptsas_shutdown(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + + mptsas_fw_event_off(ioc); + mptsas_cleanup_fw_event_q(ioc); +} + +static void mptsas_remove(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct mptsas_portinfo *p, *n; int i; + if (!ioc->sh) { + printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name); + mpt_detach(pdev); + return; + } + + mptsas_shutdown(pdev); + + mptsas_del_device_components(ioc); + ioc->sas_discovery_ignore_events = 1; sas_remove_host(ioc->sh); @@ -3306,11 +5354,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) list_del(&p->list); for (i = 0 ; i < p->num_phys ; i++) mptsas_port_delete(ioc, p->phy_info[i].port_details); + kfree(p->phy_info); kfree(p); } mutex_unlock(&ioc->sas_topology_mutex); - + ioc->hba_port_info = NULL; mptscsih_remove(pdev); } @@ -3325,6 +5374,8 @@ static struct pci_device_id mptsas_pci_table[] = { PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078, PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP, + PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, mptsas_pci_table); @@ -3334,8 +5385,8 @@ static struct pci_driver mptsas_driver = { .name = "mptsas", .id_table = mptsas_pci_table, .probe = mptsas_probe, - .remove = __devexit_p(mptsas_remove), - .shutdown = mptscsih_shutdown, + .remove = mptsas_remove, + .shutdown = mptsas_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume, @@ -3353,12 +5404,20 @@ mptsas_init(void) sas_attach_transport(&mptsas_transport_functions); if (!mptsas_transport_template) return -ENODEV; + mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out; - mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); - mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); + mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER, + "mptscsih_io_done"); + mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER, + "mptscsih_taskmgmt_complete"); mptsasInternalCtx = - mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); - mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); + mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER, + "mptscsih_scandv_complete"); + mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER, + "mptsas_mgmt_done"); + mptsasDeviceResetCtx = + mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER, + "mptsas_taskmgmt_complete"); mpt_event_register(mptsasDoneCtx, mptsas_event_process); mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); @@ -3383,6 +5442,7 @@ mptsas_exit(void) mpt_deregister(mptsasInternalCtx); mpt_deregister(mptsasTaskCtx); mpt_deregister(mptsasDoneCtx); + mpt_deregister(mptsasDeviceResetCtx); } module_init(mptsas_init); diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h index 7c150f50629..57e86ab7766 100644 --- a/drivers/message/fusion/mptsas.h +++ b/drivers/message/fusion/mptsas.h @@ -5,7 +5,7 @@ * LSIFC9xx/LSI409xx Fibre Channel * running LSI MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -53,6 +53,7 @@ struct mptsas_target_reset_event { struct list_head list; EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data; u8 target_reset_issued; + unsigned long time_count; }; enum mptsas_hotplug_action { @@ -60,12 +61,37 @@ enum mptsas_hotplug_action { MPTSAS_DEL_DEVICE, MPTSAS_ADD_RAID, MPTSAS_DEL_RAID, + MPTSAS_ADD_PHYSDISK, + MPTSAS_ADD_PHYSDISK_REPROBE, + MPTSAS_DEL_PHYSDISK, + MPTSAS_DEL_PHYSDISK_REPROBE, MPTSAS_ADD_INACTIVE_VOLUME, MPTSAS_IGNORE_EVENT, }; +struct mptsas_mapping{ + u8 id; + u8 channel; +}; + +struct mptsas_device_info { + struct list_head list; + struct mptsas_mapping os; /* operating system mapping*/ + struct mptsas_mapping fw; /* firmware mapping */ + u64 sas_address; + u32 device_info; /* specific bits for devices */ + u16 slot; /* enclosure slot id */ + u64 enclosure_logical_id; /*enclosure address */ + u8 is_logical_volume; /* is this logical volume */ + /* this belongs to volume */ + u8 is_hidden_raid_component; + /* this valid when is_hidden_raid_component set */ + u8 volume_id; + /* cached data for a removed device */ + u8 is_cached; +}; + struct mptsas_hotplug_event { - struct work_struct work; MPT_ADAPTER *ioc; enum mptsas_hotplug_action event_type; u64 sas_address; @@ -73,11 +99,18 @@ struct mptsas_hotplug_event { u8 id; u32 device_info; u16 handle; - u16 parent_handle; u8 phy_id; - u8 phys_disk_num_valid; /* hrc (hidden raid component) */ u8 phys_disk_num; /* hrc - unique index*/ - u8 hidden_raid_component; /* hrc - don't expose*/ + struct scsi_device *sdev; +}; + +struct fw_event_work { + struct list_head list; + struct delayed_work work; + MPT_ADAPTER *ioc; + u32 event; + u8 retries; + u8 __attribute__((aligned(4))) event_data[1]; }; struct mptsas_discovery_event { @@ -107,6 +140,7 @@ struct mptsas_devinfo { u64 sas_address; /* WWN of this device, SATA is assigned by HBA,expander */ u32 device_info; /* bitfield detailed info about this device */ + u16 flags; /* sas device pg0 flags */ }; /* diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index c207bda6723..2a1c6f21af2 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -3,7 +3,7 @@ * For use with LSI PCI chip/adapter(s) * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -46,6 +46,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/kdev_t.h> @@ -80,7 +81,7 @@ MODULE_VERSION(my_VERSION); /* * Other private/forward protos... */ -static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); +struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i); static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd); static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd); @@ -92,18 +93,24 @@ static int mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, SCSIIORequest_t *pReq, int req_idx); static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx); static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); -static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd); -static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ); -static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); +int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, + int lun, int ctx2abort, ulong timeout); int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); +void +mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); +static int mptscsih_get_completion_code(MPT_ADAPTER *ioc, + MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply); int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice); +static int +mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, + SCSITaskMgmtReply_t *pScsiTmReply); void mptscsih_remove(struct pci_dev *); void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM @@ -113,69 +120,6 @@ int mptscsih_resume(struct pci_dev *pdev); #define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_add_sge - Place a simple SGE at address pAddr. - * @pAddr: virtual address for SGE - * @flagslength: SGE flags and data transfer length - * @dma_addr: Physical address - * - * This routine places a MPT request frame back on the MPT adapter's - * FreeQ. - */ -static inline void -mptscsih_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) -{ - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGESimple64_t *pSge = (SGESimple64_t *) pAddr; - u32 tmp = dma_addr & 0xFFFFFFFF; - - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pSge->Address.High = cpu_to_le32(tmp); - - } else { - SGESimple32_t *pSge = (SGESimple32_t *) pAddr; - pSge->FlagsLength = cpu_to_le32(flagslength); - pSge->Address = cpu_to_le32(dma_addr); - } -} /* mptscsih_add_sge() */ - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_add_chain - Place a chain SGE at address pAddr. - * @pAddr: virtual address for SGE - * @next: nextChainOffset value (u32's) - * @length: length of next SGL segment - * @dma_addr: Physical address - * - * This routine places a MPT request frame back on the MPT adapter's - * FreeQ. - */ -static inline void -mptscsih_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) -{ - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGEChain64_t *pChain = (SGEChain64_t *) pAddr; - u32 tmp = dma_addr & 0xFFFFFFFF; - - pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); - - pChain->NextChainOffset = next; - - pChain->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pChain->Address.High = cpu_to_le32(tmp); - } else { - SGEChain32_t *pChain = (SGEChain32_t *) pAddr; - pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); - pChain->NextChainOffset = next; - pChain->Address = cpu_to_le32(dma_addr); - } -} /* mptscsih_add_chain() */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -281,10 +225,10 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, */ nextSGEset: - numSgeSlots = ((frm_sz - sgeOffset) / (sizeof(u32) + sizeof(dma_addr_t)) ); + numSgeSlots = ((frm_sz - sgeOffset) / ioc->SGE_size); numSgeThisFrame = (sges_left < numSgeSlots) ? sges_left : numSgeSlots; - sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | MPT_SGE_FLAGS_ADDRESSING | sgdir; + sgflags = MPT_SGE_FLAGS_SIMPLE_ELEMENT | sgdir; /* Get first (num - 1) SG elements * Skip any SG entries with a length of 0 @@ -293,17 +237,19 @@ nextSGEset: for (ii=0; ii < (numSgeThisFrame-1); ii++) { thisxfer = sg_dma_len(sg); if (thisxfer == 0) { - sg = sg_next(sg); /* Get next SG element from the OS */ + /* Get next SG element from the OS */ + sg = sg_next(sg); sg_done++; continue; } v2 = sg_dma_address(sg); - mptscsih_add_sge(psge, sgflags | thisxfer, v2); + ioc->add_sge(psge, sgflags | thisxfer, v2); - sg = sg_next(sg); /* Get next SG element from the OS */ - psge += (sizeof(u32) + sizeof(dma_addr_t)); - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + /* Get next SG element from the OS */ + sg = sg_next(sg); + psge += ioc->SGE_size; + sgeOffset += ioc->SGE_size; sg_done++; } @@ -320,12 +266,8 @@ nextSGEset: thisxfer = sg_dma_len(sg); v2 = sg_dma_address(sg); - mptscsih_add_sge(psge, sgflags | thisxfer, v2); - /* - sg = sg_next(sg); - psge += (sizeof(u32) + sizeof(dma_addr_t)); - */ - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); + ioc->add_sge(psge, sgflags | thisxfer, v2); + sgeOffset += ioc->SGE_size; sg_done++; if (chainSge) { @@ -334,7 +276,8 @@ nextSGEset: * Update the chain element * Offset and Length fields. */ - mptscsih_add_chain((char *)chainSge, 0, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); + ioc->add_chain((char *)chainSge, 0, sgeOffset, + ioc->ChainBufferDMA + chain_dma_off); } else { /* The current buffer is the original MF * and there is no Chain buffer. @@ -367,7 +310,7 @@ nextSGEset: * set properly). */ if (sg_done) { - u32 *ptmp = (u32 *) (psge - (sizeof(u32) + sizeof(dma_addr_t))); + u32 *ptmp = (u32 *) (psge - ioc->SGE_size); sgflags = le32_to_cpu(*ptmp); sgflags |= MPT_SGE_FLAGS_LAST_ELEMENT; *ptmp = cpu_to_le32(sgflags); @@ -381,8 +324,9 @@ nextSGEset: * Old chain element is now complete. */ u8 nextChain = (u8) (sgeOffset >> 2); - sgeOffset += (sizeof(u32) + sizeof(dma_addr_t)); - mptscsih_add_chain((char *)chainSge, nextChain, sgeOffset, ioc->ChainBufferDMA + chain_dma_off); + sgeOffset += ioc->SGE_size; + ioc->add_chain((char *)chainSge, nextChain, sgeOffset, + ioc->ChainBufferDMA + chain_dma_off); } else { /* The original MF buffer requires a chain buffer - * set the offset. @@ -461,7 +405,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget, if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n", - ioc->name,__FUNCTION__)); + ioc->name,__func__)); return; } @@ -592,14 +536,15 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc } scsi_print_command(sc); - printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n", - ioc->name, pScsiReply->Bus, pScsiReply->TargetID); + printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d, lun = %d\n", + ioc->name, pScsiReply->Bus, pScsiReply->TargetID, sc->device->lun); printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, " "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc)); printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, " "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag), le32_to_cpu(pScsiReply->TransferCount), sc->result); + printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), " "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n", ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus, @@ -654,16 +599,14 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); req_idx_MR = (mr != NULL) ? le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx; + + /* Special case, where already freed message frame is received from + * Firmware. It happens with Resetting IOC. + * Return immediately. Do not care + */ if ((req_idx != req_idx_MR) || - (mf->u.frame.linkage.arg1 == 0xdeadbeaf)) { - printk(MYIOC_s_ERR_FMT "Received a mf that was already freed\n", - ioc->name); - printk (MYIOC_s_ERR_FMT - "req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n", - ioc->name, req_idx, req_idx_MR, mf, mr, - mptscsih_get_scsi_lookup(ioc, req_idx_MR)); + (le32_to_cpu(mf->u.frame.linkage.arg1) == 0xdeadbeaf)) return 0; - } sc = mptscsih_getclear_scsi_lookup(ioc, req_idx); if (sc == NULL) { @@ -686,6 +629,16 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) return 1; } + if (ioc->bus_type == SAS) { + VirtDevice *vdevice = sc->device->hostdata; + + if (!vdevice || !vdevice->vtarget || + vdevice->vtarget->deleted) { + sc->result = DID_NO_CONNECT << 16; + goto out; + } + } + sc->host_scribble = NULL; sc->result = DID_OK << 16; /* Set default reply as OK */ pScsiReq = (SCSIIORequest_t *) mf; @@ -711,6 +664,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) u32 log_info; status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; + scsi_state = pScsiReply->SCSIState; scsi_status = pScsiReply->SCSIStatus; xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); @@ -747,6 +701,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) switch(status) { case MPI_IOCSTATUS_BUSY: /* 0x0002 */ + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ /* CHECKME! * Maybe: DRIVER_BUSY | SUGGEST_RETRY | DID_SOFT_ERROR (retry) * But not: DID_BUS_BUSY lest one risk @@ -784,13 +739,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ if ( ioc->bus_type == SAS ) { - u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus); - if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { - if ((log_info & SAS_LOGINFO_MASK) - == SAS_LOGINFO_NEXUS_LOSS) { - sc->result = (DID_BUS_BUSY << 16); - break; - } + u16 ioc_status = + le16_to_cpu(pScsiReply->IOCStatus); + if ((ioc_status & + MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) + && + ((log_info & SAS_LOGINFO_MASK) == + SAS_LOGINFO_NEXUS_LOSS)) { + VirtDevice *vdevice = + sc->device->hostdata; + + /* flag the device as being in + * device removal delay so we can + * notify the midlayer to hold off + * on timeout eh */ + if (vdevice && vdevice-> + vtarget && + vdevice->vtarget-> + raidVolume) + printk(KERN_INFO + "Skipping Raid Volume" + "for inDMD\n"); + else if (vdevice && + vdevice->vtarget) + vdevice->vtarget-> + inDMD = 1; + + sc->result = + (DID_TRANSPORT_DISRUPTED + << 16); + break; } } else if (ioc->bus_type == FC) { /* @@ -810,12 +788,17 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) */ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ /* Linux handles an unsolicited DID_RESET better * than an unsolicited DID_ABORT. */ sc->result = DID_RESET << 16; + break; + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + if (ioc->bus_type == FC) + sc->result = DID_ERROR << 16; + else + sc->result = DID_RESET << 16; break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ @@ -835,11 +818,37 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) * precedence! */ sc->result = (DID_OK << 16) | scsi_status; - if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { - /* Have already saved the status and sense data + if (!(scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)) { + + /* + * For an Errata on LSI53C1030 + * When the length of request data + * and transfer data are different + * with result of command (READ or VERIFY), + * DID_SOFT_ERROR is set. */ - ; - } else { + if (ioc->bus_type == SPI) { + if ((pScsiReq->CDB[0] == READ_6 && ((pScsiReq->CDB[1] & 0x02) == 0)) || + pScsiReq->CDB[0] == READ_10 || + pScsiReq->CDB[0] == READ_12 || + (pScsiReq->CDB[0] == READ_16 && + ((pScsiReq->CDB[1] & 0x02) == 0)) || + pScsiReq->CDB[0] == VERIFY || + pScsiReq->CDB[0] == VERIFY_16) { + if (scsi_bufflen(sc) != + xfer_cnt) { + sc->result = + DID_SOFT_ERROR << 16; + printk(KERN_WARNING "Errata" + "on LSI53C1030 occurred." + "sc->req_bufflen=0x%02x," + "xfer_cnt=0x%02x\n", + scsi_bufflen(sc), + xfer_cnt); + } + } + } + if (xfer_cnt < sc->underflow) { if (scsi_status == SAM_STAT_BUSY) sc->result = SAM_STAT_BUSY; @@ -878,7 +887,58 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) sc->result = (DID_OK << 16) | scsi_status; if (scsi_state == 0) { ; - } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { + } else if (scsi_state & + MPI_SCSI_STATE_AUTOSENSE_VALID) { + + /* + * For potential trouble on LSI53C1030. + * (date:2007.xx.) + * It is checked whether the length of + * request data is equal to + * the length of transfer and residual. + * MEDIUM_ERROR is set by incorrect data. + */ + if ((ioc->bus_type == SPI) && + (sc->sense_buffer[2] & 0x20)) { + u32 difftransfer; + difftransfer = + sc->sense_buffer[3] << 24 | + sc->sense_buffer[4] << 16 | + sc->sense_buffer[5] << 8 | + sc->sense_buffer[6]; + if (((sc->sense_buffer[3] & 0x80) == + 0x80) && (scsi_bufflen(sc) + != xfer_cnt)) { + sc->sense_buffer[2] = + MEDIUM_ERROR; + sc->sense_buffer[12] = 0xff; + sc->sense_buffer[13] = 0xff; + printk(KERN_WARNING"Errata" + "on LSI53C1030 occurred." + "sc->req_bufflen=0x%02x," + "xfer_cnt=0x%02x\n" , + scsi_bufflen(sc), + xfer_cnt); + } + if (((sc->sense_buffer[3] & 0x80) + != 0x80) && + (scsi_bufflen(sc) != + xfer_cnt + difftransfer)) { + sc->sense_buffer[2] = + MEDIUM_ERROR; + sc->sense_buffer[12] = 0xff; + sc->sense_buffer[13] = 0xff; + printk(KERN_WARNING + "Errata on LSI53C1030 occurred" + "sc->req_bufflen=0x%02x," + " xfer_cnt=0x%02x," + "difftransfer=0x%02x\n", + scsi_bufflen(sc), + xfer_cnt, + difftransfer); + } + } + /* * If running against circa 200003dd 909 MPT f/w, * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL @@ -926,7 +986,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ - case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ @@ -946,7 +1005,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) #endif } /* end of address reply case */ - +out: /* Unmap the DMA buffers, if any. */ scsi_dma_unmap(sc); @@ -967,7 +1026,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) * * Must be called while new I/Os are being queued. */ -static void +void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { MPT_ADAPTER *ioc = hd->ioc; @@ -992,12 +1051,13 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) scsi_dma_unmap(sc); sc->result = DID_RESET << 16; sc->host_scribble = NULL; - sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT - "completing cmds: fw_channel %d, fw_id %d, sc=%p," - " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii); + dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT + "completing cmds: fw_channel %d, fw_id %d, sc=%p, mf = %p, " + "idx=%x\n", ioc->name, channel, id, sc, mf, ii)); sc->scsi_done(sc); } } +EXPORT_SYMBOL(mptscsih_flush_running_cmds); /* * mptscsih_search_running_cmds - Delete any commands associated @@ -1053,9 +1113,11 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) scsi_dma_unmap(sc); sc->host_scribble = NULL; sc->result = DID_NO_CONNECT << 16; - sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d," - "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel, - vdevice->vtarget->id, sc, mf, ii); + dtmprintk(ioc, sdev_printk(KERN_INFO, sc->device, + MYIOC_s_FMT "completing cmds: fw_channel %d, " + "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, + vdevice->vtarget->channel, vdevice->vtarget->id, + sc, mf, ii)); sc->scsi_done(sc); spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); } @@ -1114,11 +1176,6 @@ mptscsih_remove(struct pci_dev *pdev) MPT_SCSI_HOST *hd; int sz1; - if(!host) { - mpt_detach(pdev); - return; - } - scsi_remove_host(host); if((hd = shost_priv(host)) == NULL) @@ -1227,101 +1284,17 @@ mptscsih_info(struct Scsi_Host *SChost) return h->info_kbuf; } -struct info_str { - char *buffer; - int length; - int offset; - int pos; -}; - -static void -mptscsih_copy_mem_info(struct info_str *info, char *data, int len) -{ - if (info->pos + len > info->length) - len = info->length - info->pos; - - if (info->pos + len < info->offset) { - info->pos += len; - return; - } - - if (info->pos < info->offset) { - data += (info->offset - info->pos); - len -= (info->offset - info->pos); - } - - if (len > 0) { - memcpy(info->buffer + info->pos, data, len); - info->pos += len; - } -} - -static int -mptscsih_copy_info(struct info_str *info, char *fmt, ...) -{ - va_list args; - char buf[81]; - int len; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - mptscsih_copy_mem_info(info, buf, len); - return len; -} - -static int -mptscsih_host_info(MPT_ADAPTER *ioc, char *pbuf, off_t offset, int len) -{ - struct info_str info; - - info.buffer = pbuf; - info.length = len; - info.offset = offset; - info.pos = 0; - - mptscsih_copy_info(&info, "%s: %s, ", ioc->name, ioc->prod_name); - mptscsih_copy_info(&info, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word); - mptscsih_copy_info(&info, "Ports=%d, ", ioc->facts.NumberOfPorts); - mptscsih_copy_info(&info, "MaxQ=%d\n", ioc->req_depth); - - return ((info.pos > info.offset) ? info.pos - info.offset : 0); -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_proc_info - Return information about MPT adapter - * @host: scsi host struct - * @buffer: if write, user data; if read, buffer for user - * @start: returns the buffer address - * @offset: if write, 0; if read, the current offset into the buffer from - * the previous read. - * @length: if write, return length; - * @func: write = 1; read = 0 - * - * (linux scsi_host_template.info routine) - */ -int -mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int func) +int mptscsih_show_info(struct seq_file *m, struct Scsi_Host *host) { MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; - int size = 0; - if (func) { - /* - * write is not supported - */ - } else { - if (start) - *start = buffer; - - size = mptscsih_host_info(ioc, buffer, offset, length); - } + seq_printf(m, "%s: %s, ", ioc->name, ioc->prod_name); + seq_printf(m, "%s%08xh, ", MPT_FW_REV_MAGIC_ID_STRING, ioc->facts.FWVersion.Word); + seq_printf(m, "Ports=%d, ", ioc->facts.NumberOfPorts); + seq_printf(m, "MaxQ=%d\n", ioc->req_depth); - return size; + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1331,7 +1304,6 @@ mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t off /** * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. * @SCpnt: Pointer to scsi_cmnd structure - * @done: Pointer SCSI mid-layer IO completion function * * (linux scsi_host_template.queuecommand routine) * This is the primary SCSI IO start routine. Create a MPI SCSIIORequest @@ -1340,13 +1312,12 @@ mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t off * Returns 0. (rtn value discarded by linux scsi mid-layer) */ int -mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +mptscsih_qcmd(struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; VirtDevice *vdevice = SCpnt->device->hostdata; - int lun; u32 datalen; u32 scsictl; u32 scsidir; @@ -1357,17 +1328,12 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) hd = shost_priv(SCpnt->device->host); ioc = hd->ioc; - lun = SCpnt->device->lun; - SCpnt->scsi_done = done; - dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n", - ioc->name, SCpnt, done)); + dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p\n", + ioc->name, SCpnt)); - if (hd->resetPending) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", - ioc->name, SCpnt)); + if (ioc->taskmgmt_quiesce_io) return SCSI_MLQUEUE_HOST_BUSY; - } /* * Put together a MPT SCSI request... @@ -1406,9 +1372,14 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; - } else { + if (SCpnt->request && SCpnt->request->ioprio) { + if (((SCpnt->request->ioprio & 0x7) == 1) || + !(SCpnt->request->ioprio & 0x7)) + scsictl |= MPI_SCSIIO_CONTROL_HEADOFQ; + } + } else scsictl = scsidir | MPI_SCSIIO_CONTROL_UNTAGGED; - } + /* Use the above information to set up the message frame */ @@ -1422,7 +1393,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) pScsiReq->CDBLength = SCpnt->cmd_len; pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; pScsiReq->Reserved = 0; - pScsiReq->MsgFlags = mpt_msg_flags(); + pScsiReq->MsgFlags = mpt_msg_flags(ioc); int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN); pScsiReq->Control = cpu_to_le32(scsictl); @@ -1448,7 +1419,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) */ if (datalen == 0) { /* Add a NULL SGE */ - mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, + ioc->add_sge((char *)&pScsiReq->SGL, + MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ @@ -1528,8 +1500,8 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_TMHandler - Generic handler for SCSI Task Management. - * @hd: Pointer to MPT SCSI HOST structure + * mptscsih_IssueTaskMgmt - Generic send Task Management function. + * @hd: Pointer to MPT_SCSI_HOST structure * @type: Task Management type * @channel: channel number for task management * @id: Logical Target ID for reset (if appropriate) @@ -1537,145 +1509,74 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx) * @ctx2abort: Context for the task to be aborted (if appropriate) * @timeout: timeout for task management control * - * Fall through to mpt_HardResetHandler if: not operational, too many - * failed TM requests or handshake failure. + * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) + * or a non-interrupt thread. In the former, must not call schedule(). * - * Remark: Currently invoked from a non-interrupt thread (_bh). + * Not all fields are meaningfull for all task types. * - * Note: With old EH code, at most 1 SCSI TaskMgmt function per IOC - * will be active. + * Returns 0 for SUCCESS, or FAILED. * - * Returns 0 for SUCCESS, or %FAILED. **/ int -mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) +mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, + int ctx2abort, ulong timeout) { - MPT_ADAPTER *ioc; - int rc = -1; + MPT_FRAME_HDR *mf; + SCSITaskMgmt_t *pScsiTm; + int ii; + int retval; + MPT_ADAPTER *ioc = hd->ioc; + unsigned long timeleft; + u8 issue_hard_reset; u32 ioc_raw_state; - unsigned long flags; - - ioc = hd->ioc; - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name)); - - // SJR - CHECKME - Can we avoid this here? - // (mpt_HardResetHandler has this check...) - spin_lock_irqsave(&ioc->diagLock, flags); - if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { - spin_unlock_irqrestore(&ioc->diagLock, flags); - return FAILED; - } - spin_unlock_irqrestore(&ioc->diagLock, flags); - - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out and not bus reset, then we return a FAILED status - * to the caller. - * The call to mptscsih_tm_pending_wait() will set the pending flag - * if we are - * successful. Otherwise, reload the FW. - */ - if (mptscsih_tm_pending_wait(hd) == FAILED) { - if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: " - "Timed out waiting for last TM (%d) to complete! \n", - ioc->name, hd->tmPending)); - return FAILED; - } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target " - "reset: Timed out waiting for last TM (%d) " - "to complete! \n", ioc->name, - hd->tmPending)); - return FAILED; - } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: " - "Timed out waiting for last TM (%d) to complete! \n", - ioc->name, hd->tmPending)); - return FAILED; - } - } else { - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmPending |= (1 << type); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - } + unsigned long time_count; + issue_hard_reset = 0; ioc_raw_state = mpt_GetIocState(ioc, 0); if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT - "TM Handler for type=%x: IOC Not operational (0x%x)!\n", + "TaskMgmt type=%x: IOC Not operational (0x%x)!\n", ioc->name, type, ioc_raw_state); - printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name); + printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", + ioc->name, __func__); if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) - printk(MYIOC_s_WARN_FMT "TMHandler: HardReset " + printk(MYIOC_s_WARN_FMT "TaskMgmt HardReset " "FAILED!!\n", ioc->name); - return FAILED; + return 0; } - if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { + /* DOORBELL ACTIVE check is not required if + * MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported. + */ + + if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) + && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) && + (ioc_raw_state & MPI_DOORBELL_ACTIVE)) { printk(MYIOC_s_WARN_FMT - "TM Handler for type=%x: ioc_state: " + "TaskMgmt type=%x: ioc_state: " "DOORBELL_ACTIVE (0x%x)!\n", ioc->name, type, ioc_raw_state); return FAILED; } - /* Isse the Task Mgmt request. - */ - if (hd->hard_resets < -1) - hd->hard_resets++; - - rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun, - ctx2abort, timeout); - if (rc) - printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", - ioc->name); - else - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n", - ioc->name)); - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - "TMHandler rc = %d!\n", ioc->name, rc)); - - return rc; -} - - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_IssueTaskMgmt - Generic send Task Management function. - * @hd: Pointer to MPT_SCSI_HOST structure - * @type: Task Management type - * @channel: channel number for task management - * @id: Logical Target ID for reset (if appropriate) - * @lun: Logical Unit for reset (if appropriate) - * @ctx2abort: Context for the task to be aborted (if appropriate) - * @timeout: timeout for task management control - * - * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) - * or a non-interrupt thread. In the former, must not call schedule(). - * - * Not all fields are meaningfull for all task types. - * - * Returns 0 for SUCCESS, or FAILED. - * - **/ -static int -mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout) -{ - MPT_FRAME_HDR *mf; - SCSITaskMgmt_t *pScsiTm; - int ii; - int retval; - MPT_ADAPTER *ioc = hd->ioc; + mutex_lock(&ioc->taskmgmt_cmds.mutex); + if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { + mf = NULL; + retval = FAILED; + goto out; + } /* Return Fail to calling function if no message frames available. */ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", - ioc->name)); - return FAILED; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt no msg frames!!\n", ioc->name)); + retval = FAILED; + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto out; } - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n", + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n", ioc->name, mf)); /* Format the Request @@ -1699,11 +1600,14 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i pScsiTm->TaskMsgContext = ctx2abort; - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) " - "type=%d\n", ioc->name, ctx2abort, type)); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt: ctx2abort (0x%08x) " + "task_type = 0x%02X, timeout = %ld\n", ioc->name, ctx2abort, + type, timeout)); DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm); + INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) + time_count = jiffies; if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf); @@ -1711,47 +1615,53 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i retval = mpt_send_handshake_request(ioc->TaskCtx, ioc, sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP); if (retval) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!" - " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd, - ioc, mf, retval)); - goto fail_out; + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt handshake FAILED!(mf=%p, rc=%d) \n", + ioc->name, mf, retval)); + mpt_free_msg_frame(ioc, mf); + mpt_clear_taskmgmt_in_progress_flag(ioc); + goto out; } } - if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) { - dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!" - " (hd %p, ioc %p, mf %p) \n", ioc->name, hd, - ioc, mf)); - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n", - ioc->name)); - retval = mpt_HardResetHandler(ioc, CAN_SLEEP); - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n", - ioc->name, retval)); - goto fail_out; + timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, + timeout*HZ); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + retval = FAILED; + dtmprintk(ioc, printk(MYIOC_s_ERR_FMT + "TaskMgmt TIMED OUT!(mf=%p)\n", ioc->name, mf)); + mpt_clear_taskmgmt_in_progress_flag(ioc); + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + issue_hard_reset = 1; + goto out; } - /* - * Handle success case, see if theres a non-zero ioc_status. - */ - if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS || - hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || - hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) - retval = 0; - else - retval = FAILED; + retval = mptscsih_taskmgmt_reply(ioc, type, + (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply); - return retval; + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt completed (%d seconds)\n", + ioc->name, jiffies_to_msecs(jiffies - time_count)/1000)); - fail_out: + out: - /* - * Free task management mf, and corresponding tm flags - */ - mpt_free_msg_frame(ioc, mf); - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - return FAILED; + CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) + if (issue_hard_reset) { + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!! doorbell=0x%08x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0)); + retval = (ioc->bus_type == SAS) ? + mpt_HardResetHandler(ioc, CAN_SLEEP) : + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + + retval = (retval == 0) ? 0 : FAILED; + mutex_unlock(&ioc->taskmgmt_cmds.mutex); + return retval; } +EXPORT_SYMBOL(mptscsih_IssueTaskMgmt); static int mptscsih_get_tm_timeout(MPT_ADAPTER *ioc) @@ -1760,10 +1670,10 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc) case FC: return 40; case SAS: - return 10; + return 30; case SPI: default: - return 2; + return 10; } } @@ -1785,7 +1695,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) int scpnt_idx; int retval; VirtDevice *vdevice; - ulong sn = SCpnt->serial_number; MPT_ADAPTER *ioc; /* If we can't locate our host adapter structure, return FAILED status. @@ -1810,7 +1719,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) ioc->name, SCpnt)); SCpnt->result = DID_NO_CONNECT << 16; SCpnt->scsi_done(SCpnt); - retval = 0; + retval = SUCCESS; goto out; } @@ -1825,6 +1734,17 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) goto out; } + /* Task aborts are not supported for volumes. + */ + if (vdevice->vtarget->raidVolume) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: raid volume (sc=%p)\n", + ioc->name, SCpnt)); + SCpnt->result = DID_RESET << 16; + retval = FAILED; + goto out; + } + /* Find this command */ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) { @@ -1835,17 +1755,15 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: " "Command not in the active list! (sc=%p)\n", ioc->name, SCpnt)); - retval = 0; + retval = SUCCESS; goto out; } - if (hd->resetPending) { - retval = FAILED; - goto out; - } + if (ioc->timeouts < -1) + ioc->timeouts++; - if (hd->timeouts < -1) - hd->timeouts++; + if (mpt_fwfault_debug) + mpt_halt_firmware(ioc); /* Most important! Set TaskMsgContext to SCpnt's MsgContext! * (the IO to be ABORT'd) @@ -1856,25 +1774,30 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) */ mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx); ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; + retval = mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, + vdevice->vtarget->channel, + vdevice->vtarget->id, vdevice->lun, + ctx2abort, mptscsih_get_tm_timeout(ioc)); - hd->abortSCpnt = SCpnt; - - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, - ctx2abort, mptscsih_get_tm_timeout(ioc)); - - if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx && - SCpnt->serial_number == sn) + if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: command still in active list! (sc=%p)\n", + ioc->name, SCpnt)); retval = FAILED; + } else { + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "task abort: command cleared from active list! (sc=%p)\n", + ioc->name, SCpnt)); + retval = SUCCESS; + } out: - printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", - ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n", + ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval, + SCpnt); - if (retval == 0) - return SUCCESS; - else - return FAILED; + return retval; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1907,11 +1830,6 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) ioc->name, SCpnt); scsi_print_command(SCpnt); - if (hd->resetPending) { - retval = FAILED; - goto out; - } - vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget) { retval = 0; @@ -1925,9 +1843,11 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) goto out; } - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0, - mptscsih_get_tm_timeout(ioc)); + retval = mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, + vdevice->vtarget->channel, + vdevice->vtarget->id, 0, 0, + mptscsih_get_tm_timeout(ioc)); out: printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n", @@ -1970,12 +1890,16 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) ioc->name, SCpnt); scsi_print_command(SCpnt); - if (hd->timeouts < -1) - hd->timeouts++; + if (ioc->timeouts < -1) + ioc->timeouts++; vdevice = SCpnt->device->hostdata; - retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc)); + if (!vdevice || !vdevice->vtarget) + return SUCCESS; + retval = mptscsih_IssueTaskMgmt(hd, + MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + vdevice->vtarget->channel, 0, 0, 0, + mptscsih_get_tm_timeout(ioc)); printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n", ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); @@ -1999,8 +1923,9 @@ int mptscsih_host_reset(struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST * hd; - int retval; + int status = SUCCESS; MPT_ADAPTER *ioc; + int retval; /* If we can't locate the host to reset, then we failed. */ if ((hd = shost_priv(SCpnt->device->host)) == NULL){ @@ -2009,6 +1934,9 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt) return FAILED; } + /* make sure we have no outstanding commands at this stage */ + mptscsih_flush_running_cmds(hd); + ioc = hd->ioc; printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n", ioc->name, SCpnt); @@ -2016,86 +1944,71 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt) /* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. */ - if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) { - retval = FAILED; - } else { - /* Make sure TM pending is cleared and TM state is set to - * NONE. - */ - retval = 0; - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - } + retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); + if (retval < 0) + status = FAILED; + else + status = SUCCESS; printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n", ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); - return retval; + return status; } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_tm_pending_wait - wait for pending task management request to complete - * @hd: Pointer to MPT host structure. - * - * Returns {SUCCESS,FAILED}. - */ static int -mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) +mptscsih_taskmgmt_reply(MPT_ADAPTER *ioc, u8 type, + SCSITaskMgmtReply_t *pScsiTmReply) { - unsigned long flags; - int loop_count = 4 * 10; /* Wait 10 seconds */ - int status = FAILED; - MPT_ADAPTER *ioc = hd->ioc; + u16 iocstatus; + u32 termination_count; + int retval; - do { - spin_lock_irqsave(&ioc->FreeQlock, flags); - if (hd->tmState == TM_STATE_NONE) { - hd->tmState = TM_STATE_IN_PROGRESS; - hd->tmPending = 1; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - status = SUCCESS; - break; - } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - msleep(250); - } while (--loop_count); + if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { + retval = FAILED; + goto out; + } - return status; -} + DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mptscsih_tm_wait_for_completion - wait for completion of TM task - * @hd: Pointer to MPT host structure. - * @timeout: timeout value - * - * Returns {SUCCESS,FAILED}. - */ -static int -mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ) -{ - unsigned long flags; - int loop_count = 4 * timeout; - int status = FAILED; - MPT_ADAPTER *ioc = hd->ioc; + iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; + termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); - do { - spin_lock_irqsave(&ioc->FreeQlock, flags); - if(hd->tmPending == 0) { - status = SUCCESS; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - break; - } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - msleep(250); - } while (--loop_count); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt fw_channel = %d, fw_id = %d, task_type = 0x%02X,\n" + "\tiocstatus = 0x%04X, loginfo = 0x%08X, response_code = 0x%02X,\n" + "\tterm_cmnds = %d\n", ioc->name, pScsiTmReply->Bus, + pScsiTmReply->TargetID, type, le16_to_cpu(pScsiTmReply->IOCStatus), + le32_to_cpu(pScsiTmReply->IOCLogInfo), pScsiTmReply->ResponseCode, + termination_count)); - return status; + if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && + pScsiTmReply->ResponseCode) + mptscsih_taskmgmt_response_code(ioc, + pScsiTmReply->ResponseCode); + + if (iocstatus == MPI_IOCSTATUS_SUCCESS) { + retval = 0; + goto out; + } + + retval = FAILED; + if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + if (termination_count == 1) + retval = 0; + goto out; + } + + if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED || + iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED) + retval = 0; + + out: + return retval; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static void +void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) { char *desc; @@ -2129,6 +2042,7 @@ mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) printk(MYIOC_s_INFO_FMT "Response Code(0x%08x): F/W: %s\n", ioc->name, response_code, desc); } +EXPORT_SYMBOL(mptscsih_taskmgmt_response_code); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -2145,97 +2059,30 @@ mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code) * Returns 1 indicating alloc'd request frame ptr should be freed. **/ int -mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, + MPT_FRAME_HDR *mr) { - SCSITaskMgmtReply_t *pScsiTmReply; - SCSITaskMgmt_t *pScsiTmReq; - MPT_SCSI_HOST *hd; - unsigned long flags; - u16 iocstatus; - u8 tmType; - u32 termination_count; - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n", - ioc->name, mf, mr)); - if (!ioc->sh) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT - "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name)); - return 1; - } - - if (mr == NULL) { - dtmprintk(ioc, printk(MYIOC_s_WARN_FMT - "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf)); - return 1; - } - - hd = shost_priv(ioc->sh); - pScsiTmReply = (SCSITaskMgmtReply_t*)mr; - pScsiTmReq = (SCSITaskMgmt_t*)mf; - tmType = pScsiTmReq->TaskType; - iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK; - termination_count = le32_to_cpu(pScsiTmReply->TerminationCount); + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "TaskMgmt completed (mf=%p, mr=%p)\n", ioc->name, mf, mr)); - if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 && - pScsiTmReply->ResponseCode) - mptscsih_taskmgmt_response_code(ioc, - pScsiTmReply->ResponseCode); - DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply); + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; -#ifdef CONFIG_FUSION_LOGGING - if ((ioc->debug_level & MPT_DEBUG_REPLY) || - (ioc->debug_level & MPT_DEBUG_TM )) - printk("%s: ha=%d [%d:%d:0] task_type=0x%02X " - "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X " - "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus, - pScsiTmReply->TargetID, pScsiTmReq->TaskType, - le16_to_cpu(pScsiTmReply->IOCStatus), - le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode, - le32_to_cpu(pScsiTmReply->TerminationCount)); -#endif - if (!iocstatus) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name)); - hd->abortSCpnt = NULL; + if (!mr) goto out; - } - - /* Error? (anything non-zero?) */ - - /* clear flags and continue. - */ - switch (tmType) { - - case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK: - if (termination_count == 1) - iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED; - hd->abortSCpnt = NULL; - break; - - case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: - - /* If an internal command is present - * or the TM failed - reload the FW. - * FC FW may respond FAILED to an ABORT - */ - if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED || - hd->cmdPtr) - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) - printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name); - break; - - case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: - default: - break; - } + ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->taskmgmt_cmds.reply, mr, + min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); out: - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->tm_iocstatus = iocstatus; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - return 1; + if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { + mpt_clear_taskmgmt_in_progress_flag(ioc); + ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->taskmgmt_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); + return 1; + } + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2285,8 +2132,10 @@ int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct inactive_raid_component_info *component_info; - int i; + int i, j; + RaidPhysDiskPage1_t *phys_disk; int rc = 0; + int num_paths; if (!ioc->raid_data.pIocPg3) goto out; @@ -2298,20 +2147,59 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id) } } + if (ioc->bus_type != SAS) + goto out; + + /* + * Check if dual path + */ + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + continue; + if ((mpt_raid_phys_disk_pg1(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum, + phys_disk))) { + kfree(phys_disk); + continue; + } + for (j = 0; j < num_paths; j++) { + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_INVALID)) + continue; + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_BROKEN)) + continue; + if ((id == phys_disk->Path[j].PhysDiskID) && + (channel == phys_disk->Path[j].PhysDiskBus)) { + rc = 1; + kfree(phys_disk); + goto out; + } + } + kfree(phys_disk); + } + + /* * Check inactive list for matching phys disks */ if (list_empty(&ioc->raid_data.inactive_list)) goto out; - down(&ioc->raid_data.inactive_list_mutex); + mutex_lock(&ioc->raid_data.inactive_list_mutex); list_for_each_entry(component_info, &ioc->raid_data.inactive_list, list) { if ((component_info->d.PhysDiskID == id) && (component_info->d.PhysDiskBus == channel)) rc = 1; } - up(&ioc->raid_data.inactive_list_mutex); + mutex_unlock(&ioc->raid_data.inactive_list_mutex); out: return rc; @@ -2322,8 +2210,10 @@ u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) { struct inactive_raid_component_info *component_info; - int i; + int i, j; + RaidPhysDiskPage1_t *phys_disk; int rc = -ENXIO; + int num_paths; if (!ioc->raid_data.pIocPg3) goto out; @@ -2335,20 +2225,58 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id) } } + if (ioc->bus_type != SAS) + goto out; + + /* + * Check if dual path + */ + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + num_paths = mpt_raid_phys_disk_get_num_paths(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum); + if (num_paths < 2) + continue; + phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + + (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); + if (!phys_disk) + continue; + if ((mpt_raid_phys_disk_pg1(ioc, + ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum, + phys_disk))) { + kfree(phys_disk); + continue; + } + for (j = 0; j < num_paths; j++) { + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_INVALID)) + continue; + if ((phys_disk->Path[j].Flags & + MPI_RAID_PHYSDISK1_FLAG_BROKEN)) + continue; + if ((id == phys_disk->Path[j].PhysDiskID) && + (channel == phys_disk->Path[j].PhysDiskBus)) { + rc = phys_disk->PhysDiskNum; + kfree(phys_disk); + goto out; + } + } + kfree(phys_disk); + } + /* * Check inactive list for matching phys disks */ if (list_empty(&ioc->raid_data.inactive_list)) goto out; - down(&ioc->raid_data.inactive_list_mutex); + mutex_lock(&ioc->raid_data.inactive_list_mutex); list_for_each_entry(component_info, &ioc->raid_data.inactive_list, list) { if ((component_info->d.PhysDiskID == id) && (component_info->d.PhysDiskBus == channel)) rc = component_info->d.PhysDiskNum; } - up(&ioc->raid_data.inactive_list_mutex); + mutex_unlock(&ioc->raid_data.inactive_list_mutex); out: return rc; @@ -2371,6 +2299,8 @@ mptscsih_slave_destroy(struct scsi_device *sdev) starget = scsi_target(sdev); vtarget = starget->hostdata; vdevice = sdev->hostdata; + if (!vdevice) + return; mptscsih_search_running_cmds(hd, vdevice); vtarget->num_luns--; @@ -2384,11 +2314,12 @@ mptscsih_slave_destroy(struct scsi_device *sdev) * mptscsih_change_queue_depth - This function will set a devices queue depth * @sdev: per scsi_device pointer * @qdepth: requested queue depth + * @reason: calling context * * Adding support for new 'change_queue_depth' api. */ int -mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) +mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) { MPT_SCSI_HOST *hd = shost_priv(sdev->host); VirtTarget *vtarget; @@ -2400,6 +2331,9 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) starget = scsi_target(sdev); vtarget = starget->hostdata; + if (reason != SCSI_QDEPTH_DEFAULT) + return -EOPNOTSUPP; + if (ioc->bus_type == SPI) { if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) max_depth = 1; @@ -2409,7 +2343,10 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) else max_depth = MPT_SCSI_CMD_PER_DEV_LOW; } else - max_depth = MPT_SCSI_CMD_PER_DEV_HIGH; + max_depth = ioc->sh->can_queue; + + if (!sdev->tagged_supported) + max_depth = 1; if (qdepth > max_depth) qdepth = max_depth; @@ -2451,14 +2388,7 @@ mptscsih_slave_configure(struct scsi_device *sdev) ioc->name, sdev->sdtr, sdev->wdtr, sdev->ppr, sdev->inquiry_len)); - if (sdev->id > sh->max_id) { - /* error case, should never happen */ - scsi_adjust_queue_depth(sdev, 0, 1); - goto slave_configure_exit; - } - vdevice->configured_lun = 1; - mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Queue depth=%d, tflags=%x\n", @@ -2470,13 +2400,15 @@ mptscsih_slave_configure(struct scsi_device *sdev) ioc->name, vtarget->negoFlags, vtarget->maxOffset, vtarget->minSyncFactor)); -slave_configure_exit: - + mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH, + SCSI_QDEPTH_DEFAULT); dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "tagged %d, simple %d, ordered %d\n", ioc->name,sdev->tagged_supported, sdev->simple_tags, sdev->ordered_tags)); + blk_queue_dma_alignment (sdev->request_queue, 512 - 1); + return 0; } @@ -2545,15 +2477,13 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR } /** - * mptscsih_get_scsi_lookup + * mptscsih_get_scsi_lookup - retrieves scmd entry * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array * - * retrieves scmd entry from ScsiLookup[] array list - * * Returns the scsi_cmd pointer - **/ -static struct scsi_cmnd * + */ +struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) { unsigned long flags; @@ -2565,15 +2495,15 @@ mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) return scmd; } +EXPORT_SYMBOL(mptscsih_get_scsi_lookup); /** - * mptscsih_getclear_scsi_lookup + * mptscsih_getclear_scsi_lookup - retrieves and clears scmd entry from ScsiLookup[] array list * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array * - * retrieves and clears scmd entry from ScsiLookup[] array list - * * Returns the scsi_cmd pointer + * **/ static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i) @@ -2590,9 +2520,7 @@ mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i) } /** - * mptscsih_set_scsi_lookup - * - * writes a scmd entry into the ScsiLookup[] array list + * mptscsih_set_scsi_lookup - write a scmd entry into the ScsiLookup[] array list * * @ioc: Pointer to MPT_ADAPTER structure * @i: index into the array @@ -2638,94 +2566,33 @@ int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { MPT_SCSI_HOST *hd; - unsigned long flags; - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT - ": IOC %s_reset routed to SCSI host driver!\n", - ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - - /* If a FW reload request arrives after base installed but - * before all scsi hosts have been attached, then an alt_ioc - * may have a NULL sh pointer. - */ if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL) return 0; - else - hd = shost_priv(ioc->sh); - - if (reset_phase == MPT_IOC_SETUP_RESET) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name)); - - /* Clean Up: - * 1. Set Hard Reset Pending Flag - * All new commands go to doneQ - */ - hd->resetPending = 1; - - } else if (reset_phase == MPT_IOC_PRE_RESET) { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name)); - - /* 2. Flush running commands - * Clean ScsiLookup (and associated memory) - * AND clean mytaskQ - */ - /* 2b. Reply to OS all known outstanding I/O commands. - */ + hd = shost_priv(ioc->sh); + switch (reset_phase) { + case MPT_IOC_SETUP_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); + break; + case MPT_IOC_PRE_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); mptscsih_flush_running_cmds(hd); - - /* 2c. If there was an internal command that - * has not completed, configuration or io request, - * free these resources. - */ - if (hd->cmdPtr) { - del_timer(&hd->timer); - mpt_free_msg_frame(ioc, hd->cmdPtr); - } - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name)); - - } else { - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name)); - - /* Once a FW reload begins, all new OS commands are - * redirected to the doneQ w/ a reset status. - * Init all control structures. - */ - - /* 2. Chain Buffer initialization - */ - - /* 4. Renegotiate to all devices, if SPI - */ - - /* 5. Enable new commands to be posted - */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - hd->resetPending = 0; - hd->tmState = TM_STATE_NONE; - - /* 6. If there was an internal command, - * wake this process up. - */ - if (hd->cmdPtr) { - /* - * Wake up the original calling thread - */ - hd->pLocal = &hd->localReply; - hd->pLocal->completion = MPT_SCANDV_DID_RESET; - hd->scandv_wait_done = 1; - wake_up(&hd->scandv_waitq); - hd->cmdPtr = NULL; + break; + case MPT_IOC_POST_RESET: + dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING) { + ioc->internal_cmds.status |= + MPT_MGMT_STATUS_DID_IOCRESET; + complete(&ioc->internal_cmds.done); } - - dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name)); - + break; + default: + break; } - return 1; /* currently means nothing really */ } @@ -2733,55 +2600,16 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { - MPT_SCSI_HOST *hd; u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; - devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", - ioc->name, event)); - - if (ioc->sh == NULL || - ((hd = shost_priv(ioc->sh)) == NULL)) - return 1; - - switch (event) { - case MPI_EVENT_UNIT_ATTENTION: /* 03 */ - /* FIXME! */ - break; - case MPI_EVENT_IOC_BUS_RESET: /* 04 */ - case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1)) - hd->soft_resets++; - break; - case MPI_EVENT_LOGOUT: /* 09 */ - /* FIXME! */ - break; - - case MPI_EVENT_RESCAN: /* 06 */ - break; - - /* - * CHECKME! Don't think we need to do - * anything for these, but... - */ - case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ - case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ - /* - * CHECKME! Falling thru... - */ - break; + devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "MPT event (=%02Xh) routed to SCSI host driver!\n", + ioc->name, event)); - case MPI_EVENT_INTEGRATED_RAID: /* 0B */ - break; - - case MPI_EVENT_NONE: /* 00 */ - case MPI_EVENT_LOG_DATA: /* 01 */ - case MPI_EVENT_STATE_CHANGE: /* 02 */ - case MPI_EVENT_EVENT_CHANGE: /* 0A */ - default: - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n", - ioc->name, event)); - break; - } + if ((event == MPI_EVENT_IOC_BUS_RESET || + event == MPI_EVENT_EXT_BUS_RESET) && + (ioc->bus_type == SPI) && (ioc->soft_resets < -1)) + ioc->soft_resets++; return 1; /* currently means nothing really */ } @@ -2812,202 +2640,138 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) * Used ONLY for DV and other internal commands. */ int -mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) +mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, + MPT_FRAME_HDR *reply) { - MPT_SCSI_HOST *hd; SCSIIORequest_t *pReq; - int completionCode; + SCSIIOReply_t *pReply; + u8 cmd; u16 req_idx; + u8 *sense_data; + int sz; - hd = shost_priv(ioc->sh); - - if ((mf == NULL) || - (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(MYIOC_s_ERR_FMT - "ScanDvComplete, %s req frame ptr! (=%p)\n", - ioc->name, mf?"BAD":"NULL", (void *) mf); - goto wakeup; - } - - del_timer(&hd->timer); - req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); - mptscsih_set_scsi_lookup(ioc, req_idx, NULL); - pReq = (SCSIIORequest_t *) mf; + ioc->internal_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; + ioc->internal_cmds.completion_code = MPT_SCANDV_GOOD; + if (!reply) + goto out; - if (mf != hd->cmdPtr) { - printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n", - ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx); + pReply = (SCSIIOReply_t *) reply; + pReq = (SCSIIORequest_t *) req; + ioc->internal_cmds.completion_code = + mptscsih_get_completion_code(ioc, req, reply); + ioc->internal_cmds.status |= MPT_MGMT_STATUS_RF_VALID; + memcpy(ioc->internal_cmds.reply, reply, + min(MPT_DEFAULT_FRAME_SIZE, 4 * reply->u.reply.MsgLength)); + cmd = reply->u.hdr.Function; + if (((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) || + (cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) && + (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID)) { + req_idx = le16_to_cpu(req->u.frame.hwhdr.msgctxu.fld.req_idx); + sense_data = ((u8 *)ioc->sense_buf_pool + + (req_idx * MPT_SENSE_BUFFER_ALLOC)); + sz = min_t(int, pReq->SenseBufferLength, + MPT_SENSE_BUFFER_ALLOC); + memcpy(ioc->internal_cmds.sense, sense_data, sz); } - hd->cmdPtr = NULL; - - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", - ioc->name, mf, mr, req_idx)); - - hd->pLocal = &hd->localReply; - hd->pLocal->scsiStatus = 0; + out: + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_PENDING)) + return 0; + ioc->internal_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->internal_cmds.done); + return 1; +} - /* If target struct exists, clear sense valid flag. - */ - if (mr == NULL) { - completionCode = MPT_SCANDV_GOOD; - } else { - SCSIIOReply_t *pReply; - u16 status; - u8 scsi_status; - pReply = (SCSIIOReply_t *) mr; +/** + * mptscsih_get_completion_code - get completion code from MPT request + * @ioc: Pointer to MPT_ADAPTER structure + * @req: Pointer to original MPT request frame + * @reply: Pointer to MPT reply frame (NULL if TurboReply) + * + **/ +static int +mptscsih_get_completion_code(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, + MPT_FRAME_HDR *reply) +{ + SCSIIOReply_t *pReply; + MpiRaidActionReply_t *pr; + u8 scsi_status; + u16 status; + int completion_code; - status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; - scsi_status = pReply->SCSIStatus; + pReply = (SCSIIOReply_t *)reply; + status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; + scsi_status = pReply->SCSIStatus; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh," + "IOCLogInfo=%08xh\n", ioc->name, status, pReply->SCSIState, + scsi_status, le32_to_cpu(pReply->IOCLogInfo))); - switch(status) { + switch (status) { - case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ - completionCode = MPT_SCANDV_SELECTION_TIMEOUT; - break; + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + completion_code = MPT_SCANDV_SELECTION_TIMEOUT; + break; - case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ - case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ - case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ - case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ - completionCode = MPT_SCANDV_DID_RESET; - break; + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + completion_code = MPT_SCANDV_DID_RESET; + break; - case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ - case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ - case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ - if (pReply->Function == MPI_FUNCTION_CONFIG) { - ConfigReply_t *pr = (ConfigReply_t *)mr; - completionCode = MPT_SCANDV_GOOD; - hd->pLocal->header.PageVersion = pr->Header.PageVersion; - hd->pLocal->header.PageLength = pr->Header.PageLength; - hd->pLocal->header.PageNumber = pr->Header.PageNumber; - hd->pLocal->header.PageType = pr->Header.PageType; - - } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { - /* If the RAID Volume request is successful, - * return GOOD, else indicate that - * some type of error occurred. - */ - MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr; - if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) - completionCode = MPT_SCANDV_GOOD; - else - completionCode = MPT_SCANDV_SOME_ERROR; - memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense)); - - } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { - u8 *sense_data; - int sz; - - /* save sense data in global structure - */ - completionCode = MPT_SCANDV_SENSE; - hd->pLocal->scsiStatus = scsi_status; - sense_data = ((u8 *)ioc->sense_buf_pool + - (req_idx * MPT_SENSE_BUFFER_ALLOC)); - - sz = min_t(int, pReq->SenseBufferLength, - SCSI_STD_SENSE_BYTES); - memcpy(hd->pLocal->sense, sense_data, sz); - - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n", - ioc->name, sense_data)); - } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { - if (pReq->CDB[0] == INQUIRY) - completionCode = MPT_SCANDV_ISSUE_SENSE; - else - completionCode = MPT_SCANDV_DID_RESET; - } - else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) - completionCode = MPT_SCANDV_DID_RESET; - else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) - completionCode = MPT_SCANDV_DID_RESET; - else { - completionCode = MPT_SCANDV_GOOD; - hd->pLocal->scsiStatus = scsi_status; - } - break; + case MPI_IOCSTATUS_BUSY: + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: + completion_code = MPT_SCANDV_BUSY; + break; - case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ - if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) - completionCode = MPT_SCANDV_DID_RESET; + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ + case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ + if (pReply->Function == MPI_FUNCTION_CONFIG) { + completion_code = MPT_SCANDV_GOOD; + } else if (pReply->Function == MPI_FUNCTION_RAID_ACTION) { + pr = (MpiRaidActionReply_t *)reply; + if (le16_to_cpu(pr->ActionStatus) == + MPI_RAID_ACTION_ASTATUS_SUCCESS) + completion_code = MPT_SCANDV_GOOD; else - completionCode = MPT_SCANDV_SOME_ERROR; - break; - - default: - completionCode = MPT_SCANDV_SOME_ERROR; - break; - - } /* switch(status) */ - - } /* end of address reply case */ - - hd->pLocal->completion = completionCode; - - /* MF and RF are freed in mpt_interrupt - */ -wakeup: - /* Free Chain buffers (will never chain) in scan or dv */ - //mptscsih_freeChainBuffers(ioc, req_idx); - - /* - * Wake up the original calling thread - */ - hd->scandv_wait_done = 1; - wake_up(&hd->scandv_waitq); - - return 1; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptscsih_timer_expired - Call back for timer process. - * Used only for dv functionality. - * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long - * - */ -void -mptscsih_timer_expired(unsigned long data) -{ - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data; - MPT_ADAPTER *ioc = hd->ioc; - - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr)); - - if (hd->cmdPtr) { - MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr; + completion_code = MPT_SCANDV_SOME_ERROR; + } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) + completion_code = MPT_SCANDV_SENSE; + else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) { + if (req->u.scsireq.CDB[0] == INQUIRY) + completion_code = MPT_SCANDV_ISSUE_SENSE; + else + completion_code = MPT_SCANDV_DID_RESET; + } else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS) + completion_code = MPT_SCANDV_DID_RESET; + else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) + completion_code = MPT_SCANDV_DID_RESET; + else if (scsi_status == MPI_SCSI_STATUS_BUSY) + completion_code = MPT_SCANDV_BUSY; + else + completion_code = MPT_SCANDV_GOOD; + break; - if (cmd->Function == MPI_FUNCTION_SCSI_IO_REQUEST) { - /* Desire to issue a task management request here. - * TM requests MUST be single threaded. - * If old eh code and no TM current, issue request. - * If new eh code, do nothing. Wait for OS cmd timeout - * for bus reset. - */ - } else { - /* Perform a FW reload */ - if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) { - printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name); - } - } - } else { - /* This should NEVER happen */ - printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name); - } + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) + completion_code = MPT_SCANDV_DID_RESET; + else + completion_code = MPT_SCANDV_SOME_ERROR; + break; + default: + completion_code = MPT_SCANDV_SOME_ERROR; + break; - /* No more processing. - * TM call will generate an interrupt for SCSI TM Management. - * The FW will reply to all outstanding commands, callback will finish cleanup. - * Hard reset clean-up will free all resources. - */ - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name)); + } /* switch(status) */ - return; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + " completionCode set to %08xh\n", ioc->name, completion_code)); + return completion_code; } - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_do_cmd - Do internal command. @@ -3033,22 +2797,27 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) { MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; - SCSIIORequest_t ReqCopy; int my_idx, ii, dir; - int rc, cmdTimeout; - int in_isr; + int timeout; char cmdLen; char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - char cmd = io->cmd; - MPT_ADAPTER *ioc = hd->ioc; + u8 cmd = io->cmd; + MPT_ADAPTER *ioc = hd->ioc; + int ret = 0; + unsigned long timeleft; + unsigned long flags; - in_isr = in_interrupt(); - if (in_isr) { - dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n", - ioc->name)); - return -EPERM; + /* don't send internal command during diag reset */ + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: busy with host reset\n", ioc->name, __func__)); + return MPT_SCANDV_BUSY; } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + mutex_lock(&ioc->internal_cmds.mutex); /* Set command specific information */ @@ -3058,13 +2827,13 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; CDB[4] = io->size; - cmdTimeout = 10; + timeout = 10; break; case TEST_UNIT_READY: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; - cmdTimeout = 10; + timeout = 10; break; case START_STOP: @@ -3072,7 +2841,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; CDB[4] = 1; /*Spin up the disk */ - cmdTimeout = 15; + timeout = 15; break; case REQUEST_SENSE: @@ -3080,7 +2849,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) CDB[0] = cmd; CDB[4] = io->size; dir = MPI_SCSIIO_CONTROL_READ; - cmdTimeout = 10; + timeout = 10; break; case READ_BUFFER: @@ -3099,7 +2868,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) CDB[6] = (io->size >> 16) & 0xFF; CDB[7] = (io->size >> 8) & 0xFF; CDB[8] = io->size & 0xFF; - cmdTimeout = 10; + timeout = 10; break; case WRITE_BUFFER: @@ -3114,21 +2883,21 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) CDB[6] = (io->size >> 16) & 0xFF; CDB[7] = (io->size >> 8) & 0xFF; CDB[8] = io->size & 0xFF; - cmdTimeout = 10; + timeout = 10; break; case RESERVE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; - cmdTimeout = 10; + timeout = 10; break; case RELEASE: cmdLen = 6; dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; - cmdTimeout = 10; + timeout = 10; break; case SYNCHRONIZE_CACHE: @@ -3136,20 +2905,23 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) dir = MPI_SCSIIO_CONTROL_READ; CDB[0] = cmd; // CDB[1] = 0x02; /* set immediate bit */ - cmdTimeout = 10; + timeout = 10; break; default: /* Error Case */ - return -EFAULT; + ret = -EFAULT; + goto out; } /* Get and Populate a free Frame + * MsgContext set in mpt_get_msg_frame call */ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { - dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n", - ioc->name)); - return -EBUSY; + dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: No msg frames!\n", + ioc->name, __func__)); + ret = MPT_SCANDV_BUSY; + goto out; } pScsiReq = (SCSIIORequest_t *) mf; @@ -3175,7 +2947,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) pScsiReq->Reserved = 0; - pScsiReq->MsgFlags = mpt_msg_flags(); + pScsiReq->MsgFlags = mpt_msg_flags(ioc); /* MsgContext set in mpt_get_msg_fram call */ int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN); @@ -3187,74 +2959,61 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) if (cmd == REQUEST_SENSE) { pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n", - ioc->name, cmd)); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Untagged! 0x%02x\n", ioc->name, __func__, cmd)); } - for (ii=0; ii < 16; ii++) + for (ii = 0; ii < 16; ii++) pScsiReq->CDB[ii] = CDB[ii]; pScsiReq->DataLength = cpu_to_le32(io->size); pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (my_idx * MPT_SENSE_BUFFER_ALLOC)); - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n", - ioc->name, cmd, io->channel, io->id, io->lun)); - - if (dir == MPI_SCSIIO_CONTROL_READ) { - mpt_add_sge((char *) &pScsiReq->SGL, - MPT_SGE_FLAGS_SSIMPLE_READ | io->size, - io->data_dma); - } else { - mpt_add_sge((char *) &pScsiReq->SGL, - MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, - io->data_dma); - } - - /* The ISR will free the request frame, but we need - * the information to initialize the target. Duplicate. - */ - memcpy(&ReqCopy, pScsiReq, sizeof(SCSIIORequest_t)); - - /* Issue this command after: - * finish init - * add timer - * Wait until the reply has been received - * ScsiScanDvCtx callback function will - * set hd->pLocal; - * set scandv_wait_done and call wake_up - */ - hd->pLocal = NULL; - hd->timer.expires = jiffies + HZ*cmdTimeout; - hd->scandv_wait_done = 0; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: Sending Command 0x%02x for fw_channel=%d fw_id=%d lun=%d\n", + ioc->name, __func__, cmd, io->channel, io->id, io->lun)); - /* Save cmd pointer, for resource free if timeout or - * FW reload occurs - */ - hd->cmdPtr = mf; + if (dir == MPI_SCSIIO_CONTROL_READ) + ioc->add_sge((char *) &pScsiReq->SGL, + MPT_SGE_FLAGS_SSIMPLE_READ | io->size, io->data_dma); + else + ioc->add_sge((char *) &pScsiReq->SGL, + MPT_SGE_FLAGS_SSIMPLE_WRITE | io->size, io->data_dma); - add_timer(&hd->timer); + INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); - wait_event(hd->scandv_waitq, hd->scandv_wait_done); - - if (hd->pLocal) { - rc = hd->pLocal->completion; - hd->pLocal->skip = 0; - - /* Always set fatal error codes in some cases. - */ - if (rc == MPT_SCANDV_SELECTION_TIMEOUT) - rc = -ENXIO; - else if (rc == MPT_SCANDV_SOME_ERROR) - rc = -rc; - } else { - rc = -EFAULT; - /* This should never happen. */ - ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n", - ioc->name)); + timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, + timeout*HZ); + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = MPT_SCANDV_DID_RESET; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s: TIMED OUT for cmd=0x%02x\n", ioc->name, __func__, + cmd)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) { + mpt_free_msg_frame(ioc, mf); + goto out; + } + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!! doorbell=0x%08xh" + " cmd=0x%02x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0), + cmd); + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + goto out; } - return rc; + ret = ioc->internal_cmds.completion_code; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: success, rc=0x%02x\n", + ioc->name, __func__, ret)); + + out: + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + mutex_unlock(&ioc->internal_cmds.mutex); + return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -3300,9 +3059,10 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice) } static ssize_t -mptscsih_version_fw_show(struct class_device *cdev, char *buf) +mptscsih_version_fw_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; @@ -3312,12 +3072,13 @@ mptscsih_version_fw_show(struct class_device *cdev, char *buf) (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, ioc->facts.FWVersion.Word & 0x000000FF); } -static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL); +static DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL); static ssize_t -mptscsih_version_bios_show(struct class_device *cdev, char *buf) +mptscsih_version_bios_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; @@ -3327,129 +3088,141 @@ mptscsih_version_bios_show(struct class_device *cdev, char *buf) (ioc->biosVersion & 0x0000FF00) >> 8, ioc->biosVersion & 0x000000FF); } -static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL); +static DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL); static ssize_t -mptscsih_version_mpi_show(struct class_device *cdev, char *buf) +mptscsih_version_mpi_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion); } -static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL); +static DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL); static ssize_t -mptscsih_version_product_show(struct class_device *cdev, char *buf) +mptscsih_version_product_show(struct device *dev, + struct device_attribute *attr, +char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name); } -static CLASS_DEVICE_ATTR(version_product, S_IRUGO, +static DEVICE_ATTR(version_product, S_IRUGO, mptscsih_version_product_show, NULL); static ssize_t -mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf) +mptscsih_version_nvdata_persistent_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02xh\n", ioc->nvdata_version_persistent); } -static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, +static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, mptscsih_version_nvdata_persistent_show, NULL); static ssize_t -mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf) +mptscsih_version_nvdata_default_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default); } -static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO, +static DEVICE_ATTR(version_nvdata_default, S_IRUGO, mptscsih_version_nvdata_default_show, NULL); static ssize_t -mptscsih_board_name_show(struct class_device *cdev, char *buf) +mptscsih_board_name_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name); } -static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL); +static DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL); static ssize_t -mptscsih_board_assembly_show(struct class_device *cdev, char *buf) +mptscsih_board_assembly_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly); } -static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO, +static DEVICE_ATTR(board_assembly, S_IRUGO, mptscsih_board_assembly_show, NULL); static ssize_t -mptscsih_board_tracer_show(struct class_device *cdev, char *buf) +mptscsih_board_tracer_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer); } -static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO, +static DEVICE_ATTR(board_tracer, S_IRUGO, mptscsih_board_tracer_show, NULL); static ssize_t -mptscsih_io_delay_show(struct class_device *cdev, char *buf) +mptscsih_io_delay_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); } -static CLASS_DEVICE_ATTR(io_delay, S_IRUGO, +static DEVICE_ATTR(io_delay, S_IRUGO, mptscsih_io_delay_show, NULL); static ssize_t -mptscsih_device_delay_show(struct class_device *cdev, char *buf) +mptscsih_device_delay_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); } -static CLASS_DEVICE_ATTR(device_delay, S_IRUGO, +static DEVICE_ATTR(device_delay, S_IRUGO, mptscsih_device_delay_show, NULL); static ssize_t -mptscsih_debug_level_show(struct class_device *cdev, char *buf) +mptscsih_debug_level_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level); } static ssize_t -mptscsih_debug_level_store(struct class_device *cdev, const char *buf, - size_t count) +mptscsih_debug_level_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct Scsi_Host *host = class_to_shost(cdev); + struct Scsi_Host *host = class_to_shost(dev); MPT_SCSI_HOST *hd = shost_priv(host); MPT_ADAPTER *ioc = hd->ioc; int val = 0; @@ -3462,24 +3235,25 @@ mptscsih_debug_level_store(struct class_device *cdev, const char *buf, ioc->name, ioc->debug_level); return strlen(buf); } -static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR, - mptscsih_debug_level_show, mptscsih_debug_level_store); - -struct class_device_attribute *mptscsih_host_attrs[] = { - &class_device_attr_version_fw, - &class_device_attr_version_bios, - &class_device_attr_version_mpi, - &class_device_attr_version_product, - &class_device_attr_version_nvdata_persistent, - &class_device_attr_version_nvdata_default, - &class_device_attr_board_name, - &class_device_attr_board_assembly, - &class_device_attr_board_tracer, - &class_device_attr_io_delay, - &class_device_attr_device_delay, - &class_device_attr_debug_level, +static DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR, + mptscsih_debug_level_show, mptscsih_debug_level_store); + +struct device_attribute *mptscsih_host_attrs[] = { + &dev_attr_version_fw, + &dev_attr_version_bios, + &dev_attr_version_mpi, + &dev_attr_version_product, + &dev_attr_version_nvdata_persistent, + &dev_attr_version_nvdata_default, + &dev_attr_board_name, + &dev_attr_board_assembly, + &dev_attr_board_tracer, + &dev_attr_io_delay, + &dev_attr_device_delay, + &dev_attr_debug_level, NULL, }; + EXPORT_SYMBOL(mptscsih_host_attrs); EXPORT_SYMBOL(mptscsih_remove); @@ -3488,7 +3262,7 @@ EXPORT_SYMBOL(mptscsih_shutdown); EXPORT_SYMBOL(mptscsih_suspend); EXPORT_SYMBOL(mptscsih_resume); #endif -EXPORT_SYMBOL(mptscsih_proc_info); +EXPORT_SYMBOL(mptscsih_show_info); EXPORT_SYMBOL(mptscsih_info); EXPORT_SYMBOL(mptscsih_qcmd); EXPORT_SYMBOL(mptscsih_slave_destroy); @@ -3504,7 +3278,5 @@ EXPORT_SYMBOL(mptscsih_scandv_complete); EXPORT_SYMBOL(mptscsih_event_process); EXPORT_SYMBOL(mptscsih_ioc_reset); EXPORT_SYMBOL(mptscsih_change_queue_depth); -EXPORT_SYMBOL(mptscsih_timer_expired); -EXPORT_SYMBOL(mptscsih_TMHandler); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index d289e97cfe8..99e3390807f 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -5,7 +5,7 @@ * LSIFC9xx/LSI409xx Fibre Channel * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -60,6 +60,7 @@ #define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008) #define MPT_SCANDV_ISSUE_SENSE (0x00000010) #define MPT_SCANDV_FALLBACK (0x00000020) +#define MPT_SCANDV_BUSY (0x00000040) #define MPT_SCANDV_MAX_RETRIES (10) @@ -89,6 +90,7 @@ #endif + typedef struct _internal_cmd { char *data; /* data pointer */ dma_addr_t data_dma; /* data dma address */ @@ -109,9 +111,11 @@ extern void mptscsih_shutdown(struct pci_dev *); extern int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); extern int mptscsih_resume(struct pci_dev *pdev); #endif -extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func); +extern int mptscsih_show_info(struct seq_file *, struct Scsi_Host *); extern const char * mptscsih_info(struct Scsi_Host *SChost); -extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)); +extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt); +extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, + u8 id, int lun, int ctx2abort, ulong timeout); extern void mptscsih_slave_destroy(struct scsi_device *device); extern int mptscsih_slave_configure(struct scsi_device *device); extern int mptscsih_abort(struct scsi_cmnd * SCpnt); @@ -124,9 +128,11 @@ extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_F extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); -extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth); -extern void mptscsih_timer_expired(unsigned long data); -extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout); +extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, + int reason); extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); -extern struct class_device_attribute *mptscsih_host_attrs[]; +extern struct device_attribute *mptscsih_host_attrs[]; +extern struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); +extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); +extern void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 25bcfcf36f2..49d11338294 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -3,7 +3,7 @@ * For use with LSI PCI chip/adapter(s) * running LSI Fusion MPT (Message Passing Technology) firmware. * - * Copyright (c) 1999-2007 LSI Corporation + * Copyright (c) 1999-2008 LSI Corporation * (mailto:DL-MPTFusionLinux@lsi.com) * */ @@ -46,6 +46,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/kdev_t.h> @@ -209,6 +210,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, target->maxOffset = offset; target->maxWidth = width; + spi_min_period(scsi_target(sdev)) = factor; + spi_max_offset(scsi_target(sdev)) = offset; + spi_max_width(scsi_target(sdev)) = width; + target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; /* Disable unused features. @@ -300,7 +305,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id) flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | (IOCPage4Ptr->Header.PageLength + ii) * 4; - mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); + ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n", @@ -447,6 +452,7 @@ static int mptspi_target_alloc(struct scsi_target *starget) spi_max_offset(starget) = ioc->spi_data.maxSyncOffset; spi_offset(starget) = 0; + spi_period(starget) = 0xFF; mptspi_write_width(starget, 0); return 0; @@ -556,6 +562,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget, cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; cfg.dir = 0; cfg.pageAddr = starget->id; + cfg.timeout = 60; if (mpt_config(ioc, &cfg)) { starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name); @@ -613,19 +620,24 @@ static void mptspi_read_parameters(struct scsi_target *starget) spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0; } -static int +int mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) { + MPT_ADAPTER *ioc = hd->ioc; MpiRaidActionRequest_t *pReq; MPT_FRAME_HDR *mf; - MPT_ADAPTER *ioc = hd->ioc; + int ret; + unsigned long timeleft; + + mutex_lock(&ioc->internal_cmds.mutex); /* Get and Populate a free Frame */ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) { - ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n", - ioc->name)); - return -EAGAIN; + dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT + "%s: no msg frames!\n", ioc->name, __func__)); + ret = -EAGAIN; + goto out; } pReq = (MpiRaidActionRequest_t *)mf; if (quiesce) @@ -642,29 +654,36 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id) pReq->Reserved2 = 0; pReq->ActionDataWord = 0; /* Reserved for this action */ - mpt_add_sge((char *)&pReq->ActionDataSGE, + ioc->add_sge((char *)&pReq->ActionDataSGE, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n", ioc->name, pReq->Action, channel, id)); - hd->pLocal = NULL; - hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */ - hd->scandv_wait_done = 0; - - /* Save cmd pointer, for resource free if timeout or - * FW reload occurs - */ - hd->cmdPtr = mf; - - add_timer(&hd->timer); + INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status) mpt_put_msg_frame(ioc->InternalCtx, ioc, mf); - wait_event(hd->scandv_waitq, hd->scandv_wait_done); + timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ); + if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { + ret = -ETIME; + dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n", + ioc->name, __func__)); + if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) + goto out; + if (!timeleft) { + printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", + ioc->name, __func__); + mpt_HardResetHandler(ioc, CAN_SLEEP); + mpt_free_msg_frame(ioc, mf); + } + goto out; + } - if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0)) - return -1; + ret = ioc->internal_cmds.completion_code; - return 0; + out: + CLEAR_MGMT_STATUS(ioc->internal_cmds.status) + mutex_unlock(&ioc->internal_cmds.mutex); + return ret; } static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd, @@ -761,29 +780,29 @@ static int mptspi_slave_configure(struct scsi_device *sdev) } static int -mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +mptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) { - struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host); + struct _MPT_SCSI_HOST *hd = shost_priv(shost); VirtDevice *vdevice = SCpnt->device->hostdata; MPT_ADAPTER *ioc = hd->ioc; if (!vdevice || !vdevice->vtarget) { SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); + SCpnt->scsi_done(SCpnt); return 0; } if (SCpnt->device->channel == 1 && mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) { SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); + SCpnt->scsi_done(SCpnt); return 0; } if (spi_dv_pending(scsi_target(SCpnt->device))) ddvprintk(ioc, scsi_print_command(SCpnt)); - return mptscsih_qcmd(SCpnt,done); + return mptscsih_qcmd(SCpnt); } static void mptspi_slave_destroy(struct scsi_device *sdev) @@ -810,7 +829,7 @@ static void mptspi_slave_destroy(struct scsi_device *sdev) static struct scsi_host_template mptspi_driver_template = { .module = THIS_MODULE, .proc_name = "mptspi", - .proc_info = mptscsih_proc_info, + .show_info = mptscsih_show_info, .name = "MPT SPI Host", .info = mptscsih_info, .queuecommand = mptspi_qcmd, @@ -846,6 +865,10 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, struct _x_config_parms cfg; struct _CONFIG_PAGE_HEADER hdr; int err = -EBUSY; + u32 nego_parms; + u32 period; + struct scsi_device *sdev; + int i; /* don't allow updating nego parameters on RAID devices */ if (starget->channel == 0 && @@ -883,6 +906,24 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget, pg1->Header.PageNumber = hdr.PageNumber; pg1->Header.PageType = hdr.PageType; + nego_parms = le32_to_cpu(pg1->RequestedParameters); + period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >> + MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD; + if (period == 8) { + /* Turn on inline data padding for TAPE when running U320 */ + for (i = 0 ; i < 16; i++) { + sdev = scsi_device_lookup_by_target(starget, i); + if (sdev && sdev->type == TYPE_TAPE) { + sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT + "IDP:ON\n", ioc->name); + nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP; + pg1->RequestedParameters = + cpu_to_le32(nego_parms); + break; + } + } + } + mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters)); if (mpt_config(ioc, &cfg)) { @@ -1138,6 +1179,9 @@ mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) u8 event = le32_to_cpu(pEvReply->Event) & 0xFF; struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); + if (ioc->bus_type != SPI) + return 0; + if (hd && event == MPI_EVENT_INTEGRATED_RAID) { int reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; @@ -1266,13 +1310,20 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd) static int mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); int rc; rc = mptscsih_ioc_reset(ioc, reset_phase); + if ((ioc->bus_type != SPI) || (!rc)) + return rc; + + /* only try to do a renegotiation if we're properly set up + * if we get an ioc fault on bringup, ioc->sh will be NULL */ + if (reset_phase == MPT_IOC_POST_RESET && + ioc->sh) { + struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh); - if (reset_phase == MPT_IOC_POST_RESET) mptspi_dv_renegotiate(hd); + } return rc; } @@ -1417,17 +1468,15 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) * A slightly different algorithm is required for * 64bit SGEs. */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { + scale = ioc->req_sz/ioc->SGE_size; + if (ioc->sg_addr_size == sizeof(u64)) { numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 60) / ioc->SGE_size; } else { numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); + (ioc->req_sz - 64) / ioc->SGE_size; } if (numSGE < sh->sg_tablesize) { @@ -1456,39 +1505,13 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", ioc->name, ioc->ScsiLookup)); - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; - - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - ioc->spi_data.Saf_Te = mpt_saf_te; - - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "saf_te %x\n", ioc->name, mpt_saf_te)); ioc->spi_data.noQas = 0; - init_waitqueue_head(&hd->scandv_waitq); - hd->scandv_wait_done = 0; hd->last_queue_full = 0; hd->spi_pending = 0; @@ -1508,7 +1531,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) * issue internal bus reset */ if (ioc->spi_data.bus_reset) - mptscsih_TMHandler(hd, + mptscsih_IssueTaskMgmt(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, 0, 0, 0, 0, 5); @@ -1525,7 +1548,7 @@ static struct pci_driver mptspi_driver = { .name = "mptspi", .id_table = mptspi_pci_table, .probe = mptspi_probe, - .remove = __devexit_p(mptscsih_remove), + .remove = mptscsih_remove, .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, @@ -1550,9 +1573,12 @@ mptspi_init(void) if (!mptspi_transport_template) return -ENODEV; - mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER); - mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER); - mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER); + mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER, + "mptscsih_io_done"); + mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER, + "mptscsih_taskmgmt_complete"); + mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, + MPTSPI_DRIVER, "mptscsih_scandv_complete"); mpt_event_register(mptspiDoneCtx, mptspi_event_process); mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset); diff --git a/drivers/message/i2o/Makefile b/drivers/message/i2o/Makefile index 2c2e39aa1ef..b0982dacfd0 100644 --- a/drivers/message/i2o/Makefile +++ b/drivers/message/i2o/Makefile @@ -5,7 +5,7 @@ # In the future, some of these should be built conditionally. # -i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o +i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o memory.o i2o_bus-y += bus-osm.o i2o_config-y += config-osm.o obj-$(CONFIG_I2O) += i2o_core.o diff --git a/drivers/message/i2o/README b/drivers/message/i2o/README index 911fc3021e3..f072a8eb304 100644 --- a/drivers/message/i2o/README +++ b/drivers/message/i2o/README @@ -53,7 +53,7 @@ Symbios Logic (Now LSI) BoxHill Corporation Loan of initial FibreChannel disk array used for development work. -European Comission +European Commission Funding the work done by the University of Helsinki SysKonnect diff --git a/drivers/message/i2o/README.ioctl b/drivers/message/i2o/README.ioctl index 65c0c47aeb7..4a7d2ebdfc9 100644 --- a/drivers/message/i2o/README.ioctl +++ b/drivers/message/i2o/README.ioctl @@ -110,7 +110,7 @@ V. Getting Logical Configuration Table ENOBUFS Buffer not large enough. If this occurs, the required buffer length is written into *(lct->reslen) -VI. Settting Parameters +VI. Setting Parameters SYNOPSIS @@ -138,7 +138,7 @@ VI. Settting Parameters The return value is the size in bytes of the data written into ops->resbuf if no errors occur. If an error occurs, -1 is returned - and errno is set appropriatly: + and errno is set appropriately: EFAULT Invalid user space pointer was passed ENXIO Invalid IOP number @@ -222,7 +222,7 @@ VIII. Downloading Software RETURNS This function returns 0 no errors occur. If an error occurs, -1 - is returned and errno is set appropriatly: + is returned and errno is set appropriately: EFAULT Invalid user space pointer was passed ENXIO Invalid IOP number @@ -264,7 +264,7 @@ IX. Uploading Software RETURNS This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriatly: + is returned and errno is set appropriately: EFAULT Invalid user space pointer was passed ENXIO Invalid IOP number @@ -301,7 +301,7 @@ X. Removing Software RETURNS This function returns 0 if no errors occur. If an error occurs, -1 - is returned and errno is set appropriatly: + is returned and errno is set appropriately: EFAULT Invalid user space pointer was passed ENXIO Invalid IOP number @@ -325,7 +325,7 @@ X. Validating Configuration RETURNS This function returns 0 if no erro occur. If an error occurs, -1 is - returned and errno is set appropriatly: + returned and errno is set appropriately: ETIMEDOUT Timeout waiting for reply message ENXIO Invalid IOP number @@ -360,7 +360,7 @@ XI. Configuration Dialog RETURNS This function returns 0 if no error occur. If an error occurs, -1 - is returned and errno is set appropriatly: + is returned and errno is set appropriately: EFAULT Invalid user space pointer was passed ENXIO Invalid IOP number diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h index cbe384fb848..91614f11f89 100644 --- a/drivers/message/i2o/core.h +++ b/drivers/message/i2o/core.h @@ -33,7 +33,7 @@ extern int __init i2o_pci_init(void); extern void __exit i2o_pci_exit(void); /* device */ -extern struct device_attribute i2o_device_attrs[]; +extern const struct attribute_group *i2o_device_groups[]; extern void i2o_device_remove(struct i2o_device *); extern int i2o_device_parse_lct(struct i2o_controller *); diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index 489d7c5c496..98348f420b5 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c @@ -52,7 +52,6 @@ static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd, /** * i2o_device_claim - claim a device for use by an OSM * @dev: I2O device to claim - * @drv: I2O driver which wants to claim the device * * Do the leg work to assign a device to a given OSM. If the claim succeeds, * the owner is the primary. If the attempt fails a negative errno code @@ -66,7 +65,7 @@ int i2o_device_claim(struct i2o_device *dev) rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY); if (!rc) - pr_debug("i2o: claim of device %d succeded\n", + pr_debug("i2o: claim of device %d succeeded\n", dev->lct_data.tid); else pr_debug("i2o: claim of device %d failed %d\n", @@ -80,7 +79,6 @@ int i2o_device_claim(struct i2o_device *dev) /** * i2o_device_claim_release - release a device that the OSM is using * @dev: device to release - * @drv: driver which claimed the device * * Drop a claim by an OSM on a given I2O device. * @@ -112,7 +110,7 @@ int i2o_device_claim_release(struct i2o_device *dev) } if (!rc) - pr_debug("i2o: claim release of device %d succeded\n", + pr_debug("i2o: claim release of device %d succeeded\n", dev->lct_data.tid); else pr_debug("i2o: claim release of device %d failed %d\n", @@ -134,51 +132,61 @@ static void i2o_device_release(struct device *dev) { struct i2o_device *i2o_dev = to_i2o_device(dev); - pr_debug("i2o: device %s released\n", dev->bus_id); + pr_debug("i2o: device %s released\n", dev_name(dev)); kfree(i2o_dev); } /** - * i2o_device_show_class_id - Displays class id of I2O device + * class_id_show - Displays class id of I2O device * @dev: device of which the class id should be displayed * @attr: pointer to device attribute * @buf: buffer into which the class id should be printed * * Returns the number of bytes which are printed into the buffer. */ -static ssize_t i2o_device_show_class_id(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t class_id_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct i2o_device *i2o_dev = to_i2o_device(dev); sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id); return strlen(buf) + 1; } +static DEVICE_ATTR_RO(class_id); /** - * i2o_device_show_tid - Displays TID of I2O device + * tid_show - Displays TID of I2O device * @dev: device of which the TID should be displayed * @attr: pointer to device attribute * @buf: buffer into which the TID should be printed * * Returns the number of bytes which are printed into the buffer. */ -static ssize_t i2o_device_show_tid(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t tid_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct i2o_device *i2o_dev = to_i2o_device(dev); sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid); return strlen(buf) + 1; } +static DEVICE_ATTR_RO(tid); /* I2O device attributes */ -struct device_attribute i2o_device_attrs[] = { - __ATTR(class_id, S_IRUGO, i2o_device_show_class_id, NULL), - __ATTR(tid, S_IRUGO, i2o_device_show_tid, NULL), - __ATTR_NULL +static struct attribute *i2o_device_attrs[] = { + &dev_attr_class_id.attr, + &dev_attr_tid.attr, + NULL, +}; + +static const struct attribute_group i2o_device_group = { + .attrs = i2o_device_attrs, +}; + +const struct attribute_group *i2o_device_groups[] = { + &i2o_device_group, + NULL, }; /** @@ -229,8 +237,8 @@ static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry) i2o_dev->lct_data = *entry; - snprintf(i2o_dev->device.bus_id, BUS_ID_SIZE, "%d:%03x", c->unit, - i2o_dev->lct_data.tid); + dev_set_name(&i2o_dev->device, "%d:%03x", c->unit, + i2o_dev->lct_data.tid); i2o_dev->iop = c; i2o_dev->device.parent = &c->device; @@ -243,36 +251,66 @@ static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry) /* create user entries for this device */ tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid); - if (tmp && (tmp != i2o_dev)) - sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, - "user"); + if (tmp && (tmp != i2o_dev)) { + rc = sysfs_create_link(&i2o_dev->device.kobj, + &tmp->device.kobj, "user"); + if (rc) + goto unreg_dev; + } - /* create user entries refering to this device */ + /* create user entries referring to this device */ list_for_each_entry(tmp, &c->devices, list) if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid) - && (tmp != i2o_dev)) - sysfs_create_link(&tmp->device.kobj, - &i2o_dev->device.kobj, "user"); + && (tmp != i2o_dev)) { + rc = sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "user"); + if (rc) + goto rmlink1; + } /* create parent entries for this device */ tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid); - if (tmp && (tmp != i2o_dev)) - sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj, - "parent"); + if (tmp && (tmp != i2o_dev)) { + rc = sysfs_create_link(&i2o_dev->device.kobj, + &tmp->device.kobj, "parent"); + if (rc) + goto rmlink1; + } - /* create parent entries refering to this device */ + /* create parent entries referring to this device */ list_for_each_entry(tmp, &c->devices, list) if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) - && (tmp != i2o_dev)) - sysfs_create_link(&tmp->device.kobj, - &i2o_dev->device.kobj, "parent"); + && (tmp != i2o_dev)) { + rc = sysfs_create_link(&tmp->device.kobj, + &i2o_dev->device.kobj, "parent"); + if (rc) + goto rmlink2; + } i2o_driver_notify_device_add_all(i2o_dev); - pr_debug("i2o: device %s added\n", i2o_dev->device.bus_id); + pr_debug("i2o: device %s added\n", dev_name(&i2o_dev->device)); return 0; +rmlink2: + /* If link creating failed halfway, we loop whole list to cleanup. + * And we don't care wrong removing of link, because sysfs_remove_link + * will take care of it. + */ + list_for_each_entry(tmp, &c->devices, list) { + if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "parent"); + } + sysfs_remove_link(&i2o_dev->device.kobj, "parent"); +rmlink1: + list_for_each_entry(tmp, &c->devices, list) + if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid) + sysfs_remove_link(&tmp->device.kobj, "user"); + sysfs_remove_link(&i2o_dev->device.kobj, "user"); +unreg_dev: + list_del(&i2o_dev->list); + device_unregister(&i2o_dev->device); err: kfree(i2o_dev); return rc; @@ -437,7 +475,7 @@ int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist, res.virt = NULL; - if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL)) + if (i2o_dma_alloc(dev, &res, reslen)) return -ENOMEM; msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index e0d474b1743..1b18a0d1d05 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -62,7 +62,7 @@ static int i2o_bus_match(struct device *dev, struct device_driver *drv) struct bus_type i2o_bus_type = { .name = "i2o", .match = i2o_bus_match, - .dev_attrs = i2o_device_attrs + .dev_groups = i2o_device_groups, }; /** @@ -84,7 +84,8 @@ int i2o_driver_register(struct i2o_driver *drv) osm_debug("Register driver %s\n", drv->name); if (drv->event) { - drv->event_queue = create_workqueue(drv->name); + drv->event_queue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, + drv->name); if (!drv->event_queue) { osm_err("Could not initialize event queue for driver " "%s\n", drv->name); @@ -104,7 +105,8 @@ int i2o_driver_register(struct i2o_driver *drv) osm_err("too many drivers registered, increase " "max_drivers\n"); spin_unlock_irqrestore(&i2o_drivers_lock, flags); - return -EFAULT; + rc = -EFAULT; + goto out; } drv->context = i; @@ -123,11 +125,14 @@ int i2o_driver_register(struct i2o_driver *drv) } rc = driver_register(&drv->driver); - if (rc) { - if (drv->event) { - destroy_workqueue(drv->event_queue); - drv->event_queue = NULL; - } + if (rc) + goto out; + + return 0; +out: + if (drv->event_queue) { + destroy_workqueue(drv->event_queue); + drv->event_queue = NULL; } return rc; @@ -173,7 +178,6 @@ void i2o_driver_unregister(struct i2o_driver *drv) * i2o_driver_dispatch - dispatch an I2O reply message * @c: I2O controller of the message * @m: I2O message number - * @msg: I2O message to be delivered * * The reply is delivered to the driver from which the original message * was. This function is only called from interrupt context. diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 6cbcc21de51..a3970e56ae5 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -19,7 +19,7 @@ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> * Deepak Saxena <deepak@plexity.net> * Boji T Kannanthanam <boji.t.kannanthanam@intel.com> - * Alan Cox <alan@redhat.com>: + * Alan Cox <alan@lxorguk.ukuu.org.uk>: * Ported to Linux 2.5. * Markus Lidel <Markus.Lidel@shadowconnect.com>: * Minor fixes for 2.6. @@ -388,13 +388,17 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) dev = &c->pdev->dev; - if (i2o_dma_realloc - (dev, &c->dlct, le32_to_cpu(sb->expected_lct_size), GFP_KERNEL)) + if (i2o_dma_realloc(dev, &c->dlct, + le32_to_cpu(sb->expected_lct_size))) { + mutex_unlock(&c->lct_lock); return -ENOMEM; + } msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); - if (IS_ERR(msg)) + if (IS_ERR(msg)) { + mutex_unlock(&c->lct_lock); return PTR_ERR(msg); + } msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6); msg->u.head[1] = cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index a9531489740..6fc3866965d 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -51,7 +51,9 @@ */ #include <linux/module.h> +#include <linux/slab.h> #include <linux/i2o.h> +#include <linux/mutex.h> #include <linux/mempool.h> @@ -67,6 +69,7 @@ #define OSM_VERSION "1.325" #define OSM_DESCRIPTION "I2O Block Device OSM" +static DEFINE_MUTEX(i2o_block_mutex); static struct i2o_driver i2o_block_driver; /* global Block OSM request mempool */ @@ -306,7 +309,7 @@ static inline void i2o_block_request_free(struct i2o_block_request *ireq) * @ireq: I2O block request * @mptr: message body pointer * - * Builds the SG list and map it to be accessable by the controller. + * Builds the SG list and map it to be accessible by the controller. * * Returns 0 on failure or 1 on success. */ @@ -354,7 +357,7 @@ static inline void i2o_block_sglist_free(struct i2o_block_request *ireq) * @req: the request to prepare * * Allocate the necessary i2o_block_request struct and connect it to - * the request. This is needed that we not loose the SG list later on. + * the request. This is needed that we not lose the SG list later on. * * Returns BLKPREP_OK on success or BLKPREP_DEFER on failure. */ @@ -371,7 +374,7 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) /* connect the i2o_block_request to the request */ if (!req->special) { ireq = i2o_block_request_alloc(); - if (unlikely(IS_ERR(ireq))) { + if (IS_ERR(ireq)) { osm_debug("unable to allocate i2o_block_request!\n"); return BLKPREP_DEFER; } @@ -426,15 +429,9 @@ static void i2o_block_end_request(struct request *req, int error, struct request_queue *q = req->q; unsigned long flags; - if (blk_end_request(req, error, nr_bytes)) { - int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT); - - if (blk_pc_request(req)) - leftover = req->data_len; - + if (blk_end_request(req, error, nr_bytes)) if (error) - blk_end_request(req, -EIO, leftover); - } + blk_end_request_all(req, -EIO); spin_lock_irqsave(q->queue_lock, flags); @@ -567,21 +564,22 @@ static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls, /** * i2o_block_open - Open the block device - * @inode: inode for block device being opened - * @file: file to open + * @bdev: block device being opened + * @mode: file open mode * * Power up the device, mount and lock the media. This function is called, * if the block device is opened for access. * * Returns 0 on success or negative error code on failure. */ -static int i2o_block_open(struct inode *inode, struct file *file) +static int i2o_block_open(struct block_device *bdev, fmode_t mode) { - struct i2o_block_device *dev = inode->i_bdev->bd_disk->private_data; + struct i2o_block_device *dev = bdev->bd_disk->private_data; if (!dev->i2o_dev) return -ENODEV; + mutex_lock(&i2o_block_mutex); if (dev->power > 0x1f) i2o_block_device_power(dev, 0x02); @@ -590,37 +588,36 @@ static int i2o_block_open(struct inode *inode, struct file *file) i2o_block_device_lock(dev->i2o_dev, -1); osm_debug("Ready.\n"); + mutex_unlock(&i2o_block_mutex); return 0; }; /** * i2o_block_release - Release the I2O block device - * @inode: inode for block device being released - * @file: file to close + * @disk: gendisk device being released + * @mode: file open mode * * Unlock and unmount the media, and power down the device. Gets called if * the block device is closed. - * - * Returns 0 on success or negative error code on failure. */ -static int i2o_block_release(struct inode *inode, struct file *file) +static void i2o_block_release(struct gendisk *disk, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct i2o_block_device *dev = disk->private_data; u8 operation; /* - * This is to deail with the case of an application - * opening a device and then the device dissapears while + * This is to deal with the case of an application + * opening a device and then the device disappears while * it's in use, and then the application tries to release * it. ex: Unmounting a deleted RAID volume at reboot. * If we send messages, it will just cause FAILs since * the TID no longer exists. */ if (!dev->i2o_dev) - return 0; + return; + mutex_lock(&i2o_block_mutex); i2o_block_device_flush(dev->i2o_dev); i2o_block_device_unlock(dev->i2o_dev, -1); @@ -631,8 +628,7 @@ static int i2o_block_release(struct inode *inode, struct file *file) operation = 0x24; i2o_block_device_power(dev, operation); - - return 0; + mutex_unlock(&i2o_block_mutex); } static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo) @@ -644,8 +640,8 @@ static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo) /** * i2o_block_ioctl - Issue device specific ioctl calls. - * @inode: inode for block device ioctl - * @file: file for ioctl + * @bdev: block device being opened + * @mode: file open mode * @cmd: ioctl command * @arg: arg * @@ -653,59 +649,71 @@ static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo) * * Return 0 on success or negative error on failure. */ -static int i2o_block_ioctl(struct inode *inode, struct file *file, +static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; struct i2o_block_device *dev = disk->private_data; + int ret = -ENOTTY; /* Anyone capable of this syscall can do *real bad* things */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; + mutex_lock(&i2o_block_mutex); switch (cmd) { case BLKI2OGRSTRAT: - return put_user(dev->rcache, (int __user *)arg); + ret = put_user(dev->rcache, (int __user *)arg); + break; case BLKI2OGWSTRAT: - return put_user(dev->wcache, (int __user *)arg); + ret = put_user(dev->wcache, (int __user *)arg); + break; case BLKI2OSRSTRAT: + ret = -EINVAL; if (arg < 0 || arg > CACHE_SMARTFETCH) - return -EINVAL; + break; dev->rcache = arg; + ret = 0; break; case BLKI2OSWSTRAT: + ret = -EINVAL; if (arg != 0 && (arg < CACHE_WRITETHROUGH || arg > CACHE_SMARTBACK)) - return -EINVAL; + break; dev->wcache = arg; + ret = 0; break; } - return -ENOTTY; + mutex_unlock(&i2o_block_mutex); + + return ret; }; /** - * i2o_block_media_changed - Have we seen a media change? + * i2o_block_check_events - Have we seen a media change? * @disk: gendisk which should be verified + * @clearing: events being cleared * * Verifies if the media has changed. * * Returns 1 if the media was changed or 0 otherwise. */ -static int i2o_block_media_changed(struct gendisk *disk) +static unsigned int i2o_block_check_events(struct gendisk *disk, + unsigned int clearing) { struct i2o_block_device *p = disk->private_data; if (p->media_change_flag) { p->media_change_flag = 0; - return 1; + return DISK_EVENT_MEDIA_CHANGE; } return 0; } /** * i2o_block_transfer - Transfer a request to/from the I2O controller - * @req: the request which should be transfered + * @req: the request which should be transferred * * This function converts the request into a I2O message. The necessary * DMA buffers are allocated and after everything is setup post the message @@ -718,7 +726,7 @@ static int i2o_block_transfer(struct request *req) { struct i2o_block_device *dev = req->rq_disk->private_data; struct i2o_controller *c; - u32 tid = dev->i2o_dev->lct_data.tid; + u32 tid; struct i2o_message *msg; u32 *mptr; struct i2o_block_request *ireq = req->special; @@ -734,6 +742,7 @@ static int i2o_block_transfer(struct request *req) goto exit; } + tid = dev->i2o_dev->lct_data.tid; c = dev->i2o_dev->iop; msg = i2o_msg_get(c); @@ -762,7 +771,7 @@ static int i2o_block_transfer(struct request *req) break; case CACHE_SMARTFETCH: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x201F0008; else ctl_flags = 0x001F0000; @@ -782,13 +791,13 @@ static int i2o_block_transfer(struct request *req) ctl_flags = 0x001F0010; break; case CACHE_SMARTBACK: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x001F0004; else ctl_flags = 0x001F0010; break; case CACHE_SMARTTHROUGH: - if (req->nr_sectors > 16) + if (blk_rq_sectors(req) > 16) ctl_flags = 0x001F0004; else ctl_flags = 0x001F0010; @@ -801,8 +810,9 @@ static int i2o_block_transfer(struct request *req) if (c->adaptec) { u8 cmd[10]; u32 scsi_flags; - u16 hwsec = queue_hardsect_size(req->q) >> KERNEL_SECTOR_SHIFT; + u16 hwsec; + hwsec = queue_logical_block_size(req->q) >> KERNEL_SECTOR_SHIFT; memset(cmd, 0, 10); sgl_offset = SGL_OFFSET_12; @@ -828,22 +838,22 @@ static int i2o_block_transfer(struct request *req) *mptr++ = cpu_to_le32(scsi_flags); - *((u32 *) & cmd[2]) = cpu_to_be32(req->sector * hwsec); - *((u16 *) & cmd[7]) = cpu_to_be16(req->nr_sectors * hwsec); + *((u32 *) & cmd[2]) = cpu_to_be32(blk_rq_pos(req) * hwsec); + *((u16 *) & cmd[7]) = cpu_to_be16(blk_rq_sectors(req) * hwsec); memcpy(mptr, cmd, 10); mptr += 4; - *mptr++ = cpu_to_le32(req->nr_sectors << KERNEL_SECTOR_SHIFT); + *mptr++ = cpu_to_le32(blk_rq_bytes(req)); } else #endif { msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid); *mptr++ = cpu_to_le32(ctl_flags); - *mptr++ = cpu_to_le32(req->nr_sectors << KERNEL_SECTOR_SHIFT); + *mptr++ = cpu_to_le32(blk_rq_bytes(req)); *mptr++ = - cpu_to_le32((u32) (req->sector << KERNEL_SECTOR_SHIFT)); + cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT)); *mptr++ = - cpu_to_le32(req->sector >> (32 - KERNEL_SECTOR_SHIFT)); + cpu_to_le32(blk_rq_pos(req) >> (32 - KERNEL_SECTOR_SHIFT)); } if (!i2o_block_sglist_alloc(c, ireq, &mptr)) { @@ -883,12 +893,8 @@ static void i2o_block_request_fn(struct request_queue *q) { struct request *req; - while (!blk_queue_plugged(q)) { - req = elv_next_request(q); - if (!req) - break; - - if (blk_fs_request(req)) { + while ((req = blk_peek_request(q)) != NULL) { + if (req->cmd_type == REQ_TYPE_FS) { struct i2o_block_delayed_request *dreq; struct i2o_block_request *ireq = req->special; unsigned int queue_depth; @@ -897,7 +903,7 @@ static void i2o_block_request_fn(struct request_queue *q) if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) { if (!i2o_block_transfer(req)) { - blkdev_dequeue_request(req); + blk_start_request(req); continue; } else osm_info("transfer error\n"); @@ -923,19 +929,22 @@ static void i2o_block_request_fn(struct request_queue *q) blk_stop_queue(q); break; } - } else - end_request(req, 0); + } else { + blk_start_request(req); + __blk_end_request_all(req, -EIO); + } } }; /* I2O Block device operations definition */ -static struct block_device_operations i2o_block_fops = { +static const struct block_device_operations i2o_block_fops = { .owner = THIS_MODULE, .open = i2o_block_open, .release = i2o_block_release, .ioctl = i2o_block_ioctl, + .compat_ioctl = i2o_block_ioctl, .getgeo = i2o_block_getgeo, - .media_changed = i2o_block_media_changed + .check_events = i2o_block_check_events, }; /** @@ -944,7 +953,7 @@ static struct block_device_operations i2o_block_fops = { * Allocate memory for the i2o_block_device struct, gendisk and request * queue and initialize them as far as no additional information is needed. * - * Returns a pointer to the allocated I2O Block device on succes or a + * Returns a pointer to the allocated I2O Block device on success or a * negative error code on failure. */ static struct i2o_block_device *i2o_block_device_alloc(void) @@ -1069,9 +1078,8 @@ static int i2o_block_probe(struct device *dev) queue = gd->queue; queue->queuedata = i2o_blk_dev; - blk_queue_max_phys_segments(queue, I2O_MAX_PHYS_SEGMENTS); - blk_queue_max_sectors(queue, max_sectors); - blk_queue_max_hw_segments(queue, i2o_sg_tablesize(c, body_size)); + blk_queue_max_hw_sectors(queue, max_sectors); + blk_queue_max_segments(queue, i2o_sg_tablesize(c, body_size)); osm_debug("max sectors = %d\n", queue->max_sectors); osm_debug("phys segments = %d\n", queue->max_phys_segments); @@ -1083,7 +1091,7 @@ static int i2o_block_probe(struct device *dev) */ if (!i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) || !i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) { - blk_queue_hardsect_size(queue, le32_to_cpu(blocksize)); + blk_queue_logical_block_size(queue, le32_to_cpu(blocksize)); } else osm_warn("unable to get blocksize of %s\n", gd->disk_name); diff --git a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h index 67f921b4419..cf8873cbca3 100644 --- a/drivers/message/i2o/i2o_block.h +++ b/drivers/message/i2o/i2o_block.h @@ -73,7 +73,7 @@ struct i2o_block_device { struct i2o_device *i2o_dev; /* pointer to I2O device */ struct gendisk *gd; spinlock_t lock; /* queue lock */ - struct list_head open_queue; /* list of transfered, but unfinished + struct list_head open_queue; /* list of transferred, but unfinished requests */ unsigned int open_queue_depth; /* number of requests in the queue */ diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c index c0fb77dc19b..04bd3b6de40 100644 --- a/drivers/message/i2o/i2o_config.c +++ b/drivers/message/i2o/i2o_config.c @@ -19,7 +19,7 @@ * Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel() * Deepak Saxena (11/18/1999): * Added event managmenet support - * Alan Cox <alan@redhat.com>: + * Alan Cox <alan@lxorguk.ukuu.org.uk>: * 2.4 rewrite ported to 2.5 * Markus Lidel <Markus.Lidel@shadowconnect.com>: * Added pass-thru support for Adaptec's raidutils @@ -31,8 +31,9 @@ */ #include <linux/miscdevice.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compat.h> +#include <linux/slab.h> #include <asm/uaccess.h> @@ -40,8 +41,8 @@ #define SG_TABLESIZE 30 -static int i2o_cfg_ioctl(struct inode *, struct file *, unsigned int, - unsigned long); +static DEFINE_MUTEX(i2o_cfg_mutex); +static long i2o_cfg_ioctl(struct file *, unsigned int, unsigned long); static spinlock_t i2o_config_lock; @@ -111,11 +112,11 @@ static int i2o_cfg_gethrt(unsigned long arg) len = 8 + ((hrt->entry_len * hrt->num_entries) << 2); - /* We did a get user...so assuming mem is ok...is this bad? */ - put_user(len, kcmd.reslen); - if (len > reslen) + if (put_user(len, kcmd.reslen)) + ret = -EFAULT; + else if (len > reslen) ret = -ENOBUFS; - if (copy_to_user(kcmd.resbuf, (void *)hrt, len)) + else if (copy_to_user(kcmd.resbuf, (void *)hrt, len)) ret = -EFAULT; return ret; @@ -147,8 +148,9 @@ static int i2o_cfg_getlct(unsigned long arg) lct = (i2o_lct *) c->lct; len = (unsigned int)lct->table_size << 2; - put_user(len, kcmd.reslen); - if (len > reslen) + if (put_user(len, kcmd.reslen)) + ret = -EFAULT; + else if (len > reslen) ret = -ENOBUFS; else if (copy_to_user(kcmd.resbuf, lct, len)) ret = -EFAULT; @@ -186,14 +188,16 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type) if (!dev) return -ENXIO; - ops = kmalloc(kcmd.oplen, GFP_KERNEL); - if (!ops) - return -ENOMEM; + /* + * Stop users being able to try and allocate arbitrary amounts + * of DMA space. 64K is way more than sufficient for this. + */ + if (kcmd.oplen > 65536) + return -EMSGSIZE; - if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) { - kfree(ops); - return -EFAULT; - } + ops = memdup_user(kcmd.opbuf, kcmd.oplen); + if (IS_ERR(ops)) + return PTR_ERR(ops); /* * It's possible to have a _very_ large table @@ -213,8 +217,9 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type) return -EAGAIN; } - put_user(len, kcmd.reslen); - if (len > reslen) + if (put_user(len, kcmd.reslen)) + ret = -EFAULT; + else if (len > reslen) ret = -ENOBUFS; else if (copy_to_user(kcmd.resbuf, res, len)) ret = -EFAULT; @@ -260,7 +265,7 @@ static int i2o_cfg_swdl(unsigned long arg) if (IS_ERR(msg)) return PTR_ERR(msg); - if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) { + if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) { i2o_msg_nop(c, msg); return -ENOMEM; } @@ -314,22 +319,22 @@ static int i2o_cfg_swul(unsigned long arg) int ret = 0; if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) - goto return_fault; + return -EFAULT; if (get_user(swlen, kxfer.swlen) < 0) - goto return_fault; + return -EFAULT; if (get_user(maxfrag, kxfer.maxfrag) < 0) - goto return_fault; + return -EFAULT; if (get_user(curfrag, kxfer.curfrag) < 0) - goto return_fault; + return -EFAULT; if (curfrag == maxfrag) fragsize = swlen - (maxfrag - 1) * 8192; if (!kxfer.buf) - goto return_fault; + return -EFAULT; c = i2o_find_iop(kxfer.iop); if (!c) @@ -339,7 +344,7 @@ static int i2o_cfg_swul(unsigned long arg) if (IS_ERR(msg)) return PTR_ERR(msg); - if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) { + if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) { i2o_msg_nop(c, msg); return -ENOMEM; } @@ -373,12 +378,8 @@ static int i2o_cfg_swul(unsigned long arg) i2o_dma_free(&c->pdev->dev, &buffer); - return_ret: return ret; - return_fault: - ret = -EFAULT; - goto return_ret; -}; +} static int i2o_cfg_swdel(unsigned long arg) { @@ -634,9 +635,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, sg_size = sg[i].flag_count & 0xffffff; p = &(sg_list[sg_index]); /* Allocate memory for the transfer */ - if (i2o_dma_alloc - (&c->pdev->dev, p, sg_size, - PCI_DMA_BIDIRECTIONAL)) { + if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) { printk(KERN_DEBUG "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", c->name, sg_size, i, sg_count); @@ -688,6 +687,11 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, } size = size >> 16; size *= 4; + if (size > sizeof(rmsg)) { + rcode = -EINVAL; + goto sg_list_cleanup; + } + /* Copy in the user's I2O command */ if (copy_from_user(rmsg, user_msg, size)) { rcode = -EFAULT; @@ -750,19 +754,19 @@ static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) { int ret; - lock_kernel(); switch (cmd) { case I2OGETIOPS: - ret = i2o_cfg_ioctl(NULL, file, cmd, arg); + ret = i2o_cfg_ioctl(file, cmd, arg); break; case I2OPASSTHRU32: + mutex_lock(&i2o_cfg_mutex); ret = i2o_cfg_passthru32(file, cmd, arg); + mutex_unlock(&i2o_cfg_mutex); break; default: ret = -ENOIOCTLCMD; break; } - unlock_kernel(); return ret; } @@ -780,12 +784,11 @@ static int i2o_cfg_passthru(unsigned long arg) u32 size = 0; u32 reply_size = 0; u32 rcode = 0; - void *sg_list[SG_TABLESIZE]; + struct i2o_dma sg_list[SG_TABLESIZE]; u32 sg_offset = 0; u32 sg_count = 0; int sg_index = 0; u32 i = 0; - void *p = NULL; i2o_status_block *sb; struct i2o_message *msg; unsigned int iop; @@ -842,6 +845,7 @@ static int i2o_cfg_passthru(unsigned long arg) memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE); if (sg_offset) { struct sg_simple_element *sg; + struct i2o_dma *p; if (sg_offset * 4 >= size) { rcode = -EFAULT; @@ -871,22 +875,22 @@ static int i2o_cfg_passthru(unsigned long arg) goto sg_list_cleanup; } sg_size = sg[i].flag_count & 0xffffff; + p = &(sg_list[sg_index]); + if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) { /* Allocate memory for the transfer */ - p = kmalloc(sg_size, GFP_KERNEL); - if (!p) { printk(KERN_DEBUG "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", c->name, sg_size, i, sg_count); rcode = -ENOMEM; goto sg_list_cleanup; } - sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. + sg_index++; /* Copy in the user's SG buffer if necessary */ if (sg[i]. flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) { // TODO 64bit fix if (copy_from_user - (p, (void __user *)sg[i].addr_bus, + (p->virt, (void __user *)sg[i].addr_bus, sg_size)) { printk(KERN_DEBUG "%s: Could not copy SG buf %d FROM user\n", @@ -895,8 +899,7 @@ static int i2o_cfg_passthru(unsigned long arg) goto sg_list_cleanup; } } - //TODO 64bit fix - sg[i].addr_bus = virt_to_bus(p); + sg[i].addr_bus = p->phys; } } @@ -908,7 +911,7 @@ static int i2o_cfg_passthru(unsigned long arg) } if (sg_offset) { - u32 rmsg[128]; + u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE]; /* Copy back the Scatter Gather buffers back to user space */ u32 j; // TODO 64bit fix @@ -924,6 +927,11 @@ static int i2o_cfg_passthru(unsigned long arg) } size = size >> 16; size *= 4; + if (size > sizeof(rmsg)) { + rcode = -EFAULT; + goto sg_list_cleanup; + } + /* Copy in the user's I2O command */ if (copy_from_user(rmsg, user_msg, size)) { rcode = -EFAULT; @@ -942,11 +950,11 @@ static int i2o_cfg_passthru(unsigned long arg) sg_size = sg[j].flag_count & 0xffffff; // TODO 64bit fix if (copy_to_user - ((void __user *)sg[j].addr_bus, sg_list[j], + ((void __user *)sg[j].addr_bus, sg_list[j].virt, sg_size)) { printk(KERN_WARNING "%s: Could not copy %p TO user %x\n", - c->name, sg_list[j], + c->name, sg_list[j].virt, sg[j].addr_bus); rcode = -EFAULT; goto sg_list_cleanup; @@ -973,7 +981,7 @@ sg_list_cleanup: } for (i = 0; i < sg_index; i++) - kfree(sg_list[i]); + i2o_dma_free(&c->pdev->dev, &sg_list[i]); cleanup: kfree(reply); @@ -987,11 +995,11 @@ out: /* * IOCTL Handler */ -static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, - unsigned long arg) +static long i2o_cfg_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { int ret; + mutex_lock(&i2o_cfg_mutex); switch (cmd) { case I2OGETIOPS: ret = i2o_cfg_getiops(arg); @@ -1047,20 +1055,20 @@ static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, osm_debug("unknown ioctl called!\n"); ret = -EINVAL; } - + mutex_unlock(&i2o_cfg_mutex); return ret; } static int cfg_open(struct inode *inode, struct file *file) { - struct i2o_cfg_info *tmp = - (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), + struct i2o_cfg_info *tmp = kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL); unsigned long flags; if (!tmp) return -ENOMEM; + mutex_lock(&i2o_cfg_mutex); file->private_data = (void *)(i2o_cfg_info_id++); tmp->fp = file; tmp->fasync = NULL; @@ -1074,6 +1082,7 @@ static int cfg_open(struct inode *inode, struct file *file) spin_lock_irqsave(&i2o_config_lock, flags); open_files = tmp; spin_unlock_irqrestore(&i2o_config_lock, flags); + mutex_unlock(&i2o_cfg_mutex); return 0; } @@ -1082,45 +1091,36 @@ static int cfg_fasync(int fd, struct file *fp, int on) { ulong id = (ulong) fp->private_data; struct i2o_cfg_info *p; + int ret = -EBADF; + mutex_lock(&i2o_cfg_mutex); for (p = open_files; p; p = p->next) if (p->q_id == id) break; - if (!p) - return -EBADF; - - return fasync_helper(fd, fp, on, &p->fasync); + if (p) + ret = fasync_helper(fd, fp, on, &p->fasync); + mutex_unlock(&i2o_cfg_mutex); + return ret; } static int cfg_release(struct inode *inode, struct file *file) { ulong id = (ulong) file->private_data; - struct i2o_cfg_info *p1, *p2; + struct i2o_cfg_info *p, **q; unsigned long flags; - lock_kernel(); - p1 = p2 = NULL; - + mutex_lock(&i2o_cfg_mutex); spin_lock_irqsave(&i2o_config_lock, flags); - for (p1 = open_files; p1;) { - if (p1->q_id == id) { - - if (p1->fasync) - cfg_fasync(-1, file, 0); - if (p2) - p2->next = p1->next; - else - open_files = p1->next; - - kfree(p1); + for (q = &open_files; (p = *q) != NULL; q = &p->next) { + if (p->q_id == id) { + *q = p->next; + kfree(p); break; } - p2 = p1; - p1 = p1->next; } spin_unlock_irqrestore(&i2o_config_lock, flags); - unlock_kernel(); + mutex_unlock(&i2o_cfg_mutex); return 0; } @@ -1128,7 +1128,7 @@ static int cfg_release(struct inode *inode, struct file *file) static const struct file_operations config_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .ioctl = i2o_cfg_ioctl, + .unlocked_ioctl = i2o_cfg_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = i2o_cfg_compat_ioctl, #endif diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c index 6fdd072201f..b7d87cd227a 100644 --- a/drivers/message/i2o/i2o_proc.c +++ b/drivers/message/i2o/i2o_proc.c @@ -40,6 +40,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/i2o.h> +#include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/init.h> @@ -55,7 +56,7 @@ /* Structure used to define /proc entries */ typedef struct _i2o_proc_entry_t { char *name; /* entry name */ - mode_t mode; /* mode */ + umode_t mode; /* mode */ const struct file_operations *fops; /* open function */ } i2o_proc_entry; @@ -111,10 +112,7 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len) break; case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */ - seq_printf(seq, - "LAN-48 MAC address @ %02X:%02X:%02X:%02X:%02X:%02X", - serialno[2], serialno[3], - serialno[4], serialno[5], serialno[6], serialno[7]); + seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]); break; case I2O_SNFORMAT_WAN: /* WAN MAC Address */ @@ -126,10 +124,8 @@ static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len) case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */ /* FIXME: Figure out what a LAN-64 address really looks like?? */ seq_printf(seq, - "LAN-64 MAC address @ [?:%02X:%02X:?] %02X:%02X:%02X:%02X:%02X:%02X", - serialno[8], serialno[9], - serialno[2], serialno[3], - serialno[4], serialno[5], serialno[6], serialno[7]); + "LAN-64 MAC address @ [?:%02X:%02X:?] %pM", + serialno[8], serialno[9], &serialno[2]); break; case I2O_SNFORMAT_DDM: /* I2O DDM */ @@ -259,9 +255,8 @@ static char *scsi_devices[] = { "Array Controller Device" }; -static char *chtostr(u8 * chars, int n) +static char *chtostr(char *tmp, u8 *chars, int n) { - char tmp[256]; tmp[0] = 0; return strncat(tmp, (char *)chars, n); } @@ -287,7 +282,6 @@ static char *bus_strings[] = { "Local Bus", "ISA", "EISA", - "MCA", "PCI", "PCMCIA", "NUBUS", @@ -355,18 +349,6 @@ static int i2o_seq_show_hrt(struct seq_file *seq, void *v) EisaSlotNumber); break; - case I2O_BUS_MCA: - seq_printf(seq, " IOBase: %0#6x,", - hrt->hrt_entry[i].bus.mca_bus. - McaBaseIOPort); - seq_printf(seq, " MemoryBase: %0#10x,", - hrt->hrt_entry[i].bus.mca_bus. - McaBaseMemoryAddress); - seq_printf(seq, " Slot: %0#4x,", - hrt->hrt_entry[i].bus.mca_bus. - McaSlotNumber); - break; - case I2O_BUS_PCI: seq_printf(seq, " Bus: %0#4x", hrt->hrt_entry[i].bus.pci_bus. @@ -808,6 +790,7 @@ static int i2o_seq_show_ddm_table(struct seq_file *seq, void *v) } *result; i2o_exec_execute_ddm_table ddm_table; + char tmp[28 + 1]; result = kmalloc(sizeof(*result), GFP_KERNEL); if (!result) @@ -843,7 +826,7 @@ static int i2o_seq_show_ddm_table(struct seq_file *seq, void *v) seq_printf(seq, "%-#7x", ddm_table.i2o_vendor_id); seq_printf(seq, "%-#8x", ddm_table.module_id); seq_printf(seq, "%-29s", - chtostr(ddm_table.module_name_version, 28)); + chtostr(tmp, ddm_table.module_name_version, 28)); seq_printf(seq, "%9d ", ddm_table.data_size); seq_printf(seq, "%8d", ddm_table.code_size); @@ -910,6 +893,7 @@ static int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v) i2o_driver_result_table *result; i2o_driver_store_table *dst; + char tmp[28 + 1]; result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL); if (result == NULL) @@ -944,8 +928,9 @@ static int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v) seq_printf(seq, "%-#7x", dst->i2o_vendor_id); seq_printf(seq, "%-#8x", dst->module_id); - seq_printf(seq, "%-29s", chtostr(dst->module_name_version, 28)); - seq_printf(seq, "%-9s", chtostr(dst->date, 8)); + seq_printf(seq, "%-29s", + chtostr(tmp, dst->module_name_version, 28)); + seq_printf(seq, "%-9s", chtostr(tmp, dst->date, 8)); seq_printf(seq, "%8d ", dst->module_size); seq_printf(seq, "%8d ", dst->mpb_size); seq_printf(seq, "0x%04x", dst->module_flags); @@ -1265,6 +1250,7 @@ static int i2o_seq_show_dev_identity(struct seq_file *seq, void *v) // == (allow) 512d bytes (max) static u16 *work16 = (u16 *) work32; int token; + char tmp[16 + 1]; token = i2o_parm_field_get(d, 0xF100, -1, &work32, sizeof(work32)); @@ -1277,13 +1263,13 @@ static int i2o_seq_show_dev_identity(struct seq_file *seq, void *v) seq_printf(seq, "Owner TID : %0#5x\n", work16[2]); seq_printf(seq, "Parent TID : %0#5x\n", work16[3]); seq_printf(seq, "Vendor info : %s\n", - chtostr((u8 *) (work32 + 2), 16)); + chtostr(tmp, (u8 *) (work32 + 2), 16)); seq_printf(seq, "Product info : %s\n", - chtostr((u8 *) (work32 + 6), 16)); + chtostr(tmp, (u8 *) (work32 + 6), 16)); seq_printf(seq, "Description : %s\n", - chtostr((u8 *) (work32 + 10), 16)); + chtostr(tmp, (u8 *) (work32 + 10), 16)); seq_printf(seq, "Product rev. : %s\n", - chtostr((u8 *) (work32 + 14), 8)); + chtostr(tmp, (u8 *) (work32 + 14), 8)); seq_printf(seq, "Serial number : "); print_serial_number(seq, (u8 *) (work32 + 16), @@ -1300,7 +1286,7 @@ static int i2o_seq_show_dev_name(struct seq_file *seq, void *v) { struct i2o_device *d = (struct i2o_device *)seq->private; - seq_printf(seq, "%s\n", d->device.bus_id); + seq_printf(seq, "%s\n", dev_name(&d->device)); return 0; } @@ -1320,6 +1306,8 @@ static int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v) u8 pad[256]; // allow up to 256 byte (max) serial number } result; + char tmp[24 + 1]; + token = i2o_parm_field_get(d, 0xF101, -1, &result, sizeof(result)); if (token < 0) { @@ -1329,9 +1317,9 @@ static int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v) seq_printf(seq, "Registering DDM TID : 0x%03x\n", result.ddm_tid); seq_printf(seq, "Module name : %s\n", - chtostr(result.module_name, 24)); + chtostr(tmp, result.module_name, 24)); seq_printf(seq, "Module revision : %s\n", - chtostr(result.module_rev, 8)); + chtostr(tmp, result.module_rev, 8)); seq_printf(seq, "Serial number : "); print_serial_number(seq, result.serial_number, sizeof(result) - 36); @@ -1355,6 +1343,8 @@ static int i2o_seq_show_uinfo(struct seq_file *seq, void *v) u8 instance_number[4]; } result; + char tmp[64 + 1]; + token = i2o_parm_field_get(d, 0xF102, -1, &result, sizeof(result)); if (token < 0) { @@ -1363,13 +1353,13 @@ static int i2o_seq_show_uinfo(struct seq_file *seq, void *v) } seq_printf(seq, "Device name : %s\n", - chtostr(result.device_name, 64)); + chtostr(tmp, result.device_name, 64)); seq_printf(seq, "Service name : %s\n", - chtostr(result.service_name, 64)); + chtostr(tmp, result.service_name, 64)); seq_printf(seq, "Physical name : %s\n", - chtostr(result.physical_location, 64)); + chtostr(tmp, result.physical_location, 64)); seq_printf(seq, "Instance number : %s\n", - chtostr(result.instance_number, 4)); + chtostr(tmp, result.instance_number, 4)); return 0; } @@ -1609,98 +1599,98 @@ static int i2o_seq_show_sensors(struct seq_file *seq, void *v) static int i2o_seq_open_hrt(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_hrt, PDE(inode)->data); + return single_open(file, i2o_seq_show_hrt, PDE_DATA(inode)); }; static int i2o_seq_open_lct(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_lct, PDE(inode)->data); + return single_open(file, i2o_seq_show_lct, PDE_DATA(inode)); }; static int i2o_seq_open_status(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_status, PDE(inode)->data); + return single_open(file, i2o_seq_show_status, PDE_DATA(inode)); }; static int i2o_seq_open_hw(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_hw, PDE(inode)->data); + return single_open(file, i2o_seq_show_hw, PDE_DATA(inode)); }; static int i2o_seq_open_ddm_table(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_ddm_table, PDE(inode)->data); + return single_open(file, i2o_seq_show_ddm_table, PDE_DATA(inode)); }; static int i2o_seq_open_driver_store(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_driver_store, PDE(inode)->data); + return single_open(file, i2o_seq_show_driver_store, PDE_DATA(inode)); }; static int i2o_seq_open_drivers_stored(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_drivers_stored, PDE(inode)->data); + return single_open(file, i2o_seq_show_drivers_stored, PDE_DATA(inode)); }; static int i2o_seq_open_groups(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_groups, PDE(inode)->data); + return single_open(file, i2o_seq_show_groups, PDE_DATA(inode)); }; static int i2o_seq_open_phys_device(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_phys_device, PDE(inode)->data); + return single_open(file, i2o_seq_show_phys_device, PDE_DATA(inode)); }; static int i2o_seq_open_claimed(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_claimed, PDE(inode)->data); + return single_open(file, i2o_seq_show_claimed, PDE_DATA(inode)); }; static int i2o_seq_open_users(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_users, PDE(inode)->data); + return single_open(file, i2o_seq_show_users, PDE_DATA(inode)); }; static int i2o_seq_open_priv_msgs(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_priv_msgs, PDE(inode)->data); + return single_open(file, i2o_seq_show_priv_msgs, PDE_DATA(inode)); }; static int i2o_seq_open_authorized_users(struct inode *inode, struct file *file) { return single_open(file, i2o_seq_show_authorized_users, - PDE(inode)->data); + PDE_DATA(inode)); }; static int i2o_seq_open_dev_identity(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_dev_identity, PDE(inode)->data); + return single_open(file, i2o_seq_show_dev_identity, PDE_DATA(inode)); }; static int i2o_seq_open_ddm_identity(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_ddm_identity, PDE(inode)->data); + return single_open(file, i2o_seq_show_ddm_identity, PDE_DATA(inode)); }; static int i2o_seq_open_uinfo(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_uinfo, PDE(inode)->data); + return single_open(file, i2o_seq_show_uinfo, PDE_DATA(inode)); }; static int i2o_seq_open_sgl_limits(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_sgl_limits, PDE(inode)->data); + return single_open(file, i2o_seq_show_sgl_limits, PDE_DATA(inode)); }; static int i2o_seq_open_sensors(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_sensors, PDE(inode)->data); + return single_open(file, i2o_seq_show_sensors, PDE_DATA(inode)); }; static int i2o_seq_open_dev_name(struct inode *inode, struct file *file) { - return single_open(file, i2o_seq_show_dev_name, PDE(inode)->data); + return single_open(file, i2o_seq_show_dev_name, PDE_DATA(inode)); }; static const struct file_operations i2o_seq_fops_lct = { @@ -1893,13 +1883,11 @@ static int i2o_proc_create_entries(struct proc_dir_entry *dir, struct proc_dir_entry *tmp; while (i2o_pe->name) { - tmp = create_proc_entry(i2o_pe->name, i2o_pe->mode, dir); + tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir, + i2o_pe->fops, data); if (!tmp) return -1; - tmp->data = data; - tmp->proc_fops = i2o_pe->fops; - i2o_pe++; } @@ -1907,25 +1895,6 @@ static int i2o_proc_create_entries(struct proc_dir_entry *dir, } /** - * i2o_proc_subdir_remove - Remove child entries from a proc entry - * @dir: proc dir entry from which the childs should be removed - * - * Iterate over each i2o proc entry under dir and remove it. If the child - * also has entries, remove them too. - */ -static void i2o_proc_subdir_remove(struct proc_dir_entry *dir) -{ - struct proc_dir_entry *pe, *tmp; - pe = dir->subdir; - while (pe) { - tmp = pe->next; - i2o_proc_subdir_remove(pe); - remove_proc_entry(pe->name, dir); - pe = tmp; - } -}; - -/** * i2o_proc_device_add - Add an I2O device to the proc dir * @dir: proc dir entry to which the device should be added * @dev: I2O device which should be added @@ -1944,14 +1913,12 @@ static void i2o_proc_device_add(struct proc_dir_entry *dir, osm_debug("adding device /proc/i2o/%s/%s\n", dev->iop->name, buff); - devdir = proc_mkdir(buff, dir); + devdir = proc_mkdir_data(buff, 0, dir, dev); if (!devdir) { osm_warn("Could not allocate procdir!\n"); return; } - devdir->data = dev; - i2o_proc_create_entries(devdir, generic_dev_entries, dev); /* Inform core that we want updates about this device's status */ @@ -1985,12 +1952,10 @@ static int i2o_proc_iop_add(struct proc_dir_entry *dir, osm_debug("adding IOP /proc/i2o/%s\n", c->name); - iopdir = proc_mkdir(c->name, dir); + iopdir = proc_mkdir_data(c->name, 0, dir, c); if (!iopdir) return -1; - iopdir->data = c; - i2o_proc_create_entries(iopdir, i2o_proc_generic_iop_entries, c); list_for_each_entry(dev, &c->devices, list) @@ -2000,31 +1965,6 @@ static int i2o_proc_iop_add(struct proc_dir_entry *dir, } /** - * i2o_proc_iop_remove - Removes an I2O controller from the i2o proc tree - * @dir: parent proc dir entry - * @c: I2O controller which should be removed - * - * Iterate over each i2o proc entry and search controller c. If it is found - * remove it from the tree. - */ -static void i2o_proc_iop_remove(struct proc_dir_entry *dir, - struct i2o_controller *c) -{ - struct proc_dir_entry *pe, *tmp; - - pe = dir->subdir; - while (pe) { - tmp = pe->next; - if (pe->data == c) { - i2o_proc_subdir_remove(pe); - remove_proc_entry(pe->name, dir); - } - osm_debug("removing IOP /proc/i2o/%s\n", c->name); - pe = tmp; - } -} - -/** * i2o_proc_fs_create - Create the i2o proc fs. * * Iterate over each I2O controller and create the entries for it. @@ -2039,8 +1979,6 @@ static int __init i2o_proc_fs_create(void) if (!i2o_proc_dir_root) return -1; - i2o_proc_dir_root->owner = THIS_MODULE; - list_for_each_entry(c, &i2o_controllers, list) i2o_proc_iop_add(i2o_proc_dir_root, c); @@ -2056,12 +1994,7 @@ static int __init i2o_proc_fs_create(void) */ static int __exit i2o_proc_fs_destroy(void) { - struct i2o_controller *c; - - list_for_each_entry(c, &i2o_controllers, list) - i2o_proc_iop_remove(i2o_proc_dir_root, c); - - remove_proc_entry("i2o", NULL); + remove_proc_subtree("i2o", NULL); return 0; }; diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index 1bcdbbb9e7d..1d31d7284cb 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -57,9 +57,8 @@ #include <linux/scatterlist.h> #include <asm/dma.h> -#include <asm/system.h> #include <asm/io.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> @@ -204,7 +203,7 @@ static int i2o_scsi_remove(struct device *dev) * i2o_scsi_probe - verify if dev is a I2O SCSI device and install it * @dev: device to verify if it is a I2O SCSI device * - * Retrieve channel, id and lun for I2O device. If everthing goes well + * Retrieve channel, id and lun for I2O device. If everything goes well * register the I2O device as SCSI device on the I2O SCSI controller. * * Returns 0 on success or negative error code on failure. @@ -361,7 +360,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m, */ error = le32_to_cpu(msg->body[0]); - osm_debug("Completed %ld\n", cmd->serial_number); + osm_debug("Completed %0x%p\n", cmd); cmd->result = error & 0xff; /* @@ -390,7 +389,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m, * @i2o_dev: the I2O device which was added * * If a I2O device is added we catch the notification, because I2O classes - * other then SCSI peripheral will not be received through + * other than SCSI peripheral will not be received through * i2o_scsi_probe(). */ static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev) @@ -506,7 +505,7 @@ static struct i2o_driver i2o_scsi_driver = { * Locks: takes the controller lock on error path only */ -static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, +static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done) (struct scsi_cmnd *)) { struct i2o_controller *c; @@ -528,7 +527,6 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, * Do the incoming paperwork */ i2o_dev = SCpnt->device->hostdata; - c = i2o_dev->iop; SCpnt->scsi_done = done; @@ -538,7 +536,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, done(SCpnt); goto exit; } - + c = i2o_dev->iop; tid = i2o_dev->lct_data.tid; osm_debug("qcmd: Tid = %03x\n", tid); @@ -679,7 +677,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, /* Queue the message */ i2o_msg_post(c, msg); - osm_debug("Issued %ld\n", SCpnt->serial_number); + osm_debug("Issued %0x%p\n", SCpnt); return 0; @@ -689,7 +687,9 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt, exit: return rc; -}; +} + +static DEF_SCSI_QCMD(i2o_scsi_queuecommand) /** * i2o_scsi_abort - abort a running command diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index da715e11c1b..92752fb5b2d 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -19,7 +19,7 @@ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> * Deepak Saxena <deepak@plexity.net> * Boji T Kannanthanam <boji.t.kannanthanam@intel.com> - * Alan Cox <alan@redhat.com>: + * Alan Cox <alan@lxorguk.ukuu.org.uk>: * Ported to Linux 2.5. * Markus Lidel <Markus.Lidel@shadowconnect.com>: * Minor fixes for 2.6. @@ -29,6 +29,7 @@ #include <linux/i2o.h> #include <linux/delay.h> #include <linux/sched.h> +#include <linux/slab.h> #include "core.h" #define OSM_NAME "i2o" @@ -49,7 +50,6 @@ static int i2o_hrt_get(struct i2o_controller *c); /** * i2o_msg_get_wait - obtain an I2O message from the IOP * @c: I2O controller - * @msg: pointer to a I2O message pointer * @wait: how long to wait until timeout * * This function waits up to wait seconds for a message slot to be @@ -133,7 +133,7 @@ u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr) * Removes a previously added pointer from the context list and returns * the matching context id. * - * Returns context id on succes or 0 on failure. + * Returns context id on success or 0 on failure. */ u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr) { @@ -199,7 +199,7 @@ void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context) * @c: controller to which the context list belong * @ptr: pointer to which the context id should be fetched * - * Returns context id which matches to the pointer on succes or 0 on + * Returns context id which matches to the pointer on success or 0 on * failure. */ u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr) @@ -540,7 +540,7 @@ static int i2o_iop_reset(struct i2o_controller *c) * which is indeterminate. We need to wait until the IOP has * rebooted before we can let the system talk to it. We read * the inbound Free_List until a message is available. If we - * can't read one in the given ammount of time, we assume the + * can't read one in the given amount of time, we assume the * IOP could not reboot properly. */ osm_debug("%s: Reset in progress, waiting for reboot...\n", @@ -652,6 +652,44 @@ static int i2o_iop_activate(struct i2o_controller *c) return i2o_hrt_get(c); }; +static void i2o_res_alloc(struct i2o_controller *c, unsigned long flags) +{ + i2o_status_block *sb = c->status_block.virt; + struct resource *res = &c->mem_resource; + resource_size_t size, align; + int err; + + res->name = c->pdev->bus->name; + res->flags = flags; + res->start = 0; + res->end = 0; + osm_info("%s: requires private memory resources.\n", c->name); + + if (flags & IORESOURCE_MEM) { + size = sb->desired_mem_size; + align = 1 << 20; /* unspecified, use 1Mb and play safe */ + } else { + size = sb->desired_io_size; + align = 1 << 12; /* unspecified, use 4Kb and play safe */ + } + + err = pci_bus_alloc_resource(c->pdev->bus, res, size, align, 0, 0, + NULL, NULL); + if (err < 0) + return; + + if (flags & IORESOURCE_MEM) { + c->mem_alloc = 1; + sb->current_mem_size = resource_size(res); + sb->current_mem_base = res->start; + } else if (flags & IORESOURCE_IO) { + c->io_alloc = 1; + sb->current_io_size = resource_size(res); + sb->current_io_base = res->start; + } + osm_info("%s: allocated PCI space %pR\n", c->name, res); +} + /** * i2o_iop_systab_set - Set the I2O System Table of the specified IOP * @c: I2O controller to which the system table should be send @@ -665,52 +703,13 @@ static int i2o_iop_systab_set(struct i2o_controller *c) struct i2o_message *msg; i2o_status_block *sb = c->status_block.virt; struct device *dev = &c->pdev->dev; - struct resource *root; int rc; - if (sb->current_mem_size < sb->desired_mem_size) { - struct resource *res = &c->mem_resource; - res->name = c->pdev->bus->name; - res->flags = IORESOURCE_MEM; - res->start = 0; - res->end = 0; - osm_info("%s: requires private memory resources.\n", c->name); - root = pci_find_parent_resource(c->pdev, res); - if (root == NULL) - osm_warn("%s: Can't find parent resource!\n", c->name); - if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ - NULL, NULL) >= 0) { - c->mem_alloc = 1; - sb->current_mem_size = 1 + res->end - res->start; - sb->current_mem_base = res->start; - osm_info("%s: allocated %llu bytes of PCI memory at " - "0x%016llX.\n", c->name, - (unsigned long long)(1 + res->end - res->start), - (unsigned long long)res->start); - } - } + if (sb->current_mem_size < sb->desired_mem_size) + i2o_res_alloc(c, IORESOURCE_MEM); - if (sb->current_io_size < sb->desired_io_size) { - struct resource *res = &c->io_resource; - res->name = c->pdev->bus->name; - res->flags = IORESOURCE_IO; - res->start = 0; - res->end = 0; - osm_info("%s: requires private memory resources.\n", c->name); - root = pci_find_parent_resource(c->pdev, res); - if (root == NULL) - osm_warn("%s: Can't find parent resource!\n", c->name); - if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ - NULL, NULL) >= 0) { - c->io_alloc = 1; - sb->current_io_size = 1 + res->end - res->start; - sb->current_mem_base = res->start; - osm_info("%s: allocated %llu bytes of PCI I/O at " - "0x%016llX.\n", c->name, - (unsigned long long)(1 + res->end - res->start), - (unsigned long long)res->start); - } - } + if (sb->current_io_size < sb->desired_io_size) + i2o_res_alloc(c, IORESOURCE_IO); msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); if (IS_ERR(msg)) @@ -1004,7 +1003,7 @@ static int i2o_hrt_get(struct i2o_controller *c) size = hrt->num_entries * hrt->entry_len << 2; if (size > c->hrt.len) { - if (i2o_dma_realloc(dev, &c->hrt, size, GFP_KERNEL)) + if (i2o_dma_realloc(dev, &c->hrt, size)) return -ENOMEM; else hrt = c->hrt.virt; @@ -1073,7 +1072,7 @@ struct i2o_controller *i2o_iop_alloc(void) c->device.release = &i2o_iop_release; - snprintf(c->device.bus_id, BUS_ID_SIZE, "iop%d", c->unit); + dev_set_name(&c->device, "iop%d", c->unit); #if BITS_PER_LONG == 64 spin_lock_init(&c->context_list_lock); diff --git a/drivers/message/i2o/memory.c b/drivers/message/i2o/memory.c new file mode 100644 index 00000000000..292b41e49fb --- /dev/null +++ b/drivers/message/i2o/memory.c @@ -0,0 +1,313 @@ +/* + * Functions to handle I2O memory + * + * Pulled from the inlines in i2o headers and uninlined + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/module.h> +#include <linux/i2o.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> +#include "core.h" + +/* Protects our 32/64bit mask switching */ +static DEFINE_MUTEX(mem_lock); + +/** + * i2o_sg_tablesize - Calculate the maximum number of elements in a SGL + * @c: I2O controller for which the calculation should be done + * @body_size: maximum body size used for message in 32-bit words. + * + * Return the maximum number of SG elements in a SG list. + */ +u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size) +{ + i2o_status_block *sb = c->status_block.virt; + u16 sg_count = + (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) - + body_size; + + if (c->pae_support) { + /* + * for 64-bit a SG attribute element must be added and each + * SG element needs 12 bytes instead of 8. + */ + sg_count -= 2; + sg_count /= 3; + } else + sg_count /= 2; + + if (c->short_req && (sg_count > 8)) + sg_count = 8; + + return sg_count; +} +EXPORT_SYMBOL_GPL(i2o_sg_tablesize); + + +/** + * i2o_dma_map_single - Map pointer to controller and fill in I2O message. + * @c: I2O controller + * @ptr: pointer to the data which should be mapped + * @size: size of data in bytes + * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE + * @sg_ptr: pointer to the SG list inside the I2O message + * + * This function does all necessary DMA handling and also writes the I2O + * SGL elements into the I2O message. For details on DMA handling see also + * dma_map_single(). The pointer sg_ptr will only be set to the end of the + * SG list if the allocation was successful. + * + * Returns DMA address which must be checked for failures using + * dma_mapping_error(). + */ +dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr, + size_t size, + enum dma_data_direction direction, + u32 ** sg_ptr) +{ + u32 sg_flags; + u32 *mptr = *sg_ptr; + dma_addr_t dma_addr; + + switch (direction) { + case DMA_TO_DEVICE: + sg_flags = 0xd4000000; + break; + case DMA_FROM_DEVICE: + sg_flags = 0xd0000000; + break; + default: + return 0; + } + + dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction); + if (!dma_mapping_error(&c->pdev->dev, dma_addr)) { +#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64 + if ((sizeof(dma_addr_t) > 4) && c->pae_support) { + *mptr++ = cpu_to_le32(0x7C020002); + *mptr++ = cpu_to_le32(PAGE_SIZE); + } +#endif + + *mptr++ = cpu_to_le32(sg_flags | size); + *mptr++ = cpu_to_le32(i2o_dma_low(dma_addr)); +#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64 + if ((sizeof(dma_addr_t) > 4) && c->pae_support) + *mptr++ = cpu_to_le32(i2o_dma_high(dma_addr)); +#endif + *sg_ptr = mptr; + } + return dma_addr; +} +EXPORT_SYMBOL_GPL(i2o_dma_map_single); + +/** + * i2o_dma_map_sg - Map a SG List to controller and fill in I2O message. + * @c: I2O controller + * @sg: SG list to be mapped + * @sg_count: number of elements in the SG list + * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE + * @sg_ptr: pointer to the SG list inside the I2O message + * + * This function does all necessary DMA handling and also writes the I2O + * SGL elements into the I2O message. For details on DMA handling see also + * dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG + * list if the allocation was successful. + * + * Returns 0 on failure or 1 on success. + */ +int i2o_dma_map_sg(struct i2o_controller *c, struct scatterlist *sg, + int sg_count, enum dma_data_direction direction, u32 ** sg_ptr) +{ + u32 sg_flags; + u32 *mptr = *sg_ptr; + + switch (direction) { + case DMA_TO_DEVICE: + sg_flags = 0x14000000; + break; + case DMA_FROM_DEVICE: + sg_flags = 0x10000000; + break; + default: + return 0; + } + + sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction); + if (!sg_count) + return 0; + +#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64 + if ((sizeof(dma_addr_t) > 4) && c->pae_support) { + *mptr++ = cpu_to_le32(0x7C020002); + *mptr++ = cpu_to_le32(PAGE_SIZE); + } +#endif + + while (sg_count-- > 0) { + if (!sg_count) + sg_flags |= 0xC0000000; + *mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg)); + *mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg))); +#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64 + if ((sizeof(dma_addr_t) > 4) && c->pae_support) + *mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg))); +#endif + sg = sg_next(sg); + } + *sg_ptr = mptr; + + return 1; +} +EXPORT_SYMBOL_GPL(i2o_dma_map_sg); + +/** + * i2o_dma_alloc - Allocate DMA memory + * @dev: struct device pointer to the PCI device of the I2O controller + * @addr: i2o_dma struct which should get the DMA buffer + * @len: length of the new DMA memory + * + * Allocate a coherent DMA memory and write the pointers into addr. + * + * Returns 0 on success or -ENOMEM on failure. + */ +int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int dma_64 = 0; + + mutex_lock(&mem_lock); + if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_BIT_MASK(64))) { + dma_64 = 1; + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + mutex_unlock(&mem_lock); + return -ENOMEM; + } + } + + addr->virt = dma_alloc_coherent(dev, len, &addr->phys, GFP_KERNEL); + + if ((sizeof(dma_addr_t) > 4) && dma_64) + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) + printk(KERN_WARNING "i2o: unable to set 64-bit DMA"); + mutex_unlock(&mem_lock); + + if (!addr->virt) + return -ENOMEM; + + memset(addr->virt, 0, len); + addr->len = len; + + return 0; +} +EXPORT_SYMBOL_GPL(i2o_dma_alloc); + + +/** + * i2o_dma_free - Free DMA memory + * @dev: struct device pointer to the PCI device of the I2O controller + * @addr: i2o_dma struct which contains the DMA buffer + * + * Free a coherent DMA memory and set virtual address of addr to NULL. + */ +void i2o_dma_free(struct device *dev, struct i2o_dma *addr) +{ + if (addr->virt) { + if (addr->phys) + dma_free_coherent(dev, addr->len, addr->virt, + addr->phys); + else + kfree(addr->virt); + addr->virt = NULL; + } +} +EXPORT_SYMBOL_GPL(i2o_dma_free); + + +/** + * i2o_dma_realloc - Realloc DMA memory + * @dev: struct device pointer to the PCI device of the I2O controller + * @addr: pointer to a i2o_dma struct DMA buffer + * @len: new length of memory + * + * If there was something allocated in the addr, free it first. If len > 0 + * than try to allocate it and write the addresses back to the addr + * structure. If len == 0 set the virtual address to NULL. + * + * Returns the 0 on success or negative error code on failure. + */ +int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len) +{ + i2o_dma_free(dev, addr); + + if (len) + return i2o_dma_alloc(dev, addr, len); + + return 0; +} +EXPORT_SYMBOL_GPL(i2o_dma_realloc); + +/* + * i2o_pool_alloc - Allocate an slab cache and mempool + * @mempool: pointer to struct i2o_pool to write data into. + * @name: name which is used to identify cache + * @size: size of each object + * @min_nr: minimum number of objects + * + * First allocates a slab cache with name and size. Then allocates a + * mempool which uses the slab cache for allocation and freeing. + * + * Returns 0 on success or negative error code on failure. + */ +int i2o_pool_alloc(struct i2o_pool *pool, const char *name, + size_t size, int min_nr) +{ + pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL); + if (!pool->name) + goto exit; + strcpy(pool->name, name); + + pool->slab = + kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL); + if (!pool->slab) + goto free_name; + + pool->mempool = mempool_create_slab_pool(min_nr, pool->slab); + if (!pool->mempool) + goto free_slab; + + return 0; + +free_slab: + kmem_cache_destroy(pool->slab); + +free_name: + kfree(pool->name); + +exit: + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(i2o_pool_alloc); + +/* + * i2o_pool_free - Free slab cache and mempool again + * @mempool: pointer to struct i2o_pool which should be freed + * + * Note that you have to return all objects to the mempool again before + * calling i2o_pool_free(). + */ +void i2o_pool_free(struct i2o_pool *pool) +{ + mempool_destroy(pool->mempool); + kmem_cache_destroy(pool->slab); + kfree(pool->name); +}; +EXPORT_SYMBOL_GPL(i2o_pool_free); diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c index 685a89547a5..0f9f3e1a2b6 100644 --- a/drivers/message/i2o/pci.c +++ b/drivers/message/i2o/pci.c @@ -19,7 +19,7 @@ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> * Deepak Saxena <deepak@plexity.net> * Boji T Kannanthanam <boji.t.kannanthanam@intel.com> - * Alan Cox <alan@redhat.com>: + * Alan Cox <alan@lxorguk.ukuu.org.uk>: * Ported to Linux 2.5. * Markus Lidel <Markus.Lidel@shadowconnect.com>: * Minor fixes for 2.6. @@ -29,13 +29,15 @@ #include <linux/pci.h> #include <linux/interrupt.h> +#include <linux/slab.h> #include <linux/i2o.h> +#include <linux/module.h> #include "core.h" #define OSM_DESCRIPTION "I2O-subsystem" /* PCI device id table for all I2O controllers */ -static struct pci_device_id __devinitdata i2o_pci_ids[] = { +static struct pci_device_id i2o_pci_ids[] = { {PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)}, {PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)}, {.vendor = PCI_VENDOR_ID_INTEL,.device = 0x1962, @@ -82,7 +84,7 @@ static void i2o_pci_free(struct i2o_controller *c) * * Returns 0 on success or negative error code on failure. */ -static int __devinit i2o_pci_alloc(struct i2o_controller *c) +static int i2o_pci_alloc(struct i2o_controller *c) { struct pci_dev *pdev = c->pdev; struct device *dev = &pdev->dev; @@ -186,31 +188,29 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c) } } - if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) { + if (i2o_dma_alloc(dev, &c->status, 8)) { i2o_pci_free(c); return -ENOMEM; } - if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt), GFP_KERNEL)) { + if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt))) { i2o_pci_free(c); return -ENOMEM; } - if (i2o_dma_alloc(dev, &c->dlct, 8192, GFP_KERNEL)) { + if (i2o_dma_alloc(dev, &c->dlct, 8192)) { i2o_pci_free(c); return -ENOMEM; } - if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block), - GFP_KERNEL)) { + if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block))) { i2o_pci_free(c); return -ENOMEM; } - if (i2o_dma_alloc - (dev, &c->out_queue, - I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE * - sizeof(u32), GFP_KERNEL)) { + if (i2o_dma_alloc(dev, &c->out_queue, + I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE * + sizeof(u32))) { i2o_pci_free(c); return -ENOMEM; } @@ -315,8 +315,7 @@ static void i2o_pci_irq_disable(struct i2o_controller *c) * * Returns 0 on success or negative error code on failure. */ -static int __devinit i2o_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int i2o_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct i2o_controller *c; int rc; @@ -336,7 +335,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev, return rc; } - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "i2o: no suitable DMA found for %s\n", pci_name(pdev)); rc = -ENODEV; @@ -399,7 +398,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev, } #ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64 if (sizeof(dma_addr_t) > 4) { - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)) + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) printk(KERN_INFO "%s: 64-bit DMA unavailable\n", c->name); else { @@ -453,7 +452,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev, * Reset the I2O controller, disable interrupts and remove all allocated * resources. */ -static void __devexit i2o_pci_remove(struct pci_dev *pdev) +static void i2o_pci_remove(struct pci_dev *pdev) { struct i2o_controller *c; c = pci_get_drvdata(pdev); @@ -474,7 +473,7 @@ static struct pci_driver i2o_pci_driver = { .name = "PCI_I2O", .id_table = i2o_pci_ids, .probe = i2o_pci_probe, - .remove = __devexit_p(i2o_pci_remove), + .remove = i2o_pci_remove, }; /** |
