diff options
| author | Matt Jacob <mjacob@FreeBSD.org> | 2006-06-08 17:48:35 +0000 |
|---|---|---|
| committer | Matt Jacob <mjacob@FreeBSD.org> | 2006-06-08 17:48:35 +0000 |
| commit | 6b80f42341b02a37104092ae84a0614d6b1596f5 (patch) | |
| tree | 7bc783f955a4e3ddfcc5e2e04685d10fc53caf80 /sys/dev/mpt | |
| parent | b803b3447aa4b676c6740e39903d0cbc0fe33593 (diff) | |
Notes
Diffstat (limited to 'sys/dev/mpt')
| -rw-r--r-- | sys/dev/mpt/mpilib/fc_log.h | 117 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi.h | 136 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi_cnfg.h | 1261 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi_fc.h | 12 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi_init.h | 262 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi_ioc.h | 379 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi_lan.h | 10 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi_raid.h | 21 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi_targ.h | 232 | ||||
| -rw-r--r-- | sys/dev/mpt/mpilib/mpi_type.h | 38 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt.c | 1158 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt.h | 498 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt_cam.c | 4144 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt_cam.h | 36 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt_debug.c | 229 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt_pci.c | 305 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt_raid.c | 263 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt_raid.h | 48 | ||||
| -rw-r--r-- | sys/dev/mpt/mpt_reg.h | 38 |
19 files changed, 7514 insertions, 1673 deletions
diff --git a/sys/dev/mpt/mpilib/fc_log.h b/sys/dev/mpt/mpilib/fc_log.h deleted file mode 100644 index 23018ab1147f..000000000000 --- a/sys/dev/mpt/mpilib/fc_log.h +++ /dev/null @@ -1,117 +0,0 @@ -/* $FreeBSD$ */ -/*- - * Copyright (c) 2000-2005, LSI Logic Corporation and its contributors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon including - * a substantially similar Disclaimer requirement for further binary - * redistribution. - * 3. Neither the name of the LSI Logic Corporation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT - * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * NAME: fc_log.h - * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips - * DESCRIPTION: Contains the enumerated list of values that may be returned - * in the IOCLogInfo field of a MPI Default Reply Message. - * - * CREATION DATE: 6/02/2000 - * ID: $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $ - */ - -/* - * MpiIocLogInfo_t enum - * - * These 32 bit values are used in the IOCLogInfo field of the MPI reply - * messages. - * The value is 0xabcccccc where - * a = The type of log info as per the MPI spec. Since these codes are - * all for Fibre Channel this value will always be 2. - * b = Specifies a subclass of the firmware where - * 0 = FCP Initiator - * 1 = FCP Target - * 2 = LAN - * 3 = MPI Message Layer - * 4 = FC Link - * 5 = Context Manager - * 6 = Invalid Field Offset - * 7 = State Change Info - * all others are reserved for future use - * c = A specific value within the subclass. - * - * NOTE: Any new values should be added to the end of each subclass so that the - * codes remain consistent across firmware releases. - */ -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_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 */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OVERRUN = 0x20000007, /* Scatter Gather overrun */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_BAD_STATUS = 0x20000008, /* Receiver detected context mismatch via invalid header */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_UNEXPECTED_FRAME= 0x20000009, /* CtxMgr detected unsupported frame type */ - MPI_IOCLOGINFO_FC_INIT_ERROR_LINK_FAILURE = 0x2000000A, /* Link failure occurred */ - MPI_IOCLOGINFO_FC_INIT_ERROR_TX_TIMEOUT = 0x2000000B, /* Transmitter timeout error */ - - MPI_IOCLOGINFO_FC_TARGET_BASE = 0x21000000, - MPI_IOCLOGINFO_FC_TARGET_NO_PDISC = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */ - MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN = 0x21000002, /* not sent because we are not logged in to the remote node */ - MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA = 0x21000005, /* Data In, Auto Response, missing data frames */ - MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP = 0x21000006, /* Data Out, No Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP = 0x21000007, /* Auto-response after a write not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP = 0x21000008, /* Data In, No Response, not completed due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA = 0x21000009, /* Data In, No Response, missing data frames */ - MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP = 0x2100000a, /* Manual Response not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3 = 0x2100000b, /* not sent because remote node does not support Class 3 */ - MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID = 0x2100000c, /* not sent because login to remote node not validated */ - MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound queue after a logout */ - MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN = 0x2100000f, /* cleared waiting for data after a logout */ - - MPI_IOCLOGINFO_FC_LAN_BASE = 0x22000000, - MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING = 0x22000001, /* Transaction Context Sgl Missing */ - MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE = 0x22000002, /* Transaction Context found before an EOB */ - MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET = 0x22000003, /* Transaction Context value has reserved bits set */ - MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG = 0x22000004, /* Invalid SGL Flags */ - - MPI_IOCLOGINFO_FC_MSG_BASE = 0x23000000, - - MPI_IOCLOGINFO_FC_LINK_BASE = 0x24000000, - MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT = 0x24000001, /* Loop initialization timed out */ - MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED = 0x24000002, /* Another system controller already initialized the loop */ - MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */ - MPI_IOCLOGINFO_FC_LINK_CRC_ERROR = 0x24000004, /* CRC check detected error on received frame */ - - MPI_IOCLOGINFO_FC_CTX_BASE = 0x25000000, - - MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid */ - MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET = 0x26ffffff, - - MPI_IOCLOGINFO_FC_STATE_CHANGE = 0x27000000 /* The lower 24 bits give additional information concerning state change */ - -} MpiIocLogInfoFc_t; diff --git a/sys/dev/mpt/mpilib/mpi.h b/sys/dev/mpt/mpilib/mpi.h index 3b3f6e9821cd..b81e1fdc306a 100644 --- a/sys/dev/mpt/mpilib/mpi.h +++ b/sys/dev/mpt/mpilib/mpi.h @@ -29,12 +29,11 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * - * Name: MPI.H + * Name: mpi.h * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * MPI.H Version: 01.02.11 + * mpi.h Version: 01.05.10 * * Version History * --------------- @@ -81,6 +80,29 @@ * 04-01-03 01.02.09 New IOCStatus code: MPI_IOCSTATUS_FC_EXCHANGE_CANCELED * 06-26-03 01.02.10 Bumped MPI_HEADER_VERSION_UNIT value. * 01-16-04 01.02.11 Added define for MPI_IOCLOGINFO_TYPE_SHIFT. + * 04-29-04 01.02.12 Added function codes for MPI_FUNCTION_DIAG_BUFFER_POST + * and MPI_FUNCTION_DIAG_RELEASE. + * Added MPI_IOCSTATUS_DIAGNOSTIC_RELEASED define. + * Bumped MPI_HEADER_VERSION_UNIT value. + * 05-11-04 01.03.01 Bumped MPI_VERSION_MINOR for MPI v1.3. + * Added codes for Inband. + * 08-19-04 01.05.01 Added defines for Host Buffer Access Control doorbell. + * Added define for offset of High Priority Request Queue. + * Added new function codes and new IOCStatus codes. + * Added a IOCLogInfo type of SAS. + * 12-07-04 01.05.02 Bumped MPI_HEADER_VERSION_UNIT. + * 12-09-04 01.05.03 Bumped MPI_HEADER_VERSION_UNIT. + * 01-15-05 01.05.04 Bumped MPI_HEADER_VERSION_UNIT. + * 02-09-05 01.05.05 Bumped MPI_HEADER_VERSION_UNIT. + * 02-22-05 01.05.06 Bumped MPI_HEADER_VERSION_UNIT. + * 03-11-05 01.05.07 Removed function codes for SCSI IO 32 and + * TargetAssistExtended requests. + * Removed EEDP IOCStatus codes. + * 06-24-05 01.05.08 Added function codes for SCSI IO 32 and + * TargetAssistExtended requests. + * Added EEDP IOCStatus codes. + * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. + * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. * -------------------------------------------------------------------------- */ @@ -95,7 +117,7 @@ *****************************************************************************/ #define MPI_VERSION_MAJOR (0x01) -#define MPI_VERSION_MINOR (0x02) +#define MPI_VERSION_MINOR (0x05) #define MPI_VERSION_MAJOR_MASK (0xFF00) #define MPI_VERSION_MAJOR_SHIFT (8) #define MPI_VERSION_MINOR_MASK (0x00FF) @@ -106,10 +128,12 @@ #define MPI_VERSION_01_00 (0x0100) #define MPI_VERSION_01_01 (0x0101) #define MPI_VERSION_01_02 (0x0102) +#define MPI_VERSION_01_03 (0x0103) +#define MPI_VERSION_01_05 (0x0105) /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x0D) +#define MPI_HEADER_VERSION_UNIT (0x0C) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) @@ -149,7 +173,11 @@ * *****************************************************************************/ -/* S y s t e m D o o r b e l l */ +/* + * Defines for working with the System Doorbell register. + * Values for doorbell function codes are included in the section that defines + * all the function codes (further on in this file). + */ #define MPI_DOORBELL_OFFSET (0x00000000) #define MPI_DOORBELL_ACTIVE (0x08000000) /* DoorbellUsed */ #define MPI_DOORBELL_USED (MPI_DOORBELL_ACTIVE) @@ -161,6 +189,13 @@ #define MPI_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) #define MPI_DOORBELL_ADD_DWORDS_SHIFT (16) #define MPI_DOORBELL_DATA_MASK (0x0000FFFF) +#define MPI_DOORBELL_FUNCTION_SPECIFIC_MASK (0x0000FFFF) + +/* values for Host Buffer Access Control doorbell function */ +#define MPI_DB_HPBAC_VALUE_MASK (0x0000F000) +#define MPI_DB_HPBAC_ENABLE_ACCESS (0x01) +#define MPI_DB_HPBAC_DISABLE_ACCESS (0x02) +#define MPI_DB_HPBAC_FREE_BUFFER (0x03) #define MPI_WRITE_SEQUENCE_OFFSET (0x00000004) @@ -204,6 +239,8 @@ #define MPI_REPLY_POST_FIFO_OFFSET (0x00000044) #define MPI_REPLY_FREE_FIFO_OFFSET (0x00000044) +#define MPI_HI_PRI_REQUEST_QUEUE_OFFSET (0x00000048) + /***************************************************************************** @@ -263,10 +300,6 @@ #define MPI_FUNCTION_TARGET_ASSIST (0x0B) #define MPI_FUNCTION_TARGET_STATUS_SEND (0x0C) #define MPI_FUNCTION_TARGET_MODE_ABORT (0x0D) -#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC (0x0E) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC (0x0F) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC (0x10) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_ABORT (0x11) /* obsolete name */ #define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST (0x0E) #define MPI_FUNCTION_FC_LINK_SRVC_RSP (0x0F) #define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND (0x10) @@ -284,15 +317,51 @@ #define MPI_FUNCTION_MAILBOX (0x19) +#define MPI_FUNCTION_SMP_PASSTHROUGH (0x1A) +#define MPI_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) +#define MPI_FUNCTION_SATA_PASSTHROUGH (0x1C) + +#define MPI_FUNCTION_DIAG_BUFFER_POST (0x1D) +#define MPI_FUNCTION_DIAG_RELEASE (0x1E) + +#define MPI_FUNCTION_SCSI_IO_32 (0x1F) + #define MPI_FUNCTION_LAN_SEND (0x20) #define MPI_FUNCTION_LAN_RECEIVE (0x21) #define MPI_FUNCTION_LAN_RESET (0x22) +#define MPI_FUNCTION_TARGET_ASSIST_EXTENDED (0x23) +#define MPI_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) +#define MPI_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) + +#define MPI_FUNCTION_INBAND_BUFFER_POST (0x28) +#define MPI_FUNCTION_INBAND_SEND (0x29) +#define MPI_FUNCTION_INBAND_RSP (0x2A) +#define MPI_FUNCTION_INBAND_ABORT (0x2B) + #define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) #define MPI_FUNCTION_IO_UNIT_RESET (0x41) #define MPI_FUNCTION_HANDSHAKE (0x42) #define MPI_FUNCTION_REPLY_FRAME_REMOVAL (0x43) +#define MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL (0x44) + +/* standard version format */ +typedef struct _MPI_VERSION_STRUCT +{ + U8 Dev; /* 00h */ + U8 Unit; /* 01h */ + U8 Minor; /* 02h */ + U8 Major; /* 03h */ +} MPI_VERSION_STRUCT, MPI_POINTER PTR_MPI_VERSION_STRUCT, + MpiVersionStruct_t, MPI_POINTER pMpiVersionStruct; + +typedef union _MPI_VERSION_FORMAT +{ + MPI_VERSION_STRUCT Struct; + U32 Word; +} MPI_VERSION_FORMAT, MPI_POINTER PTR_MPI_VERSION_FORMAT, + MpiVersionFormat_t, MPI_POINTER pMpiVersionFormat_t; /***************************************************************************** @@ -327,8 +396,8 @@ typedef struct _SGE_SIMPLE_UNION U32 Address32; U64 Address64; }u; -} SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t, - SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION; +} SGE_SIMPLE_UNION, MPI_POINTER PTR_SGE_SIMPLE_UNION, + SGESimpleUnion_t, MPI_POINTER pSGESimpleUnion_t; /****************************************************************************/ /* Chain element structures */ @@ -615,6 +684,7 @@ typedef struct _MSG_DEFAULT_REPLY #define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) #define MPI_IOCSTATUS_INVALID_FIELD (0x0007) #define MPI_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) /****************************************************************************/ /* Config IOCStatus values */ @@ -646,21 +716,35 @@ typedef struct _MSG_DEFAULT_REPLY #define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) /****************************************************************************/ -/* SCSI (SPI & FCP) target values */ +/* For use by SCSI Initiator and SCSI Target end-to-end data protection */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) +#define MPI_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) +#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + + +/****************************************************************************/ +/* SCSI Target values */ /****************************************************************************/ #define MPI_IOCSTATUS_TARGET_PRIORITY_IO (0x0060) #define MPI_IOCSTATUS_TARGET_INVALID_PORT (0x0061) -#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) /* obsolete name */ #define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) #define MPI_IOCSTATUS_TARGET_ABORTED (0x0063) #define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) #define MPI_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) #define MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) #define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT (0x006B) +#define MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) +#define MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) +#define MPI_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) +#define MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) +#define MPI_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) /****************************************************************************/ -/* Additional FCP target values */ +/* Additional FCP target values (obsolete) */ /****************************************************************************/ #define MPI_IOCSTATUS_TARGET_FC_ABORTED (0x0066) /* obsolete */ @@ -691,6 +775,26 @@ typedef struct _MSG_DEFAULT_REPLY #define MPI_IOCSTATUS_LAN_PARTIAL_PACKET (0x0086) #define MPI_IOCSTATUS_LAN_CANCELED (0x0087) +/****************************************************************************/ +/* Serial Attached SCSI values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) +#define MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) + +/****************************************************************************/ +/* Inband values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_INBAND_ABORTED (0x0098) +#define MPI_IOCSTATUS_INBAND_NO_CONNECTION (0x0099) + +/****************************************************************************/ +/* Diagnostic Tools values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) + /****************************************************************************/ /* IOCStatus flag to indicate that log info is available */ @@ -708,6 +812,8 @@ typedef struct _MSG_DEFAULT_REPLY #define MPI_IOCLOGINFO_TYPE_NONE (0x0) #define MPI_IOCLOGINFO_TYPE_SCSI (0x1) #define MPI_IOCLOGINFO_TYPE_FC (0x2) +#define MPI_IOCLOGINFO_TYPE_SAS (0x3) +#define MPI_IOCLOGINFO_TYPE_ISCSI (0x4) #define MPI_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) diff --git a/sys/dev/mpt/mpilib/mpi_cnfg.h b/sys/dev/mpt/mpilib/mpi_cnfg.h index 7ab0a9f06584..d2c4810406df 100644 --- a/sys/dev/mpt/mpilib/mpi_cnfg.h +++ b/sys/dev/mpt/mpilib/mpi_cnfg.h @@ -29,12 +29,11 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * - * Name: MPI_CNFG.H + * Name: mpi_cnfg.h * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * MPI_CNFG.H Version: 01.02.13 + * mpi_cnfg.h Version: 01.05.11 * * Version History * --------------- @@ -179,6 +178,121 @@ * MPI_FCPORTPAGE1_FLAGS_SOFT_ALPA_FALLBACK. * Added new fields to the substructures of * CONFIG_PAGE_FC_PORT_10. + * 04-29-04 01.02.14 Added define for IDP bit for CONFIG_PAGE_SCSI_PORT_0, + * CONFIG_PAGE_SCSI_DEVICE_0, and + * CONFIG_PAGE_SCSI_DEVICE_1. Also bumped Page Version for + * these pages. + * 05-11-04 01.03.01 Added structure for CONFIG_PAGE_INBAND_0. + * 08-19-04 01.05.01 Modified MSG_CONFIG request to support extended config + * pages. + * Added a new structure for extended config page header. + * Added new extended config pages types and structures for + * SAS IO Unit, SAS Expander, SAS Device, and SAS PHY. + * Replaced a reserved byte in CONFIG_PAGE_MANUFACTURING_4 + * to add a Flags field. + * Two new Manufacturing config pages (5 and 6). + * Two new bits defined for IO Unit Page 1 Flags field. + * Modified CONFIG_PAGE_IO_UNIT_2 to add three new fields + * to specify the BIOS boot device. + * Four new Flags bits defined for IO Unit Page 2. + * Added IO Unit Page 4. + * Added EEDP Flags settings to IOC Page 1. + * Added new BIOS Page 1 config page. + * 10-05-04 01.05.02 Added define for + * MPI_IOCPAGE1_INITIATOR_CONTEXT_REPLY_DISABLE. + * Added new Flags field to CONFIG_PAGE_MANUFACTURING_5 and + * associated defines. + * Added more defines for SAS IO Unit Page 0 + * DiscoveryStatus field. + * Added define for MPI_SAS_IOUNIT0_DS_SUBTRACTIVE_LINK + * and MPI_SAS_IOUNIT0_DS_TABLE_LINK. + * Added defines for Physical Mapping Modes to SAS IO Unit + * Page 2. + * Added define for + * MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH. + * 10-27-04 01.05.03 Added defines for new SAS PHY page addressing mode. + * Added defines for MaxTargetSpinUp to BIOS Page 1. + * Added 5 new ControlFlags defines for SAS IO Unit + * Page 1. + * Added MaxNumPhysicalMappedIDs field to SAS IO Unit + * Page 2. + * Added AccessStatus field to SAS Device Page 0 and added + * new Flags bits for supported SATA features. + * 12-07-04 01.05.04 Added config page structures for BIOS Page 2, RAID + * Volume Page 1, and RAID Physical Disk Page 1. + * Replaced IO Unit Page 1 BootTargetID,BootBus, and + * BootAdapterNum with reserved field. + * Added DataScrubRate and ResyncRate to RAID Volume + * Page 0. + * Added MPI_SAS_IOUNIT2_FLAGS_RESERVE_ID_0_FOR_BOOT + * define. + * 12-09-04 01.05.05 Added Target Mode Large CDB Enable to FC Port Page 1 + * Flags field. + * Added Auto Port Config flag define for SAS IOUNIT + * Page 1 ControlFlags. + * Added Disabled bad Phy define to Expander Page 1 + * Discovery Info field. + * Added SAS/SATA device support to SAS IOUnit Page 1 + * ControlFlags. + * Added Unsupported device to SAS Dev Page 0 Flags field + * Added disable use SATA Hash Address for SAS IOUNIT + * page 1 in ControlFields. + * 01-15-05 01.05.06 Added defaults for data scrub rate and resync rate to + * Manufacturing Page 4. + * Added new defines for BIOS Page 1 IOCSettings field. + * Added ExtDiskIdentifier field to RAID Physical Disk + * Page 0. + * Added new defines for SAS IO Unit Page 1 ControlFlags + * and to SAS Device Page 0 Flags to control SATA devices. + * Added defines and structures for the new Log Page 0, a + * new type of configuration page. + * 02-09-05 01.05.07 Added InactiveStatus field to RAID Volume Page 0. + * Added WWID field to RAID Volume Page 1. + * Added PhysicalPort field to SAS Expander pages 0 and 1. + * 03-11-05 01.05.08 Removed the EEDP flags from IOC Page 1. + * Added Enclosure/Slot boot device format to BIOS Page 2. + * New status value for RAID Volume Page 0 VolumeStatus + * (VolumeState subfield). + * New value for RAID Physical Page 0 InactiveStatus. + * Added Inactive Volume Member flag RAID Physical Disk + * Page 0 PhysDiskStatus field. + * New physical mapping mode in SAS IO Unit Page 2. + * Added CONFIG_PAGE_SAS_ENCLOSURE_0. + * Added Slot and Enclosure fields to SAS Device Page 0. + * 06-24-05 01.05.09 Added EEDP defines to IOC Page 1. + * Added more RAID type defines to IOC Page 2. + * Added Port Enable Delay settings to BIOS Page 1. + * Added Bad Block Table Full define to RAID Volume Page 0. + * Added Previous State defines to RAID Physical Disk + * Page 0. + * Added Max Sata Targets define for DiscoveryStatus field + * of SAS IO Unit Page 0. + * Added Device Self Test to Control Flags of SAS IO Unit + * Page 1. + * Added Direct Attach Starting Slot Number define for SAS + * IO Unit Page 2. + * Added new fields in SAS Device Page 2 for enclosure + * mapping. + * Added OwnerDevHandle and Flags field to SAS PHY Page 0. + * Added IOC GPIO Flags define to SAS Enclosure Page 0. + * Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT. + * 08-03-05 01.05.10 Removed ISDataScrubRate and ISResyncRate from + * Manufacturing Page 4. + * Added MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE bit. + * Added NumDevsPerEnclosure field to SAS IO Unit page 2. + * Added MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP + * define. + * Added EnclosureHandle field to SAS Expander page 0. + * Removed redundant NumTableEntriesProg field from SAS + * Expander Page 1. + * 08-30-05 01.05.11 Added DeviceID for FC949E and changed the DeviceID for + * SAS1078. + * Added more defines for Manufacturing Page 4 Flags field. + * Added more defines for IOCSettings and added + * ExpanderSpinup field to Bios Page 1. + * Added postpone SATA Init bit to SAS IO Unit Page 1 + * ControlFlags. + * Changed LogEntry format for Log Page 0. * -------------------------------------------------------------------------- */ @@ -210,6 +324,19 @@ typedef union _CONFIG_PAGE_HEADER_UNION } ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion, CONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION; +typedef struct _CONFIG_EXTENDED_PAGE_HEADER +{ + U8 PageVersion; /* 00h */ + U8 Reserved1; /* 01h */ + U8 PageNumber; /* 02h */ + U8 PageType; /* 03h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ + U8 Reserved2; /* 07h */ +} CONFIG_EXTENDED_PAGE_HEADER, MPI_POINTER PTR_CONFIG_EXTENDED_PAGE_HEADER, + ConfigExtendedPageHeader_t, MPI_POINTER pConfigExtendedPageHeader_t; + + /**************************************************************************** * PageType field values @@ -231,20 +358,42 @@ typedef union _CONFIG_PAGE_HEADER_UNION #define MPI_CONFIG_PAGETYPE_RAID_VOLUME (0x08) #define MPI_CONFIG_PAGETYPE_MANUFACTURING (0x09) #define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) +#define MPI_CONFIG_PAGETYPE_INBAND (0x0B) +#define MPI_CONFIG_PAGETYPE_EXTENDED (0x0F) #define MPI_CONFIG_PAGETYPE_MASK (0x0F) #define MPI_CONFIG_TYPENUM_MASK (0x0FFF) /**************************************************************************** +* ExtPageType field values +****************************************************************************/ +#define MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) +#define MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) +#define MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) +#define MPI_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) +#define MPI_CONFIG_EXTPAGETYPE_LOG (0x14) +#define MPI_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) + + +/**************************************************************************** * PageAddress field values ****************************************************************************/ #define MPI_SCSI_PORT_PGAD_PORT_MASK (0x000000FF) +#define MPI_SCSI_DEVICE_FORM_MASK (0xF0000000) +#define MPI_SCSI_DEVICE_FORM_BUS_TID (0x00000000) #define MPI_SCSI_DEVICE_TARGET_ID_MASK (0x000000FF) #define MPI_SCSI_DEVICE_TARGET_ID_SHIFT (0) #define MPI_SCSI_DEVICE_BUS_MASK (0x0000FF00) #define MPI_SCSI_DEVICE_BUS_SHIFT (8) +#define MPI_SCSI_DEVICE_FORM_TARGET_MODE (0x10000000) +#define MPI_SCSI_DEVICE_TM_RESPOND_ID_MASK (0x000000FF) +#define MPI_SCSI_DEVICE_TM_RESPOND_ID_SHIFT (0) +#define MPI_SCSI_DEVICE_TM_BUS_MASK (0x0000FF00) +#define MPI_SCSI_DEVICE_TM_BUS_SHIFT (8) +#define MPI_SCSI_DEVICE_TM_INIT_ID_MASK (0x00FF0000) +#define MPI_SCSI_DEVICE_TM_INIT_ID_SHIFT (16) #define MPI_FC_PORT_PGAD_PORT_MASK (0xF0000000) #define MPI_FC_PORT_PGAD_PORT_SHIFT (28) @@ -270,6 +419,52 @@ typedef union _CONFIG_PAGE_HEADER_UNION #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT (0) +#define MPI_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) +#define MPI_SAS_EXPAND_PGAD_FORM_SHIFT (28) +#define MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM (0x00000001) +#define MPI_SAS_EXPAND_PGAD_FORM_HANDLE (0x00000002) +#define MPI_SAS_EXPAND_PGAD_GNH_MASK_HANDLE (0x0000FFFF) +#define MPI_SAS_EXPAND_PGAD_GNH_SHIFT_HANDLE (0) +#define MPI_SAS_EXPAND_PGAD_HPN_MASK_PHY (0x00FF0000) +#define MPI_SAS_EXPAND_PGAD_HPN_SHIFT_PHY (16) +#define MPI_SAS_EXPAND_PGAD_HPN_MASK_HANDLE (0x0000FFFF) +#define MPI_SAS_EXPAND_PGAD_HPN_SHIFT_HANDLE (0) +#define MPI_SAS_EXPAND_PGAD_H_MASK_HANDLE (0x0000FFFF) +#define MPI_SAS_EXPAND_PGAD_H_SHIFT_HANDLE (0) + +#define MPI_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) +#define MPI_SAS_DEVICE_PGAD_FORM_SHIFT (28) +#define MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID (0x00000001) +#define MPI_SAS_DEVICE_PGAD_FORM_HANDLE (0x00000002) +#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_BT_BUS_MASK (0x0000FF00) +#define MPI_SAS_DEVICE_PGAD_BT_BUS_SHIFT (8) +#define MPI_SAS_DEVICE_PGAD_BT_TID_MASK (0x000000FF) +#define MPI_SAS_DEVICE_PGAD_BT_TID_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_DEVICE_PGAD_H_HANDLE_SHIFT (0) + +#define MPI_SAS_PHY_PGAD_FORM_MASK (0xF0000000) +#define MPI_SAS_PHY_PGAD_FORM_SHIFT (28) +#define MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x0) +#define MPI_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x1) +#define MPI_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) +#define MPI_SAS_PHY_PGAD_PHY_NUMBER_SHIFT (0) +#define MPI_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF) +#define MPI_SAS_PHY_PGAD_PHY_TBL_INDEX_SHIFT (0) + +#define MPI_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000) +#define MPI_SAS_ENCLOS_PGAD_FORM_SHIFT (28) +#define MPI_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI_SAS_ENCLOS_PGAD_FORM_HANDLE (0x00000001) +#define MPI_SAS_ENCLOS_PGAD_GNH_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_ENCLOS_PGAD_GNH_HANDLE_SHIFT (0) +#define MPI_SAS_ENCLOS_PGAD_H_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_ENCLOS_PGAD_H_HANDLE_SHIFT (0) + /**************************************************************************** @@ -281,7 +476,8 @@ typedef struct _MSG_CONFIG U8 Reserved; /* 01h */ U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ - U8 Reserved1[3]; /* 04h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[8]; /* 0Ch */ @@ -311,7 +507,8 @@ typedef struct _MSG_CONFIG_REPLY U8 Reserved; /* 01h */ U8 MsgLength; /* 02h */ U8 Function; /* 03h */ - U8 Reserved1[3]; /* 04h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[2]; /* 0Ch */ @@ -333,29 +530,31 @@ typedef struct _MSG_CONFIG_REPLY * Manufacturing Config pages ****************************************************************************/ #define MPI_MANUFACTPAGE_VENDORID_LSILOGIC (0x1000) -#define MPI_MANUFACTPAGE_VENDORID_TREBIA (0x1783) - +/* Fibre Channel */ #define MPI_MANUFACTPAGE_DEVICEID_FC909 (0x0621) #define MPI_MANUFACTPAGE_DEVICEID_FC919 (0x0624) #define MPI_MANUFACTPAGE_DEVICEID_FC929 (0x0622) #define MPI_MANUFACTPAGE_DEVICEID_FC919X (0x0628) #define MPI_MANUFACTPAGE_DEVICEID_FC929X (0x0626) - +#define MPI_MANUFACTPAGE_DEVICEID_FC939X (0x0642) +#define MPI_MANUFACTPAGE_DEVICEID_FC949X (0x0640) +#define MPI_MANUFACTPAGE_DEVICEID_FC949E (0x0646) +/* SCSI */ #define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030) #define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031) #define MPI_MANUFACTPAGE_DEVID_1030_53C1035 (0x0032) #define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035 (0x0033) #define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0040) #define MPI_MANUFACTPAGE_DEVID_53C1035ZC (0x0041) - -#define MPI_MANUFACTPAGE_DEVID_SA2010 (0x0804) -#define MPI_MANUFACTPAGE_DEVID_SA2010ZC (0x0805) -#define MPI_MANUFACTPAGE_DEVID_SA2020 (0x0806) -#define MPI_MANUFACTPAGE_DEVID_SA2020ZC (0x0807) - -#define MPI_MANUFACTPAGE_DEVID_SNP1000 (0x0010) -#define MPI_MANUFACTPAGE_DEVID_SNP500 (0x0020) - +/* SAS */ +#define MPI_MANUFACTPAGE_DEVID_SAS1064 (0x0050) +#define MPI_MANUFACTPAGE_DEVID_SAS1064A (0x005C) +#define MPI_MANUFACTPAGE_DEVID_SAS1064E (0x0056) +#define MPI_MANUFACTPAGE_DEVID_SAS1066 (0x005E) +#define MPI_MANUFACTPAGE_DEVID_SAS1066E (0x005A) +#define MPI_MANUFACTPAGE_DEVID_SAS1068 (0x0054) +#define MPI_MANUFACTPAGE_DEVID_SAS1068E (0x0058) +#define MPI_MANUFACTPAGE_DEVID_SAS1078 (0x0062) typedef struct _CONFIG_PAGE_MANUFACTURING_0 @@ -439,16 +638,61 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4 U8 InfoOffset1; /* 0Ah */ U8 InfoSize1; /* 0Bh */ U8 InquirySize; /* 0Ch */ - U8 Reserved2; /* 0Dh */ - U16 Reserved3; /* 0Eh */ + U8 Flags; /* 0Dh */ + U16 Reserved2; /* 0Eh */ U8 InquiryData[56]; /* 10h */ U32 ISVolumeSettings; /* 48h */ U32 IMEVolumeSettings; /* 4Ch */ U32 IMVolumeSettings; /* 50h */ + U32 Reserved3; /* 54h */ + U32 Reserved4; /* 58h */ + U32 Reserved5; /* 5Ch */ + U8 IMEDataScrubRate; /* 60h */ + U8 IMEResyncRate; /* 61h */ + U16 Reserved6; /* 62h */ + U8 IMDataScrubRate; /* 64h */ + U8 IMResyncRate; /* 65h */ + U16 Reserved7; /* 66h */ + U32 Reserved8; /* 68h */ + U32 Reserved9; /* 6Ch */ } CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4, ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t; -#define MPI_MANUFACTURING4_PAGEVERSION (0x00) +#define MPI_MANUFACTURING4_PAGEVERSION (0x03) + +/* defines for the Flags field */ +#define MPI_MANPAGE4_IME_DISABLE (0x20) +#define MPI_MANPAGE4_IM_DISABLE (0x10) +#define MPI_MANPAGE4_IS_DISABLE (0x08) +#define MPI_MANPAGE4_IR_MODEPAGE8_DISABLE (0x04) +#define MPI_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x02) +#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_5 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U64 BaseWWID; /* 04h */ + U8 Flags; /* 0Ch */ + U8 Reserved1; /* 0Dh */ + U16 Reserved2; /* 0Eh */ +} CONFIG_PAGE_MANUFACTURING_5, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_5, + ManufacturingPage5_t, MPI_POINTER pManufacturingPage5_t; + +#define MPI_MANUFACTURING5_PAGEVERSION (0x01) + +/* defines for the Flags field */ +#define MPI_MANPAGE5_TWO_WWID_PER_PHY (0x01) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_6 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} CONFIG_PAGE_MANUFACTURING_6, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_6, + ManufacturingPage6_t, MPI_POINTER pManufacturingPage6_t; + +#define MPI_MANUFACTURING6_PAGEVERSION (0x00) /**************************************************************************** @@ -472,18 +716,19 @@ typedef struct _CONFIG_PAGE_IO_UNIT_1 } CONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1, IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t; -#define MPI_IOUNITPAGE1_PAGEVERSION (0x00) +#define MPI_IOUNITPAGE1_PAGEVERSION (0x02) /* IO Unit Page 1 Flags defines */ - #define MPI_IOUNITPAGE1_MULTI_FUNCTION (0x00000000) #define MPI_IOUNITPAGE1_SINGLE_FUNCTION (0x00000001) #define MPI_IOUNITPAGE1_MULTI_PATHING (0x00000002) #define MPI_IOUNITPAGE1_SINGLE_PATHING (0x00000000) #define MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) +#define MPI_IOUNITPAGE1_DISABLE_QUEUE_FULL_HANDLING (0x00000020) #define MPI_IOUNITPAGE1_DISABLE_IR (0x00000040) #define MPI_IOUNITPAGE1_FORCE_32 (0x00000080) - +#define MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) +#define MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE (0x00000200) typedef struct _MPI_ADAPTER_INFO { @@ -502,16 +747,22 @@ typedef struct _CONFIG_PAGE_IO_UNIT_2 U32 Flags; /* 04h */ U32 BiosVersion; /* 08h */ MPI_ADAPTER_INFO AdapterOrder[4]; /* 0Ch */ + U32 Reserved1; /* 1Ch */ } CONFIG_PAGE_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_2, IOUnitPage2_t, MPI_POINTER pIOUnitPage2_t; -#define MPI_IOUNITPAGE2_PAGEVERSION (0x00) +#define MPI_IOUNITPAGE2_PAGEVERSION (0x02) #define MPI_IOUNITPAGE2_FLAGS_PAUSE_ON_ERROR (0x00000002) #define MPI_IOUNITPAGE2_FLAGS_VERBOSE_ENABLE (0x00000004) #define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE (0x00000008) #define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40 (0x00000010) +#define MPI_IOUNITPAGE2_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) +#define MPI_IOUNITPAGE2_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) +#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DISPLAY (0x00000020) +#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) + /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to @@ -539,6 +790,17 @@ typedef struct _CONFIG_PAGE_IO_UNIT_3 #define MPI_IOUNITPAGE3_GPIO_SETTING_ON (0x01) +typedef struct _CONFIG_PAGE_IO_UNIT_4 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 04h */ + SGE_SIMPLE_UNION FWImageSGE; /* 08h */ +} CONFIG_PAGE_IO_UNIT_4, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_4, + IOUnitPage4_t, MPI_POINTER pIOUnitPage4_t; + +#define MPI_IOUNITPAGE4_PAGEVERSION (0x00) + + /**************************************************************************** * IOC Config Pages ****************************************************************************/ @@ -572,8 +834,14 @@ typedef struct _CONFIG_PAGE_IOC_1 } CONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1, IOCPage1_t, MPI_POINTER pIOCPage1_t; -#define MPI_IOCPAGE1_PAGEVERSION (0x01) +#define MPI_IOCPAGE1_PAGEVERSION (0x03) +/* defines for the Flags field */ +#define MPI_IOCPAGE1_EEDP_MODE_MASK (0x07000000) +#define MPI_IOCPAGE1_EEDP_MODE_OFF (0x00000000) +#define MPI_IOCPAGE1_EEDP_MODE_T10 (0x01000000) +#define MPI_IOCPAGE1_EEDP_MODE_LSI_1 (0x02000000) +#define MPI_IOCPAGE1_INITIATOR_CONTEXT_REPLY_DISABLE (0x00000010) #define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001) #define MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) @@ -596,6 +864,11 @@ typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL #define MPI_RAID_VOL_TYPE_IS (0x00) #define MPI_RAID_VOL_TYPE_IME (0x01) #define MPI_RAID_VOL_TYPE_IM (0x02) +#define MPI_RAID_VOL_TYPE_RAID_5 (0x03) +#define MPI_RAID_VOL_TYPE_RAID_6 (0x04) +#define MPI_RAID_VOL_TYPE_RAID_10 (0x05) +#define MPI_RAID_VOL_TYPE_RAID_50 (0x06) +#define MPI_RAID_VOL_TYPE_UNKNOWN (0xFF) /* IOC Page 2 Volume Flags values */ @@ -621,13 +894,17 @@ typedef struct _CONFIG_PAGE_IOC_2 } CONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2, IOCPage2_t, MPI_POINTER pIOCPage2_t; -#define MPI_IOCPAGE2_PAGEVERSION (0x02) +#define MPI_IOCPAGE2_PAGEVERSION (0x03) /* IOC Page 2 Capabilities flags */ #define MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT (0x00000001) #define MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT (0x00000002) #define MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT (0x00000004) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT (0x00000008) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_6_SUPPORT (0x00000010) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000020) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_50_SUPPORT (0x00000040) #define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT (0x20000000) #define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT (0x40000000) #define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT (0x80000000) @@ -726,6 +1003,265 @@ typedef struct _CONFIG_PAGE_IOC_5 #define MPI_IOCPAGE5_PAGEVERSION (0x00) +/**************************************************************************** +* BIOS Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_BIOS_1 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 BiosOptions; /* 04h */ + U32 IOCSettings; /* 08h */ + U32 Reserved1; /* 0Ch */ + U32 DeviceSettings; /* 10h */ + U16 NumberOfDevices; /* 14h */ + U8 ExpanderSpinup; /* 16h */ + U8 Reserved2; /* 17h */ + U16 IOTimeoutBlockDevicesNonRM; /* 18h */ + U16 IOTimeoutSequential; /* 1Ah */ + U16 IOTimeoutOther; /* 1Ch */ + U16 IOTimeoutBlockDevicesRM; /* 1Eh */ +} CONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1, + BIOSPage1_t, MPI_POINTER pBIOSPage1_t; + +#define MPI_BIOSPAGE1_PAGEVERSION (0x03) + +/* values for the BiosOptions field */ +#define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE (0x00000400) +#define MPI_BIOSPAGE1_OPTIONS_FC_ENABLE (0x00000200) +#define MPI_BIOSPAGE1_OPTIONS_SAS_ENABLE (0x00000100) +#define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) + +/* values for the IOCSettings field */ +#define MPI_BIOSPAGE1_IOCSET_MASK_INITIAL_SPINUP_DELAY (0x0F000000) +#define MPI_BIOSPAGE1_IOCSET_SHIFT_INITIAL_SPINUP_DELAY (24) + +#define MPI_BIOSPAGE1_IOCSET_MASK_PORT_ENABLE_DELAY (0x00F00000) +#define MPI_BIOSPAGE1_IOCSET_SHIFT_PORT_ENABLE_DELAY (20) + +#define MPI_BIOSPAGE1_IOCSET_AUTO_PORT_ENABLE (0x00080000) +#define MPI_BIOSPAGE1_IOCSET_DIRECT_ATTACH_SPINUP_MODE (0x00040000) + +#define MPI_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) +#define MPI_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) + +#define MPI_BIOSPAGE1_IOCSET_MASK_MAX_TARGET_SPIN_UP (0x0000F000) +#define MPI_BIOSPAGE1_IOCSET_SHIFT_MAX_TARGET_SPIN_UP (12) + +#define MPI_BIOSPAGE1_IOCSET_MASK_SPINUP_DELAY (0x00000F00) +#define MPI_BIOSPAGE1_IOCSET_SHIFT_SPINUP_DELAY (8) + +#define MPI_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) +#define MPI_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) +#define MPI_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) + +#define MPI_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) +#define MPI_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) +#define MPI_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) +#define MPI_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) + +#define MPI_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) + +/* values for the DeviceSettings field */ +#define MPI_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) + +/* defines for the ExpanderSpinup field */ +#define MPI_BIOSPAGE1_EXPSPINUP_MASK_MAX_TARGET (0xF0) +#define MPI_BIOSPAGE1_EXPSPINUP_SHIFT_MAX_TARGET (4) +#define MPI_BIOSPAGE1_EXPSPINUP_MASK_DELAY (0x0F) + +typedef struct _MPI_BOOT_DEVICE_ADAPTER_ORDER +{ + U32 Reserved1; /* 00h */ + U32 Reserved2; /* 04h */ + U32 Reserved3; /* 08h */ + U32 Reserved4; /* 0Ch */ + U32 Reserved5; /* 10h */ + U32 Reserved6; /* 14h */ + U32 Reserved7; /* 18h */ + U32 Reserved8; /* 1Ch */ + U32 Reserved9; /* 20h */ + U32 Reserved10; /* 24h */ + U32 Reserved11; /* 28h */ + U32 Reserved12; /* 2Ch */ + U32 Reserved13; /* 30h */ + U32 Reserved14; /* 34h */ + U32 Reserved15; /* 38h */ + U32 Reserved16; /* 3Ch */ + U32 Reserved17; /* 40h */ +} MPI_BOOT_DEVICE_ADAPTER_ORDER, MPI_POINTER PTR_MPI_BOOT_DEVICE_ADAPTER_ORDER; + +typedef struct _MPI_BOOT_DEVICE_ADAPTER_NUMBER +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 AdapterNumber; /* 02h */ + U8 Reserved1; /* 03h */ + U32 Reserved2; /* 04h */ + U32 Reserved3; /* 08h */ + U32 Reserved4; /* 0Ch */ + U8 LUN[8]; /* 10h */ + U32 Reserved5; /* 18h */ + U32 Reserved6; /* 1Ch */ + U32 Reserved7; /* 20h */ + U32 Reserved8; /* 24h */ + U32 Reserved9; /* 28h */ + U32 Reserved10; /* 2Ch */ + U32 Reserved11; /* 30h */ + U32 Reserved12; /* 34h */ + U32 Reserved13; /* 38h */ + U32 Reserved14; /* 3Ch */ + U32 Reserved15; /* 40h */ +} MPI_BOOT_DEVICE_ADAPTER_NUMBER, MPI_POINTER PTR_MPI_BOOT_DEVICE_ADAPTER_NUMBER; + +typedef struct _MPI_BOOT_DEVICE_PCI_ADDRESS +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U16 PCIAddress; /* 02h */ + U32 Reserved1; /* 04h */ + U32 Reserved2; /* 08h */ + U32 Reserved3; /* 0Ch */ + U8 LUN[8]; /* 10h */ + U32 Reserved4; /* 18h */ + U32 Reserved5; /* 1Ch */ + U32 Reserved6; /* 20h */ + U32 Reserved7; /* 24h */ + U32 Reserved8; /* 28h */ + U32 Reserved9; /* 2Ch */ + U32 Reserved10; /* 30h */ + U32 Reserved11; /* 34h */ + U32 Reserved12; /* 38h */ + U32 Reserved13; /* 3Ch */ + U32 Reserved14; /* 40h */ +} MPI_BOOT_DEVICE_PCI_ADDRESS, MPI_POINTER PTR_MPI_BOOT_DEVICE_PCI_ADDRESS; + +typedef struct _MPI_BOOT_DEVICE_SLOT_NUMBER +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 PCISlotNumber; /* 02h */ + U8 Reserved1; /* 03h */ + U32 Reserved2; /* 04h */ + U32 Reserved3; /* 08h */ + U32 Reserved4; /* 0Ch */ + U8 LUN[8]; /* 10h */ + U32 Reserved5; /* 18h */ + U32 Reserved6; /* 1Ch */ + U32 Reserved7; /* 20h */ + U32 Reserved8; /* 24h */ + U32 Reserved9; /* 28h */ + U32 Reserved10; /* 2Ch */ + U32 Reserved11; /* 30h */ + U32 Reserved12; /* 34h */ + U32 Reserved13; /* 38h */ + U32 Reserved14; /* 3Ch */ + U32 Reserved15; /* 40h */ +} MPI_BOOT_DEVICE_PCI_SLOT_NUMBER, MPI_POINTER PTR_MPI_BOOT_DEVICE_PCI_SLOT_NUMBER; + +typedef struct _MPI_BOOT_DEVICE_FC_WWN +{ + U64 WWPN; /* 00h */ + U32 Reserved1; /* 08h */ + U32 Reserved2; /* 0Ch */ + U8 LUN[8]; /* 10h */ + U32 Reserved3; /* 18h */ + U32 Reserved4; /* 1Ch */ + U32 Reserved5; /* 20h */ + U32 Reserved6; /* 24h */ + U32 Reserved7; /* 28h */ + U32 Reserved8; /* 2Ch */ + U32 Reserved9; /* 30h */ + U32 Reserved10; /* 34h */ + U32 Reserved11; /* 38h */ + U32 Reserved12; /* 3Ch */ + U32 Reserved13; /* 40h */ +} MPI_BOOT_DEVICE_FC_WWN, MPI_POINTER PTR_MPI_BOOT_DEVICE_FC_WWN; + +typedef struct _MPI_BOOT_DEVICE_SAS_WWN +{ + U64 SASAddress; /* 00h */ + U32 Reserved1; /* 08h */ + U32 Reserved2; /* 0Ch */ + U8 LUN[8]; /* 10h */ + U32 Reserved3; /* 18h */ + U32 Reserved4; /* 1Ch */ + U32 Reserved5; /* 20h */ + U32 Reserved6; /* 24h */ + U32 Reserved7; /* 28h */ + U32 Reserved8; /* 2Ch */ + U32 Reserved9; /* 30h */ + U32 Reserved10; /* 34h */ + U32 Reserved11; /* 38h */ + U32 Reserved12; /* 3Ch */ + U32 Reserved13; /* 40h */ +} MPI_BOOT_DEVICE_SAS_WWN, MPI_POINTER PTR_MPI_BOOT_DEVICE_SAS_WWN; + +typedef struct _MPI_BOOT_DEVICE_ENCLOSURE_SLOT +{ + U64 EnclosureLogicalID; /* 00h */ + U32 Reserved1; /* 08h */ + U32 Reserved2; /* 0Ch */ + U8 LUN[8]; /* 10h */ + U16 SlotNumber; /* 18h */ + U16 Reserved3; /* 1Ah */ + U32 Reserved4; /* 1Ch */ + U32 Reserved5; /* 20h */ + U32 Reserved6; /* 24h */ + U32 Reserved7; /* 28h */ + U32 Reserved8; /* 2Ch */ + U32 Reserved9; /* 30h */ + U32 Reserved10; /* 34h */ + U32 Reserved11; /* 38h */ + U32 Reserved12; /* 3Ch */ + U32 Reserved13; /* 40h */ +} MPI_BOOT_DEVICE_ENCLOSURE_SLOT, + MPI_POINTER PTR_MPI_BOOT_DEVICE_ENCLOSURE_SLOT; + +typedef union _MPI_BIOSPAGE2_BOOT_DEVICE +{ + MPI_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder; + MPI_BOOT_DEVICE_ADAPTER_NUMBER AdapterNumber; + MPI_BOOT_DEVICE_PCI_ADDRESS PCIAddress; + MPI_BOOT_DEVICE_PCI_SLOT_NUMBER PCISlotNumber; + MPI_BOOT_DEVICE_FC_WWN FcWwn; + MPI_BOOT_DEVICE_SAS_WWN SasWwn; + MPI_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot; +} MPI_BIOSPAGE2_BOOT_DEVICE, MPI_POINTER PTR_MPI_BIOSPAGE2_BOOT_DEVICE; + +typedef struct _CONFIG_PAGE_BIOS_2 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 04h */ + U32 Reserved2; /* 08h */ + U32 Reserved3; /* 0Ch */ + U32 Reserved4; /* 10h */ + U32 Reserved5; /* 14h */ + U32 Reserved6; /* 18h */ + U8 BootDeviceForm; /* 1Ch */ + U8 Reserved7; /* 1Dh */ + U16 Reserved8; /* 1Eh */ + MPI_BIOSPAGE2_BOOT_DEVICE BootDevice; /* 20h */ +} CONFIG_PAGE_BIOS_2, MPI_POINTER PTR_CONFIG_PAGE_BIOS_2, + BIOSPage2_t, MPI_POINTER pBIOSPage2_t; + +#define MPI_BIOSPAGE2_PAGEVERSION (0x01) + +#define MPI_BIOSPAGE2_FORM_MASK (0x0F) +#define MPI_BIOSPAGE2_FORM_ADAPTER_ORDER (0x00) +#define MPI_BIOSPAGE2_FORM_ADAPTER_NUMBER (0x01) +#define MPI_BIOSPAGE2_FORM_PCI_ADDRESS (0x02) +#define MPI_BIOSPAGE2_FORM_PCI_SLOT_NUMBER (0x03) +#define MPI_BIOSPAGE2_FORM_FC_WWN (0x04) +#define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05) +#define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) + /**************************************************************************** * SCSI Port Config Pages @@ -739,13 +1275,34 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_0 } CONFIG_PAGE_SCSI_PORT_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_0, SCSIPortPage0_t, MPI_POINTER pSCSIPortPage0_t; -#define MPI_SCSIPORTPAGE0_PAGEVERSION (0x01) +#define MPI_SCSIPORTPAGE0_PAGEVERSION (0x02) #define MPI_SCSIPORTPAGE0_CAP_IU (0x00000001) #define MPI_SCSIPORTPAGE0_CAP_DT (0x00000002) #define MPI_SCSIPORTPAGE0_CAP_QAS (0x00000004) #define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIPORTPAGE0_SYNC_ASYNC (0x00) +#define MPI_SCSIPORTPAGE0_SYNC_5 (0x32) +#define MPI_SCSIPORTPAGE0_SYNC_10 (0x19) +#define MPI_SCSIPORTPAGE0_SYNC_20 (0x0C) +#define MPI_SCSIPORTPAGE0_SYNC_33_33 (0x0B) +#define MPI_SCSIPORTPAGE0_SYNC_40 (0x0A) +#define MPI_SCSIPORTPAGE0_SYNC_80 (0x09) +#define MPI_SCSIPORTPAGE0_SYNC_160 (0x08) +#define MPI_SCSIPORTPAGE0_SYNC_UNKNOWN (0xFF) + +#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD (8) +#define MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(Cap) \ + ( ((Cap) & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK) \ + >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD \ + ) #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET (16) +#define MPI_SCSIPORTPAGE0_CAP_GET_MAX_SYNC_OFFSET(Cap) \ + ( ((Cap) & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK) \ + >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET \ + ) +#define MPI_SCSIPORTPAGE0_CAP_IDP (0x08000000) #define MPI_SCSIPORTPAGE0_CAP_WIDE (0x20000000) #define MPI_SCSIPORTPAGE0_CAP_AIP (0x80000000) @@ -775,6 +1332,7 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_1 /* Configuration values */ #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK (0x000000FF) #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK (0xFFFF0000) +#define MPI_SCSIPORTPAGE1_CFG_SHIFT_PORT_RESPONSE_ID (16) /* TargetConfig values */ #define MPI_SCSIPORTPAGE1_TARGCONFIG_TARG_ONLY (0x01) @@ -811,6 +1369,7 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY (0x00000020) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV (0x00000060) + /* PortSettings values */ #define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK (0x0000000F) #define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA (0x00000030) @@ -819,7 +1378,11 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2 #define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA (0x00000020) #define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA (0x00000030) #define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA (0x000000C0) +#define MPI_SCSIPORTPAGE2_PORT_RM_NONE (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_RM_BOOT_ONLY (0x00000040) +#define MPI_SCSIPORTPAGE2_PORT_RM_WITH_MEDIA (0x00000080) #define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK (0x00000F00) +#define MPI_SCSIPORTPAGE2_PORT_SHIFT_SPINUP_DELAY (8) #define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS (0x00003000) #define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS (0x00000000) #define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS (0x00001000) @@ -845,7 +1408,7 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_0 } CONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0, SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t; -#define MPI_SCSIDEVPAGE0_PAGEVERSION (0x03) +#define MPI_SCSIDEVPAGE0_PAGEVERSION (0x04) #define MPI_SCSIDEVPAGE0_NP_IU (0x00000001) #define MPI_SCSIDEVPAGE0_NP_DT (0x00000002) @@ -856,7 +1419,10 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_0 #define MPI_SCSIDEVPAGE0_NP_RTI (0x00000040) #define MPI_SCSIDEVPAGE0_NP_PCOMP_EN (0x00000080) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD (8) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET (16) +#define MPI_SCSIDEVPAGE0_NP_IDP (0x08000000) #define MPI_SCSIDEVPAGE0_NP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE0_NP_AIP (0x80000000) @@ -875,7 +1441,7 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_1 } CONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1, SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t; -#define MPI_SCSIDEVPAGE1_PAGEVERSION (0x04) +#define MPI_SCSIDEVPAGE1_PAGEVERSION (0x05) #define MPI_SCSIDEVPAGE1_RP_IU (0x00000001) #define MPI_SCSIDEVPAGE1_RP_DT (0x00000002) @@ -886,7 +1452,10 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_1 #define MPI_SCSIDEVPAGE1_RP_RTI (0x00000040) #define MPI_SCSIDEVPAGE1_RP_PCOMP_EN (0x00000080) #define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD (8) #define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET (16) +#define MPI_SCSIDEVPAGE1_RP_IDP (0x08000000) #define MPI_SCSIDEVPAGE1_RP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE1_RP_AIP (0x80000000) @@ -1032,13 +1601,18 @@ typedef struct _CONFIG_PAGE_FC_PORT_0 #define MPI_FCPORTPAGE0_SUPPORT_CLASS_2 (0x00000002) #define MPI_FCPORTPAGE0_SUPPORT_CLASS_3 (0x00000004) +#define MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN (0x00000000) /* (SNIA)HBA_PORTSPEED_UNKNOWN 0 Unknown - transceiver incapable of reporting */ #define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ #define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ #define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED (0x00000008) /* (SNIA)HBA_PORTSPEED_4GBIT 8 4 GBit/sec */ +#define MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN #define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED #define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED #define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_NOT_NEGOTIATED (0x00008000) /* (SNIA)HBA_PORTSPEED_NOT_NEGOTIATED (1<<15) Speed not established */ typedef struct _CONFIG_PAGE_FC_PORT_1 @@ -1067,6 +1641,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_1 #define MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID (0x00800000) #define MPI_FCPORTPAGE1_FLAGS_PORT_OFFLINE (0x00400000) #define MPI_FCPORTPAGE1_FLAGS_SOFT_ALPA_FALLBACK (0x00200000) +#define MPI_FCPORTPAGE1_FLAGS_TARGET_LARGE_CDB_ENABLE (0x00000080) #define MPI_FCPORTPAGE1_FLAGS_MASK_RR_TOV_UNITS (0x00000070) #define MPI_FCPORTPAGE1_FLAGS_SUPPRESS_PROT_REG (0x00000008) #define MPI_FCPORTPAGE1_FLAGS_PLOGI_ON_LOGO (0x00000004) @@ -1476,15 +2051,16 @@ typedef struct _RAID_VOL0_STATUS RaidVol0Status_t, MPI_POINTER pRaidVol0Status_t; /* RAID Volume Page 0 VolumeStatus defines */ - #define MPI_RAIDVOL0_STATUS_FLAG_ENABLED (0x01) #define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED (0x02) #define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x04) #define MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x08) +#define MPI_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x10) #define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL (0x00) #define MPI_RAIDVOL0_STATUS_STATE_DEGRADED (0x01) #define MPI_RAIDVOL0_STATUS_STATE_FAILED (0x02) +#define MPI_RAIDVOL0_STATUS_STATE_MISSING (0x03) typedef struct _RAID_VOL0_SETTINGS { @@ -1495,11 +2071,11 @@ typedef struct _RAID_VOL0_SETTINGS RaidVol0Settings, MPI_POINTER pRaidVol0Settings; /* RAID Volume Page 0 VolumeSettings defines */ - #define MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE (0x0001) #define MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART (0x0002) #define MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE (0x0004) #define MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC (0x0008) +#define MPI_RAIDVOL0_SETTING_FAST_DATA_SCRUBBING_0102 (0x0020) /* obsolete */ #define MPI_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0010) #define MPI_RAIDVOL0_SETTING_USE_DEFAULTS (0x8000) @@ -1543,7 +2119,34 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 } CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0, RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t; -#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x01) +#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x05) + +/* values for RAID Volume Page 0 InactiveStatus field */ +#define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) +#define MPI_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01) +#define MPI_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02) +#define MPI_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03) +#define MPI_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04) +#define MPI_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05) +#define MPI_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06) + + +typedef struct _CONFIG_PAGE_RAID_VOL_1 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U8 VolumeID; /* 01h */ + U8 VolumeBus; /* 02h */ + U8 VolumeIOC; /* 03h */ + U8 Reserved0; /* 04h */ + U8 GUID[24]; /* 05h */ + U8 Name[32]; /* 20h */ + U64 WWID; /* 40h */ + U32 Reserved1; /* 48h */ + U32 Reserved2; /* 4Ch */ +} CONFIG_PAGE_RAID_VOL_1, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_1, + RaidVolumePage1_t, MPI_POINTER pRaidVolumePage1_t; + +#define MPI_RAIDVOLPAGE1_PAGEVERSION (0x01) /**************************************************************************** @@ -1594,6 +2197,9 @@ typedef struct _RAID_PHYS_DISK0_STATUS #define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x01) #define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED (0x02) +#define MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x04) +#define MPI_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00) +#define MPI_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x08) #define MPI_PHYSDISK0_STATUS_ONLINE (0x00) #define MPI_PHYSDISK0_STATUS_MISSING (0x01) @@ -1613,8 +2219,7 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_0 U8 PhysDiskNum; /* 07h */ RAID_PHYS_DISK0_SETTINGS PhysDiskSettings; /* 08h */ U32 Reserved1; /* 0Ch */ - U32 Reserved2; /* 10h */ - U32 Reserved3; /* 14h */ + U8 ExtDiskIdentifier[8]; /* 10h */ U8 DiskIdentifier[16]; /* 18h */ RAID_PHYS_DISK0_INQUIRY_DATA InquiryData; /* 28h */ RAID_PHYS_DISK0_STATUS PhysDiskStatus; /* 64h */ @@ -1623,7 +2228,38 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_0 } CONFIG_PAGE_RAID_PHYS_DISK_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_0, RaidPhysDiskPage0_t, MPI_POINTER pRaidPhysDiskPage0_t; -#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION (0x00) +#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION (0x02) + + +typedef struct _RAID_PHYS_DISK1_PATH +{ + U8 PhysDiskID; /* 00h */ + U8 PhysDiskBus; /* 01h */ + U16 Reserved1; /* 02h */ + U64 WWID; /* 04h */ + U64 OwnerWWID; /* 0Ch */ + U8 OwnerIdentifier; /* 14h */ + U8 Reserved2; /* 15h */ + U16 Flags; /* 16h */ +} RAID_PHYS_DISK1_PATH, MPI_POINTER PTR_RAID_PHYS_DISK1_PATH, + RaidPhysDisk1Path_t, MPI_POINTER pRaidPhysDisk1Path_t; + +/* RAID Physical Disk Page 1 Flags field defines */ +#define MPI_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) +#define MPI_RAID_PHYSDISK1_FLAG_INVALID (0x0001) + +typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U8 NumPhysDiskPaths; /* 04h */ + U8 PhysDiskNum; /* 05h */ + U16 Reserved2; /* 06h */ + U32 Reserved1; /* 08h */ + RAID_PHYS_DISK1_PATH Path[1]; /* 0Ch */ +} CONFIG_PAGE_RAID_PHYS_DISK_1, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_1, + RaidPhysDiskPage1_t, MPI_POINTER pRaidPhysDiskPage1_t; + +#define MPI_RAIDPHYSDISKPAGE1_PAGEVERSION (0x00) /**************************************************************************** @@ -1669,5 +2305,560 @@ typedef struct _CONFIG_PAGE_LAN_1 #define MPI_LAN_PAGE1_DEV_STATE_RESET (0x00) #define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL (0x01) + +/**************************************************************************** +* Inband Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_INBAND_0 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + MPI_VERSION_FORMAT InbandVersion; /* 04h */ + U16 MaximumBuffers; /* 08h */ + U16 Reserved1; /* 0Ah */ +} CONFIG_PAGE_INBAND_0, MPI_POINTER PTR_CONFIG_PAGE_INBAND_0, + InbandPage0_t, MPI_POINTER pInbandPage0_t; + +#define MPI_INBAND_PAGEVERSION (0x00) + + + +/**************************************************************************** +* SAS IO Unit Config Pages +****************************************************************************/ + +typedef struct _MPI_SAS_IO_UNIT0_PHY_DATA +{ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 NegotiatedLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo;/* 04h */ + U16 AttachedDeviceHandle; /* 08h */ + U16 ControllerDevHandle; /* 0Ah */ + U32 DiscoveryStatus; /* 0Ch */ +} MPI_SAS_IO_UNIT0_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT0_PHY_DATA, + SasIOUnit0PhyData, MPI_POINTER pSasIOUnit0PhyData; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_SAS_IOUNIT0_PHY_MAX +#define MPI_SAS_IOUNIT0_PHY_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U8 NumPhys; /* 0Ch */ + U8 Reserved2; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + MPI_SAS_IO_UNIT0_PHY_DATA PhyData[MPI_SAS_IOUNIT0_PHY_MAX]; /* 10h */ +} CONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0, + SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t; + +#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x03) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI_SAS_IOUNIT0_PHY_FLAGS_PHY_DISABLED (0x04) +#define MPI_SAS_IOUNIT0_PHY_FLAGS_TX_INVERT (0x02) +#define MPI_SAS_IOUNIT0_PHY_FLAGS_RX_INVERT (0x01) + +/* values for SAS IO Unit Page 0 NegotiatedLinkRate */ +#define MPI_SAS_IOUNIT0_RATE_UNKNOWN (0x00) +#define MPI_SAS_IOUNIT0_RATE_PHY_DISABLED (0x01) +#define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION (0x02) +#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) + +/* see mpi_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ + +/* values for SAS IO Unit Page 0 DiscoveryStatus */ +#define MPI_SAS_IOUNIT0_DS_LOOP_DETECTED (0x00000001) +#define MPI_SAS_IOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI_SAS_IOUNIT0_DS_MULTIPLE_PORTS (0x00000004) +#define MPI_SAS_IOUNIT0_DS_EXPANDER_ERR (0x00000008) +#define MPI_SAS_IOUNIT0_DS_SMP_TIMEOUT (0x00000010) +#define MPI_SAS_IOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI_SAS_IOUNIT0_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI_SAS_IOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI_SAS_IOUNIT0_DS_SMP_CRC_ERROR (0x00000100) +#define MPI_SAS_IOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI_SAS_IOUNIT0_DS_TABLE_LINK (0x00000400) +#define MPI_SAS_IOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI_SAS_IOUNIT0_DS_MAX_SATA_TARGETS (0x00001000) + + +typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA +{ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 MaxMinLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo;/* 04h */ + U32 Reserved1; /* 08h */ +} MPI_SAS_IO_UNIT1_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT1_PHY_DATA, + SasIOUnit1PhyData, MPI_POINTER pSasIOUnit1PhyData; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_SAS_IOUNIT1_PHY_MAX +#define MPI_SAS_IOUNIT1_PHY_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U16 ControlFlags; /* 08h */ + U16 MaxNumSATATargets; /* 0Ah */ + U32 Reserved1; /* 0Ch */ + U8 NumPhys; /* 10h */ + U8 SATAMaxQDepth; /* 11h */ + U16 Reserved2; /* 12h */ + MPI_SAS_IO_UNIT1_PHY_DATA PhyData[MPI_SAS_IOUNIT1_PHY_MAX]; /* 14h */ +} CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1, + SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t; + +#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x05) + +/* values for SAS IO Unit Page 1 ControlFlags */ +#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) +#define MPI_SAS_IOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) +#define MPI_SAS_IOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) +#define MPI_SAS_IOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) +#define MPI_SAS_IOUNIT1_CONTROL_DISABLE_SAS_HASH (0x0800) + +#define MPI_SAS_IOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600) +#define MPI_SAS_IOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) +#define MPI_SAS_IOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x00) +#define MPI_SAS_IOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x01) +#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x02) + +#define MPI_SAS_IOUNIT1_CONTROL_POSTPONE_SATA_INIT (0x0100) +#define MPI_SAS_IOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) +#define MPI_SAS_IOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) +#define MPI_SAS_IOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) +#define MPI_SAS_IOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) +#define MPI_SAS_IOUNIT1_CONTROL_PHY_ENABLE_ORDER_HIGH (0x0008) +#define MPI_SAS_IOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) +#define MPI_SAS_IOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) +#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) + +/* values for SAS IO Unit Page 1 PortFlags */ +#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE (0x04) +#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT (0x02) +#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT (0x01) + +/* values for SAS IO Unit Page 0 MaxMinLinkRate */ +#define MPI_SAS_IOUNIT1_MAX_RATE_MASK (0xF0) +#define MPI_SAS_IOUNIT1_MAX_RATE_1_5 (0x80) +#define MPI_SAS_IOUNIT1_MAX_RATE_3_0 (0x90) +#define MPI_SAS_IOUNIT1_MIN_RATE_MASK (0x0F) +#define MPI_SAS_IOUNIT1_MIN_RATE_1_5 (0x08) +#define MPI_SAS_IOUNIT1_MIN_RATE_3_0 (0x09) + +/* see mpi_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ + + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U8 NumDevsPerEnclosure; /* 08h */ + U8 Reserved1; /* 09h */ + U16 Reserved2; /* 0Ah */ + U16 MaxPersistentIDs; /* 0Ch */ + U16 NumPersistentIDsUsed; /* 0Eh */ + U8 Status; /* 10h */ + U8 Flags; /* 11h */ + U16 MaxNumPhysicalMappedIDs;/* 12h */ +} CONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2, + SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t; + +#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x05) + +/* values for SAS IO Unit Page 2 Status field */ +#define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02) +#define MPI_SAS_IOUNIT2_STATUS_FULL_PERSISTENT_MAPPINGS (0x01) + +/* values for SAS IO Unit Page 2 Flags field */ +#define MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS (0x01) +/* Physical Mapping Modes */ +#define MPI_SAS_IOUNIT2_FLAGS_MASK_PHYS_MAP_MODE (0x0E) +#define MPI_SAS_IOUNIT2_FLAGS_SHIFT_PHYS_MAP_MODE (1) +#define MPI_SAS_IOUNIT2_FLAGS_NO_PHYS_MAP (0x00) +#define MPI_SAS_IOUNIT2_FLAGS_DIRECT_ATTACH_PHYS_MAP (0x01) +#define MPI_SAS_IOUNIT2_FLAGS_ENCLOSURE_SLOT_PHYS_MAP (0x02) +#define MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP (0x07) + +#define MPI_SAS_IOUNIT2_FLAGS_RESERVE_ID_0_FOR_BOOT (0x10) +#define MPI_SAS_IOUNIT2_FLAGS_DA_STARTING_SLOT (0x20) + + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_3 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 MaxInvalidDwordCount; /* 0Ch */ + U32 InvalidDwordCountTime; /* 10h */ + U32 MaxRunningDisparityErrorCount; /* 14h */ + U32 RunningDisparityErrorTime; /* 18h */ + U32 MaxLossDwordSynchCount; /* 1Ch */ + U32 LossDwordSynchCountTime; /* 20h */ + U32 MaxPhyResetProblemCount; /* 24h */ + U32 PhyResetProblemTime; /* 28h */ +} CONFIG_PAGE_SAS_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_3, + SasIOUnitPage3_t, MPI_POINTER pSasIOUnitPage3_t; + +#define MPI_SASIOUNITPAGE3_PAGEVERSION (0x00) + + +/**************************************************************************** +* SAS Expander Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_SAS_EXPANDER_0 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U8 PhysicalPort; /* 08h */ + U8 Reserved1; /* 09h */ + U16 EnclosureHandle; /* 0Ah */ + U64 SASAddress; /* 0Ch */ + U32 DiscoveryStatus; /* 14h */ + U16 DevHandle; /* 18h */ + U16 ParentDevHandle; /* 1Ah */ + U16 ExpanderChangeCount; /* 1Ch */ + U16 ExpanderRouteIndexes; /* 1Eh */ + U8 NumPhys; /* 20h */ + U8 SASLevel; /* 21h */ + U8 Flags; /* 22h */ + U8 Reserved3; /* 23h */ +} CONFIG_PAGE_SAS_EXPANDER_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_0, + SasExpanderPage0_t, MPI_POINTER pSasExpanderPage0_t; + +#define MPI_SASEXPANDER0_PAGEVERSION (0x03) + +/* values for SAS Expander Page 0 DiscoveryStatus field */ +#define MPI_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) +#define MPI_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004) +#define MPI_SAS_EXPANDER0_DS_EXPANDER_ERR (0x00000008) +#define MPI_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010) +#define MPI_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100) +#define MPI_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400) +#define MPI_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) + +/* values for SAS Expander Page 0 Flags field */ +#define MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x02) +#define MPI_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x01) + + +typedef struct _CONFIG_PAGE_SAS_EXPANDER_1 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U8 PhysicalPort; /* 08h */ + U8 Reserved1; /* 09h */ + U16 Reserved2; /* 0Ah */ + U8 NumPhys; /* 0Ch */ + U8 Phy; /* 0Dh */ + U16 NumTableEntriesProgrammed; /* 0Eh */ + U8 ProgrammedLinkRate; /* 10h */ + U8 HwLinkRate; /* 11h */ + U16 AttachedDevHandle; /* 12h */ + U32 PhyInfo; /* 14h */ + U32 AttachedDeviceInfo; /* 18h */ + U16 OwnerDevHandle; /* 1Ch */ + U8 ChangeCount; /* 1Eh */ + U8 NegotiatedLinkRate; /* 1Fh */ + U8 PhyIdentifier; /* 20h */ + U8 AttachedPhyIdentifier; /* 21h */ + U8 Reserved3; /* 22h */ + U8 DiscoveryInfo; /* 23h */ + U32 Reserved4; /* 24h */ +} CONFIG_PAGE_SAS_EXPANDER_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_1, + SasExpanderPage1_t, MPI_POINTER pSasExpanderPage1_t; + +#define MPI_SASEXPANDER1_PAGEVERSION (0x01) + +/* use MPI_SAS_PHY0_PRATE_ defines for ProgrammedLinkRate */ + +/* use MPI_SAS_PHY0_HWRATE_ defines for HwLinkRate */ + +/* use MPI_SAS_PHY0_PHYINFO_ defines for PhyInfo */ + +/* see mpi_sas.h for values for SAS Expander Page 1 AttachedDeviceInfo values */ + +/* values for SAS Expander Page 1 DiscoveryInfo field */ +#define MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY DISABLED (0x04) +#define MPI_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) +#define MPI_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) + +/* values for SAS Expander Page 1 NegotiatedLinkRate field */ +#define MPI_SAS_EXPANDER1_NEG_RATE_UNKNOWN (0x00) +#define MPI_SAS_EXPANDER1_NEG_RATE_PHY_DISABLED (0x01) +#define MPI_SAS_EXPANDER1_NEG_RATE_FAILED_NEGOTIATION (0x02) +#define MPI_SAS_EXPANDER1_NEG_RATE_SATA_OOB_COMPLETE (0x03) +#define MPI_SAS_EXPANDER1_NEG_RATE_1_5 (0x08) +#define MPI_SAS_EXPANDER1_NEG_RATE_3_0 (0x09) + + +/**************************************************************************** +* SAS Device Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_SAS_DEVICE_0 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U16 Slot; /* 08h */ + U16 EnclosureHandle; /* 0Ah */ + U64 SASAddress; /* 0Ch */ + U16 ParentDevHandle; /* 14h */ + U8 PhyNum; /* 16h */ + U8 AccessStatus; /* 17h */ + U16 DevHandle; /* 18h */ + U8 TargetID; /* 1Ah */ + U8 Bus; /* 1Bh */ + U32 DeviceInfo; /* 1Ch */ + U16 Flags; /* 20h */ + U8 PhysicalPort; /* 22h */ + U8 Reserved2; /* 23h */ +} CONFIG_PAGE_SAS_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_0, + SasDevicePage0_t, MPI_POINTER pSasDevicePage0_t; + +#define MPI_SASDEVICE0_PAGEVERSION (0x04) + +/* values for SAS Device Page 0 AccessStatus field */ +#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) +#define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) + +/* values for SAS Device Page 0 Flags field */ +#define MPI_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) +#define MPI_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) +#define MPI_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) +#define MPI_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) +#define MPI_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) +#define MPI_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) +#define MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x0004) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x0002) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) + +/* see mpi_sas.h for values for SAS Device Page 0 DeviceInfo values */ + + +typedef struct _CONFIG_PAGE_SAS_DEVICE_1 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U8 TargetID; /* 1Ah */ + U8 Bus; /* 1Bh */ + U8 InitialRegDeviceFIS[20];/* 1Ch */ +} CONFIG_PAGE_SAS_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_1, + SasDevicePage1_t, MPI_POINTER pSasDevicePage1_t; + +#define MPI_SASDEVICE1_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_SAS_DEVICE_2 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U64 PhysicalIdentifier; /* 08h */ + U32 EnclosureMapping; /* 10h */ +} CONFIG_PAGE_SAS_DEVICE_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_2, + SasDevicePage2_t, MPI_POINTER pSasDevicePage2_t; + +#define MPI_SASDEVICE2_PAGEVERSION (0x01) + +/* defines for SAS Device Page 2 EnclosureMapping field */ +#define MPI_SASDEVICE2_ENC_MAP_MASK_MISSING_COUNT (0x0000000F) +#define MPI_SASDEVICE2_ENC_MAP_SHIFT_MISSING_COUNT (0) +#define MPI_SASDEVICE2_ENC_MAP_MASK_NUM_SLOTS (0x000007F0) +#define MPI_SASDEVICE2_ENC_MAP_SHIFT_NUM_SLOTS (4) +#define MPI_SASDEVICE2_ENC_MAP_MASK_START_INDEX (0x001FF800) +#define MPI_SASDEVICE2_ENC_MAP_SHIFT_START_INDEX (11) + + +/**************************************************************************** +* SAS PHY Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_SAS_PHY_0 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U16 OwnerDevHandle; /* 08h */ + U16 Reserved1; /* 0Ah */ + U64 SASAddress; /* 0Ch */ + U16 AttachedDevHandle; /* 14h */ + U8 AttachedPhyIdentifier; /* 16h */ + U8 Reserved2; /* 17h */ + U32 AttachedDeviceInfo; /* 18h */ + U8 ProgrammedLinkRate; /* 20h */ + U8 HwLinkRate; /* 21h */ + U8 ChangeCount; /* 22h */ + U8 Flags; /* 23h */ + U32 PhyInfo; /* 24h */ +} CONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0, + SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t; + +#define MPI_SASPHY0_PAGEVERSION (0x01) + +/* values for SAS PHY Page 0 ProgrammedLinkRate field */ +#define MPI_SAS_PHY0_PRATE_MAX_RATE_MASK (0xF0) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_1_5 (0x80) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_3_0 (0x90) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_MASK (0x0F) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_1_5 (0x08) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_3_0 (0x09) + +/* values for SAS PHY Page 0 HwLinkRate field */ +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_MASK (0xF0) +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5 (0x80) +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_3_0 (0x90) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK (0x0F) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5 (0x08) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_3_0 (0x09) + +/* values for SAS PHY Page 0 Flags field */ +#define MPI_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) + +/* values for SAS PHY Page 0 PhyInfo field */ +#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_ACTIVE (0x00004000) +#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_SELECTOR (0x00002000) +#define MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY (0x00001000) + +#define MPI_SAS_PHY0_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) +#define MPI_SAS_PHY0_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) + +#define MPI_SAS_PHY0_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) +#define MPI_SAS_PHY0_PHYINFO_DIRECT_ROUTING (0x00000000) +#define MPI_SAS_PHY0_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) +#define MPI_SAS_PHY0_PHYINFO_TABLE_ROUTING (0x00000020) + +#define MPI_SAS_PHY0_PHYINFO_MASK_LINK_RATE (0x0000000F) +#define MPI_SAS_PHY0_PHYINFO_UNKNOWN_LINK_RATE (0x00000000) +#define MPI_SAS_PHY0_PHYINFO_PHY_DISABLED (0x00000001) +#define MPI_SAS_PHY0_PHYINFO_NEGOTIATION_FAILED (0x00000002) +#define MPI_SAS_PHY0_PHYINFO_SATA_OOB_COMPLETE (0x00000003) +#define MPI_SAS_PHY0_PHYINFO_RATE_1_5 (0x00000008) +#define MPI_SAS_PHY0_PHYINFO_RATE_3_0 (0x00000009) + + +typedef struct _CONFIG_PAGE_SAS_PHY_1 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 InvalidDwordCount; /* 0Ch */ + U32 RunningDisparityErrorCount; /* 10h */ + U32 LossDwordSynchCount; /* 14h */ + U32 PhyResetProblemCount; /* 18h */ +} CONFIG_PAGE_SAS_PHY_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_1, + SasPhyPage1_t, MPI_POINTER pSasPhyPage1_t; + +#define MPI_SASPHY1_PAGEVERSION (0x00) + + +/**************************************************************************** +* SAS Enclosure Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_SAS_ENCLOSURE_0 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 EnclosureLogicalID; /* 0Ch */ + U16 Flags; /* 14h */ + U16 EnclosureHandle; /* 16h */ + U16 NumSlots; /* 18h */ + U16 StartSlot; /* 1Ah */ + U8 StartTargetID; /* 1Ch */ + U8 StartBus; /* 1Dh */ + U8 SEPTargetID; /* 1Eh */ + U8 SEPBus; /* 1Fh */ + U32 Reserved2; /* 20h */ + U32 Reserved3; /* 24h */ +} CONFIG_PAGE_SAS_ENCLOSURE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_ENCLOSURE_0, + SasEnclosurePage0_t, MPI_POINTER pSasEnclosurePage0_t; + +#define MPI_SASENCLOSURE0_PAGEVERSION (0x01) + +/* values for SAS Enclosure Page 0 Flags field */ +#define MPI_SAS_ENCLS0_FLAGS_SEP_BUS_ID_VALID (0x0020) +#define MPI_SAS_ENCLS0_FLAGS_START_BUS_ID_VALID (0x0010) + +#define MPI_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) +#define MPI_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) +#define MPI_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) +#define MPI_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) +#define MPI_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) +#define MPI_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) +#define MPI_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) + + +/**************************************************************************** +* Log Config Pages +****************************************************************************/ +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumLogEntries at runtime. + */ +#ifndef MPI_LOG_0_NUM_LOG_ENTRIES +#define MPI_LOG_0_NUM_LOG_ENTRIES (1) +#endif + +#define MPI_LOG_0_LOG_DATA_LENGTH (0x1C) + +typedef struct _MPI_LOG_0_ENTRY +{ + U32 TimeStamp; /* 00h */ + U32 Reserved1; /* 04h */ + U16 LogSequence; /* 08h */ + U16 LogEntryQualifier; /* 0Ah */ + U8 LogData[MPI_LOG_0_LOG_DATA_LENGTH]; /* 0Ch */ +} MPI_LOG_0_ENTRY, MPI_POINTER PTR_MPI_LOG_0_ENTRY, + MpiLog0Entry_t, MPI_POINTER pMpiLog0Entry_t; + +/* values for Log Page 0 LogEntry LogEntryQualifier field */ +#define MPI_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000) +#define MPI_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001) + +typedef struct _CONFIG_PAGE_LOG_0 +{ + CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 Reserved2; /* 0Ch */ + U16 NumLogEntries; /* 10h */ + U16 Reserved3; /* 12h */ + MPI_LOG_0_ENTRY LogEntry[MPI_LOG_0_NUM_LOG_ENTRIES]; /* 14h */ +} CONFIG_PAGE_LOG_0, MPI_POINTER PTR_CONFIG_PAGE_LOG_0, + LogPage0_t, MPI_POINTER pLogPage0_t; + +#define MPI_LOG_0_PAGEVERSION (0x01) + + #endif diff --git a/sys/dev/mpt/mpilib/mpi_fc.h b/sys/dev/mpt/mpilib/mpi_fc.h index 4067fc33e52f..b50a33261791 100644 --- a/sys/dev/mpt/mpilib/mpi_fc.h +++ b/sys/dev/mpt/mpilib/mpi_fc.h @@ -28,13 +28,13 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Name: MPI_FC.H + * + * + * Name: mpi_fc.h * Title: MPI Fibre Channel messages and structures * Creation Date: June 12, 2000 * - * MPI_FC.H Version: 01.02.04 + * mpi_fc.h Version: 01.05.01 * * Version History * --------------- @@ -65,6 +65,8 @@ * MSG_LINK_SERVICE_RSP_REPLY. * 05-31-02 01.02.03 Adding AliasIndex to FC Direct Access requests. * 01-16-04 01.02.04 Added define for MPI_FC_PRIM_SEND_FLAGS_ML_RESET_LINK. + * 05-11-04 01.03.01 Original release for MPI v1.3. + * 08-19-04 01.05.01 Original release for MPI v1.5. * -------------------------------------------------------------------------- */ @@ -74,7 +76,7 @@ /***************************************************************************** * -* F C T a r g e t M o d e M e s s a g e s +* F C D i r e c t A c c e s s M e s s a g e s * *****************************************************************************/ diff --git a/sys/dev/mpt/mpilib/mpi_init.h b/sys/dev/mpt/mpilib/mpi_init.h index a3dfa42478a9..e44e48aaf479 100644 --- a/sys/dev/mpt/mpilib/mpi_init.h +++ b/sys/dev/mpt/mpilib/mpi_init.h @@ -28,13 +28,12 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Name: MPI_INIT.H + * + * Name: mpi_init.h * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * MPI_INIT.H Version: 01.02.07 + * mpi_init.h Version: 01.05.06 * * Version History * --------------- @@ -61,6 +60,25 @@ * for SCSI IO requests. * 11-15-02 01.02.06 Added special extended SCSI Status defines for FCP. * 06-26-03 01.02.07 Added MPI_SCSI_STATUS_FCPEXT_UNASSIGNED define. + * 05-11-04 01.03.01 Original release for MPI v1.3. + * 08-19-04 01.05.01 Added MsgFlags defines for EEDP to SCSI IO request. + * Added new word to MSG_SCSI_IO_REPLY to add TaskTag field + * and a reserved U16. + * Added new MSG_SCSI_IO32_REQUEST structure. + * Added a TaskType of Clear Task Set to SCSI + * Task Management request. + * 12-07-04 01.05.02 Added support for Task Management Query Task. + * 01-15-05 01.05.03 Modified SCSI Enclosure Processor Request to support + * WWID addressing. + * 03-11-05 01.05.04 Removed EEDP flags from SCSI IO Request. + * Removed SCSI IO 32 Request. + * Modified SCSI Enclosure Processor Request and Reply to + * support Enclosure/Slot addressing rather than WWID + * addressing. + * 06-24-05 01.05.05 Added SCSI IO 32 structures and defines. + * Added four new defines for SEP SlotStatus. + * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them + * unique in the first 32 characters. * -------------------------------------------------------------------------- */ @@ -75,7 +93,7 @@ *****************************************************************************/ /****************************************************************************/ -/* SCSI IO messages and assocaited structures */ +/* SCSI IO messages and associated structures */ /****************************************************************************/ typedef struct _MSG_SCSI_IO_REQUEST @@ -104,9 +122,11 @@ typedef struct _MSG_SCSI_IO_REQUEST #define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH (0x01) #define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32 (0x00) #define MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 (0x01) + #define MPI_SCSIIO_MSGFLGS_SENSE_LOCATION (0x02) #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST (0x00) #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC (0x02) + #define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR (0x04) /* SCSI IO LUN fields */ @@ -166,6 +186,8 @@ typedef struct _MSG_SCSI_IO_REPLY U32 TransferCount; /* 14h */ U32 SenseCount; /* 18h */ U32 ResponseInfo; /* 1Ch */ + U16 TaskTag; /* 20h */ + U16 Reserved1; /* 22h */ } MSG_SCSI_IO_REPLY, MPI_POINTER PTR_MSG_SCSI_IO_REPLY, SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t; @@ -208,6 +230,199 @@ typedef struct _MSG_SCSI_IO_REPLY #define MPI_SCSI_RSP_INFO_TASK_MGMT_FAILED (0x05000000) #define MPI_SCSI_RSP_INFO_SPI_LQ_INVALID_TYPE (0x06000000) +#define MPI_SCSI_TASKTAG_UNKNOWN (0xFFFF) + + +/****************************************************************************/ +/* SCSI IO 32 messages and associated structures */ +/****************************************************************************/ + +typedef struct +{ + U8 CDB[20]; /* 00h */ + U32 PrimaryReferenceTag; /* 14h */ + U16 PrimaryApplicationTag; /* 18h */ + U16 PrimaryApplicationTagMask; /* 1Ah */ + U32 TransferLength; /* 1Ch */ +} MPI_SCSI_IO32_CDB_EEDP32, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_EEDP32, + MpiScsiIo32CdbEedp32_t, MPI_POINTER pMpiScsiIo32CdbEedp32_t; + +typedef struct +{ + U8 CDB[16]; /* 00h */ + U32 DataLength; /* 10h */ + U32 PrimaryReferenceTag; /* 14h */ + U16 PrimaryApplicationTag; /* 18h */ + U16 PrimaryApplicationTagMask; /* 1Ah */ + U32 TransferLength; /* 1Ch */ +} MPI_SCSI_IO32_CDB_EEDP16, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_EEDP16, + MpiScsiIo32CdbEedp16_t, MPI_POINTER pMpiScsiIo32CdbEedp16_t; + +typedef union +{ + U8 CDB32[32]; + MPI_SCSI_IO32_CDB_EEDP32 EEDP32; + MPI_SCSI_IO32_CDB_EEDP16 EEDP16; + SGE_SIMPLE_UNION SGE; +} MPI_SCSI_IO32_CDB_UNION, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_UNION, + MpiScsiIo32Cdb_t, MPI_POINTER pMpiScsiIo32Cdb_t; + +typedef struct +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U16 Reserved1; /* 02h */ + U32 Reserved2; /* 04h */ +} MPI_SCSI_IO32_BUS_TARGET_ID_FORM, MPI_POINTER PTR_MPI_SCSI_IO32_BUS_TARGET_ID_FORM, + MpiScsiIo32BusTargetIdForm_t, MPI_POINTER pMpiScsiIo32BusTargetIdForm_t; + +typedef union +{ + MPI_SCSI_IO32_BUS_TARGET_ID_FORM SCSIID; + U64 WWID; +} MPI_SCSI_IO32_ADDRESS, MPI_POINTER PTR_MPI_SCSI_IO32_ADDRESS, + MpiScsiIo32Address_t, MPI_POINTER pMpiScsiIo32Address_t; + +typedef struct _MSG_SCSI_IO32_REQUEST +{ + U8 Port; /* 00h */ + U8 Reserved1; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Flags; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 LUN[8]; /* 0Ch */ + U32 Control; /* 14h */ + MPI_SCSI_IO32_CDB_UNION CDB; /* 18h */ + U32 DataLength; /* 38h */ + U32 BidirectionalDataLength; /* 3Ch */ + U32 SecondaryReferenceTag; /* 40h */ + U16 SecondaryApplicationTag; /* 44h */ + U16 Reserved2; /* 46h */ + U16 EEDPFlags; /* 48h */ + U16 ApplicationTagTranslationMask; /* 4Ah */ + U32 EEDPBlockSize; /* 4Ch */ + MPI_SCSI_IO32_ADDRESS DeviceAddress; /* 50h */ + U8 SGLOffset0; /* 58h */ + U8 SGLOffset1; /* 59h */ + U8 SGLOffset2; /* 5Ah */ + U8 SGLOffset3; /* 5Bh */ + U32 Reserved3; /* 5Ch */ + U32 Reserved4; /* 60h */ + U32 SenseBufferLowAddr; /* 64h */ + SGE_IO_UNION SGL; /* 68h */ +} MSG_SCSI_IO32_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO32_REQUEST, + SCSIIO32Request_t, MPI_POINTER pSCSIIO32Request_t; + +/* SCSI IO 32 MsgFlags bits */ +#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH (0x01) +#define MPI_SCSIIO32_MSGFLGS_32_SENSE_WIDTH (0x00) +#define MPI_SCSIIO32_MSGFLGS_64_SENSE_WIDTH (0x01) + +#define MPI_SCSIIO32_MSGFLGS_SENSE_LOCATION (0x02) +#define MPI_SCSIIO32_MSGFLGS_SENSE_LOC_HOST (0x00) +#define MPI_SCSIIO32_MSGFLGS_SENSE_LOC_IOC (0x02) + +#define MPI_SCSIIO32_MSGFLGS_CMD_DETERMINES_DATA_DIR (0x04) +#define MPI_SCSIIO32_MSGFLGS_SGL_OFFSETS_CHAINS (0x08) +#define MPI_SCSIIO32_MSGFLGS_MULTICAST (0x10) +#define MPI_SCSIIO32_MSGFLGS_BIDIRECTIONAL (0x20) +#define MPI_SCSIIO32_MSGFLGS_LARGE_CDB (0x40) + +/* SCSI IO 32 Flags bits */ +#define MPI_SCSIIO32_FLAGS_FORM_MASK (0x03) +#define MPI_SCSIIO32_FLAGS_FORM_SCSIID (0x00) +#define MPI_SCSIIO32_FLAGS_FORM_WWID (0x01) + +/* SCSI IO 32 LUN fields */ +#define MPI_SCSIIO32_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI_SCSIIO32_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI_SCSIIO32_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI_SCSIIO32_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI_SCSIIO32_LUN_LEVEL_1_WORD (0xFF00) +#define MPI_SCSIIO32_LUN_LEVEL_1_DWORD (0x0000FF00) + +/* SCSI IO 32 Control bits */ +#define MPI_SCSIIO32_CONTROL_DATADIRECTION_MASK (0x03000000) +#define MPI_SCSIIO32_CONTROL_NODATATRANSFER (0x00000000) +#define MPI_SCSIIO32_CONTROL_WRITE (0x01000000) +#define MPI_SCSIIO32_CONTROL_READ (0x02000000) +#define MPI_SCSIIO32_CONTROL_BIDIRECTIONAL (0x03000000) + +#define MPI_SCSIIO32_CONTROL_ADDCDBLEN_MASK (0xFC000000) +#define MPI_SCSIIO32_CONTROL_ADDCDBLEN_SHIFT (26) + +#define MPI_SCSIIO32_CONTROL_TASKATTRIBUTE_MASK (0x00000700) +#define MPI_SCSIIO32_CONTROL_SIMPLEQ (0x00000000) +#define MPI_SCSIIO32_CONTROL_HEADOFQ (0x00000100) +#define MPI_SCSIIO32_CONTROL_ORDEREDQ (0x00000200) +#define MPI_SCSIIO32_CONTROL_ACAQ (0x00000400) +#define MPI_SCSIIO32_CONTROL_UNTAGGED (0x00000500) +#define MPI_SCSIIO32_CONTROL_NO_DISCONNECT (0x00000700) + +#define MPI_SCSIIO32_CONTROL_TASKMANAGE_MASK (0x00FF0000) +#define MPI_SCSIIO32_CONTROL_OBSOLETE (0x00800000) +#define MPI_SCSIIO32_CONTROL_CLEAR_ACA_RSV (0x00400000) +#define MPI_SCSIIO32_CONTROL_TARGET_RESET (0x00200000) +#define MPI_SCSIIO32_CONTROL_LUN_RESET_RSV (0x00100000) +#define MPI_SCSIIO32_CONTROL_RESERVED (0x00080000) +#define MPI_SCSIIO32_CONTROL_CLR_TASK_SET_RSV (0x00040000) +#define MPI_SCSIIO32_CONTROL_ABORT_TASK_SET (0x00020000) +#define MPI_SCSIIO32_CONTROL_RESERVED2 (0x00010000) + +/* SCSI IO 32 EEDPFlags */ +#define MPI_SCSIIO32_EEDPFLAGS_MASK_OP (0x0007) +#define MPI_SCSIIO32_EEDPFLAGS_NOOP_OP (0x0000) +#define MPI_SCSIIO32_EEDPFLAGS_CHK_OP (0x0001) +#define MPI_SCSIIO32_EEDPFLAGS_STRIP_OP (0x0002) +#define MPI_SCSIIO32_EEDPFLAGS_CHKRM_OP (0x0003) +#define MPI_SCSIIO32_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI_SCSIIO32_EEDPFLAGS_REPLACE_OP (0x0006) +#define MPI_SCSIIO32_EEDPFLAGS_CHKREGEN_OP (0x0007) + +#define MPI_SCSIIO32_EEDPFLAGS_PASS_REF_TAG (0x0008) +#define MPI_SCSIIO32_EEDPFLAGS_8_9THS_MODE (0x0010) + +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_MASK (0x0700) +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_GUARD (0x0100) +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_REFTAG (0x0200) +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_LBATAG (0x0400) +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_SHIFT (8) + +#define MPI_SCSIIO32_EEDPFLAGS_INC_SEC_APPTAG (0x1000) +#define MPI_SCSIIO32_EEDPFLAGS_INC_PRI_APPTAG (0x2000) +#define MPI_SCSIIO32_EEDPFLAGS_INC_SEC_REFTAG (0x4000) +#define MPI_SCSIIO32_EEDPFLAGS_INC_PRI_REFTAG (0x8000) + + +/* SCSIIO32 IO reply structure */ +typedef struct _MSG_SCSIIO32_IO_REPLY +{ + U8 Port; /* 00h */ + U8 Reserved1; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Flags; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 SCSIStatus; /* 0Ch */ + U8 SCSIState; /* 0Dh */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferCount; /* 14h */ + U32 SenseCount; /* 18h */ + U32 ResponseInfo; /* 1Ch */ + U16 TaskTag; /* 20h */ + U16 Reserved2; /* 22h */ + U32 BidirectionalTransferCount; /* 24h */ +} MSG_SCSIIO32_IO_REPLY, MPI_POINTER PTR_MSG_SCSIIO32_IO_REPLY, + SCSIIO32Reply_t, MPI_POINTER pSCSIIO32Reply_t; + /****************************************************************************/ /* SCSI Task Management messages */ @@ -237,6 +452,8 @@ typedef struct _MSG_SCSI_TASK_MGMT #define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS (0x04) #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) +#define MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) /* MsgFlags bits */ #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) @@ -250,7 +467,7 @@ typedef struct _MSG_SCSI_TASK_MGMT_REPLY U8 Bus; /* 01h */ U8 MsgLength; /* 02h */ U8 Function; /* 03h */ - U8 Reserved; /* 04h */ + U8 ResponseCode; /* 04h */ U8 TaskType; /* 05h */ U8 Reserved1; /* 06h */ U8 MsgFlags; /* 07h */ @@ -262,6 +479,15 @@ typedef struct _MSG_SCSI_TASK_MGMT_REPLY } MSG_SCSI_TASK_MGMT_REPLY, MPI_POINTER PTR_MSG_SCSI_TASK_MGMT_REPLY, SCSITaskMgmtReply_t, MPI_POINTER pSCSITaskMgmtReply_t; +/* ResponseCode values */ +#define MPI_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) +#define MPI_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) +#define MPI_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) +#define MPI_SCSITASKMGMT_RSP_TM_FAILED (0x05) +#define MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) +#define MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) + /****************************************************************************/ /* SCSI Enclosure Processor messages */ @@ -274,11 +500,16 @@ typedef struct _MSG_SEP_REQUEST U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ U8 Action; /* 04h */ - U8 Reserved1; /* 05h */ - U8 Reserved2; /* 06h */ + U8 Flags; /* 05h */ + U8 Reserved1; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U32 SlotStatus; /* 0Ch */ + U32 Reserved2; /* 10h */ + U32 Reserved3; /* 14h */ + U32 Reserved4; /* 18h */ + U16 Slot; /* 1Ch */ + U16 EnclosureHandle; /* 1Eh */ } MSG_SEP_REQUEST, MPI_POINTER PTR_MSG_SEP_REQUEST, SEPRequest_t, MPI_POINTER pSEPRequest_t; @@ -286,6 +517,10 @@ typedef struct _MSG_SEP_REQUEST #define MPI_SEP_REQ_ACTION_WRITE_STATUS (0x00) #define MPI_SEP_REQ_ACTION_READ_STATUS (0x01) +/* Flags defines */ +#define MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01) +#define MPI_SEP_REQ_FLAGS_BUS_TARGETID_ADDRESS (0x00) + /* SlotStatus bits for MSG_SEP_REQUEST */ #define MPI_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) #define MPI_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) @@ -297,10 +532,14 @@ typedef struct _MSG_SEP_REQUEST #define MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) #define MPI_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) #define MPI_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI_SEP_REQ_SLOTSTATUS_REQ_CONSISTENCY_CHECK (0x00001000) +#define MPI_SEP_REQ_SLOTSTATUS_DISABLE (0x00002000) +#define MPI_SEP_REQ_SLOTSTATUS_REQ_RESERVED_DEVICE (0x00004000) #define MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) #define MPI_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) #define MPI_SEP_REQ_SLOTSTATUS_REQUEST_INSERT (0x00080000) #define MPI_SEP_REQ_SLOTSTATUS_DO_NOT_MOVE (0x00400000) +#define MPI_SEP_REQ_SLOTSTATUS_ACTIVE (0x00800000) #define MPI_SEP_REQ_SLOTSTATUS_B_ENABLE_BYPASS (0x04000000) #define MPI_SEP_REQ_SLOTSTATUS_A_ENABLE_BYPASS (0x08000000) #define MPI_SEP_REQ_SLOTSTATUS_DEV_OFF (0x10000000) @@ -322,6 +561,9 @@ typedef struct _MSG_SEP_REPLY U16 IOCStatus; /* 0Eh */ U32 IOCLogInfo; /* 10h */ U32 SlotStatus; /* 14h */ + U32 Reserved4; /* 18h */ + U16 Slot; /* 1Ch */ + U16 EnclosureHandle; /* 1Eh */ } MSG_SEP_REPLY, MPI_POINTER PTR_MSG_SEP_REPLY, SEPReply_t, MPI_POINTER pSEPReply_t; @@ -336,11 +578,15 @@ typedef struct _MSG_SEP_REPLY #define MPI_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) #define MPI_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) #define MPI_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI_SEP_REPLY_SLOTSTATUS_CONSISTENCY_CHECK (0x00001000) +#define MPI_SEP_REPLY_SLOTSTATUS_DISABLE (0x00002000) +#define MPI_SEP_REPLY_SLOTSTATUS_RESERVED_DEVICE (0x00004000) #define MPI_SEP_REPLY_SLOTSTATUS_REPORT (0x00010000) #define MPI_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) #define MPI_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) #define MPI_SEP_REPLY_SLOTSTATUS_INSERT_READY (0x00080000) #define MPI_SEP_REPLY_SLOTSTATUS_DO_NOT_REMOVE (0x00400000) +#define MPI_SEP_REPLY_SLOTSTATUS_ACTIVE (0x00800000) #define MPI_SEP_REPLY_SLOTSTATUS_B_BYPASS_ENABLED (0x01000000) #define MPI_SEP_REPLY_SLOTSTATUS_A_BYPASS_ENABLED (0x02000000) #define MPI_SEP_REPLY_SLOTSTATUS_B_ENABLE_BYPASS (0x04000000) diff --git a/sys/dev/mpt/mpilib/mpi_ioc.h b/sys/dev/mpt/mpilib/mpi_ioc.h index 78d20bca2d85..e6deaedf3575 100644 --- a/sys/dev/mpt/mpilib/mpi_ioc.h +++ b/sys/dev/mpt/mpilib/mpi_ioc.h @@ -28,13 +28,13 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Name: MPI_IOC.H + * + * + * 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.02.08 + * mpi_ioc.h Version: 01.05.10 * * Version History * --------------- @@ -85,6 +85,36 @@ * Added AliasIndex to EVENT_DATA_LOGOUT structure. * 04-01-03 01.02.07 Added defines for MPI_FW_HEADER_SIGNATURE_. * 06-26-03 01.02.08 Added new values to the product family defines. + * 04-29-04 01.02.09 Added IOCCapabilities field to MSG_IOC_FACTS_REPLY and + * added related defines. + * 05-11-04 01.03.01 Original release for MPI v1.3. + * 08-19-04 01.05.01 Added four new fields to MSG_IOC_INIT. + * Added three new fields to MSG_IOC_FACTS_REPLY. + * Defined four new bits for the IOCCapabilities field of + * the IOCFacts reply. + * Added two new PortTypes for the PortFacts reply. + * Added six new events along with their EventData + * structures. + * Added a new MsgFlag to the FwDownload request to + * indicate last segment. + * Defined a new image type of boot loader. + * Added FW family codes for SAS product families. + * 10-05-04 01.05.02 Added ReplyFifoHostSignalingAddr field to + * MSG_IOC_FACTS_REPLY. + * 12-07-04 01.05.03 Added more defines for SAS Discovery Error event. + * 12-09-04 01.05.04 Added Unsupported device to SAS Device event. + * 01-15-05 01.05.05 Added event data for SAS SES Event. + * 02-09-05 01.05.06 Added MPI_FW_UPLOAD_ITYPE_FW_BACKUP define. + * 02-22-05 01.05.07 Added Host Page Buffer Persistent flag to IOC Facts + * Reply and IOC Init Request. + * 03-11-05 01.05.08 Added family code for 1068E family. + * Removed IOCFacts Reply EEDP Capability bit. + * 06-24-05 01.05.09 Added 5 new IOCFacts Reply IOCCapabilities bits. + * Added Max SATA Targets to SAS Discovery Error event. + * 08-30-05 01.05.10 Added 4 new events and their event data structures. + * Added new ReasonCode value for SAS Device Status Change + * event. + * Added new family code for FC949E. * -------------------------------------------------------------------------- */ @@ -117,6 +147,10 @@ typedef struct _MSG_IOC_INIT U8 Reserved1[2]; /* 0Eh */ U32 HostMfaHighAddr; /* 10h */ U32 SenseBufferHighAddr; /* 14h */ + U32 ReplyFifoHostSignalingAddr; /* 18h */ + SGE_SIMPLE_UNION HostPageBufferSGE; /* 1Ch */ + U16 MsgVersion; /* 28h */ + U16 HeaderVersion; /* 2Ah */ } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT, IOCInit_t, MPI_POINTER pIOCInit_t; @@ -129,8 +163,23 @@ typedef struct _MSG_IOC_INIT #define MPI_WHOINIT_MANUFACTURER (0x05) /* Flags values */ +#define MPI_IOCINIT_FLAGS_HOST_PAGE_BUFFER_PERSISTENT (0x04) +#define MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL (0x02) #define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE (0x01) +/* MsgVersion */ +#define MPI_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI_IOCINIT_MSGVERSION_MAJOR_SHIFT (8) +#define MPI_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI_IOCINIT_MSGVERSION_MINOR_SHIFT (0) + +/* HeaderVersion */ +#define MPI_IOCINIT_HEADERVERSION_UNIT_MASK (0xFF00) +#define MPI_IOCINIT_HEADERVERSION_UNIT_SHIFT (8) +#define MPI_IOCINIT_HEADERVERSION_DEV_MASK (0x00FF) +#define MPI_IOCINIT_HEADERVERSION_DEV_SHIFT (0) + + typedef struct _MSG_IOC_INIT_REPLY { U8 WhoInit; /* 00h */ @@ -209,25 +258,48 @@ typedef struct _MSG_IOC_FACTS_REPLY U8 MaxDevices; /* 2Eh */ U8 MaxBuses; /* 2Fh */ U32 FWImageSize; /* 30h */ - U32 Reserved4; /* 34h */ + U32 IOCCapabilities; /* 34h */ MPI_FW_VERSION FWVersion; /* 38h */ + U16 HighPriorityQueueDepth; /* 3Ch */ + U16 Reserved2; /* 3Eh */ + SGE_SIMPLE_UNION HostPageBufferSGE; /* 40h */ + U32 ReplyFifoHostSignalingAddr; /* 4Ch */ } MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY, IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t; #define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8) #define MPI_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI_IOCFACTS_MSGVERSION_MINOR_SHIFT (0) -#define MPI_IOCFACTS_HEADERVERSION_UNIT_MASK (0xFF00) -#define MPI_IOCFACTS_HEADERVERSION_DEV_MASK (0x00FF) +#define MPI_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00) +#define MPI_IOCFACTS_HDRVERSION_UNIT_SHIFT (8) +#define MPI_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF) +#define MPI_IOCFACTS_HDRVERSION_DEV_SHIFT (0) #define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) #define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) +#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) +#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL (0x0008) #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) +#define MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL (0x02) +#define MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT (0x04) #define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00) #define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01) +#define MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q (0x00000001) +#define MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL (0x00000002) +#define MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING (0x00000004) +#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) +#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) +#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) +#define MPI_IOCFACTS_CAPABILITY_EEDP (0x00000040) +#define MPI_IOCFACTS_CAPABILITY_BIDIRECTIONAL (0x00000080) +#define MPI_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) +#define MPI_IOCFACTS_CAPABILITY_SCSIIO32 (0x00000200) +#define MPI_IOCFACTS_CAPABILITY_NO_SCSIIO16 (0x00000400) /***************************************************************************** @@ -283,6 +355,8 @@ typedef struct _MSG_PORT_FACTS_REPLY #define MPI_PORTFACTS_PORTTYPE_INACTIVE (0x00) #define MPI_PORTFACTS_PORTTYPE_SCSI (0x01) #define MPI_PORTFACTS_PORTTYPE_FC (0x10) +#define MPI_PORTFACTS_PORTTYPE_ISCSI (0x20) +#define MPI_PORTFACTS_PORTTYPE_SAS (0x30) /* ProtocolFlags values */ @@ -416,6 +490,16 @@ typedef struct _MSG_EVENT_ACK_REPLY #define MPI_EVENT_INTEGRATED_RAID (0x0000000B) #define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) #define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) +#define MPI_EVENT_QUEUE_FULL (0x0000000E) +#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F) +#define MPI_EVENT_SAS_SES (0x00000010) +#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011) +#define MPI_EVENT_SAS_PHY_LINK_STATUS (0x00000012) +#define MPI_EVENT_SAS_DISCOVERY_ERROR (0x00000013) +#define MPI_EVENT_IR_RESYNC_UPDATE (0x00000014) +#define MPI_EVENT_IR2 (0x00000015) +#define MPI_EVENT_SAS_DISCOVERY (0x00000016) +#define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021) /* AckRequired field values */ @@ -432,6 +516,29 @@ typedef struct _EVENT_DATA_EVENT_CHANGE } EVENT_DATA_EVENT_CHANGE, MPI_POINTER PTR_EVENT_DATA_EVENT_CHANGE, EventDataEventChange_t, MPI_POINTER pEventDataEventChange_t; +/* LogEntryAdded Event data */ + +/* this structure matches MPI_LOG_0_ENTRY in mpi_cnfg.h */ +#define MPI_EVENT_DATA_LOG_ENTRY_DATA_LENGTH (0x1C) +typedef struct _EVENT_DATA_LOG_ENTRY +{ + U32 TimeStamp; /* 00h */ + U32 Reserved1; /* 04h */ + U16 LogSequence; /* 08h */ + U16 LogEntryQualifier; /* 0Ah */ + U8 LogData[MPI_EVENT_DATA_LOG_ENTRY_DATA_LENGTH]; /* 0Ch */ +} EVENT_DATA_LOG_ENTRY, MPI_POINTER PTR_EVENT_DATA_LOG_ENTRY, + MpiEventDataLogEntry_t, MPI_POINTER pMpiEventDataLogEntry_t; + +typedef struct _EVENT_DATA_LOG_ENTRY_ADDED +{ + U16 LogSequence; /* 00h */ + U16 Reserved1; /* 02h */ + U32 Reserved2; /* 04h */ + EVENT_DATA_LOG_ENTRY LogEntry; /* 08h */ +} EVENT_DATA_LOG_ENTRY_ADDED, MPI_POINTER PTR_EVENT_DATA_LOG_ENTRY_ADDED, + MpiEventDataLogEntryAdded_t, MPI_POINTER pMpiEventDataLogEntryAdded_t; + /* SCSI Event data for Port, Bus and Device forms */ typedef struct _EVENT_DATA_SCSI @@ -463,6 +570,148 @@ typedef struct _EVENT_DATA_SCSI_DEVICE_STATUS_CHANGE #define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING (0x04) #define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA (0x05) +/* SAS Device Status Change Event data */ + +typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ReasonCode; /* 02h */ + U8 Reserved; /* 03h */ + U8 ASC; /* 04h */ + U8 ASCQ; /* 05h */ + U16 DevHandle; /* 06h */ + U32 DeviceInfo; /* 08h */ + U16 ParentDevHandle; /* 0Ch */ + U8 PhyNum; /* 0Eh */ + U8 Reserved1; /* 0Fh */ + U64 SASAddress; /* 10h */ +} EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MpiEventDataSasDeviceStatusChange_t, + MPI_POINTER pMpiEventDataSasDeviceStatusChange_t; + +/* MPI SAS Device Status Change Event data ReasonCode values */ +#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03) +#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04) +#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06) +#define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) +#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) + + +/* SCSI Event data for Queue Full event */ + +typedef struct _EVENT_DATA_QUEUE_FULL +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U16 CurrentDepth; /* 02h */ +} EVENT_DATA_QUEUE_FULL, MPI_POINTER PTR_EVENT_DATA_QUEUE_FULL, + EventDataQueueFull_t, MPI_POINTER pEventDataQueueFull_t; + +/* MPI Integrated RAID Event data */ + +typedef struct _EVENT_DATA_RAID +{ + U8 VolumeID; /* 00h */ + U8 VolumeBus; /* 01h */ + U8 ReasonCode; /* 02h */ + U8 PhysDiskNum; /* 03h */ + U8 ASC; /* 04h */ + U8 ASCQ; /* 05h */ + U16 Reserved; /* 06h */ + U32 SettingsStatus; /* 08h */ +} EVENT_DATA_RAID, MPI_POINTER PTR_EVENT_DATA_RAID, + MpiEventDataRaid_t, MPI_POINTER pMpiEventDataRaid_t; + +/* MPI Integrated RAID Event data ReasonCode values */ +#define MPI_EVENT_RAID_RC_VOLUME_CREATED (0x00) +#define MPI_EVENT_RAID_RC_VOLUME_DELETED (0x01) +#define MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED (0x02) +#define MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED (0x03) +#define MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED (0x04) +#define MPI_EVENT_RAID_RC_PHYSDISK_CREATED (0x05) +#define MPI_EVENT_RAID_RC_PHYSDISK_DELETED (0x06) +#define MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED (0x07) +#define MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED (0x08) +#define MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED (0x09) +#define MPI_EVENT_RAID_RC_SMART_DATA (0x0A) +#define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED (0x0B) + + +/* MPI Integrated RAID Resync Update Event data */ + +typedef struct _MPI_EVENT_DATA_IR_RESYNC_UPDATE +{ + U8 VolumeID; /* 00h */ + U8 VolumeBus; /* 01h */ + U8 ResyncComplete; /* 02h */ + U8 Reserved1; /* 03h */ + U32 Reserved2; /* 04h */ +} MPI_EVENT_DATA_IR_RESYNC_UPDATE, + MPI_POINTER PTR_MPI_EVENT_DATA_IR_RESYNC_UPDATE, + MpiEventDataIrResyncUpdate_t, MPI_POINTER pMpiEventDataIrResyncUpdate_t; + +/* MPI IR2 Event data */ + +/* MPI_LD_STATE or MPI_PD_STATE */ +typedef struct _IR2_STATE_CHANGED +{ + U16 PreviousState; /* 00h */ + U16 NewState; /* 02h */ +} IR2_STATE_CHANGED, MPI_POINTER PTR_IR2_STATE_CHANGED; + +typedef struct _IR2_PD_INFO +{ + U16 DeviceHandle; /* 00h */ + U8 TruncEnclosureHandle; /* 02h */ + U8 TruncatedSlot; /* 03h */ +} IR2_PD_INFO, MPI_POINTER PTR_IR2_PD_INFO; + +typedef union _MPI_IR2_RC_EVENT_DATA +{ + IR2_STATE_CHANGED StateChanged; + U32 Lba; + IR2_PD_INFO PdInfo; +} MPI_IR2_RC_EVENT_DATA, MPI_POINTER PTR_MPI_IR2_RC_EVENT_DATA; + +typedef struct _MPI_EVENT_DATA_IR2 +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ReasonCode; /* 02h */ + U8 PhysDiskNum; /* 03h */ + MPI_IR2_RC_EVENT_DATA IR2EventData; /* 04h */ +} MPI_EVENT_DATA_IR2, MPI_POINTER PTR_MPI_EVENT_DATA_IR2, + MpiEventDataIR2_t, MPI_POINTER pMpiEventDataIR2_t; + +/* MPI IR2 Event data ReasonCode values */ +#define MPI_EVENT_IR2_RC_LD_STATE_CHANGED (0x01) +#define MPI_EVENT_IR2_RC_PD_STATE_CHANGED (0x02) +#define MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL (0x03) +#define MPI_EVENT_IR2_RC_PD_INSERTED (0x04) +#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) + +/* defines for logical disk states */ +#define MPI_LD_STATE_OPTIMAL (0x00) +#define MPI_LD_STATE_DEGRADED (0x01) +#define MPI_LD_STATE_FAILED (0x02) +#define MPI_LD_STATE_MISSING (0x03) +#define MPI_LD_STATE_OFFLINE (0x04) + +/* defines for physical disk states */ +#define MPI_PD_STATE_ONLINE (0x00) +#define MPI_PD_STATE_MISSING (0x01) +#define MPI_PD_STATE_NOT_COMPATIBLE (0x02) +#define MPI_PD_STATE_FAILED (0x03) +#define MPI_PD_STATE_INITIALIZING (0x04) +#define MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST (0x05) +#define MPI_PD_STATE_FAILED_AT_HOST_REQUEST (0x06) +#define MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON (0xFF) + /* MPI Link Status Change Event data */ typedef struct _EVENT_DATA_LINK_STATUS @@ -510,35 +759,78 @@ typedef struct _EVENT_DATA_LOGOUT #define MPI_EVENT_LOGOUT_ALL_ALIASES (0xFF) +/* SAS SES Event data */ -/* MPI Integrated RAID Event data */ +typedef struct _EVENT_DATA_SAS_SES +{ + U8 PhyNum; /* 00h */ + U8 Port; /* 01h */ + U8 PortWidth; /* 02h */ + U8 Reserved1; /* 04h */ +} EVENT_DATA_SAS_SES, MPI_POINTER PTR_EVENT_DATA_SAS_SES, + MpiEventDataSasSes_t, MPI_POINTER pMpiEventDataSasSes_t; -typedef struct _EVENT_DATA_RAID +/* SAS Phy Link Status Event data */ + +typedef struct _EVENT_DATA_SAS_PHY_LINK_STATUS { - U8 VolumeID; /* 00h */ - U8 VolumeBus; /* 01h */ - U8 ReasonCode; /* 02h */ - U8 PhysDiskNum; /* 03h */ - U8 ASC; /* 04h */ - U8 ASCQ; /* 05h */ - U16 Reserved; /* 06h */ - U32 SettingsStatus; /* 08h */ -} EVENT_DATA_RAID, MPI_POINTER PTR_EVENT_DATA_RAID, - MpiEventDataRaid_t, MPI_POINTER pMpiEventDataRaid_t; + U8 PhyNum; /* 00h */ + U8 LinkRates; /* 01h */ + U16 DevHandle; /* 02h */ + U64 SASAddress; /* 04h */ +} EVENT_DATA_SAS_PHY_LINK_STATUS, MPI_POINTER PTR_EVENT_DATA_SAS_PHY_LINK_STATUS, + MpiEventDataSasPhyLinkStatus_t, MPI_POINTER pMpiEventDataSasPhyLinkStatus_t; -/* MPI Integrated RAID Event data ReasonCode values */ -#define MPI_EVENT_RAID_RC_VOLUME_CREATED (0x00) -#define MPI_EVENT_RAID_RC_VOLUME_DELETED (0x01) -#define MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED (0x02) -#define MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED (0x03) -#define MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED (0x04) -#define MPI_EVENT_RAID_RC_PHYSDISK_CREATED (0x05) -#define MPI_EVENT_RAID_RC_PHYSDISK_DELETED (0x06) -#define MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED (0x07) -#define MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED (0x08) -#define MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED (0x09) -#define MPI_EVENT_RAID_RC_SMART_DATA (0x0A) -#define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED (0x0B) +/* defines for the LinkRates field of the SAS PHY Link Status event */ +#define MPI_EVENT_SAS_PLS_LR_CURRENT_MASK (0xF0) +#define MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT (4) +#define MPI_EVENT_SAS_PLS_LR_PREVIOUS_MASK (0x0F) +#define MPI_EVENT_SAS_PLS_LR_PREVIOUS_SHIFT (0) +#define MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN (0x00) +#define MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED (0x01) +#define MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION (0x02) +#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) + +/* SAS Discovery Event data */ + +typedef struct _EVENT_DATA_SAS_DISCOVERY +{ + U32 DiscoveryStatus; /* 00h */ + U32 Reserved1; /* 04h */ +} EVENT_DATA_SAS_DISCOVERY, MPI_POINTER PTR_EVENT_DATA_SAS_DISCOVERY, + EventDataSasDiscovery_t, MPI_POINTER pEventDataSasDiscovery_t; + +#define MPI_EVENT_SAS_DSCVRY_COMPLETE (0x00000000) +#define MPI_EVENT_SAS_DSCVRY_IN_PROGRESS (0x00000001) +#define MPI_EVENT_SAS_DSCVRY_PHY_BITS_MASK (0xFFFF0000) +#define MPI_EVENT_SAS_DSCVRY_PHY_BITS_SHIFT (16) + +/* SAS Discovery Errror Event data */ + +typedef struct _EVENT_DATA_DISCOVERY_ERROR +{ + U32 DiscoveryStatus; /* 00h */ + U8 Port; /* 04h */ + U8 Reserved1; /* 05h */ + U16 Reserved2; /* 06h */ +} EVENT_DATA_DISCOVERY_ERROR, MPI_POINTER PTR_EVENT_DATA_DISCOVERY_ERROR, + EventDataDiscoveryError_t, MPI_POINTER pEventDataDiscoveryError_t; + +#define MPI_EVENT_DSCVRY_ERR_DS_LOOP_DETECTED (0x00000001) +#define MPI_EVENT_DSCVRY_ERR_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI_EVENT_DSCVRY_ERR_DS_MULTIPLE_PORTS (0x00000004) +#define MPI_EVENT_DSCVRY_ERR_DS_EXPANDER_ERR (0x00000008) +#define MPI_EVENT_DSCVRY_ERR_DS_SMP_TIMEOUT (0x00000010) +#define MPI_EVENT_DSCVRY_ERR_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI_EVENT_DSCVRY_ERR_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI_EVENT_DSCVRY_ERR_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI_EVENT_DSCVRY_ERR_DS_SMP_CRC_ERROR (0x00000100) +#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_SUBTRACTIVE (0x00000200) +#define MPI_EVENT_DSCVRY_ERR_DS_TABLE_TO_TABLE (0x00000400) +#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800) +#define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000) /***************************************************************************** @@ -564,10 +856,13 @@ typedef struct _MSG_FW_DOWNLOAD } MSG_FW_DOWNLOAD, MPI_POINTER PTR_MSG_FW_DOWNLOAD, FWDownload_t, MPI_POINTER pFWDownload_t; +#define MPI_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01) + #define MPI_FW_DOWNLOAD_ITYPE_RESERVED (0x00) #define MPI_FW_DOWNLOAD_ITYPE_FW (0x01) #define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) #define MPI_FW_DOWNLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER (0x04) typedef struct _FWDownloadTCSGE @@ -620,6 +915,8 @@ typedef struct _MSG_FW_UPLOAD #define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) #define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04) +#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) typedef struct _FWUploadTCSGE { @@ -683,6 +980,7 @@ typedef struct _MPI_FW_HEADER #define MPI_FW_HEADER_PID_TYPE_MASK (0xF000) #define MPI_FW_HEADER_PID_TYPE_SCSI (0x0000) #define MPI_FW_HEADER_PID_TYPE_FC (0x1000) +#define MPI_FW_HEADER_PID_TYPE_SAS (0x2000) #define MPI_FW_HEADER_SIGNATURE_0 (0x5AEAA55A) #define MPI_FW_HEADER_SIGNATURE_1 (0xA55AEAA5) @@ -695,8 +993,10 @@ typedef struct _MPI_FW_HEADER #define MPI_FW_HEADER_PID_PROD_IM_SCSI (0x0400) #define MPI_FW_HEADER_PID_PROD_IS_SCSI (0x0500) #define MPI_FW_HEADER_PID_PROD_CTX_SCSI (0x0600) +#define MPI_FW_HEADER_PID_PROD_IR_SCSI (0x0700) #define MPI_FW_HEADER_PID_FAMILY_MASK (0x00FF) +/* SCSI */ #define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI (0x0001) #define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI (0x0002) #define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI (0x0003) @@ -709,9 +1009,19 @@ typedef struct _MPI_FW_HEADER #define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI (0x000A) #define MPI_FW_HEADER_PID_FAMILY_1030TA0_SCSI (0x000B) #define MPI_FW_HEADER_PID_FAMILY_1020TA0_SCSI (0x000C) +/* Fibre Channel */ #define MPI_FW_HEADER_PID_FAMILY_909_FC (0x0000) -#define MPI_FW_HEADER_PID_FAMILY_919_FC (0x0001) -#define MPI_FW_HEADER_PID_FAMILY_919X_FC (0x0002) +#define MPI_FW_HEADER_PID_FAMILY_919_FC (0x0001) /* 919 and 929 */ +#define MPI_FW_HEADER_PID_FAMILY_919X_FC (0x0002) /* 919X and 929X */ +#define MPI_FW_HEADER_PID_FAMILY_919XL_FC (0x0003) /* 919XL and 929XL */ +#define MPI_FW_HEADER_PID_FAMILY_939X_FC (0x0004) /* 939X and 949X */ +#define MPI_FW_HEADER_PID_FAMILY_959_FC (0x0005) +#define MPI_FW_HEADER_PID_FAMILY_949E_FC (0x0006) +/* SAS */ +#define MPI_FW_HEADER_PID_FAMILY_1064_SAS (0x0001) +#define MPI_FW_HEADER_PID_FAMILY_1068_SAS (0x0002) +#define MPI_FW_HEADER_PID_FAMILY_1078_SAS (0x0003) +#define MPI_FW_HEADER_PID_FAMILY_106xE_SAS (0x0004) /* 1068E, 1066E, and 1064E */ typedef struct _MPI_EXT_IMAGE_HEADER { @@ -730,5 +1040,6 @@ typedef struct _MPI_EXT_IMAGE_HEADER #define MPI_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) #define MPI_EXT_IMAGE_TYPE_FW (0x01) #define MPI_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI_EXT_IMAGE_TYPE_BOOTLOADER (0x04) #endif diff --git a/sys/dev/mpt/mpilib/mpi_lan.h b/sys/dev/mpt/mpilib/mpi_lan.h index a7551c621064..935706463712 100644 --- a/sys/dev/mpt/mpilib/mpi_lan.h +++ b/sys/dev/mpt/mpilib/mpi_lan.h @@ -28,13 +28,13 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Name: MPI_LAN.H + * + * + * Name: mpi_lan.h * Title: MPI LAN messages and structures * Creation Date: June 30, 2000 * - * MPI_LAN.H Version: 01.02.01 + * mpi_lan.h Version: 01.05.01 * * Version History * --------------- @@ -56,6 +56,8 @@ * 02-20-01 01.01.02 Started using MPI_POINTER. * 03-27-01 01.01.03 Added structure offset comments. * 08-08-01 01.02.01 Original release for v1.2 work. + * 05-11-04 01.03.01 Original release for MPI v1.3. + * 08-19-04 01.05.01 Original release for MPI v1.5. * -------------------------------------------------------------------------- */ diff --git a/sys/dev/mpt/mpilib/mpi_raid.h b/sys/dev/mpt/mpilib/mpi_raid.h index 97dcd20e4acb..8dc5a5038a1c 100644 --- a/sys/dev/mpt/mpilib/mpi_raid.h +++ b/sys/dev/mpt/mpilib/mpi_raid.h @@ -28,13 +28,13 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Name: MPI_RAID.H + * + * + * Name: mpi_raid.h * Title: MPI RAID message and structures * Creation Date: February 27, 2001 * - * MPI_RAID.H Version: 01.02.09 + * mpi_raid.h Version: 01.05.02 * * Version History * --------------- @@ -56,6 +56,10 @@ * 11-15-02 01.02.08 Added missing MsgContext field to MSG_MAILBOX_REQUEST. * 04-01-03 01.02.09 New action data option flag for * MPI_RAID_ACTION_DELETE_VOLUME. + * 05-11-04 01.03.01 Original release for MPI v1.3. + * 08-19-04 01.05.01 Original release for MPI v1.5. + * 01-15-05 01.05.02 Added defines for the two new RAID Actions for + * _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE. * -------------------------------------------------------------------------- */ @@ -71,7 +75,7 @@ /****************************************************************************/ -/* RAID Volume Request */ +/* RAID Action Request */ /****************************************************************************/ typedef struct _MSG_RAID_ACTION @@ -129,6 +133,13 @@ typedef struct _MSG_RAID_ACTION /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */ #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL (0x00000001) +/* ActionDataWord defines for use with MPI_RAID_ACTION_SET_RESYNC_RATE action */ +#define MPI_RAID_ACTION_ADATA_RESYNC_RATE_MASK (0x000000FF) + +/* ActionDataWord defines for use with MPI_RAID_ACTION_SET_DATA_SCRUB_RATE action */ +#define MPI_RAID_ACTION_ADATA_DATA_SCRUB_RATE_MASK (0x000000FF) + + /* RAID Action reply message */ diff --git a/sys/dev/mpt/mpilib/mpi_targ.h b/sys/dev/mpt/mpilib/mpi_targ.h index 2642a67d13d3..fb232fe42b48 100644 --- a/sys/dev/mpt/mpilib/mpi_targ.h +++ b/sys/dev/mpt/mpilib/mpi_targ.h @@ -30,11 +30,11 @@ * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * - * Name: MPI_TARG.H + * Name: mpi_targ.h * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * MPI_TARG.H Version: 01.02.09 + * mpi_targ.h Version: 01.05.05 * * Version History * --------------- @@ -71,6 +71,17 @@ * Added PRIORITY_REASON_TARGET_BUSY. * 11-15-02 01.02.08 Added AliasID field to MPI_TARGET_SCSI_SPI_CMD_BUFFER. * 04-01-03 01.02.09 Added OptionalOxid field to MPI_TARGET_FCP_CMD_BUFFER. + * 05-11-04 01.03.01 Original release for MPI v1.3. + * 08-19-04 01.05.01 Added new request message structures for + * MSG_TARGET_CMD_BUF_POST_BASE_REQUEST, + * MSG_TARGET_CMD_BUF_POST_LIST_REQUEST, and + * MSG_TARGET_ASSIST_EXT_REQUEST. + * Added new structures for SAS SSP Command buffer, SSP + * Task buffer, and SSP Status IU. + * 10-05-04 01.05.02 MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY added. + * 02-22-05 01.05.03 Changed a comment. + * 03-11-05 01.05.04 Removed TargetAssistExtended Request. + * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines. * -------------------------------------------------------------------------- */ @@ -161,6 +172,25 @@ typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY } MSG_PRIORITY_CMD_RECEIVED_REPLY, MPI_POINTER PTR_MSG_PRIORITY_CMD_RECEIVED_REPLY, PriorityCommandReceivedReply_t, MPI_POINTER pPriorityCommandReceivedReply_t; + +typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY +{ + U16 Reserved; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 PriorityReason; /* 0Ch */ + U8 Reserved3; /* 0Dh */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 ReplyWord; /* 14h */ +} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY, + MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY, + TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t; + #define PRIORITY_REASON_NO_DISCONNECT (0x00) #define PRIORITY_REASON_SCSI_TASK_MANAGEMENT (0x01) #define PRIORITY_REASON_CMD_PARITY_ERR (0x02) @@ -174,7 +204,34 @@ typedef struct _MSG_PRIORITY_CMD_RECEIVED_REPLY #define PRIORITY_REASON_UNKNOWN (0xFF) -typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY +/****************************************************************************/ +/* Target Command Buffer Post Base Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_CMD_BUF_POST_BASE_REQUEST +{ + U8 BufferPostFlags; /* 00h */ + U8 PortNumber; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 TotalCmdBuffers; /* 04h */ + U8 Reserved; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved1; /* 0Ch */ + U16 CmdBufferLength; /* 10h */ + U16 NextCmdBufferOffset; /* 12h */ + U32 BaseAddressLow; /* 14h */ + U32 BaseAddressHigh; /* 18h */ +} MSG_TARGET_CMD_BUF_POST_BASE_REQUEST, + MPI_POINTER PTR__MSG_TARGET_CMD_BUF_POST_BASE_REQUEST, + TargetCmdBufferPostBaseRequest_t, + MPI_POINTER pTargetCmdBufferPostBaseRequest_t; + +#define CMD_BUFFER_POST_BASE_FLAGS_AUTO_POST_ALL (0x01) + + +typedef struct _MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY { U16 Reserved; /* 00h */ U8 MsgLength; /* 02h */ @@ -183,16 +240,41 @@ typedef struct _MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY U8 Reserved2; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ - U8 PriorityReason; /* 0Ch */ - U8 Reserved3; /* 0Dh */ + U16 Reserved3; /* 0Ch */ U16 IOCStatus; /* 0Eh */ U32 IOCLogInfo; /* 10h */ - U32 ReplyWord; /* 14h */ -} MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY, - MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_ERROR_REPLY, - TargetCmdBufferPostErrorReply_t, MPI_POINTER pTargetCmdBufferPostErrorReply_t; +} MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY, + MPI_POINTER PTR_MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY, + TargetCmdBufferPostBaseListReply_t, + MPI_POINTER pTargetCmdBufferPostBaseListReply_t; +/****************************************************************************/ +/* Target Command Buffer Post List Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_CMD_BUF_POST_LIST_REQUEST +{ + U8 Reserved; /* 00h */ + U8 PortNumber; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 CmdBufferCount; /* 04h */ + U8 Reserved1; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved2; /* 0Ch */ + U16 IoIndex[2]; /* 10h */ +} MSG_TARGET_CMD_BUF_POST_LIST_REQUEST, + MPI_POINTER PTR_MSG_TARGET_CMD_BUF_POST_LIST_REQUEST, + TargetCmdBufferPostListRequest_t, + MPI_POINTER pTargetCmdBufferPostListRequest_t; + + +/****************************************************************************/ +/* Command Buffer Formats (with 16 byte CDB) */ +/****************************************************************************/ + typedef struct _MPI_TARGET_FCP_CMD_BUFFER { U8 FcpLun[8]; /* 00h */ @@ -229,6 +311,46 @@ typedef struct _MPI_TARGET_SCSI_SPI_CMD_BUFFER MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer; +typedef struct _MPI_TARGET_SSP_CMD_BUFFER +{ + U8 FrameType; /* 00h */ + U8 Reserved1; /* 01h */ + U16 Reserved2; /* 02h */ + U16 InitiatorTag; /* 04h */ + U16 DevHandle; /* 06h */ + /* COMMAND information unit starts here */ + U8 LogicalUnitNumber[8]; /* 08h */ + U8 Reserved3; /* 10h */ + U8 TaskAttribute; /* lower 3 bits */ /* 11h */ + U8 Reserved4; /* 12h */ + U8 AdditionalCDBLength; /* upper 5 bits */ /* 13h */ + U8 CDB[16]; /* 14h */ + /* Additional CDB bytes extend past the CDB field */ +} MPI_TARGET_SSP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_SSP_CMD_BUFFER, + MpiTargetSspCmdBuffer, MPI_POINTER pMpiTargetSspCmdBuffer; + +typedef struct _MPI_TARGET_SSP_TASK_BUFFER +{ + U8 FrameType; /* 00h */ + U8 Reserved1; /* 01h */ + U16 Reserved2; /* 02h */ + U16 InitiatorTag; /* 04h */ + U16 DevHandle; /* 06h */ + /* TASK information unit starts here */ + U8 LogicalUnitNumber[8]; /* 08h */ + U8 Reserved3; /* 10h */ + U8 Reserved4; /* 11h */ + U8 TaskManagementFunction; /* 12h */ + U8 Reserved5; /* 13h */ + U16 ManagedTaskTag; /* 14h */ + U16 Reserved6; /* 16h */ + U32 Reserved7; /* 18h */ + U32 Reserved8; /* 1Ch */ + U32 Reserved9; /* 20h */ +} MPI_TARGET_SSP_TASK_BUFFER, MPI_POINTER PTR_MPI_TARGET_SSP_TASK_BUFFER, + MpiTargetSspTaskBuffer, MPI_POINTER pMpiTargetSspTaskBuffer; + + /****************************************************************************/ /* Target Assist Request */ /****************************************************************************/ @@ -278,6 +400,77 @@ typedef struct _MSG_TARGET_ERROR_REPLY /****************************************************************************/ +/* Target Assist Extended Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_ASSIST_EXT_REQUEST +{ + U8 StatusCode; /* 00h */ + U8 TargetAssistFlags; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 QueueTag; /* 04h */ + U8 Reserved1; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 ReplyWord; /* 0Ch */ + U8 LUN[8]; /* 10h */ + U32 RelativeOffset; /* 18h */ + U32 Reserved2; /* 1Ch */ + U32 Reserved3; /* 20h */ + U32 PrimaryReferenceTag; /* 24h */ + U16 PrimaryApplicationTag; /* 28h */ + U16 PrimaryApplicationTagMask; /* 2Ah */ + U32 Reserved4; /* 2Ch */ + U32 DataLength; /* 30h */ + U32 BidirectionalDataLength; /* 34h */ + U32 SecondaryReferenceTag; /* 38h */ + U16 SecondaryApplicationTag; /* 3Ch */ + U16 Reserved5; /* 3Eh */ + U16 EEDPFlags; /* 40h */ + U16 ApplicationTagTranslationMask; /* 42h */ + U32 EEDPBlockSize; /* 44h */ + U8 SGLOffset0; /* 48h */ + U8 SGLOffset1; /* 49h */ + U8 SGLOffset2; /* 4Ah */ + U8 SGLOffset3; /* 4Bh */ + U32 Reserved6; /* 4Ch */ + SGE_IO_UNION SGL[1]; /* 50h */ +} MSG_TARGET_ASSIST_EXT_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_EXT_REQUEST, + TargetAssistExtRequest_t, MPI_POINTER pTargetAssistExtRequest_t; + +/* see the defines after MSG_TARGET_ASSIST_REQUEST for TargetAssistFlags */ + +/* defines for the MsgFlags field */ +#define TARGET_ASSIST_EXT_MSGFLAGS_BIDIRECTIONAL (0x20) +#define TARGET_ASSIST_EXT_MSGFLAGS_MULTICAST (0x10) +#define TARGET_ASSIST_EXT_MSGFLAGS_SGL_OFFSET_CHAINS (0x08) + +/* defines for the EEDPFlags field */ +#define TARGET_ASSIST_EXT_EEDP_MASK_OP (0x0007) +#define TARGET_ASSIST_EXT_EEDP_NOOP_OP (0x0000) +#define TARGET_ASSIST_EXT_EEDP_CHK_OP (0x0001) +#define TARGET_ASSIST_EXT_EEDP_STRIP_OP (0x0002) +#define TARGET_ASSIST_EXT_EEDP_CHKRM_OP (0x0003) +#define TARGET_ASSIST_EXT_EEDP_INSERT_OP (0x0004) +#define TARGET_ASSIST_EXT_EEDP_REPLACE_OP (0x0006) +#define TARGET_ASSIST_EXT_EEDP_CHKREGEN_OP (0x0007) + +#define TARGET_ASSIST_EXT_EEDP_PASS_REF_TAG (0x0008) + +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_MASK (0x0700) +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_GUARD (0x0100) +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_APPTAG (0x0200) +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_REFTAG (0x0400) +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_SHIFT (8) + +#define TARGET_ASSIST_EXT_EEDP_INC_SEC_APPTAG (0x1000) +#define TARGET_ASSIST_EXT_EEDP_INC_PRI_APPTAG (0x2000) +#define TARGET_ASSIST_EXT_EEDP_INC_SEC_REFTAG (0x4000) +#define TARGET_ASSIST_EXT_EEDP_INC_PRI_REFTAG (0x8000) + + +/****************************************************************************/ /* Target Status Send Request */ /****************************************************************************/ @@ -336,6 +529,27 @@ typedef struct _MPI_TARGET_SCSI_SPI_STATUS_IU } MPI_TARGET_SCSI_SPI_STATUS_IU, MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_STATUS_IU, TargetScsiSpiStatusIU_t, MPI_POINTER pTargetScsiSpiStatusIU_t; +/* + * NOTE: The SSP status IU is big-endian. When used on a little-endian system, + * this structure properly orders the bytes. + */ +typedef struct _MPI_TARGET_SSP_RSP_IU +{ + U32 Reserved0[6]; /* reserved for SSP header */ /* 00h */ + /* start of RESPONSE information unit */ + U32 Reserved1; /* 18h */ + U32 Reserved2; /* 1Ch */ + U16 Reserved3; /* 20h */ + U8 DataPres; /* lower 2 bits */ /* 22h */ + U8 Status; /* 23h */ + U32 Reserved4; /* 24h */ + U32 SenseDataLength; /* 28h */ + U32 ResponseDataLength; /* 2Ch */ + U8 ResponseSenseData[4]; /* 30h */ +} MPI_TARGET_SSP_RSP_IU, MPI_POINTER PTR_MPI_TARGET_SSP_RSP_IU, + MpiTargetSspRspIu_t, MPI_POINTER pMpiTargetSspRspIu_t; + + /****************************************************************************/ /* Target Mode Abort Request */ /****************************************************************************/ diff --git a/sys/dev/mpt/mpilib/mpi_type.h b/sys/dev/mpt/mpilib/mpi_type.h index c505388ca6d7..236baf674f20 100644 --- a/sys/dev/mpt/mpilib/mpi_type.h +++ b/sys/dev/mpt/mpilib/mpi_type.h @@ -28,13 +28,13 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Name: MPI_TYPE.H + * + * + * Name: mpi_type.h * Title: MPI Basic type definitions * Creation Date: June 6, 2000 * - * MPI Version: 01.02.01 + * mpi_type.h Version: 01.05.02 * * Version History * --------------- @@ -46,6 +46,9 @@ * 11-02-00 01.01.01 Original release for post 1.0 work * 02-20-01 01.01.02 Added define and ifdef for MPI_POINTER. * 08-08-01 01.02.01 Original release for v1.2 work. + * 05-11-04 01.03.01 Original release for MPI v1.3. + * 08-19-04 01.05.01 Original release for MPI v1.5. + * 08-30-05 01.05.02 Added PowerPC option to #ifdef's. * -------------------------------------------------------------------------- */ @@ -69,13 +72,32 @@ * *****************************************************************************/ -typedef int8_t S8; -typedef uint8_t U8; -typedef int16_t S16; -typedef uint16_t U16; +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; + +#ifdef __FreeBSD__ + typedef int32_t S32; typedef uint32_t U32; +#else + +#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc) + + typedef signed int S32; + typedef unsigned int U32; + +#else + + typedef signed long S32; + typedef unsigned long U32; + +#endif +#endif + + typedef struct _S64 { U32 Low; diff --git a/sys/dev/mpt/mpt.c b/sys/dev/mpt/mpt.c index 8c7dbc994d9f..096cec2c932c 100644 --- a/sys/dev/mpt/mpt.c +++ b/sys/dev/mpt/mpt.c @@ -1,5 +1,5 @@ /*- - * Generic routines for LSI '909 FC adapters. + * Generic routines for LSI Fusion adapters. * FreeBSD Version. * * Copyright (c) 2000, 2001 by Greg Ansley @@ -24,15 +24,50 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + */ +/*- + * Copyright (c) 2002, 2006 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon including + * a substantially similar Disclaimer requirement for further binary + * redistribution. + * 3. Neither the names of the above listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT + * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Support from Chris Ellsworth in order to make SAS adapters work + * is gratefully acknowledged. * - * Additional Copyright (c) 2002 by Matthew Jacob under same license. + * + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. */ -/* +/*- * Copyright (c) 2004, Avid Technology, Inc. and its contributors. * Copyright (c) 2005, WHEEL Sp. z o.o. * Copyright (c) 2004, 2005 Justin T. Gibbs * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: @@ -46,7 +81,7 @@ * 3. Neither the names of the above listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -69,6 +104,8 @@ __FBSDID("$FreeBSD$"); #include <dev/mpt/mpilib/mpi.h> #include <dev/mpt/mpilib/mpi_ioc.h> +#include <dev/mpt/mpilib/mpi_fc.h> +#include <dev/mpt/mpilib/mpi_targ.h> #include <sys/sysctl.h> @@ -88,10 +125,11 @@ static mpt_reply_handler_t mpt_handshake_reply_handler; static mpt_reply_handler_t mpt_event_reply_handler; static void mpt_send_event_ack(struct mpt_softc *mpt, request_t *ack_req, MSG_EVENT_NOTIFY_REPLY *msg, uint32_t context); +static int mpt_send_event_request(struct mpt_softc *mpt, int onoff); static int mpt_soft_reset(struct mpt_softc *mpt); static void mpt_hard_reset(struct mpt_softc *mpt); static int mpt_configure_ioc(struct mpt_softc *mpt); -static int mpt_enable_ioc(struct mpt_softc *mpt); +static int mpt_enable_ioc(struct mpt_softc *mpt, int); /************************* Personality Module Support *************************/ /* @@ -118,7 +156,7 @@ mpt_pers_find(struct mpt_softc *mpt, u_int start_at) } /* - * Used infrequenstly, so no need to optimize like a forward + * Used infrequently, so no need to optimize like a forward * traversal where we use the MAX+1 is guaranteed to be NULL * trick. */ @@ -147,6 +185,7 @@ mpt_pers_find_reverse(struct mpt_softc *mpt, u_int start_at) static mpt_load_handler_t mpt_stdload; static mpt_probe_handler_t mpt_stdprobe; static mpt_attach_handler_t mpt_stdattach; +static mpt_enable_handler_t mpt_stdenable; static mpt_event_handler_t mpt_stdevent; static mpt_reset_handler_t mpt_stdreset; static mpt_shutdown_handler_t mpt_stdshutdown; @@ -157,6 +196,7 @@ static struct mpt_personality mpt_default_personality = .load = mpt_stdload, .probe = mpt_stdprobe, .attach = mpt_stdattach, + .enable = mpt_stdenable, .event = mpt_stdevent, .reset = mpt_stdreset, .shutdown = mpt_stdshutdown, @@ -166,6 +206,7 @@ static struct mpt_personality mpt_default_personality = static mpt_load_handler_t mpt_core_load; static mpt_attach_handler_t mpt_core_attach; +static mpt_enable_handler_t mpt_core_enable; static mpt_reset_handler_t mpt_core_ioc_reset; static mpt_event_handler_t mpt_core_event; static mpt_shutdown_handler_t mpt_core_shutdown; @@ -176,6 +217,7 @@ static struct mpt_personality mpt_core_personality = .name = "mpt_core", .load = mpt_core_load, .attach = mpt_core_attach, + .enable = mpt_core_enable, .event = mpt_core_event, .reset = mpt_core_ioc_reset, .shutdown = mpt_core_shutdown, @@ -194,8 +236,7 @@ static moduledata_t mpt_core_mod = { DECLARE_MODULE(mpt_core, mpt_core_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); MODULE_VERSION(mpt_core, 1); -#define MPT_PERS_ATACHED(pers, mpt) \ - ((mpt)->pers_mask & (0x1 << pers->id)) +#define MPT_PERS_ATTACHED(pers, mpt) ((mpt)->mpt_pers_mask & (0x1 << pers->id)) int @@ -242,8 +283,10 @@ mpt_modevent(module_t mod, int type, void *data) } case MOD_SHUTDOWN: break; +#if __FreeBSD_version >= 500000 case MOD_QUIESCE: break; +#endif case MOD_UNLOAD: error = pers->unload(pers); mpt_personalities[pers->id] = NULL; @@ -277,8 +320,16 @@ mpt_stdattach(struct mpt_softc *mpt) } int -mpt_stdevent(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *rep) +mpt_stdenable(struct mpt_softc *mpt) +{ + /* Enable is always successfull. */ + return (0); +} + +int +mpt_stdevent(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *msg) { + mpt_lprt(mpt, MPT_PRT_DEBUG, "mpt_stdevent: 0x%x\n", msg->Event & 0xFF); /* Event was not for us. */ return (0); } @@ -352,13 +403,14 @@ mpt_register_handler(struct mpt_softc *mpt, mpt_handler_type type, * that the full table is checked to see if * this handler was previously registered. */ - if (free_cbi == MPT_HANDLER_ID_NONE - && (mpt_reply_handlers[cbi] + if (free_cbi == MPT_HANDLER_ID_NONE && + (mpt_reply_handlers[cbi] == mpt_default_reply_handler)) free_cbi = cbi; } - if (free_cbi == MPT_HANDLER_ID_NONE) + if (free_cbi == MPT_HANDLER_ID_NONE) { return (ENOMEM); + } mpt_reply_handlers[free_cbi] = handler.reply_handler; *phandler_id = MPT_CBI_TO_HID(free_cbi); break; @@ -396,22 +448,23 @@ mpt_deregister_handler(struct mpt_softc *mpt, mpt_handler_type type, static int mpt_default_reply_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame) + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { - mpt_prt(mpt, "XXXX Default Handler Called. Req %p, Frame %p\n", - req, reply_frame); + mpt_prt(mpt, + "Default Handler Called: req=%p:%u reply_descriptor=%x frame=%p\n", + req, req->serno, reply_desc, reply_frame); if (reply_frame != NULL) mpt_dump_reply_frame(mpt, reply_frame); - mpt_prt(mpt, "XXXX Reply Frame Ignored\n"); + mpt_prt(mpt, "Reply Frame Ignored\n"); return (/*free_reply*/TRUE); } static int mpt_config_reply_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame) + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { if (req != NULL) { @@ -428,32 +481,30 @@ mpt_config_reply_handler(struct mpt_softc *mpt, request_t *req, req->state &= ~REQ_STATE_QUEUED; req->state |= REQ_STATE_DONE; TAILQ_REMOVE(&mpt->request_pending_list, req, links); - - if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) + if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) { wakeup(req); + } } - return (/*free_reply*/TRUE); + return (TRUE); } static int mpt_handshake_reply_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame) + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { /* Nothing to be done. */ - return (/*free_reply*/TRUE); + return (TRUE); } static int mpt_event_reply_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame) + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { int free_reply; - if (reply_frame == NULL) { - mpt_prt(mpt, "Event Handler: req %p - Unexpected NULL reply\n"); - return (/*free_reply*/TRUE); - } + KASSERT(reply_frame != NULL, ("null reply in mpt_event_reply_handler")); + KASSERT(req != NULL, ("null request in mpt_event_reply_handler")); free_reply = TRUE; switch (reply_frame->Function) { @@ -468,17 +519,24 @@ mpt_event_reply_handler(struct mpt_softc *mpt, request_t *req, MPT_PERS_FOREACH(mpt, pers) handled += pers->event(mpt, req, msg); - if (handled == 0) - mpt_prt(mpt, - "Unhandled Event Notify Frame. Event %#x.\n", - msg->Event); + if (handled == 0 && mpt->mpt_pers_mask == 0) { + mpt_lprt(mpt, MPT_PRT_INFO, + "No Handlers For Any Event Notify Frames. " + "Event %#x (ACK %sequired).\n", + msg->Event, msg->AckRequired? "r" : "not r"); + } else if (handled == 0) { + mpt_lprt(mpt, MPT_PRT_WARN, + "Unhandled Event Notify Frame. Event %#x " + "(ACK %sequired).\n", + msg->Event, msg->AckRequired? "r" : "not r"); + } if (msg->AckRequired) { request_t *ack_req; uint32_t context; context = htole32(req->index|MPT_REPLY_HANDLER_EVENTS); - ack_req = mpt_get_request(mpt, /*sleep_ok*/FALSE); + ack_req = mpt_get_request(mpt, FALSE); if (ack_req == NULL) { struct mpt_evtf_record *evtf; @@ -489,32 +547,59 @@ mpt_event_reply_handler(struct mpt_softc *mpt, request_t *req, break; } mpt_send_event_ack(mpt, ack_req, msg, context); + /* + * Don't check for CONTINUATION_REPLY here + */ + return (free_reply); } break; } case MPI_FUNCTION_PORT_ENABLE: - mpt_lprt(mpt, MPT_PRT_DEBUG, "enable port reply\n"); + mpt_lprt(mpt, MPT_PRT_DEBUG , "enable port reply\n"); break; case MPI_FUNCTION_EVENT_ACK: break; default: - mpt_prt(mpt, "Unknown Event Function: %x\n", + mpt_prt(mpt, "unknown event function: %x\n", reply_frame->Function); break; } - if (req != NULL - && (reply_frame->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) == 0) { - - req->state &= ~REQ_STATE_QUEUED; - req->state |= REQ_STATE_DONE; + /* + * I'm not sure that this continuation stuff works as it should. + * + * I've had FC async events occur that free the frame up because + * the continuation bit isn't set, and then additional async events + * then occur using the same context. As you might imagine, this + * leads to Very Bad Thing. + * + * Let's just be safe for now and not free them up until we figure + * out what's actually happening here. + */ +#if 0 + if ((reply_frame->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) == 0) { TAILQ_REMOVE(&mpt->request_pending_list, req, links); - - if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) - wakeup(req); - else - mpt_free_request(mpt, req); + mpt_free_request(mpt, req); + mpt_prt(mpt, "event_reply %x for req %p:%u NOT a continuation", + reply_frame->Function, req, req->serno); + if (reply_frame->Function == MPI_FUNCTION_EVENT_NOTIFICATION) { + MSG_EVENT_NOTIFY_REPLY *msg = + (MSG_EVENT_NOTIFY_REPLY *)reply_frame; + mpt_prtc(mpt, " Event=0x%x AckReq=%d", + msg->Event, msg->AckRequired); + } + } else { + mpt_prt(mpt, "event_reply %x for %p:%u IS a continuation", + reply_frame->Function, req, req->serno); + if (reply_frame->Function == MPI_FUNCTION_EVENT_NOTIFICATION) { + MSG_EVENT_NOTIFY_REPLY *msg = + (MSG_EVENT_NOTIFY_REPLY *)reply_frame; + mpt_prtc(mpt, " Event=0x%x AckReq=%d", + msg->Event, msg->AckRequired); + } + mpt_prtc(mpt, "\n"); } +#endif return (free_reply); } @@ -525,6 +610,8 @@ static int mpt_core_event(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *msg) { + mpt_lprt(mpt, MPT_PRT_DEBUG, "mpt_core_event: 0x%x\n", + msg->Event & 0xFF); switch(msg->Event & 0xFF) { case MPI_EVENT_NONE: break; @@ -547,11 +634,13 @@ mpt_core_event(struct mpt_softc *mpt, request_t *req, * of our mpt_send_event_request. */ break; + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + break; default: - return (/*handled*/0); + return (0); break; } - return (/*handled*/1); + return (1); } static void @@ -561,7 +650,7 @@ mpt_send_event_ack(struct mpt_softc *mpt, request_t *ack_req, MSG_EVENT_ACK *ackp; ackp = (MSG_EVENT_ACK *)ack_req->req_vbuf; - bzero(ackp, sizeof *ackp); + memset(ackp, 0, sizeof (*ackp)); ackp->Function = MPI_FUNCTION_EVENT_ACK; ackp->Event = msg->Event; ackp->EventContext = msg->EventContext; @@ -575,13 +664,16 @@ void mpt_intr(void *arg) { struct mpt_softc *mpt; - uint32_t reply_desc; + uint32_t reply_desc; + int ntrips = 0; mpt = (struct mpt_softc *)arg; + mpt_lprt(mpt, MPT_PRT_DEBUG2, "enter mpt_intr\n"); while ((reply_desc = mpt_pop_reply_queue(mpt)) != MPT_REPLY_EMPTY) { request_t *req; MSG_DEFAULT_REPLY *reply_frame; uint32_t reply_baddr; + uint32_t ctxt_idx; u_int cb_index; u_int req_index; int free_rf; @@ -591,28 +683,108 @@ mpt_intr(void *arg) reply_baddr = 0; if ((reply_desc & MPI_ADDRESS_REPLY_A_BIT) != 0) { u_int offset; - /* * Insure that the reply frame is coherent. */ - reply_baddr = (reply_desc << 1); + reply_baddr = MPT_REPLY_BADDR(reply_desc); offset = reply_baddr - (mpt->reply_phys & 0xFFFFFFFF); - bus_dmamap_sync_range(mpt->reply_dmat, mpt->reply_dmap, - offset, MPT_REPLY_SIZE, - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync_range(mpt->reply_dmat, + mpt->reply_dmap, offset, MPT_REPLY_SIZE, + BUS_DMASYNC_POSTREAD); reply_frame = MPT_REPLY_OTOV(mpt, offset); - reply_desc = le32toh(reply_frame->MsgContext); + ctxt_idx = le32toh(reply_frame->MsgContext); + } else { + uint32_t type; + + type = MPI_GET_CONTEXT_REPLY_TYPE(reply_desc); + ctxt_idx = reply_desc; + mpt_lprt(mpt, MPT_PRT_DEBUG1, "Context Reply: 0x%08x\n", + reply_desc); + + switch (type) { + case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT: + ctxt_idx &= MPI_CONTEXT_REPLY_CONTEXT_MASK; + break; + case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: + ctxt_idx = GET_IO_INDEX(reply_desc); + if (mpt->tgt_cmd_ptrs == NULL) { + mpt_prt(mpt, + "mpt_intr: no target cmd ptrs\n"); + reply_desc = MPT_REPLY_EMPTY; + break; + } + if (ctxt_idx >= mpt->tgt_cmds_allocated) { + mpt_prt(mpt, + "mpt_intr: bad tgt cmd ctxt %u\n", + ctxt_idx); + reply_desc = MPT_REPLY_EMPTY; + ntrips = 1000; + break; + } + req = mpt->tgt_cmd_ptrs[ctxt_idx]; + if (req == NULL) { + mpt_prt(mpt, "no request backpointer " + "at index %u", ctxt_idx); + reply_desc = MPT_REPLY_EMPTY; + ntrips = 1000; + break; + } + /* + * Reformulate ctxt_idx to be just as if + * it were another type of context reply + * so the code below will find the request + * via indexing into the pool. + */ + ctxt_idx = + req->index | mpt->scsi_tgt_handler_id; + req = NULL; + break; + case MPI_CONTEXT_REPLY_TYPE_LAN: + mpt_prt(mpt, "LAN CONTEXT REPLY: 0x%08x\n", + reply_desc); + reply_desc = MPT_REPLY_EMPTY; + break; + default: + mpt_prt(mpt, "Context Reply 0x%08x?\n", type); + reply_desc = MPT_REPLY_EMPTY; + break; + } + if (reply_desc == MPT_REPLY_EMPTY) { + if (ntrips++ > 1000) { + break; + } + continue; + } } - cb_index = MPT_CONTEXT_TO_CBI(reply_desc); - req_index = MPT_CONTEXT_TO_REQI(reply_desc); - if (req_index < MPT_MAX_REQUESTS(mpt)) + + cb_index = MPT_CONTEXT_TO_CBI(ctxt_idx); + req_index = MPT_CONTEXT_TO_REQI(ctxt_idx); + if (req_index < MPT_MAX_REQUESTS(mpt)) { req = &mpt->request_pool[req_index]; + } else { + mpt_prt(mpt, "WARN: mpt_intr index == %d (reply_desc ==" + " 0x%x)\n", req_index, reply_desc); + } - free_rf = mpt_reply_handlers[cb_index](mpt, req, reply_frame); + free_rf = mpt_reply_handlers[cb_index](mpt, req, + reply_desc, reply_frame); - if (reply_frame != NULL && free_rf) + if (reply_frame != NULL && free_rf) { mpt_free_reply(mpt, reply_baddr); + } + + /* + * If we got ourselves disabled, don't get stuck in a loop + */ + if (mpt->disabled) { + mpt_disable_ints(mpt); + break; + } + if (ntrips++ > 1000) { + break; + } } + mpt_lprt(mpt, MPT_PRT_DEBUG2, "exit mpt_intr\n"); } /******************************* Error Recovery *******************************/ @@ -623,18 +795,20 @@ mpt_complete_request_chain(struct mpt_softc *mpt, struct req_queue *chain, MSG_DEFAULT_REPLY ioc_status_frame; request_t *req; - bzero(&ioc_status_frame, sizeof(ioc_status_frame)); + memset(&ioc_status_frame, 0, sizeof(ioc_status_frame)); ioc_status_frame.MsgLength = roundup2(sizeof(ioc_status_frame), 4); - ioc_status_frame.IOCStatus = iocstatus; + ioc_status_frame.IOCStatus = iocstatus; while((req = TAILQ_FIRST(chain)) != NULL) { MSG_REQUEST_HEADER *msg_hdr; u_int cb_index; + TAILQ_REMOVE(chain, req, links); msg_hdr = (MSG_REQUEST_HEADER *)req->req_vbuf; - ioc_status_frame.Function = msg_hdr->Function; - ioc_status_frame.MsgContext = msg_hdr->MsgContext; + ioc_status_frame.Function = msg_hdr->Function; + ioc_status_frame.MsgContext = msg_hdr->MsgContext; cb_index = MPT_CONTEXT_TO_CBI(le32toh(msg_hdr->MsgContext)); - mpt_reply_handlers[cb_index](mpt, req, &ioc_status_frame); + mpt_reply_handlers[cb_index](mpt, req, msg_hdr->MsgContext, + &ioc_status_frame); } } @@ -645,7 +819,6 @@ mpt_complete_request_chain(struct mpt_softc *mpt, struct req_queue *chain, void mpt_dump_reply_frame(struct mpt_softc *mpt, MSG_DEFAULT_REPLY *reply_frame) { - mpt_prt(mpt, "Address Reply:\n"); mpt_print_reply(reply_frame); } @@ -674,12 +847,11 @@ mpt_wait_db_ack(struct mpt_softc *mpt) for (i=0; i < MPT_MAX_WAIT; i++) { if (!MPT_DB_IS_BUSY(mpt_rd_intr(mpt))) { maxwait_ack = i > maxwait_ack ? i : maxwait_ack; - return MPT_OK; + return (MPT_OK); } - - DELAY(1000); + DELAY(200); } - return MPT_FAIL; + return (MPT_FAIL); } /* Busy wait for a door bell interrupt */ @@ -694,7 +866,7 @@ mpt_wait_db_int(struct mpt_softc *mpt) } DELAY(100); } - return MPT_FAIL; + return (MPT_FAIL); } /* Wait for IOC to transition to a give state */ @@ -738,7 +910,7 @@ mpt_soft_reset(struct mpt_softc *mpt) /* Have to use hard reset if we are not in Running state */ if (MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_RUNNING) { mpt_prt(mpt, "soft reset failed: device not running\n"); - return MPT_FAIL; + return (MPT_FAIL); } /* If door bell is in use we don't have a chance of getting @@ -747,7 +919,7 @@ mpt_soft_reset(struct mpt_softc *mpt) */ if (MPT_DB_IS_IN_USE(mpt_rd_db(mpt))) { mpt_prt(mpt, "soft reset failed: doorbell wedged\n"); - return MPT_FAIL; + return (MPT_FAIL); } /* Send the reset request to the IOC */ @@ -755,13 +927,13 @@ mpt_soft_reset(struct mpt_softc *mpt) MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET << MPI_DOORBELL_FUNCTION_SHIFT); if (mpt_wait_db_ack(mpt) != MPT_OK) { mpt_prt(mpt, "soft reset failed: ack timeout\n"); - return MPT_FAIL; + return (MPT_FAIL); } /* Wait for the IOC to reload and come out of reset state */ if (mpt_wait_state(mpt, MPT_DB_STATE_READY) != MPT_OK) { mpt_prt(mpt, "soft reset failed: device did not restart\n"); - return MPT_FAIL; + return (MPT_FAIL); } return MPT_OK; @@ -800,7 +972,7 @@ mpt_disable_diag_mode(struct mpt_softc *mpt) } /* This is a magic diagnostic reset that resets all the ARM - * processors in the chip. + * processors in the chip. */ static void mpt_hard_reset(struct mpt_softc *mpt) @@ -891,30 +1063,58 @@ mpt_reset(struct mpt_softc *mpt, int reinit) { struct mpt_personality *pers; int ret; + int retry_cnt = 0; - /* Try a soft reset */ + /* + * Try a soft reset. If that fails, get out the big hammer. + */ + again: if ((ret = mpt_soft_reset(mpt)) != MPT_OK) { - /* Failed; do a hard reset */ - mpt_hard_reset(mpt); + int cnt; + for (cnt = 0; cnt < 5; cnt++) { + /* Failed; do a hard reset */ + mpt_hard_reset(mpt); - /* Wait for the IOC to reload and come out of reset state */ - ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); - if (ret != MPT_OK) - mpt_prt(mpt, "failed to reset device\n"); + /* + * Wait for the IOC to reload + * and come out of reset state + */ + ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); + if (ret == MPT_OK) { + break; + } + /* + * Okay- try to check again... + */ + ret = mpt_wait_state(mpt, MPT_DB_STATE_READY); + if (ret == MPT_OK) { + break; + } + mpt_prt(mpt, "mpt_reset: failed hard reset (%d:%d)\n", + retry_cnt, cnt); + } } - /* - * Invoke reset handlers. We bump the reset count so - * that mpt_wait_req() understands that regardless of - * the specified wait condition, it should stop its wait. - */ - mpt->reset_cnt++; - MPT_PERS_FOREACH(mpt, pers) - pers->reset(mpt, ret); - - if (reinit != 0) - mpt_enable_ioc(mpt); + if (retry_cnt == 0) { + /* + * Invoke reset handlers. We bump the reset count so + * that mpt_wait_req() understands that regardless of + * the specified wait condition, it should stop its wait. + */ + mpt->reset_cnt++; + MPT_PERS_FOREACH(mpt, pers) + pers->reset(mpt, ret); + } + if (reinit) { + ret = mpt_enable_ioc(mpt, 1); + if (ret == MPT_OK) { + mpt_enable_ints(mpt); + } + } + if (ret != MPT_OK && retry_cnt++ < 2) { + goto again; + } return ret; } @@ -922,6 +1122,7 @@ mpt_reset(struct mpt_softc *mpt, int reinit) void mpt_free_request(struct mpt_softc *mpt, request_t *req) { + request_t *nxt; struct mpt_evtf_record *record; uint32_t reply_baddr; @@ -929,10 +1130,34 @@ mpt_free_request(struct mpt_softc *mpt, request_t *req) panic("mpt_free_request bad req ptr\n"); return; } + if ((nxt = req->chain) != NULL) { + req->chain = NULL; + mpt_free_request(mpt, nxt); /* NB: recursion */ + } + KASSERT(req->state != REQ_STATE_FREE, ("freeing free request")); + KASSERT(!(req->state & REQ_STATE_LOCKED), ("freeing locked request")); + KASSERT(MPT_OWNED(mpt), ("mpt_free_request: mpt not locked\n")); + KASSERT(mpt_req_on_free_list(mpt, req) == 0, + ("mpt_free_request: req %p:%u func %x already on freelist", + req, req->serno, ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function)); + KASSERT(mpt_req_on_pending_list(mpt, req) == 0, + ("mpt_free_request: req %p:%u func %x on pending list", + req, req->serno, ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function)); +#ifdef INVARIANTS + mpt_req_not_spcl(mpt, req, "mpt_free_request", __LINE__); +#endif + req->ccb = NULL; - req->state = REQ_STATE_FREE; if (LIST_EMPTY(&mpt->ack_frames)) { - TAILQ_INSERT_HEAD(&mpt->request_free_list, req, links); + /* + * Insert free ones at the tail + */ + req->serno = 0; + req->state = REQ_STATE_FREE; +#ifdef INVARIANTS + memset(req->req_vbuf, 0xff, sizeof (MSG_REQUEST_HEADER)); +#endif + TAILQ_INSERT_TAIL(&mpt->request_free_list, req, links); if (mpt->getreqwaiter != 0) { mpt->getreqwaiter = 0; wakeup(&mpt->request_free_list); @@ -945,6 +1170,8 @@ mpt_free_request(struct mpt_softc *mpt, request_t *req) */ record = LIST_FIRST(&mpt->ack_frames); LIST_REMOVE(record, links); + req->state = REQ_STATE_ALLOCATED; + mpt_assign_serno(mpt, req); mpt_send_event_ack(mpt, req, &record->reply, record->context); reply_baddr = (uint32_t)((uint8_t *)record - mpt->reply) + (mpt->reply_phys & 0xFFFFFFFF); @@ -958,41 +1185,43 @@ mpt_get_request(struct mpt_softc *mpt, int sleep_ok) request_t *req; retry: + KASSERT(MPT_OWNED(mpt), ("mpt_get_request: mpt not locked\n")); req = TAILQ_FIRST(&mpt->request_free_list); if (req != NULL) { KASSERT(req == &mpt->request_pool[req->index], ("mpt_get_request: corrupted request free list\n")); + KASSERT(req->state == REQ_STATE_FREE, + ("req %p:%u not free on free list %x index %d function %x", + req, req->serno, req->state, req->index, + ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function)); TAILQ_REMOVE(&mpt->request_free_list, req, links); req->state = REQ_STATE_ALLOCATED; + req->chain = NULL; + mpt_assign_serno(mpt, req); } else if (sleep_ok != 0) { mpt->getreqwaiter = 1; mpt_sleep(mpt, &mpt->request_free_list, PUSER, "mptgreq", 0); goto retry; } - return req; + return (req); } /* Pass the command to the IOC */ void mpt_send_cmd(struct mpt_softc *mpt, request_t *req) { - uint32_t *pReq; - - pReq = req->req_vbuf; - mpt_lprt(mpt, MPT_PRT_TRACE, "Send Request %d (0x%x):\n", - req->index, req->req_pbuf); - mpt_lprt(mpt, MPT_PRT_TRACE, "%08x %08x %08x %08x\n", - pReq[0], pReq[1], pReq[2], pReq[3]); - mpt_lprt(mpt, MPT_PRT_TRACE, "%08x %08x %08x %08x\n", - pReq[4], pReq[5], pReq[6], pReq[7]); - mpt_lprt(mpt, MPT_PRT_TRACE, "%08x %08x %08x %08x\n", - pReq[8], pReq[9], pReq[10], pReq[11]); - mpt_lprt(mpt, MPT_PRT_TRACE, "%08x %08x %08x %08x\n", - pReq[12], pReq[13], pReq[14], pReq[15]); - + if (mpt->verbose > MPT_PRT_DEBUG2) { + mpt_dump_request(mpt, req); + } bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, BUS_DMASYNC_PREWRITE); req->state |= REQ_STATE_QUEUED; + KASSERT(mpt_req_on_free_list(mpt, req) == 0, + ("req %p:%u func %x on freelist list in mpt_send_cmd", + req, req->serno, ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function)); + KASSERT(mpt_req_on_pending_list(mpt, req) == 0, + ("req %p:%u func %x already on pending list in mpt_send_cmd", + req, req->serno, ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function)); TAILQ_INSERT_HEAD(&mpt->request_pending_list, req, links); mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (uint32_t) req->req_pbuf); } @@ -1024,16 +1253,15 @@ mpt_wait_req(struct mpt_softc *mpt, request_t *req, * Convert to ticks or 500us units depending on * our sleep mode. */ - if (sleep_ok != 0) + if (sleep_ok != 0) { timeout = (time_ms * hz) / 1000; - else + } else { timeout = time_ms * 2; - saved_cnt = mpt->reset_cnt; + } req->state |= REQ_STATE_NEED_WAKEUP; mask &= ~REQ_STATE_NEED_WAKEUP; - while ((req->state & mask) != state - && mpt->reset_cnt == saved_cnt) { - + saved_cnt = mpt->reset_cnt; + while ((req->state & mask) != state && mpt->reset_cnt == saved_cnt) { if (sleep_ok != 0) { error = mpt_sleep(mpt, req, PUSER, "mptreq", timeout); if (error == EWOULDBLOCK) { @@ -1042,7 +1270,6 @@ mpt_wait_req(struct mpt_softc *mpt, request_t *req, } } else { if (time_ms != 0 && --timeout == 0) { - mpt_prt(mpt, "mpt_wait_req timed out\n"); break; } DELAY(500); @@ -1050,10 +1277,14 @@ mpt_wait_req(struct mpt_softc *mpt, request_t *req, } } req->state &= ~REQ_STATE_NEED_WAKEUP; - if (mpt->reset_cnt != saved_cnt) + if (mpt->reset_cnt != saved_cnt) { return (EIO); - if (time_ms && timeout == 0) + } + if (time_ms && timeout <= 0) { + MSG_REQUEST_HEADER *msg_hdr = req->req_vbuf; + mpt_prt(mpt, "mpt_wait_req(%x) timed out\n", msg_hdr->Function); return (ETIMEDOUT); + } return (0); } @@ -1114,7 +1345,7 @@ mpt_send_handshake_cmd(struct mpt_softc *mpt, size_t len, void *cmd) for (i = 0; i < len; i++) { mpt_write(mpt, MPT_OFFSET_DOORBELL, *data32++); if (mpt_wait_db_ack(mpt) != MPT_OK) { - mpt_prt(mpt, + mpt_prt(mpt, "mpt_send_handshake_cmd timeout! index = %d\n", i); return (ETIMEDOUT); @@ -1153,11 +1384,21 @@ mpt_recv_handshake_reply(struct mpt_softc *mpt, size_t reply_len, void *reply) *data16++ = mpt_read(mpt, MPT_OFFSET_DOORBELL) & MPT_DB_DATA_MASK; mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); - /* With the second word, we can now look at the length */ - if (((reply_len >> 1) != hdr->MsgLength)) { + /* + * With the second word, we can now look at the length. + * Warn about a reply that's too short (except for IOC FACTS REPLY) + */ + if ((reply_len >> 1) != hdr->MsgLength && + (hdr->Function != MPI_FUNCTION_IOC_FACTS)){ +#if __FreeBSD_version >= 500000 + mpt_prt(mpt, "reply length does not match message length: " + "got %x; expected %zx for function %x\n", + hdr->MsgLength << 2, reply_len << 1, hdr->Function); +#else mpt_prt(mpt, "reply length does not match message length: " - "got 0x%02x, expected 0x%02x\n", - hdr->MsgLength << 2, reply_len << 1); + "got %x; expected %x for function %x\n", + hdr->MsgLength << 2, reply_len << 1, hdr->Function); +#endif } /* Get rest of the reply; but don't overflow the provided buffer */ @@ -1200,7 +1441,7 @@ mpt_get_iocfacts(struct mpt_softc *mpt, MSG_IOC_FACTS_REPLY *freplp) MSG_IOC_FACTS f_req; int error; - bzero(&f_req, sizeof f_req); + memset(&f_req, 0, sizeof f_req); f_req.Function = MPI_FUNCTION_IOC_FACTS; f_req.MsgContext = htole32(MPT_REPLY_HANDLER_HANDSHAKE); error = mpt_send_handshake_cmd(mpt, sizeof f_req, &f_req); @@ -1240,16 +1481,21 @@ mpt_send_ioc_init(struct mpt_softc *mpt, uint32_t who) MSG_IOC_INIT init; MSG_IOC_INIT_REPLY reply; - bzero(&init, sizeof init); + memset(&init, 0, sizeof init); init.WhoInit = who; init.Function = MPI_FUNCTION_IOC_INIT; if (mpt->is_fc) { init.MaxDevices = 255; + } else if (mpt->is_sas) { + init.MaxDevices = mpt->mpt_max_devices; } else { init.MaxDevices = 16; } init.MaxBuses = 1; - init.ReplyFrameSize = MPT_REPLY_SIZE; + + init.MsgVersion = htole16(MPI_VERSION); + init.HeaderVersion = htole16(MPI_HEADER_VERSION); + init.ReplyFrameSize = htole16(MPT_REPLY_SIZE); init.MsgContext = htole32(MPT_REPLY_HANDLER_HANDSHAKE); if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) { @@ -1306,12 +1552,13 @@ mpt_read_cfg_header(struct mpt_softc *mpt, int PageType, int PageNumber, int sleep_ok, int timeout_ms) { request_t *req; + MSG_CONFIG *cfgp; int error; req = mpt_get_request(mpt, sleep_ok); if (req == NULL) { mpt_prt(mpt, "mpt_read_cfg_header: Get request failed!\n"); - return (-1); + return (ENOMEM); } error = mpt_issue_cfg_req(mpt, req, MPI_CONFIG_ACTION_PAGE_HEADER, @@ -1319,27 +1566,33 @@ mpt_read_cfg_header(struct mpt_softc *mpt, int PageType, int PageNumber, PageType, PageAddress, /*addr*/0, /*len*/0, sleep_ok, timeout_ms); if (error != 0) { + mpt_free_request(mpt, req); mpt_prt(mpt, "read_cfg_header timed out\n"); - return (-1); + return (ETIMEDOUT); } - if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { - mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x\n", - req->IOCStatus); - error = -1; - } else { - MSG_CONFIG *cfgp; - + switch (req->IOCStatus & MPI_IOCSTATUS_MASK) { + case MPI_IOCSTATUS_SUCCESS: cfgp = req->req_vbuf; bcopy(&cfgp->Header, rslt, sizeof(*rslt)); error = 0; + break; + case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: + mpt_lprt(mpt, MPT_PRT_DEBUG, + "Invalid Page Type %d Number %d Addr 0x%0x\n", + PageType, PageNumber, PageAddress); + error = EINVAL; + break; + default: + mpt_prt(mpt, "mpt_read_cfg_header: Config Info Status %x\n", + req->IOCStatus); + error = EIO; + break; } mpt_free_request(mpt, req); return (error); } -#define CFG_DATA_OFF 128 - int mpt_read_cfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, CONFIG_PAGE_HEADER *hdr, size_t len, int sleep_ok, @@ -1357,7 +1610,7 @@ mpt_read_cfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, error = mpt_issue_cfg_req(mpt, req, Action, hdr->PageVersion, hdr->PageLength, hdr->PageNumber, hdr->PageType & MPI_CONFIG_PAGETYPE_MASK, - PageAddress, req->req_pbuf + CFG_DATA_OFF, + PageAddress, req->req_pbuf + MPT_RQSL(mpt), len, sleep_ok, timeout_ms); if (error != 0) { mpt_prt(mpt, "read_cfg_page(%d) timed out\n", Action); @@ -1372,7 +1625,7 @@ mpt_read_cfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, } bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, BUS_DMASYNC_POSTREAD); - memcpy(hdr, ((uint8_t *)req->req_vbuf)+CFG_DATA_OFF, len); + memcpy(hdr, ((uint8_t *)req->req_vbuf)+MPT_RQSL(mpt), len); mpt_free_request(mpt, req); return (0); } @@ -1399,14 +1652,14 @@ mpt_write_cfg_page(struct mpt_softc *mpt, int Action, uint32_t PageAddress, if (req == NULL) return (-1); - memcpy(((caddr_t)req->req_vbuf)+CFG_DATA_OFF, hdr, len); + memcpy(((caddr_t)req->req_vbuf)+MPT_RQSL(mpt), hdr, len); /* Restore stripped out attributes */ hdr->PageType |= hdr_attr; error = mpt_issue_cfg_req(mpt, req, Action, hdr->PageVersion, hdr->PageLength, hdr->PageNumber, hdr->PageType & MPI_CONFIG_PAGETYPE_MASK, - PageAddress, req->req_pbuf + CFG_DATA_OFF, + PageAddress, req->req_pbuf + MPT_RQSL(mpt), len, sleep_ok, timeout_ms); if (error != 0) { mpt_prt(mpt, "mpt_write_cfg_page timed out\n"); @@ -1436,34 +1689,53 @@ mpt_read_config_info_ioc(struct mpt_softc *mpt) size_t len; rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_IOC, - /*PageNumber*/2, /*PageAddress*/0, &hdr, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) - return (EIO); + 2, 0, &hdr, FALSE, 5000); + /* + * If it's an invalid page, so what? Not a supported function.... + */ + if (rv == EINVAL) { + return (0); + } + if (rv) { + return (rv); + } - mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC Page 2 Header: ver %x, len %x, " +#if __FreeBSD_version >= 500000 + mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC Page 2 Header: ver %x, len %zx, " + "num %x, type %x\n", hdr.PageVersion, + hdr.PageLength * sizeof(uint32_t), + hdr.PageNumber, hdr.PageType); +#else + mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC Page 2 Header: ver %x, len %z, " "num %x, type %x\n", hdr.PageVersion, hdr.PageLength * sizeof(uint32_t), hdr.PageNumber, hdr.PageType); +#endif len = hdr.PageLength * sizeof(uint32_t); mpt->ioc_page2 = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); - if (mpt->ioc_page2 == NULL) + if (mpt->ioc_page2 == NULL) { + mpt_prt(mpt, "unable to allocate memory for IOC page 2\n"); + mpt_raid_free_mem(mpt); return (ENOMEM); + } memcpy(&mpt->ioc_page2->Header, &hdr, sizeof(hdr)); - rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0, - &mpt->ioc_page2->Header, len, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); + rv = mpt_read_cur_cfg_page(mpt, 0, + &mpt->ioc_page2->Header, len, FALSE, 5000); if (rv) { mpt_prt(mpt, "failed to read IOC Page 2\n"); - } else if (mpt->ioc_page2->CapabilitiesFlags != 0) { + mpt_raid_free_mem(mpt); + return (EIO); + } + + if (mpt->ioc_page2->CapabilitiesFlags != 0) { uint32_t mask; mpt_prt(mpt, "Capabilities: ("); for (mask = 1; mask != 0; mask <<= 1) { - if ((mpt->ioc_page2->CapabilitiesFlags & mask) == 0) + if ((mpt->ioc_page2->CapabilitiesFlags & mask) == 0) { continue; - + } switch (mask) { case MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT: mpt_prtc(mpt, " RAID-0"); @@ -1505,11 +1777,11 @@ mpt_read_config_info_ioc(struct mpt_softc *mpt) } len = mpt->ioc_page2->MaxVolumes * sizeof(struct mpt_raid_volume); - mpt->raid_volumes = malloc(len, M_DEVBUF, M_NOWAIT); + mpt->raid_volumes = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); if (mpt->raid_volumes == NULL) { mpt_prt(mpt, "Could not allocate RAID volume data\n"); - } else { - memset(mpt->raid_volumes, 0, len); + mpt_raid_free_mem(mpt); + return (ENOMEM); } /* @@ -1519,284 +1791,57 @@ mpt_read_config_info_ioc(struct mpt_softc *mpt) */ mpt->raid_max_volumes = mpt->ioc_page2->MaxVolumes; - len = sizeof(*mpt->raid_volumes->config_page) - + (sizeof(RAID_VOL0_PHYS_DISK)*(mpt->ioc_page2->MaxPhysDisks - 1)); + len = sizeof(*mpt->raid_volumes->config_page) + + (sizeof (RAID_VOL0_PHYS_DISK) * (mpt->ioc_page2->MaxPhysDisks - 1)); for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) { mpt_raid = &mpt->raid_volumes[i]; - mpt_raid->config_page = malloc(len, M_DEVBUF, M_NOWAIT); + mpt_raid->config_page = + malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); if (mpt_raid->config_page == NULL) { mpt_prt(mpt, "Could not allocate RAID page data\n"); - break; + mpt_raid_free_mem(mpt); + return (ENOMEM); } - memset(mpt_raid->config_page, 0, len); } mpt->raid_page0_len = len; len = mpt->ioc_page2->MaxPhysDisks * sizeof(struct mpt_raid_disk); - mpt->raid_disks = malloc(len, M_DEVBUF, M_NOWAIT); + mpt->raid_disks = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); if (mpt->raid_disks == NULL) { mpt_prt(mpt, "Could not allocate RAID disk data\n"); - } else { - memset(mpt->raid_disks, 0, len); + mpt_raid_free_mem(mpt); + return (ENOMEM); } - mpt->raid_max_disks = mpt->ioc_page2->MaxPhysDisks; + /* + * Load page 3. + */ rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_IOC, - /*PageNumber*/3, /*PageAddress*/0, &hdr, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) + 3, 0, &hdr, FALSE, 5000); + if (rv) { + mpt_raid_free_mem(mpt); return (EIO); + } mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC Page 3 Header: %x %x %x %x\n", - hdr.PageVersion, hdr.PageLength, hdr.PageNumber, hdr.PageType); + hdr.PageVersion, hdr.PageLength, hdr.PageNumber, hdr.PageType); - if (mpt->ioc_page3 != NULL) - free(mpt->ioc_page3, M_DEVBUF); len = hdr.PageLength * sizeof(uint32_t); mpt->ioc_page3 = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); - if (mpt->ioc_page3 == NULL) - return (-1); + if (mpt->ioc_page3 == NULL) { + mpt_prt(mpt, "unable to allocate memory for IOC page 3\n"); + mpt_raid_free_mem(mpt); + return (ENOMEM); + } memcpy(&mpt->ioc_page3->Header, &hdr, sizeof(hdr)); - rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0, - &mpt->ioc_page3->Header, len, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); + rv = mpt_read_cur_cfg_page(mpt, 0, + &mpt->ioc_page3->Header, len, FALSE, 5000); if (rv) { - mpt_prt(mpt, "failed to read IOC Page 3\n"); + mpt_raid_free_mem(mpt); + return (EIO); } - mpt_raid_wakeup(mpt); - - return (0); -} - -/* - * Read SCSI configuration information - */ -static int -mpt_read_config_info_spi(struct mpt_softc *mpt) -{ - int rv, i; - - rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, - 0, &mpt->mpt_port_page0.Header, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) - return (-1); - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Port Page 0 Header: %x %x %x %x\n", - mpt->mpt_port_page0.Header.PageVersion, - mpt->mpt_port_page0.Header.PageLength, - mpt->mpt_port_page0.Header.PageNumber, - mpt->mpt_port_page0.Header.PageType); - - rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, - 0, &mpt->mpt_port_page1.Header, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) - return (-1); - - mpt_lprt(mpt, MPT_PRT_DEBUG, "SPI Port Page 1 Header: %x %x %x %x\n", - mpt->mpt_port_page1.Header.PageVersion, - mpt->mpt_port_page1.Header.PageLength, - mpt->mpt_port_page1.Header.PageNumber, - mpt->mpt_port_page1.Header.PageType); - - rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, - /*PageAddress*/0, &mpt->mpt_port_page2.Header, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) - return (-1); - - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Port Page 2 Header: %x %x %x %x\n", - mpt->mpt_port_page1.Header.PageVersion, - mpt->mpt_port_page1.Header.PageLength, - mpt->mpt_port_page1.Header.PageNumber, - mpt->mpt_port_page1.Header.PageType); - - for (i = 0; i < 16; i++) { - rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, - 0, i, &mpt->mpt_dev_page0[i].Header, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) - return (-1); - - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Target %d Device Page 0 Header: %x %x %x %x\n", - i, mpt->mpt_dev_page0[i].Header.PageVersion, - mpt->mpt_dev_page0[i].Header.PageLength, - mpt->mpt_dev_page0[i].Header.PageNumber, - mpt->mpt_dev_page0[i].Header.PageType); - - rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, - 1, i, &mpt->mpt_dev_page1[i].Header, - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) - return (-1); - - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Target %d Device Page 1 Header: %x %x %x %x\n", - i, mpt->mpt_dev_page1[i].Header.PageVersion, - mpt->mpt_dev_page1[i].Header.PageLength, - mpt->mpt_dev_page1[i].Header.PageNumber, - mpt->mpt_dev_page1[i].Header.PageType); - } - - /* - * At this point, we don't *have* to fail. As long as we have - * valid config header information, we can (barely) lurch - * along. - */ - - rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0, - &mpt->mpt_port_page0.Header, - sizeof(mpt->mpt_port_page0), - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, "failed to read SPI Port Page 0\n"); - } else { - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Port Page 0: Capabilities %x PhysicalInterface %x\n", - mpt->mpt_port_page0.Capabilities, - mpt->mpt_port_page0.PhysicalInterface); - } - - rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0, - &mpt->mpt_port_page1.Header, - sizeof(mpt->mpt_port_page1), - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, "failed to read SPI Port Page 1\n"); - } else { - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Port Page 1: Configuration %x OnBusTimerValue %x\n", - mpt->mpt_port_page1.Configuration, - mpt->mpt_port_page1.OnBusTimerValue); - } - - rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0, - &mpt->mpt_port_page2.Header, - sizeof(mpt->mpt_port_page2), - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, "failed to read SPI Port Page 2\n"); - } else { - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Port Page 2: Flags %x Settings %x\n", - mpt->mpt_port_page2.PortFlags, - mpt->mpt_port_page2.PortSettings); - for (i = 0; i < 16; i++) { - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Port Page 2 Tgt %d: timo %x SF %x Flags %x\n", - i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, - mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, - mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); - } - } - - for (i = 0; i < 16; i++) { - rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/i, - &mpt->mpt_dev_page0[i].Header, - sizeof(*mpt->mpt_dev_page0), - /*sleep_ok*/FALSE, - /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, - "cannot read SPI Tgt %d Device Page 0\n", i); - continue; - } - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Tgt %d Page 0: NParms %x Information %x", - i, mpt->mpt_dev_page0[i].NegotiatedParameters, - mpt->mpt_dev_page0[i].Information); - - rv = mpt_read_cur_cfg_page(mpt, /*PageAddress*/i, - &mpt->mpt_dev_page1[i].Header, - sizeof(*mpt->mpt_dev_page1), - /*sleep_ok*/FALSE, - /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, - "cannot read SPI Tgt %d Device Page 1\n", i); - continue; - } - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Tgt %d Page 1: RParms %x Configuration %x\n", - i, mpt->mpt_dev_page1[i].RequestedParameters, - mpt->mpt_dev_page1[i].Configuration); - } - return (0); -} - -/* - * Validate SPI configuration information. - * - * In particular, validate SPI Port Page 1. - */ -static int -mpt_set_initial_config_spi(struct mpt_softc *mpt) -{ - int i, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; - int error; - - mpt->mpt_disc_enable = 0xff; - mpt->mpt_tag_enable = 0; - - if (mpt->mpt_port_page1.Configuration != pp1val) { - CONFIG_PAGE_SCSI_PORT_1 tmp; - - mpt_prt(mpt, - "SPI Port Page 1 Config value bad (%x)- should be %x\n", - mpt->mpt_port_page1.Configuration, pp1val); - tmp = mpt->mpt_port_page1; - tmp.Configuration = pp1val; - error = mpt_write_cur_cfg_page(mpt, /*PageAddress*/0, - &tmp.Header, sizeof(tmp), - /*sleep_ok*/FALSE, - /*timeout_ms*/5000); - if (error) - return (-1); - error = mpt_read_cur_cfg_page(mpt, /*PageAddress*/0, - &tmp.Header, sizeof(tmp), - /*sleep_ok*/FALSE, - /*timeout_ms*/5000); - if (error) - return (-1); - if (tmp.Configuration != pp1val) { - mpt_prt(mpt, - "failed to reset SPI Port Page 1 Config value\n"); - return (-1); - } - mpt->mpt_port_page1 = tmp; - } - - for (i = 0; i < 16; i++) { - CONFIG_PAGE_SCSI_DEVICE_1 tmp; - tmp = mpt->mpt_dev_page1[i]; - tmp.RequestedParameters = 0; - tmp.Configuration = 0; - mpt_lprt(mpt, MPT_PRT_DEBUG, - "Set Tgt %d SPI DevicePage 1 values to %x 0 %x\n", - i, tmp.RequestedParameters, tmp.Configuration); - error = mpt_write_cur_cfg_page(mpt, /*PageAddress*/i, - &tmp.Header, sizeof(tmp), - /*sleep_ok*/FALSE, - /*timeout_ms*/5000); - if (error) - return (-1); - error = mpt_read_cur_cfg_page(mpt, /*PageAddress*/i, - &tmp.Header, sizeof(tmp), - /*sleep_ok*/FALSE, - /*timeout_ms*/5000); - if (error) - return (-1); - mpt->mpt_dev_page1[i] = tmp; - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Tgt %d Page 1: RParm %x Configuration %x\n", i, - mpt->mpt_dev_page1[i].RequestedParameters, - mpt->mpt_dev_page1[i].Configuration); - } return (0); } @@ -1815,7 +1860,7 @@ mpt_send_port_enable(struct mpt_softc *mpt, int port) return (-1); enable_req = req->req_vbuf; - bzero(enable_req, sizeof *enable_req); + memset(enable_req, 0, MPT_RQSL(mpt)); enable_req->Function = MPI_FUNCTION_PORT_ENABLE; enable_req->MsgContext = htole32(req->index | MPT_REPLY_HANDLER_CONFIG); @@ -1826,20 +1871,18 @@ mpt_send_port_enable(struct mpt_softc *mpt, int port) mpt_send_cmd(mpt, req); error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, - /*sleep_ok*/FALSE, /*time_ms*/500); + FALSE, (mpt->is_sas || mpt->is_fc)? 30000 : 3000); if (error != 0) { - mpt_prt(mpt, "port enable timed out"); + mpt_prt(mpt, "port %d enable timed out\n", port); return (-1); } mpt_free_request(mpt, req); + mpt_lprt(mpt, MPT_PRT_DEBUG, "enabled port %d\n", port); return (0); } /* * Enable/Disable asynchronous event reporting. - * - * NB: this is the first command we send via shared memory - * instead of the handshake register. */ static int mpt_send_event_request(struct mpt_softc *mpt, int onoff) @@ -1847,20 +1890,24 @@ mpt_send_event_request(struct mpt_softc *mpt, int onoff) request_t *req; MSG_EVENT_NOTIFY *enable_req; - req = mpt_get_request(mpt, /*sleep_ok*/FALSE); - + req = mpt_get_request(mpt, FALSE); + if (req == NULL) { + return (ENOMEM); + } enable_req = req->req_vbuf; - bzero(enable_req, sizeof *enable_req); + memset(enable_req, 0, sizeof *enable_req); enable_req->Function = MPI_FUNCTION_EVENT_NOTIFICATION; enable_req->MsgContext = htole32(req->index | MPT_REPLY_HANDLER_EVENTS); enable_req->Switch = onoff; mpt_check_doorbell(mpt); - mpt_lprt(mpt, MPT_PRT_DEBUG, - "%sabling async events\n", onoff ? "en" : "dis"); + mpt_lprt(mpt, MPT_PRT_DEBUG, "%sabling async events\n", + onoff ? "en" : "dis"); + /* + * Send the command off, but don't wait for it. + */ mpt_send_cmd(mpt, req); - return (0); } @@ -1881,34 +1928,35 @@ void mpt_disable_ints(struct mpt_softc *mpt) { /* Mask all interrupts */ - mpt_write(mpt, MPT_OFFSET_INTR_MASK, + mpt_write(mpt, MPT_OFFSET_INTR_MASK, MPT_INTR_REPLY_MASK | MPT_INTR_DB_MASK); } static void mpt_sysctl_attach(struct mpt_softc *mpt) { +#if __FreeBSD_version >= 500000 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(mpt->dev); struct sysctl_oid *tree = device_get_sysctl_tree(mpt->dev); - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &mpt->verbose, 0, "Debugging/Verbose level"); +#endif } int mpt_attach(struct mpt_softc *mpt) { + struct mpt_personality *pers; int i; + int error; for (i = 0; i < MPT_MAX_PERSONALITIES; i++) { - struct mpt_personality *pers; - int error; - pers = mpt_personalities[i]; - if (pers == NULL) + if (pers == NULL) { continue; - + } if (pers->probe(mpt) == 0) { error = pers->attach(mpt); if (error != 0) { @@ -1919,6 +1967,25 @@ mpt_attach(struct mpt_softc *mpt) pers->use_count++; } } + + /* + * Now that we've attached everything, do the enable function + * for all of the personalities. This allows the personalities + * to do setups that are appropriate for them prior to enabling + * any ports. + */ + for (i = 0; i < MPT_MAX_PERSONALITIES; i++) { + pers = mpt_personalities[i]; + if (pers != NULL && MPT_PERS_ATTACHED(pers, mpt) != 0) { + error = pers->enable(mpt); + if (error != 0) { + mpt_prt(mpt, "personality %s attached but would" + " not enable (%d)\n", pers->name, error); + mpt_detach(mpt); + return (error); + } + } + } return (0); } @@ -1927,10 +1994,9 @@ mpt_shutdown(struct mpt_softc *mpt) { struct mpt_personality *pers; - MPT_PERS_FOREACH_REVERSE(mpt, pers) + MPT_PERS_FOREACH_REVERSE(mpt, pers) { pers->shutdown(mpt); - - mpt_reset(mpt, /*reinit*/FALSE); + } return (0); } @@ -1957,8 +2023,9 @@ mpt_core_load(struct mpt_personality *pers) * Setup core handlers and insert the default handler * into all "empty slots". */ - for (i = 0; i < MPT_NUM_REPLY_HANDLERS; i++) + for (i = 0; i < MPT_NUM_REPLY_HANDLERS; i++) { mpt_reply_handlers[i] = mpt_default_reply_handler; + } mpt_reply_handlers[MPT_CBI(MPT_REPLY_HANDLER_EVENTS)] = mpt_event_reply_handler; @@ -1966,7 +2033,6 @@ mpt_core_load(struct mpt_personality *pers) mpt_config_reply_handler; mpt_reply_handlers[MPT_CBI(MPT_REPLY_HANDLER_HANDSHAKE)] = mpt_handshake_reply_handler; - return (0); } @@ -1980,32 +2046,95 @@ mpt_core_attach(struct mpt_softc *mpt) int val; int error; + LIST_INIT(&mpt->ack_frames); /* Put all request buffers on the free list */ TAILQ_INIT(&mpt->request_pending_list); TAILQ_INIT(&mpt->request_free_list); - for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) - mpt_free_request(mpt, &mpt->request_pool[val]); + TAILQ_INIT(&mpt->request_timeout_list); + for (val = 0; val < MPT_MAX_REQUESTS(mpt); val++) { + request_t *req = &mpt->request_pool[val]; + req->state = REQ_STATE_ALLOCATED; + mpt_free_request(mpt, req); + } + + for (val = 0; val < MPT_MAX_LUNS; val++) { + STAILQ_INIT(&mpt->trt[val].atios); + STAILQ_INIT(&mpt->trt[val].inots); + } + STAILQ_INIT(&mpt->trt_wildcard.atios); + STAILQ_INIT(&mpt->trt_wildcard.inots); + + mpt->scsi_tgt_handler_id = MPT_HANDLER_ID_NONE; mpt_sysctl_attach(mpt); mpt_lprt(mpt, MPT_PRT_DEBUG, "doorbell req = %s\n", - mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); + mpt_ioc_diag(mpt_read(mpt, MPT_OFFSET_DOORBELL))); error = mpt_configure_ioc(mpt); return (error); } +int +mpt_core_enable(struct mpt_softc *mpt) +{ + /* + * We enter with the IOC enabled, but async events + * not enabled, ports not enabled and interrupts + * not enabled. + */ + + /* + * Enable asynchronous event reporting- all personalities + * have attached so that they should be able to now field + * async events. + */ + mpt_send_event_request(mpt, 1); + + /* + * Catch any pending interrupts + * + * This seems to be crucial- otherwise + * the portenable below times out. + */ + mpt_intr(mpt); + + /* + * Enable Interrupts + */ + mpt_enable_ints(mpt); + + /* + * Catch any pending interrupts + * + * This seems to be crucial- otherwise + * the portenable below times out. + */ + mpt_intr(mpt); + + /* + * Enable the port. + */ + if (mpt_send_port_enable(mpt, 0) != MPT_OK) { + mpt_prt(mpt, "failed to enable port 0\n"); + return (ENXIO); + } + return (0); +} + void mpt_core_shutdown(struct mpt_softc *mpt) { + mpt_disable_ints(mpt); } void mpt_core_detach(struct mpt_softc *mpt) { + mpt_disable_ints(mpt); } int @@ -2060,11 +2189,13 @@ mpt_diag_outsl(struct mpt_softc *mpt, uint32_t addr, uint32_t *data_end; data_end = data + (roundup2(len, sizeof(uint32_t)) / 4); + pci_enable_io(mpt->dev, SYS_RES_IOPORT); mpt_pio_write(mpt, MPT_OFFSET_DIAG_ADDR, addr); while (data != data_end) { mpt_pio_write(mpt, MPT_OFFSET_DIAG_DATA, *data); data++; } + pci_disable_io(mpt->dev, SYS_RES_IOPORT); } static int @@ -2102,6 +2233,7 @@ mpt_download_fw(struct mpt_softc *mpt) ext->ImageSize); } + pci_enable_io(mpt->dev, SYS_RES_IOPORT); /* Setup the address to jump to on reset. */ mpt_pio_write(mpt, MPT_OFFSET_DIAG_ADDR, fw_hdr->IopResetRegAddr); mpt_pio_write(mpt, MPT_OFFSET_DIAG_DATA, fw_hdr->IopResetVectorValue); @@ -2116,6 +2248,8 @@ mpt_download_fw(struct mpt_softc *mpt) mpt_pio_write(mpt, MPT_OFFSET_DIAG_ADDR, MPT_DIAG_MEM_CFG_BASE); mpt_pio_write(mpt, MPT_OFFSET_DIAG_DATA, data); + pci_disable_io(mpt->dev, SYS_RES_IOPORT); + /* * Re-enable the processor and clear the boot halt flag. */ @@ -2138,6 +2272,7 @@ mpt_configure_ioc(struct mpt_softc *mpt) MSG_IOC_FACTS_REPLY facts; int try; int needreset; + uint32_t max_chain_depth; needreset = 0; for (try = 0; try < MPT_MAX_TRYS; try++) { @@ -2148,13 +2283,14 @@ mpt_configure_ioc(struct mpt_softc *mpt) * Force reset if initialization failed previously. * Note that a hard_reset of the second channel of a '929 * will stop operation of the first channel. Hopefully, if the - * first channel is ok, the second will not require a hard + * first channel is ok, the second will not require a hard * reset. */ - if (needreset || (mpt_rd_db(mpt) & MPT_DB_STATE_MASK) != + if (needreset || MPT_STATE(mpt_rd_db(mpt)) != MPT_DB_STATE_READY) { - if (mpt_reset(mpt, /*reinit*/FALSE) != MPT_OK) + if (mpt_reset(mpt, FALSE) != MPT_OK) { continue; + } } needreset = 0; @@ -2166,23 +2302,65 @@ mpt_configure_ioc(struct mpt_softc *mpt) mpt->mpt_global_credits = le16toh(facts.GlobalCredits); mpt->request_frame_size = le16toh(facts.RequestFrameSize); + mpt->ioc_facts_flags = facts.Flags; mpt_prt(mpt, "MPI Version=%d.%d.%d.%d\n", le16toh(facts.MsgVersion) >> 8, le16toh(facts.MsgVersion) & 0xFF, le16toh(facts.HeaderVersion) >> 8, le16toh(facts.HeaderVersion) & 0xFF); + + /* + * Now that we know request frame size, we can calculate + * the actual (reasonable) segment limit for read/write I/O. + * + * This limit is constrained by: + * + * + The size of each area we allocate per command (and how + * many chain segments we can fit into it). + * + The total number of areas we've set up. + * + The actual chain depth the card will allow. + * + * The first area's segment count is limited by the I/O request + * at the head of it. We cannot allocate realistically more + * than MPT_MAX_REQUESTS areas. Therefore, to account for both + * conditions, we'll just start out with MPT_MAX_REQUESTS-2. + * + */ + max_chain_depth = facts.MaxChainDepth; + + /* total number of request areas we (can) allocate */ + mpt->max_seg_cnt = MPT_MAX_REQUESTS(mpt) - 2; + + /* converted to the number of chain areas possible */ + mpt->max_seg_cnt *= MPT_NRFM(mpt); + + /* limited by the number of chain areas the card will support */ + if (mpt->max_seg_cnt > max_chain_depth) { + mpt_lprt(mpt, MPT_PRT_DEBUG, + "chain depth limited to %u (from %u)\n", + max_chain_depth, mpt->max_seg_cnt); + mpt->max_seg_cnt = max_chain_depth; + } + + /* converted to the number of simple sges in chain segments. */ + mpt->max_seg_cnt *= (MPT_NSGL(mpt) - 1); + + mpt_lprt(mpt, MPT_PRT_DEBUG, + "Maximum Segment Count: %u\n", mpt->max_seg_cnt); mpt_lprt(mpt, MPT_PRT_DEBUG, "MsgLength=%u IOCNumber = %d\n", facts.MsgLength, facts.IOCNumber); mpt_lprt(mpt, MPT_PRT_DEBUG, - "IOCFACTS: GlobalCredits=%d BlockSize=%u " - "Request Frame Size %u\n", mpt->mpt_global_credits, - facts.BlockSize * 8, mpt->request_frame_size * 8); + "IOCFACTS: GlobalCredits=%d BlockSize=%u bytes " + "Request Frame Size %u bytes Max Chain Depth %u\n", + mpt->mpt_global_credits, facts.BlockSize, + mpt->request_frame_size << 2, max_chain_depth); mpt_lprt(mpt, MPT_PRT_DEBUG, "IOCFACTS: Num Ports %d, FWImageSize %d, " "Flags=%#x\n", facts.NumberOfPorts, le32toh(facts.FWImageSize), facts.Flags); + if ((facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) != 0) { struct mpt_map_info mi; int error; @@ -2249,46 +2427,60 @@ mpt_configure_ioc(struct mpt_softc *mpt) mpt->mpt_port_type = pfp.PortType; mpt->mpt_proto_flags = pfp.ProtocolFlags; if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI && + pfp.PortType != MPI_PORTFACTS_PORTTYPE_SAS && pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) { mpt_prt(mpt, "Unsupported Port Type (%x)\n", pfp.PortType); return (ENXIO); } - if (!(pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR)) { - mpt_prt(mpt, "initiator role unsupported\n"); - return (ENXIO); - } + mpt->mpt_max_tgtcmds = le16toh(pfp.MaxPostedCmdBuffers); + if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) { mpt->is_fc = 1; + mpt->is_sas = 0; + mpt->is_spi = 0; + } else if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_SAS) { + mpt->is_fc = 0; + mpt->is_sas = 1; + mpt->is_spi = 0; } else { mpt->is_fc = 0; + mpt->is_sas = 0; + mpt->is_spi = 1; } mpt->mpt_ini_id = pfp.PortSCSIID; + mpt->mpt_max_devices = pfp.MaxDevices; + + /* + * Set our expected role with what this port supports. + */ - if (mpt_enable_ioc(mpt) != 0) { - mpt_prt(mpt, "Unable to initialize IOC\n"); + mpt->role = MPT_ROLE_NONE; + if (pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) { + mpt->role |= MPT_ROLE_INITIATOR; + } + if (pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { + mpt->role |= MPT_ROLE_TARGET; + } + if (mpt->role == MPT_ROLE_NONE) { + mpt_prt(mpt, "port does not support either target or " + "initiator role\n"); + return (ENXIO); + } + + if (mpt_enable_ioc(mpt, 0) != MPT_OK) { + mpt_prt(mpt, "unable to initialize IOC\n"); return (ENXIO); } /* - * Read and set up initial configuration information - * (IOC and SPI only for now) + * Read IOC configuration information. * - * XXX Should figure out what "personalities" are - * available and defer all initialization junk to - * them. + * We need this to determine whether or not we have certain + * settings for Integrated Mirroring (e.g.). */ mpt_read_config_info_ioc(mpt); - if (mpt->is_fc == 0) { - if (mpt_read_config_info_spi(mpt)) { - return (EIO); - } - if (mpt_set_initial_config_spi(mpt)) { - return (EIO); - } - } - /* Everything worked */ break; } @@ -2298,19 +2490,16 @@ mpt_configure_ioc(struct mpt_softc *mpt) return (EIO); } - mpt_lprt(mpt, MPT_PRT_DEBUG, "enabling interrupts\n"); - - mpt_enable_ints(mpt); return (0); } static int -mpt_enable_ioc(struct mpt_softc *mpt) +mpt_enable_ioc(struct mpt_softc *mpt, int portenable) { uint32_t pptr; int val; - if (mpt_send_ioc_init(mpt, MPT_DB_INIT_HOST) != MPT_OK) { + if (mpt_send_ioc_init(mpt, MPI_WHOINIT_HOST_DRIVER) != MPT_OK) { mpt_prt(mpt, "mpt_send_ioc_init failed\n"); return (EIO); } @@ -2321,35 +2510,36 @@ mpt_enable_ioc(struct mpt_softc *mpt) mpt_prt(mpt, "IOC failed to go to run state\n"); return (ENXIO); } - mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC now at RUNSTATE"); + mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC now at RUNSTATE\n"); /* * Give it reply buffers * * Do *not* exceed global credits. */ - for (val = 0, pptr = mpt->reply_phys; - (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); + for (val = 0, pptr = mpt->reply_phys; + (pptr + MPT_REPLY_SIZE) < (mpt->reply_phys + PAGE_SIZE); pptr += MPT_REPLY_SIZE) { mpt_free_reply(mpt, pptr); if (++val == mpt->mpt_global_credits - 1) break; } - /* - * Enable asynchronous event reporting - */ - mpt_send_event_request(mpt, 1); /* - * Now enable the port + * Enable the port if asked. This is only done if we're resetting + * the IOC after initial startup. */ - if (mpt_send_port_enable(mpt, 0) != MPT_OK) { - mpt_prt(mpt, "failed to enable port 0\n"); - return (ENXIO); - } - - mpt_lprt(mpt, MPT_PRT_DEBUG, "enabled port 0\n"); + if (portenable) { + /* + * Enable asynchronous event reporting + */ + mpt_send_event_request(mpt, 1); - return (0); + if (mpt_send_port_enable(mpt, 0) != MPT_OK) { + mpt_prt(mpt, "failed to enable port 0\n"); + return (ENXIO); + } + } + return (MPT_OK); } diff --git a/sys/dev/mpt/mpt.h b/sys/dev/mpt/mpt.h index c7a7ed0faab7..21ef5d8bfcc9 100644 --- a/sys/dev/mpt/mpt.h +++ b/sys/dev/mpt/mpt.h @@ -25,8 +25,43 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + */ +/*- + * Copyright (c) 2002, 2006 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon including + * a substantially similar Disclaimer requirement for further binary + * redistribution. + * 3. Neither the names of the above listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT + * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Support from Chris Ellsworth in order to make SAS adapters work + * is gratefully acknowledged. + * * - * Additional Copyright (c) 2002 by Matthew Jacob under same license. + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. */ /* * Copyright (c) 2004, Avid Technology, Inc. and its contributors. @@ -86,13 +121,25 @@ #include <sys/bus.h> #include <sys/module.h> -#include <machine/bus.h> -#include <machine/clock.h> #include <machine/cpu.h> #include <machine/resource.h> +#if __FreeBSD_version < 500000 +#include <machine/bus.h> +#include <machine/clock.h> +#endif + #include <sys/rman.h> +#if __FreeBSD_version < 500000 +#include <pci/pcireg.h> +#include <pci/pcivar.h> +#else +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#endif + +#include <machine/bus.h> #include "opt_ddb.h" /**************************** Register Definitions ****************************/ @@ -114,6 +161,12 @@ #define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array)) +#define MPT_ROLE_NONE 0 +#define MPT_ROLE_INITIATOR 1 +#define MPT_ROLE_TARGET 2 +#define MPT_ROLE_BOTH 3 +#define MPT_ROLE_DEFAULT MPT_ROLE_INITIATOR + /**************************** Forward Declarations ****************************/ struct mpt_softc; struct mpt_personality; @@ -123,6 +176,7 @@ typedef struct req_entry request_t; typedef int mpt_load_handler_t(struct mpt_personality *); typedef int mpt_probe_handler_t(struct mpt_softc *); typedef int mpt_attach_handler_t(struct mpt_softc *); +typedef int mpt_enable_handler_t(struct mpt_softc *); typedef int mpt_event_handler_t(struct mpt_softc *, request_t *, MSG_EVENT_NOTIFY_REPLY *); typedef void mpt_reset_handler_t(struct mpt_softc *, int /*type*/); @@ -140,6 +194,7 @@ struct mpt_personality #define MPT_PERS_FIRST_HANDLER(pers) (&(pers)->load) mpt_probe_handler_t *probe; /* configure personailty */ mpt_attach_handler_t *attach; /* initialize device instance */ + mpt_enable_handler_t *enable; /* enable device */ mpt_event_handler_t *event; /* Handle MPI event. */ mpt_reset_handler_t *reset; /* Re-init after reset. */ mpt_shutdown_handler_t *shutdown; /* Shutdown instance. */ @@ -227,12 +282,14 @@ u64toh(U64 s) /**************************** MPI Transaction State ***************************/ typedef enum { - REQ_STATE_FREE = 0x00, - REQ_STATE_ALLOCATED = 0x01, - REQ_STATE_QUEUED = 0x02, - REQ_STATE_DONE = 0x04, - REQ_STATE_TIMEDOUT = 0x08, - REQ_STATE_NEED_WAKEUP = 0x10, + REQ_STATE_NIL = 0x00, + REQ_STATE_FREE = 0x01, + REQ_STATE_ALLOCATED = 0x02, + REQ_STATE_QUEUED = 0x04, + REQ_STATE_DONE = 0x08, + REQ_STATE_TIMEDOUT = 0x10, + REQ_STATE_NEED_WAKEUP = 0x20, + REQ_STATE_LOCKED = 0x80, /* can't be freed */ REQ_STATE_MASK = 0xFF } mpt_req_state_t; @@ -241,14 +298,70 @@ struct req_entry { mpt_req_state_t state; /* Request State Information */ uint16_t index; /* Index of this entry */ uint16_t IOCStatus; /* Completion status */ + uint16_t ResponseCode; /* TMF Reponse Code */ + uint16_t serno; /* serial number */ union ccb *ccb; /* CAM request */ void *req_vbuf; /* Virtual Address of Entry */ void *sense_vbuf; /* Virtual Address of sense data */ bus_addr_t req_pbuf; /* Physical Address of Entry */ bus_addr_t sense_pbuf; /* Physical Address of sense data */ - bus_dmamap_t dmap; /* DMA map for data buffer */ + bus_dmamap_t dmap; /* DMA map for data buffers */ + struct req_entry *chain; /* for SGE overallocations */ }; +/**************************** MPI Target State Info ***************************/ + +typedef struct { + uint32_t reply_desc; /* current reply descriptor */ + uint32_t resid; /* current data residual */ + uint32_t bytes_xfered; /* current relative offset */ + union ccb *ccb; /* pointer to currently active ccb */ + request_t *req; /* pointer to currently active assist request */ + int nxfers; + uint32_t tag_id; + enum { + TGT_STATE_NIL, + TGT_STATE_LOADING, + TGT_STATE_LOADED, + TGT_STATE_IN_CAM, + TGT_STATE_SETTING_UP_FOR_DATA, + TGT_STATE_MOVING_DATA, + TGT_STATE_MOVING_DATA_AND_STATUS, + TGT_STATE_SENDING_STATUS + } state; +} mpt_tgt_state_t; + +/* + * When we get an incoming command it has its own tag which is called the + * IoIndex. This is the value we gave that particular command buffer when + * we originally assigned it. It's just a number, really. The FC card uses + * it as an RX_ID. We can use it to index into mpt->tgt_cmd_ptrs, which + * contains pointers the request_t structures related to that IoIndex. + * + * What *we* do is construct a tag out of the index for the target command + * which owns the incoming ATIO plus a rolling sequence number. + */ +#define MPT_MAKE_TAGID(mpt, req, ioindex) \ + ((ioindex << 18) | (((mpt->sequence++) & 0x3f) << 12) | (req->index & 0xfff)) + +#ifdef INVARIANTS +#define MPT_TAG_2_REQ(a, b) mpt_tag_2_req(a, (uint32_t) b) +#else +#define MPT_TAG_2_REQ(mpt, tag) mpt->tgt_cmd_ptrs[tag >> 18] +#endif + +#define MPT_TGT_STATE(mpt, req) ((mpt_tgt_state_t *) \ + (&((uint8_t *)req->req_vbuf)[MPT_RQSL(mpt) - sizeof (mpt_tgt_state_t)])) + +STAILQ_HEAD(mpt_hdr_stailq, ccb_hdr); +#define MPT_MAX_LUNS 256 +typedef struct { + struct mpt_hdr_stailq atios; + struct mpt_hdr_stailq inots; + int enabled; +} tgt_resource_t; +#define MPT_MAX_ELS 64 + /**************************** Handler Registration ****************************/ /* * Global table of registered reply handlers. The @@ -270,12 +383,12 @@ struct req_entry { * all commonly executed handlers fit in a single cache * line. */ -#define MPT_NUM_REPLY_HANDLERS (16) +#define MPT_NUM_REPLY_HANDLERS (32) #define MPT_REPLY_HANDLER_EVENTS MPT_CBI_TO_HID(0) #define MPT_REPLY_HANDLER_CONFIG MPT_CBI_TO_HID(MPT_NUM_REPLY_HANDLERS-1) #define MPT_REPLY_HANDLER_HANDSHAKE MPT_CBI_TO_HID(MPT_NUM_REPLY_HANDLERS-2) typedef int mpt_reply_handler_t(struct mpt_softc *mpt, request_t *request, - MSG_DEFAULT_REPLY *reply_frame); + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame); typedef union { mpt_reply_handler_t *reply_handler; } mpt_handler_t; @@ -338,7 +451,7 @@ struct mpt_raid_volume { CONFIG_PAGE_RAID_VOL_0 *config_page; MPI_RAID_VOL_INDICATOR sync_progress; mpt_raid_volume_flags flags; - u_int quieced_disks; + u_int quiesced_disks; }; typedef enum { @@ -370,23 +483,30 @@ LIST_HEAD(mpt_evtf_list, mpt_evtf_record); struct mpt_softc { device_t dev; #if __FreeBSD_version < 500000 - int mpt_splsaved; uint32_t mpt_islocked; + int mpt_splsaved; #else struct mtx mpt_lock; + int mpt_locksetup; #endif uint32_t mpt_pers_mask; - uint32_t : 15, + uint32_t : 8, + unit : 8, + : 1, + twildcard : 1, + tenabled : 1, + role : 2, /* none, ini, target, both */ + : 1, + raid_enabled : 1, raid_mwce_set : 1, getreqwaiter : 1, shutdwn_raid : 1, shutdwn_recovery: 1, - unit : 8, outofbeer : 1, - mpt_locksetup : 1, disabled : 1, - is_fc : 1, - bus : 1; /* FC929/1030 have two busses */ + is_spi : 1, + is_sas : 1, + is_fc : 1; u_int verbose; @@ -397,6 +517,8 @@ struct mpt_softc { uint16_t request_frame_size; uint8_t mpt_max_devices; uint8_t mpt_max_buses; + uint8_t ioc_facts_flags; + uint8_t padding0; /* * Port Facts @@ -405,6 +527,7 @@ struct mpt_softc { uint16_t mpt_ini_id; uint16_t mpt_port_type; uint16_t mpt_proto_flags; + uint16_t mpt_max_tgtcmds; /* * Device Configuration Information @@ -418,8 +541,6 @@ struct mpt_softc { CONFIG_PAGE_SCSI_DEVICE_1 _dev_page1[16]; uint16_t _tag_enable; uint16_t _disc_enable; - uint16_t _update_params0; - uint16_t _update_params1; } spi; #define mpt_port_page0 cfg.spi._port_page0 #define mpt_port_page1 cfg.spi._port_page1 @@ -428,14 +549,13 @@ struct mpt_softc { #define mpt_dev_page1 cfg.spi._dev_page1 #define mpt_tag_enable cfg.spi._tag_enable #define mpt_disc_enable cfg.spi._disc_enable -#define mpt_update_params0 cfg.spi._update_params0 -#define mpt_update_params1 cfg.spi._update_params1 struct mpi_fc_cfg { - uint8_t nada; + CONFIG_PAGE_FC_PORT_0 _port_page0; +#define mpt_fcport_page0 cfg.fc._port_page0 } fc; } cfg; - /* Controller Info */ + /* Controller Info for RAID information */ CONFIG_PAGE_IOC_2 * ioc_page2; CONFIG_PAGE_IOC_3 * ioc_page3; @@ -450,6 +570,7 @@ struct mpt_softc { u_int raid_resync_rate; u_int raid_mwce_setting; u_int raid_queue_depth; + u_int raid_nonopt_volumes; struct proc *raid_thread; struct callout raid_timer; @@ -483,8 +604,13 @@ struct mpt_softc { bus_dma_tag_t request_dmat; /* DMA tag for request memroy */ bus_dmamap_t request_dmap; /* DMA map for request memroy */ uint8_t *request; /* KVA of Request memory */ - bus_addr_t request_phys; /* BusADdr of request memory */ + bus_addr_t request_phys; /* BusAddr of request memory */ + uint32_t max_seg_cnt; /* calculated after IOC facts */ + + /* + * Hardware management + */ u_int reset_cnt; /* @@ -495,11 +621,6 @@ struct mpt_softc { struct req_queue request_pending_list; struct req_queue request_timeout_list; - /* - * Deferred frame acks due to resource shortage. - */ - struct mpt_evtf_list ack_frames; - struct cam_sim *sim; struct cam_path *path; @@ -510,11 +631,35 @@ struct mpt_softc { struct proc *recovery_thread; request_t *tmf_req; - uint32_t sequence; /* Sequence Number */ - uint32_t timeouts; /* timeout count */ - uint32_t success; /* successes afer timeout */ + /* + * Deferred frame acks due to resource shortage. + */ + struct mpt_evtf_list ack_frames; + + /* + * Target Mode Support + */ + uint32_t scsi_tgt_handler_id; + request_t ** tgt_cmd_ptrs; + request_t ** els_cmd_ptrs; /* FC only */ + + /* + * *snork*- this is chosen to be here *just in case* somebody + * forgets to point to it exactly and we index off of trt with + * CAM_LUN_WILDCARD. + */ + tgt_resource_t trt_wildcard; /* wildcard luns */ + tgt_resource_t trt[MPT_MAX_LUNS]; + uint16_t tgt_cmds_allocated; + uint16_t els_cmds_allocated; /* FC only */ + + uint16_t timeouts; /* timeout count */ + uint16_t success; /* successes afer timeout */ + uint16_t sequence; /* Sequence Number */ + uint16_t pad3; + - /* Opposing port in a 929 or 1030, or NULL */ + /* Paired port in some dual adapters configurations */ struct mpt_softc * mpt2; /* FW Image management */ @@ -522,7 +667,7 @@ struct mpt_softc { uint8_t *fw_image; bus_dma_tag_t fw_dmat; /* DMA tag for firmware image */ bus_dmamap_t fw_dmap; /* DMA map for firmware image */ - bus_addr_t fw_phys; /* BusAddr of request memory */ + bus_addr_t fw_phys; /* BusAddr of firmware image */ /* Shutdown Event Handler. */ eventhandler_tag eh; @@ -530,11 +675,22 @@ struct mpt_softc { TAILQ_ENTRY(mpt_softc) links; }; -/***************************** Locking Primatives *****************************/ +static __inline void mpt_assign_serno(struct mpt_softc *, request_t *); + +static __inline void +mpt_assign_serno(struct mpt_softc *mpt, request_t *req) +{ + if ((req->serno = mpt->sequence++) == 0) { + req->serno = mpt->sequence++; + } +} + +/***************************** Locking Primitives *****************************/ #if __FreeBSD_version < 500000 #define MPT_IFLAGS INTR_TYPE_CAM #define MPT_LOCK(mpt) mpt_lockspl(mpt) #define MPT_UNLOCK(mpt) mpt_unlockspl(mpt) +#define MPT_OWNED(mpt) mpt->mpt_islocked #define MPTLOCK_2_CAMLOCK MPT_UNLOCK #define CAMLOCK_2_MPTLOCK MPT_LOCK #define MPT_LOCK_SETUP(mpt) @@ -581,14 +737,14 @@ mpt_sleep(struct mpt_softc *mpt, void *ident, int priority, saved_spl = mpt->mpt_splsaved; mpt->mpt_islocked = 0; error = tsleep(ident, priority, wmesg, timo); - KASSERT(mpt->mpt_islocked = 0, ("Invalid lock count on wakeup")); + KASSERT(mpt->mpt_islocked == 0, ("Invalid lock count on wakeup")); mpt->mpt_islocked = saved_cnt; mpt->mpt_splsaved = saved_spl; return (error); } #else -#if LOCKING_WORKED_AS_IT_SHOULD +#ifdef LOCKING_WORKED_AS_IT_SHOULD #error "Shouldn't Be Here!" #define MPT_IFLAGS INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE #define MPT_LOCK_SETUP(mpt) \ @@ -602,22 +758,56 @@ mpt_sleep(struct mpt_softc *mpt, void *ident, int priority, #define MPT_LOCK(mpt) mtx_lock(&(mpt)->mpt_lock) #define MPT_UNLOCK(mpt) mtx_unlock(&(mpt)->mpt_lock) +#define MPT_OWNED(mpt) mtx_owned(&(mpt)->mpt_lock) #define MPTLOCK_2_CAMLOCK(mpt) \ mtx_unlock(&(mpt)->mpt_lock); mtx_lock(&Giant) #define CAMLOCK_2_MPTLOCK(mpt) \ mtx_unlock(&Giant); mtx_lock(&(mpt)->mpt_lock) #define mpt_sleep(mpt, ident, priority, wmesg, timo) \ msleep(ident, &(mpt)->mpt_lock, priority, wmesg, timo) + #else + #define MPT_IFLAGS INTR_TYPE_CAM | INTR_ENTROPY #define MPT_LOCK_SETUP(mpt) do { } while (0) #define MPT_LOCK_DESTROY(mpt) do { } while (0) -#define MPT_LOCK(mpt) do { } while (0) -#define MPT_UNLOCK(mpt) do { } while (0) -#define MPTLOCK_2_CAMLOCK(mpt) do { } while (0) -#define CAMLOCK_2_MPTLOCK(mpt) do { } while (0) -#define mpt_sleep(mpt, ident, priority, wmesg, timo) \ - tsleep(ident, priority, wmesg, timo) +#if 0 +#define MPT_LOCK(mpt) \ + device_printf(mpt->dev, "LOCK %s:%d\n", __FILE__, __LINE__); \ + KASSERT(mpt->mpt_locksetup == 0, \ + ("recursive lock acquire at %s:%d", __FILE__, __LINE__)); \ + mpt->mpt_locksetup = 1 +#define MPT_UNLOCK(mpt) \ + device_printf(mpt->dev, "UNLK %s:%d\n", __FILE__, __LINE__); \ + KASSERT(mpt->mpt_locksetup == 1, \ + ("release unowned lock at %s:%d", __FILE__, __LINE__)); \ + mpt->mpt_locksetup = 0 +#else +#define MPT_LOCK(mpt) \ + KASSERT(mpt->mpt_locksetup == 0, \ + ("recursive lock acquire at %s:%d", __FILE__, __LINE__)); \ + mpt->mpt_locksetup = 1 +#define MPT_UNLOCK(mpt) \ + KASSERT(mpt->mpt_locksetup == 1, \ + ("release unowned lock at %s:%d", __FILE__, __LINE__)); \ + mpt->mpt_locksetup = 0 +#endif +#define MPT_OWNED(mpt) mpt->mpt_locksetup +#define MPTLOCK_2_CAMLOCK(mpt) MPT_UNLOCK(mpt) +#define CAMLOCK_2_MPTLOCK(mpt) MPT_LOCK(mpt) + +static __inline int +mpt_sleep(struct mpt_softc *, void *, int, const char *, int); + +static __inline int +mpt_sleep(struct mpt_softc *mpt, void *i, int p, const char *w, int t) +{ + int r; + MPT_UNLOCK(mpt); + r = tsleep(i, p, w, t); + MPT_LOCK(mpt); + return (r); +} #endif #endif @@ -657,21 +847,23 @@ mpt_pio_read(struct mpt_softc *mpt, int offset) } /*********************** Reply Frame/Request Management ***********************/ /* Max MPT Reply we are willing to accept (must be power of 2) */ -#define MPT_REPLY_SIZE 128 +#define MPT_REPLY_SIZE 256 -#define MPT_MAX_REQUESTS(mpt) ((mpt)->is_fc ? 1024 : 256) -#define MPT_REQUEST_AREA 512 -#define MPT_SENSE_SIZE 32 /* included in MPT_REQUEST_SIZE */ +/* + * Must be less than 16384 in order for target mode to work + */ +#define MPT_MAX_REQUESTS(mpt) 512 +#define MPT_REQUEST_AREA 512 +#define MPT_SENSE_SIZE 32 /* included in MPT_REQUEST_AREA */ #define MPT_REQ_MEM_SIZE(mpt) (MPT_MAX_REQUESTS(mpt) * MPT_REQUEST_AREA) #define MPT_CONTEXT_CB_SHIFT (16) -#define MPT_CBI(handle) (handle >> MPT_CONTEXT_CB_SHIFT) +#define MPT_CBI(handle) (handle >> MPT_CONTEXT_CB_SHIFT) #define MPT_CBI_TO_HID(cbi) ((cbi) << MPT_CONTEXT_CB_SHIFT) #define MPT_CONTEXT_TO_CBI(x) \ (((x) >> MPT_CONTEXT_CB_SHIFT) & (MPT_NUM_REPLY_HANDLERS - 1)) -#define MPT_CONTEXT_REQI_MASK 0xFFFF -#define MPT_CONTEXT_TO_REQI(x) \ - ((x) & MPT_CONTEXT_REQI_MASK) +#define MPT_CONTEXT_REQI_MASK 0xFFFF +#define MPT_CONTEXT_TO_REQI(x) ((x) & MPT_CONTEXT_REQI_MASK) /* * Convert a 32bit physical address returned from IOC to an @@ -686,7 +878,7 @@ mpt_pio_read(struct mpt_softc *mpt, int offset) #define MPT_DUMP_REPLY_FRAME(mpt, reply_frame) \ do { \ - if (mpt->verbose >= MPT_PRT_DEBUG) \ + if (mpt->verbose > MPT_PRT_DEBUG) \ mpt_dump_reply_frame(mpt, reply_frame); \ } while(0) @@ -710,41 +902,34 @@ mpt_pop_reply_queue(struct mpt_softc *mpt) return mpt_read(mpt, MPT_OFFSET_REPLY_Q); } -void mpt_complete_request_chain(struct mpt_softc *mpt, - struct req_queue *chain, u_int iocstatus); -/************************** Scatter Gather Managment **************************/ -/* - * We cannot tell prior to getting IOC facts how big the IOC's request - * area is. Because of this we cannot tell at compile time how many - * simple SG elements we can fit within an IOC request prior to having - * to put in a chain element. - * - * Experimentally we know that the Ultra4 parts have a 96 byte request - * element size and the Fibre Channel units have a 144 byte request - * element size. Therefore, if we have 512-32 (== 480) bytes of request - * area to play with, we have room for between 3 and 5 request sized - * regions- the first of which is the command plus a simple SG list, - * the rest of which are chained continuation SG lists. Given that the - * normal request we use is 48 bytes w/o the first SG element, we can - * assume we have 480-48 == 432 bytes to have simple SG elements and/or - * chain elements. If we assume 32 bit addressing, this works out to - * 54 SG or chain elements. If we assume 5 chain elements, then we have - * a maximum of 49 seperate actual SG segments. - */ -#define MPT_SGL_MAX 49 +void +mpt_complete_request_chain(struct mpt_softc *, struct req_queue *, u_int); +/************************** Scatter Gather Managment **************************/ +/* MPT_RQSL- size of request frame, in bytes */ #define MPT_RQSL(mpt) (mpt->request_frame_size << 2) -#define MPT_NSGL(mpt) (MPT_RQSL(mpt) / sizeof (SGE_SIMPLE32)) -#define MPT_NSGL_FIRST(mpt) \ - (((mpt->request_frame_size << 2) - \ - sizeof (MSG_SCSI_IO_REQUEST) - \ - sizeof (SGE_IO_UNION)) / sizeof (SGE_SIMPLE32)) +/* MPT_NSGL- how many SG entries can fit in a request frame size */ +#define MPT_NSGL(mpt) (MPT_RQSL(mpt) / sizeof (SGE_IO_UNION)) + +/* MPT_NRFM- how many request frames can fit in each request alloc we make */ +#define MPT_NRFM(mpt) (MPT_REQUEST_AREA / MPT_RQSL(mpt)) + +/* + * MPT_NSGL_FIRST- # of SG elements that can fit after + * an I/O request but still within the request frame. + * Do this safely based upon SGE_IO_UNION. + * + * Note that the first element is *within* the SCSI request. + */ +#define MPT_NSGL_FIRST(mpt) \ + ((MPT_RQSL(mpt) - sizeof (MSG_SCSI_IO_REQUEST) + sizeof (SGE_IO_UNION)) / \ + sizeof (SGE_IO_UNION)) /***************************** IOC Initialization *****************************/ int mpt_reset(struct mpt_softc *, int /*reinit*/); -/****************************** Debugging/Logging *****************************/ +/****************************** Debugging ************************************/ typedef struct mpt_decode_entry { char *name; u_int value; @@ -755,16 +940,24 @@ int mpt_decode_value(mpt_decode_entry_t *table, u_int num_entries, const char *name, u_int value, u_int *cur_column, u_int wrap_point); +void mpt_dump_request(struct mpt_softc *, request_t *); + enum { MPT_PRT_ALWAYS, MPT_PRT_FATAL, MPT_PRT_ERROR, MPT_PRT_WARN, MPT_PRT_INFO, + MPT_PRT_NEGOTIATION, MPT_PRT_DEBUG, - MPT_PRT_TRACE + MPT_PRT_DEBUG1, + MPT_PRT_DEBUG2, + MPT_PRT_DEBUG3, + MPT_PRT_TRACE, + MPT_PRT_NONE=100 }; +#if __FreeBSD_version > 500000 #define mpt_lprt(mpt, level, ...) \ do { \ if (level <= (mpt)->verbose) \ @@ -776,9 +969,143 @@ do { \ if (level <= (mpt)->debug_level) \ mpt_prtc(mpt, __VA_ARGS__); \ } while (0) +#else +void mpt_lprt(struct mpt_softc *, int, const char *, ...) + __printflike(3, 4); +void mpt_lprtc(struct mpt_softc *, int, const char *, ...) + __printflike(3, 4); +#endif +void mpt_prt(struct mpt_softc *, const char *, ...) + __printflike(2, 3); +void mpt_prtc(struct mpt_softc *, const char *, ...) + __printflike(2, 3); + +/**************************** Target Mode Related ***************************/ +static __inline int mpt_cdblen(uint8_t, int); +static __inline int +mpt_cdblen(uint8_t cdb0, int maxlen) +{ + int group = cdb0 >> 5; + switch (group) { + case 0: + return (6); + case 1: + return (10); + case 4: + case 5: + return (12); + default: + return (16); + } +} +#ifdef INVARIANTS +static __inline request_t * mpt_tag_2_req(struct mpt_softc *, uint32_t); +static __inline request_t * +mpt_tag_2_req(struct mpt_softc *mpt, uint32_t tag) +{ + uint16_t rtg = (tag >> 18); + KASSERT(rtg < mpt->tgt_cmds_allocated, ("bad tag %d\n", tag)); + KASSERT(mpt->tgt_cmd_ptrs, ("no cmd backpointer array")); + KASSERT(mpt->tgt_cmd_ptrs[rtg], ("no cmd backpointer")); + return (mpt->tgt_cmd_ptrs[rtg]); +} + + +static __inline int +mpt_req_on_free_list(struct mpt_softc *, request_t *); +static __inline int +mpt_req_on_pending_list(struct mpt_softc *, request_t *); + +static __inline void +mpt_req_spcl(struct mpt_softc *, request_t *, const char *, int); +static __inline void +mpt_req_not_spcl(struct mpt_softc *, request_t *, const char *, int); + + +/* + * Is request on freelist? + */ +static __inline int +mpt_req_on_free_list(struct mpt_softc *mpt, request_t *req) +{ + request_t *lrq; + + TAILQ_FOREACH(lrq, &mpt->request_free_list, links) { + if (lrq == req) { + return (1); + } + } + return (0); +} + +/* + * Is request on pending list? + */ +static __inline int +mpt_req_on_pending_list(struct mpt_softc *mpt, request_t *req) +{ + request_t *lrq; + + TAILQ_FOREACH(lrq, &mpt->request_pending_list, links) { + if (lrq == req) { + return (1); + } + } + return (0); +} + +/* + * Make sure that req *is* part of one of the special lists + */ +static __inline void +mpt_req_spcl(struct mpt_softc *mpt, request_t *req, const char *s, int line) +{ + int i; + for (i = 0; i < mpt->els_cmds_allocated; i++) { + if (req == mpt->els_cmd_ptrs[i]) { + return; + } + } + for (i = 0; i < mpt->tgt_cmds_allocated; i++) { + if (req == mpt->tgt_cmd_ptrs[i]) { + return; + } + } + panic("%s(%d): req %p:%u function %x not in els or tgt ptrs\n", + s, line, req, req->serno, + ((PTR_MSG_REQUEST_HEADER)req->req_vbuf)->Function); +} -void mpt_prt(struct mpt_softc *, const char *, ...); -void mpt_prtc(struct mpt_softc *, const char *, ...); +/* + * Make sure that req is *not* part of one of the special lists. + */ +static __inline void +mpt_req_not_spcl(struct mpt_softc *mpt, request_t *req, const char *s, int line) +{ + int i; + for (i = 0; i < mpt->els_cmds_allocated; i++) { + KASSERT(req != mpt->els_cmd_ptrs[i], + ("%s(%d): req %p:%u func %x in els ptrs at ioindex %d\n", + s, line, req, req->serno, + ((PTR_MSG_REQUEST_HEADER)req->req_vbuf)->Function, i)); + } + for (i = 0; i < mpt->tgt_cmds_allocated; i++) { + KASSERT(req != mpt->tgt_cmd_ptrs[i], + ("%s(%d): req %p:%u func %x in tgt ptrs at ioindex %d\n", + s, line, req, req->serno, + ((PTR_MSG_REQUEST_HEADER)req->req_vbuf)->Function, i)); + } +} +#endif + +typedef enum { + MPT_ABORT_TASK_SET=1234, + MPT_CLEAR_TASK_SET, + MPT_TARGET_RESET, + MPT_CLEAR_ACA, + MPT_TERMINATE_TASK, + MPT_NIL_TMT_VALUE=5678 +} mpt_task_mgmt_t; /**************************** Unclassified Routines ***************************/ void mpt_send_cmd(struct mpt_softc *mpt, request_t *req); @@ -849,4 +1176,5 @@ void mpt_req_state(mpt_req_state_t state); void mpt_print_config_request(void *vmsg); void mpt_print_request(void *vmsg); void mpt_print_scsi_io_request(MSG_SCSI_IO_REQUEST *msg); +void mpt_dump_sgl(SGE_IO_UNION *se, int offset); #endif /* _MPT_H_ */ diff --git a/sys/dev/mpt/mpt_cam.c b/sys/dev/mpt/mpt_cam.c index b9437ef87780..5e2f3ba18c9c 100644 --- a/sys/dev/mpt/mpt_cam.c +++ b/sys/dev/mpt/mpt_cam.c @@ -24,8 +24,42 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + */ +/*- + * Copyright (c) 2002, 2006 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon including + * a substantially similar Disclaimer requirement for further binary + * redistribution. + * 3. Neither the names of the above listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT + * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Support from Chris Ellsworth in order to make SAS adapters work + * is gratefully acknowledged. * - * Additional Copyright (c) 2002 by Matthew Jacob under same license. + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. */ /*- * Copyright (c) 2004, Avid Technology, Inc. and its contributors. @@ -69,6 +103,7 @@ __FBSDID("$FreeBSD$"); #include "dev/mpt/mpilib/mpi_ioc.h" /* XXX Fix Event Handling!!! */ #include "dev/mpt/mpilib/mpi_init.h" #include "dev/mpt/mpilib/mpi_targ.h" +#include "dev/mpt/mpilib/mpi_fc.h" #include <sys/callout.h> #include <sys/kthread.h> @@ -76,29 +111,56 @@ __FBSDID("$FreeBSD$"); static void mpt_poll(struct cam_sim *); static timeout_t mpt_timeout; static void mpt_action(struct cam_sim *, union ccb *); -static int mpt_setwidth(struct mpt_softc *, int, int); -static int mpt_setsync(struct mpt_softc *, int, int, int); +static int +mpt_get_spi_settings(struct mpt_softc *, struct ccb_trans_settings *); +static void mpt_setwidth(struct mpt_softc *, int, int); +static void mpt_setsync(struct mpt_softc *, int, int, int); +static int mpt_update_spi_config(struct mpt_softc *, int); static void mpt_calc_geometry(struct ccb_calc_geometry *ccg, int extended); + static mpt_reply_handler_t mpt_scsi_reply_handler; static mpt_reply_handler_t mpt_scsi_tmf_reply_handler; -static int mpt_scsi_reply_frame_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame); -static int mpt_bus_reset(struct mpt_softc *, int /*sleep_ok*/); +static mpt_reply_handler_t mpt_fc_els_reply_handler; +static int mpt_scsi_reply_frame_handler(struct mpt_softc *, request_t *, + MSG_DEFAULT_REPLY *); +static int mpt_bus_reset(struct mpt_softc *, int); +static int mpt_fc_reset_link(struct mpt_softc *, int); static int mpt_spawn_recovery_thread(struct mpt_softc *mpt); static void mpt_terminate_recovery_thread(struct mpt_softc *mpt); static void mpt_recovery_thread(void *arg); -static int mpt_scsi_send_tmf(struct mpt_softc *, u_int /*type*/, - u_int /*flags*/, u_int /*channel*/, - u_int /*target*/, u_int /*lun*/, - u_int /*abort_ctx*/, int /*sleep_ok*/); static void mpt_recover_commands(struct mpt_softc *mpt); +static int mpt_scsi_send_tmf(struct mpt_softc *, u_int, u_int, u_int, + u_int, u_int, u_int, int); + +static void mpt_fc_post_els(struct mpt_softc *mpt, request_t *, int); +static void mpt_post_target_command(struct mpt_softc *, request_t *, int); +static int mpt_add_els_buffers(struct mpt_softc *mpt); +static int mpt_add_target_commands(struct mpt_softc *mpt); +static void mpt_free_els_buffers(struct mpt_softc *mpt); +static void mpt_free_target_commands(struct mpt_softc *mpt); +static int mpt_enable_lun(struct mpt_softc *, target_id_t, lun_id_t); +static int mpt_disable_lun(struct mpt_softc *, target_id_t, lun_id_t); +static void mpt_target_start_io(struct mpt_softc *, union ccb *); +static cam_status mpt_abort_target_ccb(struct mpt_softc *, union ccb *); +static int mpt_abort_target_cmd(struct mpt_softc *, request_t *); +static void mpt_scsi_tgt_status(struct mpt_softc *, union ccb *, request_t *, + uint8_t, uint8_t const *); +static void +mpt_scsi_tgt_tsk_mgmt(struct mpt_softc *, request_t *, mpt_task_mgmt_t, + tgt_resource_t *, int); +static void mpt_tgt_dump_tgt_state(struct mpt_softc *, request_t *); +static void mpt_tgt_dump_req_state(struct mpt_softc *, request_t *); +static mpt_reply_handler_t mpt_scsi_tgt_reply_handler; + static uint32_t scsi_io_handler_id = MPT_HANDLER_ID_NONE; static uint32_t scsi_tmf_handler_id = MPT_HANDLER_ID_NONE; +static uint32_t fc_els_handler_id = MPT_HANDLER_ID_NONE; static mpt_probe_handler_t mpt_cam_probe; static mpt_attach_handler_t mpt_cam_attach; +static mpt_enable_handler_t mpt_cam_enable; static mpt_event_handler_t mpt_cam_event; static mpt_reset_handler_t mpt_cam_ioc_reset; static mpt_detach_handler_t mpt_cam_detach; @@ -108,6 +170,7 @@ static struct mpt_personality mpt_cam_personality = .name = "mpt_cam", .probe = mpt_cam_probe, .attach = mpt_cam_attach, + .enable = mpt_cam_enable, .event = mpt_cam_event, .reset = mpt_cam_ioc_reset, .detach = mpt_cam_detach, @@ -119,13 +182,14 @@ int mpt_cam_probe(struct mpt_softc *mpt) { /* - * Only attach to nodes that support the initiator - * role or have RAID physical devices that need - * CAM pass-thru support. + * Only attach to nodes that support the initiator or target + * role or have RAID physical devices that need CAM pass-thru support. */ if ((mpt->mpt_proto_flags & MPI_PORTFACTS_PROTOCOL_INITIATOR) != 0 - || (mpt->ioc_page2 != NULL && mpt->ioc_page2->MaxPhysDisks != 0)) + || (mpt->mpt_proto_flags & MPI_PORTFACTS_PROTOCOL_TARGET) != 0 + || (mpt->ioc_page2 != NULL && mpt->ioc_page2->MaxPhysDisks != 0)) { return (0); + } return (ENODEV); } @@ -137,31 +201,63 @@ mpt_cam_attach(struct mpt_softc *mpt) int maxq; int error; - MPTLOCK_2_CAMLOCK(mpt); TAILQ_INIT(&mpt->request_timeout_list); - mpt->bus = 0; maxq = (mpt->mpt_global_credits < MPT_MAX_REQUESTS(mpt))? mpt->mpt_global_credits : MPT_MAX_REQUESTS(mpt); handler.reply_handler = mpt_scsi_reply_handler; error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, &scsi_io_handler_id); - if (error != 0) - goto cleanup; + if (error != 0) { + goto cleanup0; + } + handler.reply_handler = mpt_scsi_tmf_reply_handler; error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, &scsi_tmf_handler_id); - if (error != 0) - goto cleanup; + if (error != 0) { + goto cleanup0; + } + + /* + * If we're fibre channel and could support target mode, we register + * an ELS reply handler and give it resources. + */ + if (mpt->is_fc && (mpt->role & MPT_ROLE_TARGET) != 0) { + handler.reply_handler = mpt_fc_els_reply_handler; + error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, + &fc_els_handler_id); + if (error != 0) { + goto cleanup0; + } + if (mpt_add_els_buffers(mpt) == FALSE) { + error = ENOMEM; + goto cleanup0; + } + maxq -= mpt->els_cmds_allocated; + } + + /* + * If we support target mode, we register a reply handler for it, + * but don't add resources until we actually enable target mode. + */ + if ((mpt->role & MPT_ROLE_TARGET) != 0) { + handler.reply_handler = mpt_scsi_tgt_reply_handler; + error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, + &mpt->scsi_tgt_handler_id); + if (error != 0) { + goto cleanup0; + } + } /* * We keep one request reserved for timeout TMF requests. */ - mpt->tmf_req = mpt_get_request(mpt, /*sleep_ok*/FALSE); + mpt->tmf_req = mpt_get_request(mpt, FALSE); if (mpt->tmf_req == NULL) { mpt_prt(mpt, "Unable to allocate dedicated TMF request!\n"); error = ENOMEM; - goto cleanup; + goto cleanup0; } /* @@ -176,10 +272,15 @@ mpt_cam_attach(struct mpt_softc *mpt) if (mpt_spawn_recovery_thread(mpt) != 0) { mpt_prt(mpt, "Unable to spawn recovery thread!\n"); error = ENOMEM; - goto cleanup; + goto cleanup0; } /* + * The rest of this is CAM foo, for which we need to drop our lock + */ + MPTLOCK_2_CAMLOCK(mpt); + + /* * Create the device queue for our SIM(s). */ devq = cam_simq_alloc(maxq); @@ -202,7 +303,7 @@ mpt_cam_attach(struct mpt_softc *mpt) } /* - * Register exactly the bus. + * Register exactly this bus. */ if (xpt_bus_register(mpt->sim, 0) != CAM_SUCCESS) { mpt_prt(mpt, "Bus registration Failed!\n"); @@ -221,9 +322,10 @@ mpt_cam_attach(struct mpt_softc *mpt) * Only register a second bus for RAID physical * devices if the controller supports RAID. */ - if (mpt->ioc_page2 == NULL - || mpt->ioc_page2->MaxPhysDisks == 0) + if (mpt->ioc_page2 == NULL || mpt->ioc_page2->MaxPhysDisks == 0) { + CAMLOCK_2_MPTLOCK(mpt); return (0); + } /* * Create a "bus" to export all hidden disks to CAM. @@ -237,7 +339,7 @@ mpt_cam_attach(struct mpt_softc *mpt) } /* - * Register exactly the bus. + * Register this bus. */ if (xpt_bus_register(mpt->phydisk_sim, 1) != CAM_SUCCESS) { mpt_prt(mpt, "Physical Disk Bus registration Failed!\n"); @@ -252,15 +354,388 @@ mpt_cam_attach(struct mpt_softc *mpt) error = ENOMEM; goto cleanup; } - CAMLOCK_2_MPTLOCK(mpt); return (0); + cleanup: CAMLOCK_2_MPTLOCK(mpt); +cleanup0: mpt_cam_detach(mpt); return (error); } +/* + * Read FC configuration information + */ +static int +mpt_read_config_info_fc(struct mpt_softc *mpt) +{ + char *topology = NULL; + int rv, speed = 0; + + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_FC_PORT, 0, + 0, &mpt->mpt_fcport_page0.Header, FALSE, 5000); + if (rv) { + return (-1); + } + mpt_lprt(mpt, MPT_PRT_DEBUG, "FC Port Page 0 Header: %x %x %x %x\n", + mpt->mpt_fcport_page0.Header.PageVersion, + mpt->mpt_fcport_page0.Header.PageLength, + mpt->mpt_fcport_page0.Header.PageNumber, + mpt->mpt_fcport_page0.Header.PageType); + + + rv = mpt_read_cur_cfg_page(mpt, 0, &mpt->mpt_fcport_page0.Header, + sizeof(mpt->mpt_fcport_page0), FALSE, 5000); + if (rv) { + mpt_prt(mpt, "failed to read FC Port Page 0\n"); + return (-1); + } + + speed = mpt->mpt_fcport_page0.CurrentSpeed; + + switch (mpt->mpt_fcport_page0.Flags & + MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK) { + case MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT: + speed = 0; + topology = "<NO LOOP>"; + break; + case MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT: + topology = "N-Port"; + break; + case MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP: + topology = "NL-Port"; + break; + case MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT: + topology = "F-Port"; + break; + case MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP: + topology = "FL-Port"; + break; + default: + speed = 0; + topology = "?"; + break; + } + + mpt_lprt(mpt, MPT_PRT_INFO, + "FC Port Page 0: Topology <%s> WWNN 0x%08x%08x WWPN 0x%08x%08x " + "Speed %u-Gbit\n", topology, + mpt->mpt_fcport_page0.WWNN.High, + mpt->mpt_fcport_page0.WWNN.Low, + mpt->mpt_fcport_page0.WWPN.High, + mpt->mpt_fcport_page0.WWPN.Low, + speed); + + return (0); +} + +/* + * Set FC configuration information. + */ +static int +mpt_set_initial_config_fc(struct mpt_softc *mpt) +{ +#if 0 + CONFIG_PAGE_FC_PORT_1 fc; + U32 fl; + int r, doit = 0; + + if ((mpt->role & MPT_ROLE_TARGET) == 0) { + return (0); + } + + r = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, + &fc.Header, FALSE, 5000); + if (r) { + return (mpt_fc_reset_link(mpt, 1)); + } + + r = mpt_read_cfg_page(mpt, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, 0, + &fc.Header, sizeof (fc), FALSE, 5000); + if (r) { + return (mpt_fc_reset_link(mpt, 1)); + } + + fl = le32toh(fc.Flags); + if ((fl & MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID) == 0) { + fl |= MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID; + doit = 1; + } + if (doit) { + const char *cc; + + mpt_lprt(mpt, MPT_PRT_INFO, + "FC Port Page 1: New Flags %x \n", fl); + fc.Flags = htole32(fl); + r = mpt_write_cfg_page(mpt, + MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT, 0, &fc.Header, + sizeof(fc), FALSE, 5000); + if (r != 0) { + cc = "FC PORT PAGE1 UPDATE: FAILED\n"; + } else { + cc = "FC PORT PAGE1 UPDATED: SYSTEM NEEDS RESET\n"; + } + mpt_prt(mpt, cc); + } +#endif + return (0); +} + +/* + * Read SAS configuration information. Nothing to do yet. + */ +static int +mpt_read_config_info_sas(struct mpt_softc *mpt) +{ + return (0); +} + +/* + * Set SAS configuration information. Nothing to do yet. + */ +static int +mpt_set_initial_config_sas(struct mpt_softc *mpt) +{ + return (0); +} + +/* + * Read SCSI configuration information + */ +static int +mpt_read_config_info_spi(struct mpt_softc *mpt) +{ + int rv, i; + + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 0, + &mpt->mpt_port_page0.Header, FALSE, 5000); + if (rv) { + return (-1); + } + mpt_lprt(mpt, MPT_PRT_DEBUG, "SPI Port Page 0 Header: %x %x %x %x\n", + mpt->mpt_port_page0.Header.PageVersion, + mpt->mpt_port_page0.Header.PageLength, + mpt->mpt_port_page0.Header.PageNumber, + mpt->mpt_port_page0.Header.PageType); + + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 0, + &mpt->mpt_port_page1.Header, FALSE, 5000); + if (rv) { + return (-1); + } + mpt_lprt(mpt, MPT_PRT_DEBUG, "SPI Port Page 1 Header: %x %x %x %x\n", + mpt->mpt_port_page1.Header.PageVersion, + mpt->mpt_port_page1.Header.PageLength, + mpt->mpt_port_page1.Header.PageNumber, + mpt->mpt_port_page1.Header.PageType); + + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0, + &mpt->mpt_port_page2.Header, FALSE, 5000); + if (rv) { + return (-1); + } + mpt_lprt(mpt, MPT_PRT_DEBUG, "SPI Port Page 2 Header: %x %x %x %x\n", + mpt->mpt_port_page2.Header.PageVersion, + mpt->mpt_port_page2.Header.PageLength, + mpt->mpt_port_page2.Header.PageNumber, + mpt->mpt_port_page2.Header.PageType); + + for (i = 0; i < 16; i++) { + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, + 0, i, &mpt->mpt_dev_page0[i].Header, FALSE, 5000); + if (rv) { + return (-1); + } + mpt_lprt(mpt, MPT_PRT_DEBUG, + "SPI Target %d Device Page 0 Header: %x %x %x %x\n", i, + mpt->mpt_dev_page0[i].Header.PageVersion, + mpt->mpt_dev_page0[i].Header.PageLength, + mpt->mpt_dev_page0[i].Header.PageNumber, + mpt->mpt_dev_page0[i].Header.PageType); + + rv = mpt_read_cfg_header(mpt, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, + 1, i, &mpt->mpt_dev_page1[i].Header, FALSE, 5000); + if (rv) { + return (-1); + } + mpt_lprt(mpt, MPT_PRT_DEBUG, + "SPI Target %d Device Page 1 Header: %x %x %x %x\n", i, + mpt->mpt_dev_page1[i].Header.PageVersion, + mpt->mpt_dev_page1[i].Header.PageLength, + mpt->mpt_dev_page1[i].Header.PageNumber, + mpt->mpt_dev_page1[i].Header.PageType); + } + + /* + * At this point, we don't *have* to fail. As long as we have + * valid config header information, we can (barely) lurch + * along. + */ + + rv = mpt_read_cur_cfg_page(mpt, 0, &mpt->mpt_port_page0.Header, + sizeof(mpt->mpt_port_page0), FALSE, 5000); + if (rv) { + mpt_prt(mpt, "failed to read SPI Port Page 0\n"); + } else { + mpt_lprt(mpt, MPT_PRT_DEBUG, + "SPI Port Page 0: Capabilities %x PhysicalInterface %x\n", + mpt->mpt_port_page0.Capabilities, + mpt->mpt_port_page0.PhysicalInterface); + } + + rv = mpt_read_cur_cfg_page(mpt, 0, &mpt->mpt_port_page1.Header, + sizeof(mpt->mpt_port_page1), FALSE, 5000); + if (rv) { + mpt_prt(mpt, "failed to read SPI Port Page 1\n"); + } else { + mpt_lprt(mpt, MPT_PRT_DEBUG, + "SPI Port Page 1: Configuration %x OnBusTimerValue %x\n", + mpt->mpt_port_page1.Configuration, + mpt->mpt_port_page1.OnBusTimerValue); + } + + rv = mpt_read_cur_cfg_page(mpt, 0, &mpt->mpt_port_page2.Header, + sizeof(mpt->mpt_port_page2), FALSE, 5000); + if (rv) { + mpt_prt(mpt, "failed to read SPI Port Page 2\n"); + } else { + mpt_lprt(mpt, MPT_PRT_NEGOTIATION, + "Port Page 2: Flags %x Settings %x\n", + mpt->mpt_port_page2.PortFlags, + mpt->mpt_port_page2.PortSettings); + for (i = 0; i < 16; i++) { + mpt_lprt(mpt, MPT_PRT_NEGOTIATION, + " Port Page 2 Tgt %d: timo %x SF %x Flags %x\n", + i, mpt->mpt_port_page2.DeviceSettings[i].Timeout, + mpt->mpt_port_page2.DeviceSettings[i].SyncFactor, + mpt->mpt_port_page2.DeviceSettings[i].DeviceFlags); + } + } + + for (i = 0; i < 16; i++) { + rv = mpt_read_cur_cfg_page(mpt, i, + &mpt->mpt_dev_page0[i].Header, sizeof(*mpt->mpt_dev_page0), + FALSE, 5000); + if (rv) { + mpt_prt(mpt, + "cannot read SPI Target %d Device Page 0\n", i); + continue; + } + mpt_lprt(mpt, MPT_PRT_NEGOTIATION, + "target %d page 0: Negotiated Params %x Information %x\n", + i, mpt->mpt_dev_page0[i].NegotiatedParameters, + mpt->mpt_dev_page0[i].Information); + + rv = mpt_read_cur_cfg_page(mpt, i, + &mpt->mpt_dev_page1[i].Header, sizeof(*mpt->mpt_dev_page1), + FALSE, 5000); + if (rv) { + mpt_prt(mpt, + "cannot read SPI Target %d Device Page 1\n", i); + continue; + } + mpt_lprt(mpt, MPT_PRT_NEGOTIATION, + "target %d page 1: Requested Params %x Configuration %x\n", + i, mpt->mpt_dev_page1[i].RequestedParameters, + mpt->mpt_dev_page1[i].Configuration); + } + return (0); +} + +/* + * Validate SPI configuration information. + * + * In particular, validate SPI Port Page 1. + */ +static int +mpt_set_initial_config_spi(struct mpt_softc *mpt) +{ + int i, j, pp1val = ((1 << mpt->mpt_ini_id) << 16) | mpt->mpt_ini_id; + int error; + + mpt->mpt_disc_enable = 0xff; + mpt->mpt_tag_enable = 0; + + if (mpt->mpt_port_page1.Configuration != pp1val) { + CONFIG_PAGE_SCSI_PORT_1 tmp; + + mpt_prt(mpt, "SPI Port Page 1 Config value bad (%x)- should " + "be %x\n", mpt->mpt_port_page1.Configuration, pp1val); + tmp = mpt->mpt_port_page1; + tmp.Configuration = pp1val; + error = mpt_write_cur_cfg_page(mpt, 0, + &tmp.Header, sizeof(tmp), FALSE, 5000); + if (error) { + return (-1); + } + error = mpt_read_cur_cfg_page(mpt, 0, + &tmp.Header, sizeof(tmp), FALSE, 5000); + if (error) { + return (-1); + } + if (tmp.Configuration != pp1val) { + mpt_prt(mpt, + "failed to reset SPI Port Page 1 Config value\n"); + return (-1); + } + mpt->mpt_port_page1 = tmp; + } + + /* + * The purpose of this exercise is to get + * all targets back to async/narrow. + * + * We skip this step if the BIOS has already negotiated + * speeds with the targets and does not require us to + * do Domain Validation. + */ + i = mpt->mpt_port_page2.PortSettings & + MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS; + j = mpt->mpt_port_page2.PortFlags & + MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK; + if (i == MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS /* && + j == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV */) { + mpt_lprt(mpt, MPT_PRT_NEGOTIATION, + "honoring BIOS transfer negotiations\n"); + } else { + for (i = 0; i < 16; i++) { + mpt->mpt_dev_page1[i].RequestedParameters = 0; + mpt->mpt_dev_page1[i].Configuration = 0; + (void) mpt_update_spi_config(mpt, i); + } + } + return (0); +} + +int +mpt_cam_enable(struct mpt_softc *mpt) +{ + if (mpt->is_fc) { + if (mpt_read_config_info_fc(mpt)) { + return (EIO); + } + if (mpt_set_initial_config_fc(mpt)) { + return (EIO); + } + } else if (mpt->is_sas) { + if (mpt_read_config_info_sas(mpt)) { + return (EIO); + } + if (mpt_set_initial_config_sas(mpt)) { + return (EIO); + } + } else if (mpt->is_spi) { + if (mpt_read_config_info_spi(mpt)) { + return (EIO); + } + if (mpt_set_initial_config_spi(mpt)) { + return (EIO); + } + } + return (0); +} + void mpt_cam_detach(struct mpt_softc *mpt) { @@ -274,29 +749,39 @@ mpt_cam_detach(struct mpt_softc *mpt) handler.reply_handler = mpt_scsi_tmf_reply_handler; mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, scsi_tmf_handler_id); + handler.reply_handler = mpt_fc_els_reply_handler; + mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, + fc_els_handler_id); + handler.reply_handler = mpt_scsi_tgt_reply_handler; + mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, + mpt->scsi_tgt_handler_id); if (mpt->tmf_req != NULL) { + mpt->tmf_req->state = REQ_STATE_ALLOCATED; mpt_free_request(mpt, mpt->tmf_req); mpt->tmf_req = NULL; } if (mpt->sim != NULL) { + MPTLOCK_2_CAMLOCK(mpt); xpt_free_path(mpt->path); xpt_bus_deregister(cam_sim_path(mpt->sim)); cam_sim_free(mpt->sim, TRUE); mpt->sim = NULL; + CAMLOCK_2_MPTLOCK(mpt); } if (mpt->phydisk_sim != NULL) { + MPTLOCK_2_CAMLOCK(mpt); xpt_free_path(mpt->phydisk_path); xpt_bus_deregister(cam_sim_path(mpt->phydisk_sim)); cam_sim_free(mpt->phydisk_sim, TRUE); mpt->phydisk_sim = NULL; + CAMLOCK_2_MPTLOCK(mpt); } } -/* This routine is used after a system crash to dump core onto the - * swap device. +/* This routine is used after a system crash to dump core onto the swap device. */ static void mpt_poll(struct cam_sim *sim) @@ -320,17 +805,13 @@ mpt_timeout(void *arg) request_t *req; ccb = (union ccb *)arg; -#if NOTYET - mpt = mpt_find_softc(mpt); - if (mpt == NULL) - return; -#else mpt = ccb->ccb_h.ccb_mpt_ptr; -#endif MPT_LOCK(mpt); req = ccb->ccb_h.ccb_req_ptr; - mpt_prt(mpt, "Request %p Timed out.\n", req); + mpt_prt(mpt, "request %p:%u timed out for ccb %p (req->ccb %p)\n", req, + req->serno, ccb, req->ccb); +/* XXX: WHAT ARE WE TRYING TO DO HERE? */ if ((req->state & REQ_STATE_QUEUED) == REQ_STATE_QUEUED) { TAILQ_REMOVE(&mpt->request_pending_list, req, links); TAILQ_INSERT_TAIL(&mpt->request_timeout_list, req, links); @@ -348,188 +829,769 @@ mpt_timeout(void *arg) * aborted the transaction. */ static void -mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) +mpt_execute_req_a64(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) { - request_t *req; + request_t *req, *trq; + char *mpt_off; union ccb *ccb; struct mpt_softc *mpt; - MSG_SCSI_IO_REQUEST *mpt_req; - SGE_SIMPLE32 *se; + int seg, first_lim; + uint32_t flags, nxt_off; + void *sglp = NULL; + MSG_REQUEST_HEADER *hdrp; + SGE_SIMPLE64 *se; + SGE_CHAIN64 *ce; + int istgt = 0; req = (request_t *)arg; ccb = req->ccb; mpt = ccb->ccb_h.ccb_mpt_ptr; req = ccb->ccb_h.ccb_req_ptr; - mpt_req = req->req_vbuf; - if (error == 0 && nseg > MPT_SGL_MAX) { + hdrp = req->req_vbuf; + mpt_off = req->req_vbuf; + + if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) { + error = EFBIG; + } + + if (error == 0) { + switch (hdrp->Function) { + case MPI_FUNCTION_SCSI_IO_REQUEST: + case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: + istgt = 0; + sglp = &((PTR_MSG_SCSI_IO_REQUEST)hdrp)->SGL; + break; + case MPI_FUNCTION_TARGET_ASSIST: + istgt = 1; + sglp = &((PTR_MSG_TARGET_ASSIST_REQUEST)hdrp)->SGL; + break; + default: + mpt_prt(mpt, "bad fct 0x%x in mpt_execute_req_a64\n", + hdrp->Function); + error = EINVAL; + break; + } + } + + if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) { error = EFBIG; + mpt_prt(mpt, "segment count %d too large (max %u)\n", + nseg, mpt->max_seg_cnt); } +bad: if (error != 0) { - if (error != EFBIG) - mpt_prt(mpt, "bus_dmamap_load returned %d\n", error); - if (ccb->ccb_h.status == CAM_REQ_INPROG) { - xpt_freeze_devq(ccb->ccb_h.path, 1); - ccb->ccb_h.status = CAM_DEV_QFRZN; - if (error == EFBIG) - ccb->ccb_h.status |= CAM_REQ_TOO_BIG; - else - ccb->ccb_h.status |= CAM_REQ_CMP_ERR; + if (error != EFBIG && error != ENOMEM) { + mpt_prt(mpt, "mpt_execute_req_a64: err %d\n", error); + } + if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { + cam_status status; + mpt_freeze_ccb(ccb); + if (error == EFBIG) { + status = CAM_REQ_TOO_BIG; + } else if (error == ENOMEM) { + if (mpt->outofbeer == 0) { + mpt->outofbeer = 1; + xpt_freeze_simq(mpt->sim, 1); + mpt_lprt(mpt, MPT_PRT_DEBUG, + "FREEZEQ\n"); + } + status = CAM_REQUEUE_REQ; + } else { + status = CAM_REQ_CMP_ERR; + } + mpt_set_ccb_status(ccb, status); + } + if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { + request_t *cmd_req = + MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); + MPT_TGT_STATE(mpt, cmd_req)->state = TGT_STATE_IN_CAM; + MPT_TGT_STATE(mpt, cmd_req)->ccb = NULL; + MPT_TGT_STATE(mpt, cmd_req)->req = NULL; } ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d\n", __LINE__)); xpt_done(ccb); CAMLOCK_2_MPTLOCK(mpt); mpt_free_request(mpt, req); MPTLOCK_2_CAMLOCK(mpt); return; } - - if (nseg > MPT_NSGL_FIRST(mpt)) { - int i, nleft = nseg; - uint32_t flags; - bus_dmasync_op_t op; - SGE_CHAIN32 *ce; - mpt_req->DataLength = ccb->csio.dxfer_len; - flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; - if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) + /* + * No data to transfer? + * Just make a single simple SGL with zero length. + */ + + if (mpt->verbose >= MPT_PRT_DEBUG) { + int tidx = ((char *)sglp) - mpt_off; + memset(&mpt_off[tidx], 0xff, MPT_REQUEST_AREA - tidx); + } + + if (nseg == 0) { + SGE_SIMPLE32 *se1 = (SGE_SIMPLE32 *) sglp; + MPI_pSGE_SET_FLAGS(se1, + (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); + goto out; + } + + + flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_64_BIT_ADDRESSING; + if (istgt == 0) { + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { + flags |= MPI_SGE_FLAGS_HOST_TO_IOC; + } + } else { + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { flags |= MPI_SGE_FLAGS_HOST_TO_IOC; + } + } + + if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) { + bus_dmasync_op_t op; + if (istgt == 0) { + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + op = BUS_DMASYNC_PREREAD; + } else { + op = BUS_DMASYNC_PREWRITE; + } + } else { + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + op = BUS_DMASYNC_PREWRITE; + } else { + op = BUS_DMASYNC_PREREAD; + } + } + bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op); + } - se = (SGE_SIMPLE32 *) &mpt_req->SGL; - for (i = 0; i < MPT_NSGL_FIRST(mpt) - 1; i++, se++, dm_segs++) { - uint32_t tf; + /* + * Okay, fill in what we can at the end of the command frame. + * If we have up to MPT_NSGL_FIRST, we can fit them all into + * the command frame. + * + * Otherwise, we fill up through MPT_NSGL_FIRST less one + * SIMPLE64 pointers and start doing CHAIN64 entries after + * that. + */ - bzero(se, sizeof (*se)); - se->Address = dm_segs->ds_addr; + if (nseg < MPT_NSGL_FIRST(mpt)) { + first_lim = nseg; + } else { + /* + * Leave room for CHAIN element + */ + first_lim = MPT_NSGL_FIRST(mpt) - 1; + } + + se = (SGE_SIMPLE64 *) sglp; + for (seg = 0; seg < first_lim; seg++, se++, dm_segs++) { + uint32_t tf; + + memset(se, 0, sizeof (*se)); + se->Address.Low = dm_segs->ds_addr; + if (sizeof(bus_addr_t) > 4) { + se->Address.High = ((uint64_t) dm_segs->ds_addr) >> 32; + } + MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); + tf = flags; + if (seg == first_lim - 1) { + tf |= MPI_SGE_FLAGS_LAST_ELEMENT; + } + if (seg == nseg - 1) { + tf |= MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_END_OF_BUFFER; + } + MPI_pSGE_SET_FLAGS(se, tf); + } + + if (seg == nseg) { + goto out; + } + + /* + * Tell the IOC where to find the first chain element. + */ + hdrp->ChainOffset = ((char *)se - (char *)hdrp) >> 2; + nxt_off = MPT_RQSL(mpt); + trq = req; + + /* + * Make up the rest of the data segments out of a chain element + * (contiained in the current request frame) which points to + * SIMPLE64 elements in the next request frame, possibly ending + * with *another* chain element (if there's more). + */ + while (seg < nseg) { + int this_seg_lim; + uint32_t tf, cur_off; + bus_addr_t chain_list_addr; + + /* + * Point to the chain descriptor. Note that the chain + * descriptor is at the end of the *previous* list (whether + * chain or simple). + */ + ce = (SGE_CHAIN64 *) se; + + /* + * Before we change our current pointer, make sure we won't + * overflow the request area with this frame. Note that we + * test against 'greater than' here as it's okay in this case + * to have next offset be just outside the request area. + */ + if ((nxt_off + MPT_RQSL(mpt)) > MPT_REQUEST_AREA) { + nxt_off = MPT_REQUEST_AREA; + goto next_chain; + } + + /* + * Set our SGE element pointer to the beginning of the chain + * list and update our next chain list offset. + */ + se = (SGE_SIMPLE64 *) &mpt_off[nxt_off]; + cur_off = nxt_off; + nxt_off += MPT_RQSL(mpt); + + /* + * Now initialized the chain descriptor. + */ + memset(ce, 0, sizeof (*ce)); + + /* + * Get the physical address of the chain list. + */ + chain_list_addr = trq->req_pbuf; + chain_list_addr += cur_off; + if (sizeof (bus_addr_t) > 4) { + ce->Address.High = + (uint32_t) ((uint64_t)chain_list_addr >> 32); + } + ce->Address.Low = (uint32_t) chain_list_addr; + ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | + MPI_SGE_FLAGS_64_BIT_ADDRESSING; + + /* + * If we have more than a frame's worth of segments left, + * set up the chain list to have the last element be another + * chain descriptor. + */ + if ((nseg - seg) > MPT_NSGL(mpt)) { + this_seg_lim = seg + MPT_NSGL(mpt) - 1; + /* + * The length of the chain is the length in bytes of the + * number of segments plus the next chain element. + * + * The next chain descriptor offset is the length, + * in words, of the number of segments. + */ + ce->Length = (this_seg_lim - seg) * + sizeof (SGE_SIMPLE64); + ce->NextChainOffset = ce->Length >> 2; + ce->Length += sizeof (SGE_CHAIN64); + } else { + this_seg_lim = nseg; + ce->Length = (this_seg_lim - seg) * + sizeof (SGE_SIMPLE64); + } + + /* + * Fill in the chain list SGE elements with our segment data. + * + * If we're the last element in this chain list, set the last + * element flag. If we're the completely last element period, + * set the end of list and end of buffer flags. + */ + while (seg < this_seg_lim) { + memset(se, 0, sizeof (*se)); + se->Address.Low = dm_segs->ds_addr; + if (sizeof (bus_addr_t) > 4) { + se->Address.High = + ((uint64_t)dm_segs->ds_addr) >> 32; + } MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); tf = flags; - if (i == MPT_NSGL_FIRST(mpt) - 2) { - tf |= MPI_SGE_FLAGS_LAST_ELEMENT; + if (seg == this_seg_lim - 1) { + tf |= MPI_SGE_FLAGS_LAST_ELEMENT; + } + if (seg == nseg - 1) { + tf |= MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_END_OF_BUFFER; } MPI_pSGE_SET_FLAGS(se, tf); - nleft -= 1; + se++; + seg++; + dm_segs++; } + next_chain: /* - * Tell the IOC where to find the first chain element + * If we have more segments to do and we've used up all of + * the space in a request area, go allocate another one + * and chain to that. */ - mpt_req->ChainOffset = ((char *)se - (char *)mpt_req) >> 2; + if (seg < nseg && nxt_off >= MPT_REQUEST_AREA) { + request_t *nrq; + + CAMLOCK_2_MPTLOCK(mpt); + nrq = mpt_get_request(mpt, FALSE); + MPTLOCK_2_CAMLOCK(mpt); + + if (nrq == NULL) { + error = ENOMEM; + goto bad; + } - /* - * Until we're finished with all segments... - */ - while (nleft) { - int ntodo; /* - * Construct the chain element that point to the - * next segment. + * Append the new request area on the tail of our list. */ - ce = (SGE_CHAIN32 *) se++; - if (nleft > MPT_NSGL(mpt)) { - ntodo = MPT_NSGL(mpt) - 1; - ce->NextChainOffset = (MPT_RQSL(mpt) - - sizeof (SGE_SIMPLE32)) >> 2; - ce->Length = MPT_NSGL(mpt) * - sizeof (SGE_SIMPLE32); + if ((trq = req->chain) == NULL) { + req->chain = nrq; } else { - ntodo = nleft; - ce->NextChainOffset = 0; - ce->Length = ntodo * sizeof (SGE_SIMPLE32); + while (trq->chain != NULL) { + trq = trq->chain; + } + trq->chain = nrq; + } + trq = nrq; + mpt_off = trq->req_vbuf; + if (mpt->verbose >= MPT_PRT_DEBUG) { + memset(mpt_off, 0xff, MPT_REQUEST_AREA); } - ce->Address = req->req_pbuf + - ((char *)se - (char *)mpt_req); - ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; - for (i = 0; i < ntodo; i++, se++, dm_segs++) { - uint32_t tf; + nxt_off = 0; + } + } +out: + + /* + * Last time we need to check if this CCB needs to be aborted. + */ + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { + if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { + request_t *cmd_req = + MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); + MPT_TGT_STATE(mpt, cmd_req)->state = TGT_STATE_IN_CAM; + MPT_TGT_STATE(mpt, cmd_req)->ccb = NULL; + MPT_TGT_STATE(mpt, cmd_req)->req = NULL; + } + mpt_prt(mpt, + "mpt_execute_req_a64: I/O cancelled (status 0x%x)\n", + ccb->ccb_h.status & CAM_STATUS_MASK); + if (nseg && (ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { + bus_dmamap_unload(mpt->buffer_dmat, req->dmap); + } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d\n", __LINE__)); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + mpt_free_request(mpt, req); + MPTLOCK_2_CAMLOCK(mpt); + return; + } + + ccb->ccb_h.status |= CAM_SIM_QUEUED; + if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { + ccb->ccb_h.timeout_ch = + timeout(mpt_timeout, (caddr_t)ccb, + (ccb->ccb_h.timeout * hz) / 1000); + } else { + callout_handle_init(&ccb->ccb_h.timeout_ch); + } + if (mpt->verbose > MPT_PRT_DEBUG) { + int nc = 0; + mpt_print_request(req->req_vbuf); + for (trq = req->chain; trq; trq = trq->chain) { + printf(" Additional Chain Area %d\n", nc++); + mpt_dump_sgl(trq->req_vbuf, 0); + } + } + + if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { + request_t *cmd_req = MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); + mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, cmd_req); +#ifdef WE_TRUST_AUTO_GOOD_STATUS + if ((ccb->ccb_h.flags & CAM_SEND_STATUS) && + csio->scsi_status == SCSI_STATUS_OK && tgt->resid == 0) { + tgt->state = TGT_STATE_MOVING_DATA_AND_STATUS; + } else { + tgt->state = TGT_STATE_MOVING_DATA; + } +#else + tgt->state = TGT_STATE_MOVING_DATA; +#endif + } + CAMLOCK_2_MPTLOCK(mpt); + mpt_send_cmd(mpt, req); + MPTLOCK_2_CAMLOCK(mpt); +} + +static void +mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) +{ + request_t *req, *trq; + char *mpt_off; + union ccb *ccb; + struct mpt_softc *mpt; + int seg, first_lim; + uint32_t flags, nxt_off; + void *sglp = NULL; + MSG_REQUEST_HEADER *hdrp; + SGE_SIMPLE32 *se; + SGE_CHAIN32 *ce; + int istgt = 0; - bzero(se, sizeof (*se)); - se->Address = dm_segs->ds_addr; - MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); - tf = flags; - if (i == ntodo - 1) { - tf |= MPI_SGE_FLAGS_LAST_ELEMENT; - if (ce->NextChainOffset == 0) { - tf |= - MPI_SGE_FLAGS_END_OF_LIST | - MPI_SGE_FLAGS_END_OF_BUFFER; - } + req = (request_t *)arg; + ccb = req->ccb; + + mpt = ccb->ccb_h.ccb_mpt_ptr; + req = ccb->ccb_h.ccb_req_ptr; + + hdrp = req->req_vbuf; + mpt_off = req->req_vbuf; + + + if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) { + error = EFBIG; + } + + if (error == 0) { + switch (hdrp->Function) { + case MPI_FUNCTION_SCSI_IO_REQUEST: + case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: + sglp = &((PTR_MSG_SCSI_IO_REQUEST)hdrp)->SGL; + break; + case MPI_FUNCTION_TARGET_ASSIST: + istgt = 1; + sglp = &((PTR_MSG_TARGET_ASSIST_REQUEST)hdrp)->SGL; + break; + default: + mpt_prt(mpt, "bad fct 0x%x in mpt_execute_req\n", + hdrp->Function); + error = EINVAL; + break; + } + } + + if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) { + error = EFBIG; + mpt_prt(mpt, "segment count %d too large (max %u)\n", + nseg, mpt->max_seg_cnt); + } + +bad: + if (error != 0) { + if (error != EFBIG && error != ENOMEM) { + mpt_prt(mpt, "mpt_execute_req: err %d\n", error); + } + if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { + cam_status status; + mpt_freeze_ccb(ccb); + if (error == EFBIG) { + status = CAM_REQ_TOO_BIG; + } else if (error == ENOMEM) { + if (mpt->outofbeer == 0) { + mpt->outofbeer = 1; + xpt_freeze_simq(mpt->sim, 1); + mpt_lprt(mpt, MPT_PRT_DEBUG, + "FREEZEQ\n"); } - MPI_pSGE_SET_FLAGS(se, tf); - nleft -= 1; + status = CAM_REQUEUE_REQ; + } else { + status = CAM_REQ_CMP_ERR; } - + mpt_set_ccb_status(ccb, status); + } + if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { + request_t *cmd_req = + MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); + MPT_TGT_STATE(mpt, cmd_req)->state = TGT_STATE_IN_CAM; + MPT_TGT_STATE(mpt, cmd_req)->ccb = NULL; + MPT_TGT_STATE(mpt, cmd_req)->req = NULL; } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d\n", __LINE__)); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + mpt_free_request(mpt, req); + MPTLOCK_2_CAMLOCK(mpt); + return; + } - if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) - op = BUS_DMASYNC_PREREAD; - else - op = BUS_DMASYNC_PREWRITE; - if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) { - bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op); + /* + * No data to transfer? + * Just make a single simple SGL with zero length. + */ + + if (mpt->verbose >= MPT_PRT_DEBUG) { + int tidx = ((char *)sglp) - mpt_off; + memset(&mpt_off[tidx], 0xff, MPT_REQUEST_AREA - tidx); + } + + if (nseg == 0) { + SGE_SIMPLE32 *se1 = (SGE_SIMPLE32 *) sglp; + MPI_pSGE_SET_FLAGS(se1, + (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); + goto out; + } + + + flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; + if (istgt == 0) { + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { + flags |= MPI_SGE_FLAGS_HOST_TO_IOC; } - } else if (nseg > 0) { - int i; - uint32_t flags; + } else { + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + flags |= MPI_SGE_FLAGS_HOST_TO_IOC; + } + } + + if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) { bus_dmasync_op_t op; + if (istgt) { + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + op = BUS_DMASYNC_PREREAD; + } else { + op = BUS_DMASYNC_PREWRITE; + } + } else { + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + op = BUS_DMASYNC_PREWRITE; + } else { + op = BUS_DMASYNC_PREREAD; + } + } + bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op); + } + + /* + * Okay, fill in what we can at the end of the command frame. + * If we have up to MPT_NSGL_FIRST, we can fit them all into + * the command frame. + * + * Otherwise, we fill up through MPT_NSGL_FIRST less one + * SIMPLE32 pointers and start doing CHAIN32 entries after + * that. + */ + + if (nseg < MPT_NSGL_FIRST(mpt)) { + first_lim = nseg; + } else { + /* + * Leave room for CHAIN element + */ + first_lim = MPT_NSGL_FIRST(mpt) - 1; + } + + se = (SGE_SIMPLE32 *) sglp; + for (seg = 0; seg < first_lim; seg++, se++, dm_segs++) { + uint32_t tf; + + memset(se, 0,sizeof (*se)); + se->Address = dm_segs->ds_addr; - mpt_req->DataLength = ccb->csio.dxfer_len; - flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT; - if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) - flags |= MPI_SGE_FLAGS_HOST_TO_IOC; - /* Copy the segments into our SG list */ - se = (SGE_SIMPLE32 *) &mpt_req->SGL; - for (i = 0; i < nseg; i++, se++, dm_segs++) { - uint32_t tf; - bzero(se, sizeof (*se)); + MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); + tf = flags; + if (seg == first_lim - 1) { + tf |= MPI_SGE_FLAGS_LAST_ELEMENT; + } + if (seg == nseg - 1) { + tf |= MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_END_OF_BUFFER; + } + MPI_pSGE_SET_FLAGS(se, tf); + } + + if (seg == nseg) { + goto out; + } + + /* + * Tell the IOC where to find the first chain element. + */ + hdrp->ChainOffset = ((char *)se - (char *)hdrp) >> 2; + nxt_off = MPT_RQSL(mpt); + trq = req; + + /* + * Make up the rest of the data segments out of a chain element + * (contiained in the current request frame) which points to + * SIMPLE32 elements in the next request frame, possibly ending + * with *another* chain element (if there's more). + */ + while (seg < nseg) { + int this_seg_lim; + uint32_t tf, cur_off; + bus_addr_t chain_list_addr; + + /* + * Point to the chain descriptor. Note that the chain + * descriptor is at the end of the *previous* list (whether + * chain or simple). + */ + ce = (SGE_CHAIN32 *) se; + + /* + * Before we change our current pointer, make sure we won't + * overflow the request area with this frame. Note that we + * test against 'greater than' here as it's okay in this case + * to have next offset be just outside the request area. + */ + if ((nxt_off + MPT_RQSL(mpt)) > MPT_REQUEST_AREA) { + nxt_off = MPT_REQUEST_AREA; + goto next_chain; + } + + /* + * Set our SGE element pointer to the beginning of the chain + * list and update our next chain list offset. + */ + se = (SGE_SIMPLE32 *) &mpt_off[nxt_off]; + cur_off = nxt_off; + nxt_off += MPT_RQSL(mpt); + + /* + * Now initialized the chain descriptor. + */ + memset(ce, 0, sizeof (*ce)); + + /* + * Get the physical address of the chain list. + */ + chain_list_addr = trq->req_pbuf; + chain_list_addr += cur_off; + + + + ce->Address = chain_list_addr; + ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; + + + /* + * If we have more than a frame's worth of segments left, + * set up the chain list to have the last element be another + * chain descriptor. + */ + if ((nseg - seg) > MPT_NSGL(mpt)) { + this_seg_lim = seg + MPT_NSGL(mpt) - 1; + /* + * The length of the chain is the length in bytes of the + * number of segments plus the next chain element. + * + * The next chain descriptor offset is the length, + * in words, of the number of segments. + */ + ce->Length = (this_seg_lim - seg) * + sizeof (SGE_SIMPLE32); + ce->NextChainOffset = ce->Length >> 2; + ce->Length += sizeof (SGE_CHAIN32); + } else { + this_seg_lim = nseg; + ce->Length = (this_seg_lim - seg) * + sizeof (SGE_SIMPLE32); + } + + /* + * Fill in the chain list SGE elements with our segment data. + * + * If we're the last element in this chain list, set the last + * element flag. If we're the completely last element period, + * set the end of list and end of buffer flags. + */ + while (seg < this_seg_lim) { + memset(se, 0, sizeof (*se)); se->Address = dm_segs->ds_addr; + + + + MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len); tf = flags; - if (i == nseg - 1) { - tf |= - MPI_SGE_FLAGS_LAST_ELEMENT | - MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_END_OF_LIST; + if (seg == this_seg_lim - 1) { + tf |= MPI_SGE_FLAGS_LAST_ELEMENT; + } + if (seg == nseg - 1) { + tf |= MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_END_OF_BUFFER; } MPI_pSGE_SET_FLAGS(se, tf); + se++; + seg++; + dm_segs++; } - if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) - op = BUS_DMASYNC_PREREAD; - else - op = BUS_DMASYNC_PREWRITE; - if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) { - bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op); - } - } else { - se = (SGE_SIMPLE32 *) &mpt_req->SGL; + next_chain: /* - * No data to transfer so we just make a single simple SGL - * with zero length. + * If we have more segments to do and we've used up all of + * the space in a request area, go allocate another one + * and chain to that. */ - MPI_pSGE_SET_FLAGS(se, - (MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | - MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST)); + if (seg < nseg && nxt_off >= MPT_REQUEST_AREA) { + request_t *nrq; + + CAMLOCK_2_MPTLOCK(mpt); + nrq = mpt_get_request(mpt, FALSE); + MPTLOCK_2_CAMLOCK(mpt); + + if (nrq == NULL) { + error = ENOMEM; + goto bad; + } + + /* + * Append the new request area on the tail of our list. + */ + if ((trq = req->chain) == NULL) { + req->chain = nrq; + } else { + while (trq->chain != NULL) { + trq = trq->chain; + } + trq->chain = nrq; + } + trq = nrq; + mpt_off = trq->req_vbuf; + if (mpt->verbose >= MPT_PRT_DEBUG) { + memset(mpt_off, 0xff, MPT_REQUEST_AREA); + } + nxt_off = 0; + } } +out: /* * Last time we need to check if this CCB needs to be aborted. */ - if (ccb->ccb_h.status != CAM_REQ_INPROG) { - if (nseg && (ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { + if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { + request_t *cmd_req = + MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); + MPT_TGT_STATE(mpt, cmd_req)->state = TGT_STATE_IN_CAM; + MPT_TGT_STATE(mpt, cmd_req)->ccb = NULL; + MPT_TGT_STATE(mpt, cmd_req)->req = NULL; + } + mpt_prt(mpt, + "mpt_execute_req: I/O cancelled (status 0x%x)\n", + ccb->ccb_h.status & CAM_STATUS_MASK); + if (nseg && (ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { bus_dmamap_unload(mpt->buffer_dmat, req->dmap); + } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d\n", __LINE__)); + xpt_done(ccb); CAMLOCK_2_MPTLOCK(mpt); mpt_free_request(mpt, req); MPTLOCK_2_CAMLOCK(mpt); - xpt_done(ccb); return; } ccb->ccb_h.status |= CAM_SIM_QUEUED; - CAMLOCK_2_MPTLOCK(mpt); if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { ccb->ccb_h.timeout_ch = timeout(mpt_timeout, (caddr_t)ccb, @@ -537,8 +1599,30 @@ mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) } else { callout_handle_init(&ccb->ccb_h.timeout_ch); } - if (mpt->verbose >= MPT_PRT_DEBUG) - mpt_print_scsi_io_request(mpt_req); + if (mpt->verbose > MPT_PRT_DEBUG) { + int nc = 0; + mpt_print_request(req->req_vbuf); + for (trq = req->chain; trq; trq = trq->chain) { + printf(" Additional Chain Area %d\n", nc++); + mpt_dump_sgl(trq->req_vbuf, 0); + } + } + + if (hdrp->Function == MPI_FUNCTION_TARGET_ASSIST) { + request_t *cmd_req = MPT_TAG_2_REQ(mpt, ccb->csio.tag_id); + mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, cmd_req); +#ifdef WE_TRUST_AUTO_GOOD_STATUS + if ((ccb->ccb_h.flags & CAM_SEND_STATUS) && + csio->scsi_status == SCSI_STATUS_OK && tgt->resid == 0) { + tgt->state = TGT_STATE_MOVING_DATA_AND_STATUS; + } else { + tgt->state = TGT_STATE_MOVING_DATA; + } +#else + tgt->state = TGT_STATE_MOVING_DATA; +#endif + } + CAMLOCK_2_MPTLOCK(mpt); mpt_send_cmd(mpt, req); MPTLOCK_2_CAMLOCK(mpt); } @@ -551,6 +1635,8 @@ mpt_start(struct cam_sim *sim, union ccb *ccb) MSG_SCSI_IO_REQUEST *mpt_req; struct ccb_scsiio *csio = &ccb->csio; struct ccb_hdr *ccbh = &ccb->ccb_h; + bus_dmamap_callback_t *cb; + target_id_t tgt; int raid_passthru; /* Get the pointer for the physical addapter */ @@ -558,27 +1644,28 @@ mpt_start(struct cam_sim *sim, union ccb *ccb) raid_passthru = (sim == mpt->phydisk_sim); CAMLOCK_2_MPTLOCK(mpt); - /* Get a request structure off the free list */ - if ((req = mpt_get_request(mpt, /*sleep_ok*/FALSE)) == NULL) { + if ((req = mpt_get_request(mpt, FALSE)) == NULL) { if (mpt->outofbeer == 0) { mpt->outofbeer = 1; xpt_freeze_simq(mpt->sim, 1); mpt_lprt(mpt, MPT_PRT_DEBUG, "FREEZEQ\n"); } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + mpt_set_ccb_status(ccb, CAM_REQUEUE_REQ); MPTLOCK_2_CAMLOCK(mpt); - ccb->ccb_h.status = CAM_REQUEUE_REQ; xpt_done(ccb); return; } - +#ifdef INVARIANTS + mpt_req_not_spcl(mpt, req, "mpt_start", __LINE__); +#endif MPTLOCK_2_CAMLOCK(mpt); -#if 0 - COWWWWW - if (raid_passthru) { - status = mpt_raid_quiesce_disk(mpt, mpt->raid_disks + ccb->ccb_h.target_id, - request_t *req) -#endif + if (sizeof (bus_addr_t) > 4) { + cb = mpt_execute_req_a64; + } else { + cb = mpt_execute_req; + } /* * Link the ccb and the request structure so we can find @@ -589,14 +1676,26 @@ mpt_start(struct cam_sim *sim, union ccb *ccb) /* Now we build the command for the IOC */ mpt_req = req->req_vbuf; - bzero(mpt_req, sizeof *mpt_req); + memset(mpt_req, 0, sizeof (MSG_SCSI_IO_REQUEST)); mpt_req->Function = MPI_FUNCTION_SCSI_IO_REQUEST; - if (raid_passthru) + if (raid_passthru) { mpt_req->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; - - mpt_req->Bus = mpt->bus; - + CAMLOCK_2_MPTLOCK(mpt); + if (mpt_map_physdisk(mpt, ccb, &tgt) != 0) { + MPTLOCK_2_CAMLOCK(mpt); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + mpt_set_ccb_status(ccb, CAM_DEV_NOT_THERE); + xpt_done(ccb); + return; + } + MPTLOCK_2_CAMLOCK(mpt); + mpt_req->Bus = 0; /* we never set bus here */ + } else { + tgt = ccb->ccb_h.target_id; + mpt_req->Bus = 0; /* XXX */ + + } mpt_req->SenseBufferLength = (csio->sense_len < MPT_SENSE_SIZE) ? csio->sense_len : MPT_SENSE_SIZE; @@ -608,19 +1707,24 @@ mpt_start(struct cam_sim *sim, union ccb *ccb) mpt_req->MsgContext = htole32(req->index | scsi_io_handler_id); /* Which physical device to do the I/O on */ - mpt_req->TargetID = ccb->ccb_h.target_id; - /* - * XXX Assumes Single level, Single byte, CAM LUN type. - */ - mpt_req->LUN[1] = ccb->ccb_h.target_lun; + mpt_req->TargetID = tgt; + + /* We assume a single level LUN type */ + if (ccb->ccb_h.target_lun >= 256) { + mpt_req->LUN[0] = 0x40 | ((ccb->ccb_h.target_lun >> 8) & 0x3f); + mpt_req->LUN[1] = ccb->ccb_h.target_lun & 0xff; + } else { + mpt_req->LUN[1] = ccb->ccb_h.target_lun; + } /* Set the direction of the transfer */ - if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { mpt_req->Control = MPI_SCSIIO_CONTROL_READ; - else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) + } else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { mpt_req->Control = MPI_SCSIIO_CONTROL_WRITE; - else + } else { mpt_req->Control = MPI_SCSIIO_CONTROL_NODATATRANSFER; + } if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { switch(ccb->csio.tag_action) { @@ -639,34 +1743,51 @@ mpt_start(struct cam_sim *sim, union ccb *ccb) break; } } else { - if (mpt->is_fc) + if (mpt->is_fc || mpt->is_sas) { mpt_req->Control |= MPI_SCSIIO_CONTROL_SIMPLEQ; - else + } else { /* XXX No such thing for a target doing packetized. */ mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED; + } } - if (mpt->is_fc == 0) { + if (mpt->is_spi) { if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT; } } /* Copy the scsi command block into place */ - if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) + if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { bcopy(csio->cdb_io.cdb_ptr, mpt_req->CDB, csio->cdb_len); - else + } else { bcopy(csio->cdb_io.cdb_bytes, mpt_req->CDB, csio->cdb_len); + } mpt_req->CDBLength = csio->cdb_len; mpt_req->DataLength = csio->dxfer_len; mpt_req->SenseBufferLowAddr = req->sense_pbuf; /* - * If we have any data to send with this command, - * map it into bus space. + * Do a *short* print here if we're set to MPT_PRT_DEBUG */ + if (mpt->verbose == MPT_PRT_DEBUG) { + mpt_prt(mpt, "mpt_start: %s op 0x%x ", + (mpt_req->Function == MPI_FUNCTION_SCSI_IO_REQUEST)? + "SCSI_IO_REQUEST" : "SCSI_IO_PASSTHRU", mpt_req->CDB[0]); + if (mpt_req->Control != MPI_SCSIIO_CONTROL_NODATATRANSFER) { + mpt_prtc(mpt, "(%s %u byte%s ", + (mpt_req->Control == MPI_SCSIIO_CONTROL_READ)? + "read" : "write", csio->dxfer_len, + (csio->dxfer_len == 1)? ")" : "s)"); + } + mpt_prtc(mpt, "tgt %u lun %u req %p:%u\n", tgt, + ccb->ccb_h.target_lun, req, req->serno); + } + /* + * If we have any data to send with this command map it into bus space. + */ if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { /* @@ -678,10 +1799,11 @@ mpt_start(struct cam_sim *sim, union ccb *ccb) * one or more physical address ranges. */ int error; - + int s = splsoftvm(); error = bus_dmamap_load(mpt->buffer_dmat, req->dmap, csio->data_ptr, csio->dxfer_len, - mpt_execute_req, req, 0); + cb, req, 0); + splx(s); if (error == EINPROGRESS) { /* * So as to maintain ordering, @@ -701,7 +1823,7 @@ mpt_start(struct cam_sim *sim, union ccb *ccb) seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr; seg.ds_len = csio->dxfer_len; - mpt_execute_req(req, &seg, 1, 0); + (*cb)(req, &seg, 1, 0); } } else { /* @@ -712,17 +1834,15 @@ mpt_start(struct cam_sim *sim, union ccb *ccb) */ struct bus_dma_segment *segs; if ((ccbh->flags & CAM_SG_LIST_PHYS) == 0) { - mpt_execute_req(req, NULL, 0, EFAULT); + (*cb)(req, NULL, 0, EFAULT); } else { /* Just use the segments provided */ segs = (struct bus_dma_segment *)csio->data_ptr; - mpt_execute_req(req, segs, csio->sglist_cnt, - (csio->sglist_cnt < MPT_SGL_MAX)? - 0 : EFBIG); + (*cb)(req, segs, csio->sglist_cnt, 0); } } } else { - mpt_execute_req(req, NULL, 0, 0); + (*cb)(req, NULL, 0, 0); } } @@ -730,12 +1850,12 @@ static int mpt_bus_reset(struct mpt_softc *mpt, int sleep_ok) { int error; - u_int status; + uint16_t status; + uint8_t response; error = mpt_scsi_send_tmf(mpt, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, mpt->is_fc ? MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION : 0, - /*bus*/0, /*target_id*/0, /*target_lun*/0, /*abort_ctx*/0, - sleep_ok); + 0, 0, 0, 0, sleep_ok); if (error != 0) { /* @@ -749,25 +1869,64 @@ mpt_bus_reset(struct mpt_softc *mpt, int sleep_ok) /* Wait for bus reset to be processed by the IOC. */ error = mpt_wait_req(mpt, mpt->tmf_req, REQ_STATE_DONE, - REQ_STATE_DONE, sleep_ok, /*time_ms*/5000); + REQ_STATE_DONE, sleep_ok, 5000); status = mpt->tmf_req->IOCStatus; + response = mpt->tmf_req->ResponseCode; mpt->tmf_req->state = REQ_STATE_FREE; + if (error) { - mpt_prt(mpt, "mpt_bus_reset: Reset timed-out." - "Resetting controller.\n"); - mpt_reset(mpt, /*reinit*/TRUE); + mpt_prt(mpt, "mpt_bus_reset: Reset timed-out. " + "Resetting controller.\n"); + mpt_reset(mpt, TRUE); return (ETIMEDOUT); - } else if ((status & MPI_IOCSTATUS_MASK) != MPI_SCSI_STATUS_SUCCESS) { - mpt_prt(mpt, "mpt_bus_reset: TMF Status %d." - "Resetting controller.\n", status); - mpt_reset(mpt, /*reinit*/TRUE); + } + + if ((status & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { + mpt_prt(mpt, "mpt_bus_reset: TMF IOC Status 0x%x. " + "Resetting controller.\n", status); + mpt_reset(mpt, TRUE); + return (EIO); + } + + if (response != MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED && + response != MPI_SCSITASKMGMT_RSP_TM_COMPLETE) { + mpt_prt(mpt, "mpt_bus_reset: TMF Response 0x%x. " + "Resetting controller.\n", response); + mpt_reset(mpt, TRUE); return (EIO); } return (0); } static int +mpt_fc_reset_link(struct mpt_softc *mpt, int dowait) +{ + int r = 0; + request_t *req; + PTR_MSG_FC_PRIMITIVE_SEND_REQUEST fc; + + req = mpt_get_request(mpt, FALSE); + if (req == NULL) { + return (ENOMEM); + } + fc = req->req_vbuf; + memset(fc, 0, sizeof(*fc)); + fc->SendFlags = MPI_FC_PRIM_SEND_FLAGS_RESET_LINK; + fc->Function = MPI_FUNCTION_FC_PRIMITIVE_SEND; + fc->MsgContext = htole32(req->index | fc_els_handler_id); + mpt_send_cmd(mpt, req); + if (dowait) { + r = mpt_wait_req(mpt, req, REQ_STATE_DONE, + REQ_STATE_DONE, FALSE, 60 * 1000); + if (r == 0) { + mpt_free_request(mpt, req); + } + } + return (r); +} + +static int mpt_cam_event(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *msg) { @@ -786,7 +1945,7 @@ mpt_cam_event(struct mpt_softc *mpt, request_t *req, case MPI_EVENT_EXT_BUS_RESET: /* Someone else generated a bus reset */ - mpt_prt(mpt, "Ext Bus Reset\n"); + mpt_prt(mpt, "External Bus Reset Detected\n"); /* * These replies don't return EventData like the MPI * spec says they do @@ -796,8 +1955,7 @@ mpt_cam_event(struct mpt_softc *mpt, request_t *req, case MPI_EVENT_RESCAN: /* - * In general this means a device has been added - * to the loop. + * In general this means a device has been added to the loop. */ mpt_prt(mpt, "Rescan Port: %d\n", (msg->Data[0] >> 8) & 0xff); /* xpt_async(AC_FOUND_DEVICE, path, NULL); */ @@ -821,26 +1979,26 @@ mpt_cam_event(struct mpt_softc *mpt, request_t *req, switch ((msg->Data[0] >> 8) & 0xff) { case 0xF7: if ((msg->Data[0] & 0xff) == 0xF7) { - printf("Device needs AL_PA\n"); + mpt_prt(mpt, "Device needs AL_PA\n"); } else { - printf("Device %02x doesn't like " + mpt_prt(mpt, "Device %02x doesn't like " "FC performance\n", msg->Data[0] & 0xFF); } break; case 0xF8: if ((msg->Data[0] & 0xff) == 0xF7) { - printf("Device had loop failure at its " - "receiver prior to acquiring " - "AL_PA\n"); + mpt_prt(mpt, "Device had loop failure " + "at its receiver prior to acquiring" + " AL_PA\n"); } else { - printf("Device %02x detected loop " - "failure at its receiver\n", + mpt_prt(mpt, "Device %02x detected loop" + " failure at its receiver\n", msg->Data[0] & 0xFF); } break; default: - printf("Device %02x requests that device " + mpt_prt(mpt, "Device %02x requests that device " "%02x reset itself\n", msg->Data[0] & 0xFF, (msg->Data[0] >> 8) & 0xFF); @@ -875,10 +2033,23 @@ mpt_cam_event(struct mpt_softc *mpt, request_t *req, mpt_prt(mpt, "FC Logout Port: %d N_PortID: %02x\n", (msg->Data[1] >> 8) & 0xff, msg->Data[0]); break; + case MPI_EVENT_EVENT_CHANGE: + mpt_lprt(mpt, MPT_PRT_DEBUG, + "mpt_cam_event: MPI_EVENT_EVENT_CHANGE\n"); + break; + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + /* + * Devices are attachin'..... + */ + mpt_prt(mpt, + "mpt_cam_event: MPI_EVENT_SAS_DEVICE_STATUS_CHANGE\n"); + break; default: - return (/*handled*/0); + mpt_lprt(mpt, MPT_PRT_WARN, "mpt_cam_event: 0x%x\n", + msg->Event & 0xFF); + return (0); } - return (/*handled*/1); + return (1); } /* @@ -893,21 +2064,28 @@ mpt_cam_event(struct mpt_softc *mpt, request_t *req, */ static int mpt_scsi_reply_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame) + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { MSG_SCSI_IO_REQUEST *scsi_req; union ccb *ccb; - + target_id_t tgt; + + if (req->state == REQ_STATE_FREE) { + mpt_prt(mpt, "mpt_scsi_reply_handler: req already free\n"); + return (TRUE); + } + scsi_req = (MSG_SCSI_IO_REQUEST *)req->req_vbuf; ccb = req->ccb; if (ccb == NULL) { - mpt_prt(mpt, "Completion without CCB. Flags %#x, Func %#x\n", - req->state, scsi_req->Function); - mpt_print_scsi_io_request(scsi_req); - return (/*free_reply*/TRUE); + mpt_prt(mpt, "mpt_scsi_reply_handler: req %p:%u with no ccb\n", + req, req->serno); + return (TRUE); } + tgt = scsi_req->TargetID; untimeout(mpt_timeout, ccb, ccb->ccb_h.timeout_ch); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { bus_dmasync_op_t op; @@ -922,8 +2100,7 @@ mpt_scsi_reply_handler(struct mpt_softc *mpt, request_t *req, if (reply_frame == NULL) { /* - * Context only reply, completion - * without error status. + * Context only reply, completion without error status. */ ccb->csio.resid = 0; mpt_set_ccb_status(ccb, CAM_REQ_CMP); @@ -937,63 +2114,393 @@ mpt_scsi_reply_handler(struct mpt_softc *mpt, request_t *req, mpt->outofbeer = 0; mpt_lprt(mpt, MPT_PRT_DEBUG, "THAWQ\n"); } - ccb->ccb_h.status &= ~CAM_SIM_QUEUED; - MPTLOCK_2_CAMLOCK(mpt); - if (scsi_req->Function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH - && scsi_req->CDB[0] == INQUIRY - && (scsi_req->CDB[1] & SI_EVPD) == 0) { - struct scsi_inquiry_data *inq; - - /* - * Fake out the device type so that only the - * pass-thru device will attach. - */ - inq = (struct scsi_inquiry_data *)ccb->csio.data_ptr; - inq->device &= ~0x1F; - inq->device |= T_NODEVICE; + if (scsi_req->CDB[0] == INQUIRY && (scsi_req->CDB[1] & SI_EVPD) == 0) { + struct scsi_inquiry_data *iq = + (struct scsi_inquiry_data *)ccb->csio.data_ptr; + if (scsi_req->Function == + MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { + /* + * Fake out the device type so that only the + * pass-thru device will attach. + */ + iq->device &= ~0x1F; + iq->device |= T_NODEVICE; + } + } + if (mpt->verbose == MPT_PRT_DEBUG) { + mpt_prt(mpt, "mpt_scsi_reply_handler: %p:%u complete\n", + req, req->serno); } + KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d\n", __LINE__)); + MPTLOCK_2_CAMLOCK(mpt); xpt_done(ccb); CAMLOCK_2_MPTLOCK(mpt); - if ((req->state & REQ_STATE_TIMEDOUT) == 0) + if ((req->state & REQ_STATE_TIMEDOUT) == 0) { TAILQ_REMOVE(&mpt->request_pending_list, req, links); - else + } else { + mpt_prt(mpt, "completing timedout/aborted req %p:%u\n", + req, req->serno); TAILQ_REMOVE(&mpt->request_timeout_list, req, links); - - if ((req->state & REQ_STATE_NEED_WAKEUP) == 0) { - mpt_free_request(mpt, req); - return (/*free_reply*/TRUE); } - req->state &= ~REQ_STATE_QUEUED; - req->state |= REQ_STATE_DONE; - wakeup(req); - return (/*free_reply*/TRUE); + KASSERT((req->state & REQ_STATE_NEED_WAKEUP) == 0, + ("CCB req needed wakeup")); +#ifdef INVARIANTS + mpt_req_not_spcl(mpt, req, "mpt_scsi_reply_handler", __LINE__); +#endif + mpt_free_request(mpt, req); + return (TRUE); } static int mpt_scsi_tmf_reply_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame) + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { MSG_SCSI_TASK_MGMT_REPLY *tmf_reply; - u_int status; - mpt_lprt(mpt, MPT_PRT_DEBUG, "TMF Complete: req %p, reply %p\n", - req, reply_frame); KASSERT(req == mpt->tmf_req, ("TMF Reply not using mpt->tmf_req")); - +#ifdef INVARIANTS + mpt_req_not_spcl(mpt, req, "mpt_scsi_tmf_reply_handler", __LINE__); +#endif tmf_reply = (MSG_SCSI_TASK_MGMT_REPLY *)reply_frame; + /* Record IOC Status and Response Code of TMF for any waiters. */ + req->IOCStatus = le16toh(tmf_reply->IOCStatus); + req->ResponseCode = tmf_reply->ResponseCode; - /* Record status of TMF for any waiters. */ - req->IOCStatus = tmf_reply->IOCStatus; - status = le16toh(tmf_reply->IOCStatus); - mpt_lprt(mpt, MPT_PRT_DEBUG, "TMF Complete: status 0x%x\n", status); + mpt_lprt(mpt, MPT_PRT_INFO, "TMF complete: req %p:%u status 0x%x\n", + req, req->serno, le16toh(tmf_reply->IOCStatus)); TAILQ_REMOVE(&mpt->request_pending_list, req, links); if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) { req->state |= REQ_STATE_DONE; wakeup(req); - } else + } else { mpt->tmf_req->state = REQ_STATE_FREE; + } + return (TRUE); +} - return (/*free_reply*/TRUE); +/* + * XXX: Move to definitions file + */ +#define ELS 0x22 +#define FC4LS 0x32 +#define ABTS 0x81 +#define BA_ACC 0x84 + +#define LS_RJT 0x01 +#define LS_ACC 0x02 +#define PLOGI 0x03 +#define LOGO 0x05 +#define SRR 0x14 +#define PRLI 0x20 +#define PRLO 0x21 +#define ADISC 0x52 +#define RSCN 0x61 + +static void +mpt_fc_els_send_response(struct mpt_softc *mpt, request_t *req, + PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY rp, U8 length) +{ + MSG_LINK_SERVICE_RSP_REQUEST tmp; + PTR_MSG_LINK_SERVICE_RSP_REQUEST rsp; + + /* + * We are going to reuse the ELS request to send this response back. + */ + rsp = &tmp; + memset(rsp, 0, sizeof(*rsp)); + +#ifdef USE_IMMEDIATE_LINK_DATA + /* + * Apparently the IMMEDIATE stuff doesn't seem to work. + */ + rsp->RspFlags = LINK_SERVICE_RSP_FLAGS_IMMEDIATE; +#endif + rsp->RspLength = length; + rsp->Function = MPI_FUNCTION_FC_LINK_SRVC_RSP; + rsp->MsgContext = htole32(req->index | fc_els_handler_id); + + /* + * Copy over information from the original reply frame to + * it's correct place in the response. + */ + memcpy((U8 *)rsp + 0x0c, (U8 *)rp + 0x1c, 24); + + /* + * And now copy back the temporary area to the original frame. + */ + memcpy(req->req_vbuf, rsp, sizeof (MSG_LINK_SERVICE_RSP_REQUEST)); + rsp = req->req_vbuf; + +#ifdef USE_IMMEDIATE_LINK_DATA + memcpy((U8 *)&rsp->SGL, &((U8 *)req->req_vbuf)[MPT_RQSL(mpt)], length); +#else +{ + PTR_SGE_SIMPLE32 se = (PTR_SGE_SIMPLE32) &rsp->SGL; + bus_addr_t paddr = req->req_pbuf; + paddr += MPT_RQSL(mpt); + + se->FlagsLength = + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_END_OF_BUFFER; + se->FlagsLength <<= MPI_SGE_FLAGS_SHIFT; + se->FlagsLength |= (length); + se->Address = (uint32_t) paddr; +} +#endif + + /* + * Send it on... + */ + mpt_send_cmd(mpt, req); +} + +static int +mpt_fc_els_reply_handler(struct mpt_softc *mpt, request_t *req, + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) +{ + PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY rp = + (PTR_MSG_LINK_SERVICE_BUFFER_POST_REPLY) reply_frame; + U8 rctl; + U8 type; + U8 cmd; + U16 status = le16toh(reply_frame->IOCStatus); + U32 *elsbuf; + int ioindex; + int do_refresh = TRUE; + +#ifdef INVARIANTS + KASSERT(mpt_req_on_free_list(mpt, req) == 0, + ("fc_els_reply_handler: req %p:%u for function %x on freelist!", + req, req->serno, rp->Function)); + if (rp->Function != MPI_FUNCTION_FC_PRIMITIVE_SEND) { + mpt_req_spcl(mpt, req, "fc_els_reply_handler", __LINE__); + } else { + mpt_req_not_spcl(mpt, req, "fc_els_reply_handler", __LINE__); + } +#endif + mpt_lprt(mpt, MPT_PRT_DEBUG, + "FC_ELS Complete: req %p:%u, reply %p function %x\n", + req, req->serno, reply_frame, reply_frame->Function); + + if (status != MPI_IOCSTATUS_SUCCESS) { + mpt_prt(mpt, "ELS REPLY STATUS 0x%x for Function %x\n", + status, reply_frame->Function); + if (status == MPI_IOCSTATUS_INVALID_STATE) { + /* + * XXX: to get around shutdown issue + */ + mpt->disabled = 1; + return (TRUE); + } + return (TRUE); + } + + /* + * If the function of a link service response, we recycle the + * response to be a refresh for a new link service request. + * + * The request pointer is bogus in this case and we have to fetch + * it based upon the TransactionContext. + */ + if (rp->Function == MPI_FUNCTION_FC_LINK_SRVC_RSP) { + /* Freddie Uncle Charlie Katie */ + /* We don't get the IOINDEX as part of the Link Svc Rsp */ + for (ioindex = 0; ioindex < mpt->els_cmds_allocated; ioindex++) + if (mpt->els_cmd_ptrs[ioindex] == req) { + break; + } + + KASSERT(ioindex < mpt->els_cmds_allocated, + ("can't find my mommie!")); + + /* remove from active list as we're going to re-post it */ + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + req->state &= ~REQ_STATE_QUEUED; + req->state |= REQ_STATE_DONE; + mpt_fc_post_els(mpt, req, ioindex); + return (TRUE); + } + + if (rp->Function == MPI_FUNCTION_FC_PRIMITIVE_SEND) { + /* remove from active list as we're done */ + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + req->state &= ~REQ_STATE_QUEUED; + req->state |= REQ_STATE_DONE; + if ((req->state & REQ_STATE_NEED_WAKEUP) == 0) { + mpt_lprt(mpt, MPT_PRT_DEBUG, + "Async Primitive Send Complete\n"); + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + mpt_free_request(mpt, req); + } else { + mpt_lprt(mpt, MPT_PRT_DEBUG, + "Sync Primitive Send Complete\n"); + wakeup(req); + } + return (TRUE); + } + + if (rp->Function != MPI_FUNCTION_FC_LINK_SRVC_BUF_POST) { + mpt_prt(mpt, "unexpected ELS_REPLY: Function 0x%x Flags %x " + "Length %d Message Flags %x\n", rp->Function, rp->Flags, + rp->MsgLength, rp->MsgFlags); + return (TRUE); + } + + if (rp->MsgLength <= 5) { + /* + * This is just a ack of an original ELS buffer post + */ + mpt_lprt(mpt, MPT_PRT_DEBUG, + "RECV'd ACK of FC_ELS buf post %p:%u\n", req, req->serno); + return (TRUE); + } + + + rctl = (le32toh(rp->Rctl_Did) & MPI_FC_RCTL_MASK) >> MPI_FC_RCTL_SHIFT; + type = (le32toh(rp->Type_Fctl) & MPI_FC_TYPE_MASK) >> MPI_FC_TYPE_SHIFT; + + elsbuf = &((U32 *)req->req_vbuf)[MPT_RQSL(mpt)/sizeof (U32)]; + cmd = be32toh(elsbuf[0]) >> 24; + + if (rp->Flags & MPI_LS_BUF_POST_REPLY_FLAG_NO_RSP_NEEDED) { + mpt_lprt(mpt, MPT_PRT_ALWAYS, "ELS_REPLY: response unneeded\n"); + return (TRUE); + } + + ioindex = le32toh(rp->TransactionContext); + req = mpt->els_cmd_ptrs[ioindex]; + + if (rctl == ELS && type == 1) { + switch (cmd) { + case PRLI: + /* + * Send back a PRLI ACC + */ + mpt_prt(mpt, "PRLI from 0x%08x%08x\n", + le32toh(rp->Wwn.PortNameHigh), + le32toh(rp->Wwn.PortNameLow)); + elsbuf[0] = htobe32(0x02100014); + elsbuf[1] |= htobe32(0x00000100); + elsbuf[4] = htobe32(0x00000002); + if (mpt->role & MPT_ROLE_TARGET) + elsbuf[4] |= htobe32(0x00000010); + if (mpt->role & MPT_ROLE_INITIATOR) + elsbuf[4] |= htobe32(0x00000020); + /* remove from active list as we're done */ + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + req->state &= ~REQ_STATE_QUEUED; + req->state |= REQ_STATE_DONE; + mpt_fc_els_send_response(mpt, req, rp, 20); + do_refresh = FALSE; + break; + case PRLO: + memset(elsbuf, 0, 5 * (sizeof (U32))); + elsbuf[0] = htobe32(0x02100014); + elsbuf[1] = htobe32(0x08000100); + mpt_prt(mpt, "PRLO from 0x%08x%08x\n", + le32toh(rp->Wwn.PortNameHigh), + le32toh(rp->Wwn.PortNameLow)); + /* remove from active list as we're done */ + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + req->state &= ~REQ_STATE_QUEUED; + req->state |= REQ_STATE_DONE; + mpt_fc_els_send_response(mpt, req, rp, 20); + do_refresh = FALSE; + break; + default: + mpt_prt(mpt, "ELS TYPE 1 COMMAND: %x\n", cmd); + break; + } + } else if (rctl == ABTS && type == 0) { + uint16_t rx_id = le16toh(rp->Rxid); + uint16_t ox_id = le16toh(rp->Oxid); + request_t *tgt_req = NULL; + + mpt_prt(mpt, + "ELS: ABTS OX_ID 0x%x RX_ID 0x%x from 0x%08x%08x\n", + ox_id, rx_id, le32toh(rp->Wwn.PortNameHigh), + le32toh(rp->Wwn.PortNameLow)); + if (rx_id >= mpt->mpt_max_tgtcmds) { + mpt_prt(mpt, "Bad RX_ID 0x%x\n", rx_id); + } else if (mpt->tgt_cmd_ptrs == NULL) { + mpt_prt(mpt, "No TGT CMD PTRS\n"); + } else { + tgt_req = mpt->tgt_cmd_ptrs[rx_id]; + } + if (tgt_req) { + mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, tgt_req); + uint8_t *vbuf; + union ccb *ccb = tgt->ccb; + uint32_t ct_id; + + vbuf = tgt_req->req_vbuf; + vbuf += MPT_RQSL(mpt); + + /* + * Check to make sure we have the correct command + * The reply descriptor in the target state should + * should contain an IoIndex that should match the + * RX_ID. + * + * It'd be nice to have OX_ID to crosscheck with + * as well. + */ + ct_id = GET_IO_INDEX(tgt->reply_desc); + + if (ct_id != rx_id) { + mpt_lprt(mpt, MPT_PRT_ERROR, "ABORT Mismatch: " + "RX_ID received=0x%x; RX_ID in cmd=0x%x\n", + rx_id, ct_id); + goto skip; + } + + ccb = tgt->ccb; + if (ccb) { + mpt_prt(mpt, + "CCB (%p): lun %u flags %x status %x\n", + ccb, ccb->ccb_h.target_lun, + ccb->ccb_h.flags, ccb->ccb_h.status); + } + mpt_prt(mpt, "target state 0x%x resid %u xfrd %u rpwrd " + "%x nxfers %x\n", tgt->state, + tgt->resid, tgt->bytes_xfered, tgt->reply_desc, + tgt->nxfers); + skip: + if (mpt_abort_target_cmd(mpt, tgt_req)) { + mpt_prt(mpt, "unable to start TargetAbort\n"); + } + } else { + mpt_prt(mpt, "no back pointer for RX_ID 0x%x\n", rx_id); + } + memset(elsbuf, 0, 5 * (sizeof (U32))); + elsbuf[0] = htobe32(0); + elsbuf[1] = htobe32((ox_id << 16) | rx_id); + elsbuf[2] = htobe32(0x000ffff); + /* + * Dork with the reply frame so that the reponse to it + * will be correct. + */ + rp->Rctl_Did += ((BA_ACC - ABTS) << MPI_FC_RCTL_SHIFT); + /* remove from active list as we're done */ + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + req->state &= ~REQ_STATE_QUEUED; + req->state |= REQ_STATE_DONE; + mpt_fc_els_send_response(mpt, req, rp, 12); + do_refresh = FALSE; + } else { + mpt_prt(mpt, "ELS: RCTL %x TYPE %x CMD %x\n", rctl, type, cmd); + } + if (do_refresh == TRUE) { + /* remove from active list as we're done */ + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + req->state &= ~REQ_STATE_QUEUED; + req->state |= REQ_STATE_DONE; + mpt_fc_post_els(mpt, req, ioindex); + } + return (TRUE); } /* @@ -1012,6 +2519,10 @@ mpt_cam_ioc_reset(struct mpt_softc *mpt, int type) MPI_IOCSTATUS_INVALID_STATE); /* + * XXX: We need to repost ELS and Target Command Buffers? + */ + + /* * Inform the XPT that a bus reset has occurred. */ xpt_async(AC_BUS_RESET, mpt->path, NULL); @@ -1172,39 +2683,40 @@ XXXX break; } - if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { mpt_freeze_ccb(ccb); + } - return (/*free_reply*/TRUE); + return (TRUE); } static void mpt_action(struct cam_sim *sim, union ccb *ccb) { - struct mpt_softc *mpt; - struct ccb_trans_settings *cts; - u_int tgt; - int raid_passthru; + struct mpt_softc *mpt; + struct ccb_trans_settings *cts; + target_id_t tgt; + int raid_passthru; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("mpt_action\n")); mpt = (struct mpt_softc *)cam_sim_softc(sim); + KASSERT(MPT_OWNED(mpt) == 0, ("mpt owned on entrance to mpt_action")); raid_passthru = (sim == mpt->phydisk_sim); tgt = ccb->ccb_h.target_id; - if (raid_passthru - && ccb->ccb_h.func_code != XPT_PATH_INQ - && ccb->ccb_h.func_code != XPT_RESET_BUS) { + if (raid_passthru && ccb->ccb_h.func_code != XPT_PATH_INQ && + ccb->ccb_h.func_code != XPT_RESET_BUS) { CAMLOCK_2_MPTLOCK(mpt); if (mpt_map_physdisk(mpt, ccb, &tgt) != 0) { - ccb->ccb_h.status = CAM_DEV_NOT_THERE; MPTLOCK_2_CAMLOCK(mpt); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + mpt_set_ccb_status(ccb, CAM_DEV_NOT_THERE); xpt_done(ccb); return; } MPTLOCK_2_CAMLOCK(mpt); } - ccb->ccb_h.ccb_mpt_ptr = mpt; switch (ccb->ccb_h.func_code) { @@ -1214,8 +2726,8 @@ mpt_action(struct cam_sim *sim, union ccb *ccb) */ if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { - ccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(ccb); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + mpt_set_ccb_status(ccb, CAM_REQ_INVALID); break; } } @@ -1223,37 +2735,53 @@ mpt_action(struct cam_sim *sim, union ccb *ccb) /* XXX Unless we implement the new 32byte message type */ if (ccb->csio.cdb_len > sizeof (((PTR_MSG_SCSI_IO_REQUEST)0)->CDB)) { - ccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(ccb); - return; + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + mpt_set_ccb_status(ccb, CAM_REQ_INVALID); + break; } ccb->csio.scsi_status = SCSI_STATUS_OK; mpt_start(sim, ccb); - break; + return; case XPT_RESET_BUS: mpt_lprt(mpt, MPT_PRT_DEBUG, "XPT_RESET_BUS\n"); - if (!raid_passthru) { - CAMLOCK_2_MPTLOCK(mpt); - (void)mpt_bus_reset(mpt, /*sleep_ok*/FALSE); - MPTLOCK_2_CAMLOCK(mpt); - } + + CAMLOCK_2_MPTLOCK(mpt); + (void) mpt_bus_reset(mpt, FALSE); + MPTLOCK_2_CAMLOCK(mpt); + /* * mpt_bus_reset is always successful in that it * will fall back to a hard reset should a bus * reset attempt fail. */ + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; mpt_set_ccb_status(ccb, CAM_REQ_CMP); - xpt_done(ccb); break; case XPT_ABORT: - /* - * XXX: Need to implement - */ - ccb->ccb_h.status = CAM_UA_ABORT; - xpt_done(ccb); + { + union ccb *accb = ccb->cab.abort_ccb; + CAMLOCK_2_MPTLOCK(mpt); + switch (accb->ccb_h.func_code) { + case XPT_ACCEPT_TARGET_IO: + case XPT_IMMED_NOTIFY: + ccb->ccb_h.status = mpt_abort_target_ccb(mpt, ccb); + break; + case XPT_CONT_TARGET_IO: + mpt_prt(mpt, "cannot abort active CTIOs yet\n"); + ccb->ccb_h.status = CAM_UA_ABORT; + break; + case XPT_SCSI_IO: + ccb->ccb_h.status = CAM_UA_ABORT; + break; + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + break; + } + MPTLOCK_2_CAMLOCK(mpt); break; + } #ifdef CAM_NEW_TRAN_CODE #define IS_CURRENT_SETTINGS(c) (c->type == CTS_TYPE_CURRENT_SETTINGS) @@ -1275,115 +2803,137 @@ mpt_action(struct cam_sim *sim, union ccb *ccb) #define DP_SYNC 0x40 case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ + { +#ifdef CAM_NEW_TRAN_CODE + struct ccb_trans_settings_scsi *scsi; + struct ccb_trans_settings_spi *spi; +#endif + uint8_t dval; + u_int period; + u_int offset; + int i, j; + cts = &ccb->cts; if (!IS_CURRENT_SETTINGS(cts)) { mpt_prt(mpt, "Attempt to set User settings\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(ccb); + mpt_set_ccb_status(ccb, CAM_REQ_INVALID); + break; + } + + if (mpt->is_fc || mpt->is_sas) { + mpt_set_ccb_status(ccb, CAM_REQ_CMP); + break; + } + + /* + * Skip attempting settings on RAID volume disks. + * Other devices on the bus get the normal treatment. + */ + if (mpt->phydisk_sim && raid_passthru == 0 && + mpt_is_raid_volume(mpt, tgt) != 0) { + mpt_lprt(mpt, MPT_PRT_NEGOTIATION, + "skipping transfer settings for RAID volumes\n"); + mpt_set_ccb_status(ccb, CAM_REQ_CMP); + break; + } + + i = mpt->mpt_port_page2.PortSettings & + MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS; + j = mpt->mpt_port_page2.PortFlags & + MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK; + if (i == MPI_SCSIPORTPAGE2_PORT_ALL_MASTER_SETTINGS && + j == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) { + mpt_lprt(mpt, MPT_PRT_ALWAYS, + "honoring BIOS transfer negotiations\n"); + mpt_set_ccb_status(ccb, CAM_REQ_CMP); break; } - if (mpt->is_fc == 0) { - uint8_t dval = 0; - u_int period = 0, offset = 0; + + dval = 0; + period = 0; + offset = 0; + #ifndef CAM_NEW_TRAN_CODE - if (cts->valid & CCB_TRANS_DISC_VALID) { - dval |= DP_DISC_ENABLE; - } - if (cts->valid & CCB_TRANS_TQ_VALID) { - dval |= DP_TQING_ENABLE; - } - if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { - if (cts->bus_width) - dval |= DP_WIDE; - else - dval |= DP_NARROW; - } - /* - * Any SYNC RATE of nonzero and SYNC_OFFSET - * of nonzero will cause us to go to the - * selected (from NVRAM) maximum value for - * this device. At a later point, we'll - * allow finer control. - */ - if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && - (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID)) { - dval |= DP_SYNC; - period = cts->sync_period; - offset = cts->sync_offset; - } + if (cts->valid & CCB_TRANS_DISC_VALID) { + dval |= DP_DISC_ENABLE; + } + if (cts->valid & CCB_TRANS_TQ_VALID) { + dval |= DP_TQING_ENABLE; + } + if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { + if (cts->bus_width) + dval |= DP_WIDE; + else + dval |= DP_NARROW; + } + if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && + (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID)) { + dval |= DP_SYNC; + period = cts->sync_period; + offset = cts->sync_offset; + } #else - struct ccb_trans_settings_scsi *scsi = - &cts->proto_specific.scsi; - struct ccb_trans_settings_spi *spi = - &cts->xport_specific.spi; + scsi = &cts->proto_specific.scsi; + spi = &cts->xport_specific.spi; - if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { - if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) - dval |= DP_DISC_ENABLE; - else - dval |= DP_DISC_DISABL; + if ((spi->valid & CTS_SPI_VALID_DISC) != 0) { + if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) { + dval |= DP_DISC_ENABLE; + } else { + dval |= DP_DISC_DISABL; } + } - if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { - if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) - dval |= DP_TQING_ENABLE; - else - dval |= DP_TQING_DISABL; + if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { + if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) { + dval |= DP_TQING_ENABLE; + } else { + dval |= DP_TQING_DISABL; } + } - if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { - if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) - dval |= DP_WIDE; - else - dval |= DP_NARROW; + if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { + if (spi->bus_width == MSG_EXT_WDTR_BUS_16_BIT) { + dval |= DP_WIDE; + } else { + dval |= DP_NARROW; } + } - if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && - (spi->valid & CTS_SPI_VALID_SYNC_RATE) && - (spi->sync_period && spi->sync_offset)) { - dval |= DP_SYNC; - period = spi->sync_period; - offset = spi->sync_offset; - } + if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) && + (spi->valid & CTS_SPI_VALID_SYNC_RATE) && + (spi->sync_period && spi->sync_offset)) { + dval |= DP_SYNC; + period = spi->sync_period; + offset = spi->sync_offset; + } #endif - CAMLOCK_2_MPTLOCK(mpt); - if (dval & DP_DISC_ENABLE) { - mpt->mpt_disc_enable |= (1 << tgt); - } else if (dval & DP_DISC_DISABL) { - mpt->mpt_disc_enable &= ~(1 << tgt); - } - if (dval & DP_TQING_ENABLE) { - mpt->mpt_tag_enable |= (1 << tgt); - } else if (dval & DP_TQING_DISABL) { - mpt->mpt_tag_enable &= ~(1 << tgt); - } - if (dval & DP_WIDTH) { - if (mpt_setwidth(mpt, tgt, dval & DP_WIDE)) { -mpt_prt(mpt, "Set width Failed!\n"); - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - MPTLOCK_2_CAMLOCK(mpt); - xpt_done(ccb); - break; - } - } - if (dval & DP_SYNC) { - if (mpt_setsync(mpt, tgt, period, offset)) { -mpt_prt(mpt, "Set sync Failed!\n"); - ccb->ccb_h.status = CAM_REQ_CMP_ERR; - MPTLOCK_2_CAMLOCK(mpt); - xpt_done(ccb); - break; - } - } - MPTLOCK_2_CAMLOCK(mpt); - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SET tgt %d flags %x period %x off %x\n", - tgt, dval, period, offset); + CAMLOCK_2_MPTLOCK(mpt); + if (dval & DP_DISC_ENABLE) { + mpt->mpt_disc_enable |= (1 << tgt); + } else if (dval & DP_DISC_DISABL) { + mpt->mpt_disc_enable &= ~(1 << tgt); + } + if (dval & DP_TQING_ENABLE) { + mpt->mpt_tag_enable |= (1 << tgt); + } else if (dval & DP_TQING_DISABL) { + mpt->mpt_tag_enable &= ~(1 << tgt); + } + if (dval & DP_WIDTH) { + mpt_setwidth(mpt, tgt, 1); + } + if (dval & DP_SYNC) { + mpt_setsync(mpt, tgt, period, offset); } - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - break; + if (mpt_update_spi_config(mpt, tgt)) { + mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); + } else { + mpt_set_ccb_status(ccb, CAM_REQ_CMP); + } + MPTLOCK_2_CAMLOCK(mpt); + break; + } case XPT_GET_TRAN_SETTINGS: cts = &ccb->cts; if (mpt->is_fc) { @@ -1414,130 +2964,35 @@ mpt_prt(mpt, "Set sync Failed!\n"); fc->bitrate = 100000; /* XXX: Need for 2Gb/s */ /* XXX: need a port database for each target */ #endif - } else { -#ifdef CAM_NEW_TRAN_CODE - struct ccb_trans_settings_scsi *scsi = - &cts->proto_specific.scsi; - struct ccb_trans_settings_spi *spi = - &cts->xport_specific.spi; -#endif - uint8_t dval, pval, oval; - int rv; - + } else if (mpt->is_sas) { +#ifndef CAM_NEW_TRAN_CODE + cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; + cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; /* - * We aren't going off of Port PAGE2 params for - * tagged queuing or disconnect capabilities - * for current settings. For goal settings, - * we assert all capabilities- we've had some - * problems with reading NVRAM data. + * How do you measure the width of a high + * speed serial bus? Well, in bytes. + * + * Offset and period make no sense, though, so we set + * (above) a 'base' transfer speed to be gigabit. */ - if (IS_CURRENT_SETTINGS(cts)) { - CONFIG_PAGE_SCSI_DEVICE_0 tmp; - dval = 0; - - tmp = mpt->mpt_dev_page0[tgt]; - CAMLOCK_2_MPTLOCK(mpt); - rv = mpt_read_cur_cfg_page(mpt, tgt, - &tmp.Header, - sizeof(tmp), - /*sleep_ok*/FALSE, - /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, - "cannot get target %d DP0\n", tgt); - } - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Tgt %d Page 0: NParms %x " - "Information %x\n", tgt, - tmp.NegotiatedParameters, - tmp.Information); - MPTLOCK_2_CAMLOCK(mpt); - - if (tmp.NegotiatedParameters & - MPI_SCSIDEVPAGE0_NP_WIDE) - dval |= DP_WIDE; - - if (mpt->mpt_disc_enable & (1 << tgt)) { - dval |= DP_DISC_ENABLE; - } - if (mpt->mpt_tag_enable & (1 << tgt)) { - dval |= DP_TQING_ENABLE; - } - oval = (tmp.NegotiatedParameters >> 16) & 0xff; - pval = (tmp.NegotiatedParameters >> 8) & 0xff; - } else { - /* - * XXX: Fix wrt NVRAM someday. Attempts - * XXX: to read port page2 device data - * XXX: just returns zero in these areas. - */ - dval = DP_WIDE|DP_DISC|DP_TQING; - oval = (mpt->mpt_port_page0.Capabilities >> 16); - pval = (mpt->mpt_port_page0.Capabilities >> 8); - } -#ifndef CAM_NEW_TRAN_CODE - cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); - if (dval & DP_DISC_ENABLE) { - cts->flags |= CCB_TRANS_DISC_ENB; - } - if (dval & DP_TQING_ENABLE) { - cts->flags |= CCB_TRANS_TAG_ENB; - } - if (dval & DP_WIDE) { - cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; - } else { - cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; - } - cts->valid = CCB_TRANS_BUS_WIDTH_VALID | - CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; - if (oval) { - cts->sync_period = pval; - cts->sync_offset = oval; - cts->valid |= - CCB_TRANS_SYNC_RATE_VALID | - CCB_TRANS_SYNC_OFFSET_VALID; - } + cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; #else + struct ccb_trans_settings_sas *sas = + &cts->xport_specific.sas; + cts->protocol = PROTO_SCSI; - cts->protocol_version = SCSI_REV_2; - cts->transport = XPORT_SPI; - cts->transport_version = 2; + cts->protocol_version = SCSI_REV_3; + cts->transport = XPORT_SAS; + cts->transport_version = 0; - scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; - spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; - if (dval & DP_DISC_ENABLE) { - spi->flags |= CTS_SPI_FLAGS_DISC_ENB; - } - if (dval & DP_TQING_ENABLE) { - scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; - } - if (oval && pval) { - spi->sync_offset = oval; - spi->sync_period = pval; - spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; - spi->valid |= CTS_SPI_VALID_SYNC_RATE; - } - spi->valid |= CTS_SPI_VALID_BUS_WIDTH; - if (dval & DP_WIDE) { - spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; - } else { - spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; - } - if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { - scsi->valid = CTS_SCSI_VALID_TQ; - spi->valid |= CTS_SPI_VALID_DISC; - } else { - scsi->valid = 0; - } + sas->valid = CTS_SAS_VALID_SPEED; + sas->bitrate = 300000; /* XXX: Default 3Gbps */ #endif - mpt_lprt(mpt, MPT_PRT_DEBUG, - "GET %s tgt %d flags %x period %x offset %x\n", - IS_CURRENT_SETTINGS(cts) - ? "ACTIVE" : "NVRAM", - tgt, dval, pval, oval); + } else if (mpt_get_spi_settings(mpt, cts) != 0) { + mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); + break; } - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); + mpt_set_ccb_status(ccb, CAM_REQ_CMP); break; case XPT_CALC_GEOMETRY: @@ -1546,13 +3001,12 @@ mpt_prt(mpt, "Set sync Failed!\n"); ccg = &ccb->ccg; if (ccg->block_size == 0) { - ccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(ccb); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + mpt_set_ccb_status(ccb, CAM_REQ_INVALID); break; } - mpt_calc_geometry(ccg, /*extended*/1); - xpt_done(ccb); + KASSERT(ccb->ccb_h.status, ("zero ccb sts at %d\n", __LINE__)); break; } case XPT_PATH_INQ: /* Path routing inquiry */ @@ -1565,126 +3019,296 @@ mpt_prt(mpt, "Set sync Failed!\n"); cpi->max_lun = 7; cpi->bus_id = cam_sim_bus(sim); /* XXX Report base speed more accurately for FC/SAS, etc.*/ - if (raid_passthru) { - cpi->max_target = mpt->ioc_page2->MaxPhysDisks; - cpi->hba_misc = PIM_NOBUSRESET; - cpi->initiator_id = cpi->max_target + 1; - cpi->hba_inquiry = PI_TAG_ABLE; - if (mpt->is_fc) { - cpi->base_transfer_speed = 100000; - } else { - cpi->base_transfer_speed = 3300; - cpi->hba_inquiry |= - PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; - } - } else if (mpt->is_fc) { + if (mpt->is_fc) { + /* XXX SHOULD BE BASED UPON IOC FACTS XXX XXX */ cpi->max_target = 255; cpi->hba_misc = PIM_NOBUSRESET; - cpi->initiator_id = cpi->max_target + 1; + cpi->initiator_id = mpt->mpt_ini_id; cpi->base_transfer_speed = 100000; cpi->hba_inquiry = PI_TAG_ABLE; + } else if (mpt->is_sas) { + cpi->max_target = 63; /* XXX */ + cpi->hba_misc = PIM_NOBUSRESET; + cpi->initiator_id = mpt->mpt_ini_id; + cpi->base_transfer_speed = 300000; + cpi->hba_inquiry = PI_TAG_ABLE; } else { + cpi->max_target = 15; + cpi->hba_misc = PIM_SEQSCAN; cpi->initiator_id = mpt->mpt_ini_id; cpi->base_transfer_speed = 3300; cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; - cpi->hba_misc = 0; - cpi->max_target = 15; } + /* + * We give our fake RAID passhtru bus a width that is MaxVolumes + * wide, restrict it to one lun and have it *not* be a bus + * that can have a SCSI bus reset. + */ + if (raid_passthru) { + cpi->max_target = mpt->ioc_page2->MaxPhysDisks - 1; + cpi->initiator_id = cpi->max_target + 1; + cpi->max_lun = 0; + cpi->hba_misc |= PIM_NOBUSRESET; + } + + if ((mpt->role & MPT_ROLE_INITIATOR) == 0) { + cpi->hba_misc |= PIM_NOINITIATOR; + } + if ((mpt->role & MPT_ROLE_TARGET) != 0) { + cpi->target_sprt = + PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; + } else { + cpi->target_sprt = 0; + } strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "LSI", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); cpi->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); break; } + case XPT_EN_LUN: /* Enable LUN as a target */ + { + int result; + + CAMLOCK_2_MPTLOCK(mpt); + if (ccb->cel.enable) + result = mpt_enable_lun(mpt, + ccb->ccb_h.target_id, ccb->ccb_h.target_lun); + else + result = mpt_disable_lun(mpt, + ccb->ccb_h.target_id, ccb->ccb_h.target_lun); + MPTLOCK_2_CAMLOCK(mpt); + if (result == 0) { + mpt_set_ccb_status(ccb, CAM_REQ_CMP); + } else { + mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); + } + break; + } + case XPT_NOTIFY_ACK: /* recycle notify ack */ + case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ + case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ + { + tgt_resource_t *trtp; + lun_id_t lun = ccb->ccb_h.target_lun; + ccb->ccb_h.sim_priv.entries[0].field = 0; + ccb->ccb_h.sim_priv.entries[1].ptr = mpt; + ccb->ccb_h.flags = 0; + + if (lun == CAM_LUN_WILDCARD) { + if (ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { + mpt_set_ccb_status(ccb, CAM_REQ_INVALID); + break; + } + trtp = &mpt->trt_wildcard; + } else if (lun >= MPT_MAX_LUNS) { + mpt_set_ccb_status(ccb, CAM_REQ_INVALID); + break; + } else { + trtp = &mpt->trt[lun]; + } + CAMLOCK_2_MPTLOCK(mpt); + if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { + mpt_lprt(mpt, MPT_PRT_DEBUG1, + "Put FREE ATIO %p lun %d\n", ccb, lun); + STAILQ_INSERT_TAIL(&trtp->atios, &ccb->ccb_h, + sim_links.stqe); + } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) { + mpt_lprt(mpt, MPT_PRT_DEBUG1, + "Put FREE INOT lun %d\n", lun); + STAILQ_INSERT_TAIL(&trtp->inots, &ccb->ccb_h, + sim_links.stqe); + } else { + mpt_lprt(mpt, MPT_PRT_ALWAYS, "Got Notify ACK\n"); + } + mpt_set_ccb_status(ccb, CAM_REQ_INPROG); + MPTLOCK_2_CAMLOCK(mpt); + break; + } + case XPT_CONT_TARGET_IO: + CAMLOCK_2_MPTLOCK(mpt); + mpt_target_start_io(mpt, ccb); + MPTLOCK_2_CAMLOCK(mpt); + break; default: ccb->ccb_h.status = CAM_REQ_INVALID; - xpt_done(ccb); break; } + xpt_done(ccb); } static int -mpt_setwidth(struct mpt_softc *mpt, int tgt, int onoff) +mpt_get_spi_settings(struct mpt_softc *mpt, struct ccb_trans_settings *cts) { - CONFIG_PAGE_SCSI_DEVICE_1 tmp; +#ifdef CAM_NEW_TRAN_CODE + struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; + struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi; +#endif + target_id_t tgt; + uint8_t dval, pval, oval; int rv; - tmp = mpt->mpt_dev_page1[tgt]; - if (onoff) { - tmp.RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE; + if (xpt_path_sim(cts->ccb_h.path) == mpt->phydisk_sim) { + if (mpt_map_physdisk(mpt, (union ccb *)cts, &tgt)) { + return (-1); + } } else { - tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE; + tgt = cts->ccb_h.target_id; } - rv = mpt_write_cur_cfg_page(mpt, tgt, &tmp.Header, sizeof(tmp), - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, "mpt_setwidth: write cur page failed\n"); - return (-1); + + /* + * XXX: We aren't looking Port Page 2 BIOS settings here. + * XXX: For goal settings, we pick the max from port page 0 + * + * For current settings we read the current settings out from + * device page 0 for that target. + */ + if (IS_CURRENT_SETTINGS(cts)) { + CONFIG_PAGE_SCSI_DEVICE_0 tmp; + dval = 0; + + CAMLOCK_2_MPTLOCK(mpt); + tmp = mpt->mpt_dev_page0[tgt]; + rv = mpt_read_cur_cfg_page(mpt, tgt, &tmp.Header, + sizeof(tmp), FALSE, 5000); + if (rv) { + MPTLOCK_2_CAMLOCK(mpt); + mpt_prt(mpt, "can't get tgt %d config page 0\n", tgt); + return (rv); + } + MPTLOCK_2_CAMLOCK(mpt); + if (tmp.NegotiatedParameters & MPI_SCSIDEVPAGE0_NP_WIDE) { + dval |= DP_WIDE; + } + if (mpt->mpt_disc_enable & (1 << tgt)) { + dval |= DP_DISC_ENABLE; + } + if (mpt->mpt_tag_enable & (1 << tgt)) { + dval |= DP_TQING_ENABLE; + } + oval = (tmp.NegotiatedParameters >> 16) & 0xff; + pval = (tmp.NegotiatedParameters >> 8) & 0xff; + mpt->mpt_dev_page0[tgt] = tmp; + } else { + /* + * XXX: Just make theoretical maximum. + */ + dval = DP_WIDE|DP_DISC|DP_TQING; + oval = (mpt->mpt_port_page0.Capabilities >> 16); + pval = (mpt->mpt_port_page0.Capabilities >> 8); } - rv = mpt_read_cur_cfg_page(mpt, tgt, &tmp.Header, sizeof(tmp), - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, "mpt_setwidth: read cur page failed\n"); - return (-1); +#ifndef CAM_NEW_TRAN_CODE + cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); + if (dval & DP_DISC_ENABLE) { + cts->flags |= CCB_TRANS_DISC_ENB; } - mpt->mpt_dev_page1[tgt] = tmp; - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Target %d Page 1: RequestedParameters %x Config %x\n", - tgt, mpt->mpt_dev_page1[tgt].RequestedParameters, - mpt->mpt_dev_page1[tgt].Configuration); + if (dval & DP_TQING_ENABLE) { + cts->flags |= CCB_TRANS_TAG_ENB; + } + if (dval & DP_WIDE) { + cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; + } else { + cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; + } + cts->valid = CCB_TRANS_BUS_WIDTH_VALID | + CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; + if (oval) { + cts->sync_period = pval; + cts->sync_offset = oval; + cts->valid |= + CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID; + } +#else + cts->protocol = PROTO_SCSI; + cts->protocol_version = SCSI_REV_2; + cts->transport = XPORT_SPI; + cts->transport_version = 2; + + scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; + spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; + if (dval & DP_DISC_ENABLE) { + spi->flags |= CTS_SPI_FLAGS_DISC_ENB; + } + if (dval & DP_TQING_ENABLE) { + scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; + } + if (oval && pval) { + spi->sync_offset = oval; + spi->sync_period = pval; + spi->valid |= CTS_SPI_VALID_SYNC_OFFSET; + spi->valid |= CTS_SPI_VALID_SYNC_RATE; + } + spi->valid |= CTS_SPI_VALID_BUS_WIDTH; + if (dval & DP_WIDE) { + spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; + } else { + spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT; + } + if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) { + scsi->valid = CTS_SCSI_VALID_TQ; + spi->valid |= CTS_SPI_VALID_DISC; + } else { + scsi->valid = 0; + } +#endif + mpt_lprt(mpt, MPT_PRT_NEGOTIATION, + "mpt_get_spi_settings[%d]: %s 0x%x period 0x%x offset %d\n", tgt, + IS_CURRENT_SETTINGS(cts)? "ACTIVE" : "NVRAM ", dval, pval, oval); return (0); } -static int +static void +mpt_setwidth(struct mpt_softc *mpt, int tgt, int onoff) +{ + PTR_CONFIG_PAGE_SCSI_DEVICE_1 ptr; + + ptr = &mpt->mpt_dev_page1[tgt]; + if (onoff) { + ptr->RequestedParameters |= MPI_SCSIDEVPAGE1_RP_WIDE; + } else { + ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_WIDE; + } +} + +static void mpt_setsync(struct mpt_softc *mpt, int tgt, int period, int offset) { + PTR_CONFIG_PAGE_SCSI_DEVICE_1 ptr; + + ptr = &mpt->mpt_dev_page1[tgt]; + ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK; + ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK; + ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_DT; + ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_QAS; + ptr->RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_IU; + ptr->RequestedParameters |= (period << 8) | (offset << 16); + if (period < 0xa) { + ptr->RequestedParameters |= MPI_SCSIDEVPAGE1_RP_DT; + } + if (period < 0x9) { + ptr->RequestedParameters |= MPI_SCSIDEVPAGE1_RP_QAS; + ptr->RequestedParameters |= MPI_SCSIDEVPAGE1_RP_IU; + } +} + +static int +mpt_update_spi_config(struct mpt_softc *mpt, int tgt) +{ CONFIG_PAGE_SCSI_DEVICE_1 tmp; int rv; + mpt_lprt(mpt, MPT_PRT_NEGOTIATION, + "mpt_update_spi_config[%d].page1: Requested Params 0x%08x\n", + tgt, mpt->mpt_dev_page1[tgt].RequestedParameters); tmp = mpt->mpt_dev_page1[tgt]; - tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK; - tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK; - tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_DT; - tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_QAS; - tmp.RequestedParameters &= ~MPI_SCSIDEVPAGE1_RP_IU; - /* - * XXX: For now, we're ignoring specific settings - */ - if (period && offset) { - int factor, offset, np; - factor = (mpt->mpt_port_page0.Capabilities >> 8) & 0xff; - offset = (mpt->mpt_port_page0.Capabilities >> 16) & 0xff; - np = 0; - if (factor < 0x9) { - np |= MPI_SCSIDEVPAGE1_RP_QAS; - np |= MPI_SCSIDEVPAGE1_RP_IU; - } - if (factor < 0xa) { - np |= MPI_SCSIDEVPAGE1_RP_DT; - } - np |= (factor << 8) | (offset << 16); - tmp.RequestedParameters |= np; - } - rv = mpt_write_cur_cfg_page(mpt, tgt, &tmp.Header, sizeof(tmp), - /*sleep_ok*/FALSE, /*timeout_ms*/5000); - if (rv) { - mpt_prt(mpt, "mpt_setsync: write cur page failed\n"); - return (-1); - } - rv = mpt_read_cur_cfg_page(mpt, tgt, &tmp.Header, sizeof(tmp), - /*sleep_ok*/FALSE, /*timeout_ms*/500); + rv = mpt_write_cur_cfg_page(mpt, tgt, + &tmp.Header, sizeof(tmp), FALSE, 5000); if (rv) { - mpt_prt(mpt, "mpt_setsync: read cur page failed\n"); + mpt_prt(mpt, "mpt_update_spi_config: write cur page failed\n"); return (-1); } - mpt->mpt_dev_page1[tgt] = tmp; - mpt_lprt(mpt, MPT_PRT_DEBUG, - "SPI Target %d Page 1: RParams %x Config %x\n", - tgt, mpt->mpt_dev_page1[tgt].RequestedParameters, - mpt->mpt_dev_page1[tgt].Configuration); return (0); } @@ -1697,6 +3321,10 @@ mpt_calc_geometry(struct ccb_calc_geometry *ccg, int extended) uint32_t size_mb; uint32_t secs_per_cylinder; + if (ccg->block_size == 0) { + ccg->ccb_h.status = CAM_REQ_INVALID; + return; + } size_mb = ccg->volume_size / ((1024L * 1024L) / ccg->block_size); if (size_mb > 1024 && extended) { ccg->heads = 255; @@ -1723,16 +3351,10 @@ mpt_spawn_recovery_thread(struct mpt_softc *mpt) return (error); } -/* - * Lock is not held on entry. - */ static void mpt_terminate_recovery_thread(struct mpt_softc *mpt) { - - MPT_LOCK(mpt); if (mpt->recovery_thread == NULL) { - MPT_UNLOCK(mpt); return; } mpt->shutdwn_recovery = 1; @@ -1742,7 +3364,6 @@ mpt_terminate_recovery_thread(struct mpt_softc *mpt) * for this interlock just for added safety. */ mpt_sleep(mpt, &mpt->recovery_thread, PUSER, "thtrm", 0); - MPT_UNLOCK(mpt); } static void @@ -1756,17 +3377,15 @@ mpt_recovery_thread(void *arg) mpt = (struct mpt_softc *)arg; MPT_LOCK(mpt); for (;;) { - - if (TAILQ_EMPTY(&mpt->request_timeout_list) != 0 - && mpt->shutdwn_recovery == 0) - mpt_sleep(mpt, mpt, PUSER, "idle", 0); - - if (mpt->shutdwn_recovery != 0) + if (TAILQ_EMPTY(&mpt->request_timeout_list) != 0) { + if (mpt->shutdwn_recovery == 0) { + mpt_sleep(mpt, mpt, PUSER, "idle", 0); + } + } + if (mpt->shutdwn_recovery != 0) { break; - - MPT_UNLOCK(mpt); + } mpt_recover_commands(mpt); - MPT_LOCK(mpt); } mpt->recovery_thread = NULL; wakeup(&mpt->recovery_thread); @@ -1778,9 +3397,8 @@ mpt_recovery_thread(void *arg) } static int -mpt_scsi_send_tmf(struct mpt_softc *mpt, u_int type, - u_int flags, u_int channel, u_int target, u_int lun, - u_int abort_ctx, int sleep_ok) +mpt_scsi_send_tmf(struct mpt_softc *mpt, u_int type, u_int flags, + u_int channel, u_int target, u_int lun, u_int abort_ctx, int sleep_ok) { MSG_SCSI_TASK_MGMT *tmf_req; int error; @@ -1789,18 +3407,18 @@ mpt_scsi_send_tmf(struct mpt_softc *mpt, u_int type, * Wait for any current TMF request to complete. * We're only allowed to issue one TMF at a time. */ - error = mpt_wait_req(mpt, mpt->tmf_req, REQ_STATE_FREE, REQ_STATE_MASK, + error = mpt_wait_req(mpt, mpt->tmf_req, REQ_STATE_FREE, REQ_STATE_FREE, sleep_ok, MPT_TMF_MAX_TIMEOUT); if (error != 0) { - mpt_reset(mpt, /*reinit*/TRUE); + mpt_reset(mpt, TRUE); return (ETIMEDOUT); } + mpt_assign_serno(mpt, mpt->tmf_req); mpt->tmf_req->state = REQ_STATE_ALLOCATED|REQ_STATE_QUEUED; - TAILQ_INSERT_HEAD(&mpt->request_pending_list, mpt->tmf_req, links); tmf_req = (MSG_SCSI_TASK_MGMT *)mpt->tmf_req->req_vbuf; - bzero(tmf_req, sizeof(*tmf_req)); + memset(tmf_req, 0, sizeof(*tmf_req)); tmf_req->TargetID = target; tmf_req->Bus = channel; tmf_req->ChainOffset = 0; @@ -1811,19 +3429,30 @@ mpt_scsi_send_tmf(struct mpt_softc *mpt, u_int type, tmf_req->MsgFlags = flags; tmf_req->MsgContext = htole32(mpt->tmf_req->index | scsi_tmf_handler_id); - bzero(&tmf_req->LUN, sizeof(tmf_req->LUN) + sizeof(tmf_req->Reserved2)); - tmf_req->LUN[1] = lun; + memset(&tmf_req->LUN, 0, + sizeof(tmf_req->LUN) + sizeof(tmf_req->Reserved2)); + if (lun > 256) { + tmf_req->LUN[0] = 0x40 | ((lun >> 8) & 0x3f); + tmf_req->LUN[1] = lun & 0xff; + } else { + tmf_req->LUN[1] = lun; + } tmf_req->TaskMsgContext = abort_ctx; - mpt_lprt(mpt, MPT_PRT_DEBUG, - "Issuing TMF %p with MsgContext of 0x%x\n", tmf_req, - tmf_req->MsgContext); - if (mpt->verbose > MPT_PRT_DEBUG) + mpt_lprt(mpt, MPT_PRT_INFO, + "Issuing TMF %p:%u with MsgContext of 0x%x\n", mpt->tmf_req, + mpt->tmf_req->serno, tmf_req->MsgContext); + if (mpt->verbose > MPT_PRT_DEBUG) { mpt_print_request(tmf_req); + } + KASSERT(mpt_req_on_pending_list(mpt, mpt->tmf_req) == 0, + ("mpt_scsi_send_tmf: tmf_req already on pending list")); + TAILQ_INSERT_HEAD(&mpt->request_pending_list, mpt->tmf_req, links); error = mpt_send_handshake_cmd(mpt, sizeof(*tmf_req), tmf_req); - if (error != 0) - mpt_reset(mpt, /*reinit*/TRUE); + if (error != MPT_OK) { + mpt_reset(mpt, TRUE); + } return (error); } @@ -1842,11 +3471,16 @@ mpt_recover_commands(struct mpt_softc *mpt) union ccb *ccb; int error; - MPT_LOCK(mpt); + if (TAILQ_EMPTY(&mpt->request_timeout_list) != 0) { + /* + * No work to do- leave. + */ + mpt_prt(mpt, "mpt_recover_commands: no requests.\n"); + return; + } /* - * Flush any commands whose completion coincides - * with their timeout. + * Flush any commands whose completion coincides with their timeout. */ mpt_intr(mpt); @@ -1860,28 +3494,57 @@ mpt_recover_commands(struct mpt_softc *mpt) * are not happening. */ mpt_prt(mpt, "Timedout requests already complete. " - "Interrupts may not be functioning.\n"); - MPT_UNLOCK(mpt); - return; + "Interrupts may not be functioning.\n"); + mpt_enable_ints(mpt); + return; } /* * We have no visibility into the current state of the * controller, so attempt to abort the commands in the - * order they timed-out. + * order they timed-out. For initiator commands, we + * depend on the reply handler pulling requests off + * the timeout list. */ while ((req = TAILQ_FIRST(&mpt->request_timeout_list)) != NULL) { - u_int status; - - mpt_prt(mpt, "Attempting to Abort Req %p\n", req); + uint16_t status; + uint8_t response; + MSG_REQUEST_HEADER *hdrp = req->req_vbuf; + mpt_prt(mpt, "attempting to abort req %p:%u function %x\n", + req, req->serno, hdrp->Function); ccb = req->ccb; + if (ccb == NULL) { + mpt_prt(mpt, "null ccb in timed out request. " + "Resetting Controller.\n"); + mpt_reset(mpt, TRUE); + continue; + } mpt_set_ccb_status(ccb, CAM_CMD_TIMEOUT); + + /* + * Check to see if this is not an initiator command and + * deal with it differently if it is. + */ + switch (hdrp->Function) { + case MPI_FUNCTION_SCSI_IO_REQUEST: + case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: + break; + default: + /* + * XXX: FIX ME: need to abort target assists... + */ + mpt_prt(mpt, "just putting it back on the pend q\n"); + TAILQ_REMOVE(&mpt->request_timeout_list, req, links); + TAILQ_INSERT_HEAD(&mpt->request_pending_list, req, + links); + continue; + } + error = mpt_scsi_send_tmf(mpt, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - /*MsgFlags*/0, mpt->bus, ccb->ccb_h.target_id, - ccb->ccb_h.target_lun, - htole32(req->index | scsi_io_handler_id), /*sleep_ok*/TRUE); + 0, 0, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, + htole32(req->index | scsi_io_handler_id), TRUE); if (error != 0) { /* @@ -1893,39 +3556,1248 @@ mpt_recover_commands(struct mpt_softc *mpt) } error = mpt_wait_req(mpt, mpt->tmf_req, REQ_STATE_DONE, - REQ_STATE_DONE, /*sleep_ok*/TRUE, /*time_ms*/5000); + REQ_STATE_DONE, TRUE, 500); status = mpt->tmf_req->IOCStatus; - if (error != 0) { + response = mpt->tmf_req->ResponseCode; + mpt->tmf_req->state = REQ_STATE_FREE; + if (error != 0) { /* - * If we've errored out and the transaction is still - * pending, reset the controller. + * If we've errored out,, reset the controller. */ - mpt_prt(mpt, "mpt_recover_commands: Abort timed-out." - "Resetting controller\n"); - mpt_reset(mpt, /*reinit*/TRUE); + mpt_prt(mpt, "mpt_recover_commands: abort timed-out. " + "Resetting controller\n"); + mpt_reset(mpt, TRUE); + continue; + } + + if ((status & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { + mpt_prt(mpt, "mpt_recover_commands: IOC Status 0x%x. " + "Resetting controller.\n", status); + mpt_reset(mpt, TRUE); continue; } + if (response != MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED && + response != MPI_SCSITASKMGMT_RSP_TM_COMPLETE) { + mpt_prt(mpt, "mpt_recover_commands: TMF Response 0x%x. " + "Resetting controller.\n", response); + mpt_reset(mpt, TRUE); + continue; + } + mpt_prt(mpt, "abort of req %p:%u completed\n", req, req->serno); + } +} + +/************************ Target Mode Support ****************************/ +static void +mpt_fc_post_els(struct mpt_softc *mpt, request_t *req, int ioindex) +{ + MSG_LINK_SERVICE_BUFFER_POST_REQUEST *fc; + PTR_SGE_TRANSACTION32 tep; + PTR_SGE_SIMPLE32 se; + bus_addr_t paddr; + + paddr = req->req_pbuf; + paddr += MPT_RQSL(mpt); + + fc = req->req_vbuf; + memset(fc, 0, MPT_REQUEST_AREA); + fc->BufferCount = 1; + fc->Function = MPI_FUNCTION_FC_LINK_SRVC_BUF_POST; + fc->MsgContext = htole32(req->index | fc_els_handler_id); + + /* + * Okay, set up ELS buffer pointers. ELS buffer pointers + * consist of a TE SGL element (with details length of zero) + * followe by a SIMPLE SGL element which holds the address + * of the buffer. + */ + + tep = (PTR_SGE_TRANSACTION32) &fc->SGL; + + tep->ContextSize = 4; + tep->Flags = 0; + tep->TransactionContext[0] = htole32(ioindex); + + se = (PTR_SGE_SIMPLE32) &tep->TransactionDetails[0]; + se->FlagsLength = + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_END_OF_BUFFER; + se->FlagsLength <<= MPI_SGE_FLAGS_SHIFT; + se->FlagsLength |= (MPT_NRFM(mpt) - MPT_RQSL(mpt)); + se->Address = (uint32_t) paddr; + mpt_lprt(mpt, MPT_PRT_DEBUG, + "add ELS index %d ioindex %d for %p:%u\n", + req->index, ioindex, req, req->serno); + KASSERT(((req->state & REQ_STATE_LOCKED) != 0), + ("mpt_fc_post_els: request not locked")); + mpt_send_cmd(mpt, req); +} + +static void +mpt_post_target_command(struct mpt_softc *mpt, request_t *req, int ioindex) +{ + PTR_MSG_TARGET_CMD_BUFFER_POST_REQUEST fc; + PTR_CMD_BUFFER_DESCRIPTOR cb; + bus_addr_t paddr; + + paddr = req->req_pbuf; + paddr += MPT_RQSL(mpt); + memset(req->req_vbuf, 0, MPT_REQUEST_AREA); + MPT_TGT_STATE(mpt, req)->state = TGT_STATE_LOADING; + + fc = req->req_vbuf; + fc->BufferCount = 1; + fc->Function = MPI_FUNCTION_TARGET_CMD_BUFFER_POST; + fc->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); + + cb = &fc->Buffer[0]; + cb->IoIndex = htole16(ioindex); + cb->u.PhysicalAddress32 = (U32) paddr; + + mpt_check_doorbell(mpt); + mpt_send_cmd(mpt, req); +} + +static int +mpt_add_els_buffers(struct mpt_softc *mpt) +{ + int i; + + if (mpt->is_fc == 0) { + return (TRUE); + } + + if (mpt->els_cmds_allocated) { + return (TRUE); + } + + mpt->els_cmd_ptrs = malloc(MPT_MAX_ELS * sizeof (request_t *), + M_DEVBUF, M_NOWAIT | M_ZERO); + + if (mpt->els_cmd_ptrs == NULL) { + return (FALSE); + } + + /* + * Feed the chip some ELS buffer resources + */ + for (i = 0; i < MPT_MAX_ELS; i++) { + request_t *req = mpt_get_request(mpt, FALSE); + if (req == NULL) { + break; + } + req->state |= REQ_STATE_LOCKED; + mpt->els_cmd_ptrs[i] = req; + mpt_fc_post_els(mpt, req, i); + } + + if (i == 0) { + mpt_prt(mpt, "unable to add ELS buffer resources\n"); + free(mpt->els_cmd_ptrs, M_DEVBUF); + mpt->els_cmd_ptrs = NULL; + return (FALSE); + } + if (i != MPT_MAX_ELS) { + mpt_lprt(mpt, MPT_PRT_INFO, + "only added %d of %d ELS buffers\n", i, MPT_MAX_ELS); + } + mpt->els_cmds_allocated = i; + return(TRUE); +} + +static int +mpt_add_target_commands(struct mpt_softc *mpt) +{ + int i, max; + + if (mpt->tgt_cmd_ptrs) { + return (TRUE); + } + + max = MPT_MAX_REQUESTS(mpt) >> 1; + if (max > mpt->mpt_max_tgtcmds) { + max = mpt->mpt_max_tgtcmds; + } + mpt->tgt_cmd_ptrs = + malloc(max * sizeof (request_t *), M_DEVBUF, M_NOWAIT | M_ZERO); + if (mpt->tgt_cmd_ptrs == NULL) { + mpt_prt(mpt, + "mpt_add_target_commands: could not allocate cmd ptrs\n"); + return (FALSE); + } + + for (i = 0; i < max; i++) { + request_t *req; + + req = mpt_get_request(mpt, FALSE); + if (req == NULL) { + break; + } + req->state |= REQ_STATE_LOCKED; + mpt->tgt_cmd_ptrs[i] = req; + mpt_post_target_command(mpt, req, i); + } + + + if (i == 0) { + mpt_lprt(mpt, MPT_PRT_ERROR, "could not add any target bufs\n"); + free(mpt->tgt_cmd_ptrs, M_DEVBUF); + mpt->tgt_cmd_ptrs = NULL; + return (FALSE); + } + + mpt->tgt_cmds_allocated = i; + + if (i < max) { + mpt_lprt(mpt, MPT_PRT_INFO, + "added %d of %d target bufs\n", i, max); + } + return (i); +} + +static void +mpt_free_els_buffers(struct mpt_softc *mpt) +{ + mpt_prt(mpt, "fix me! need to implement mpt_free_els_buffers"); +} + +static void +mpt_free_target_commands(struct mpt_softc *mpt) +{ + mpt_prt(mpt, "fix me! need to implement mpt_free_target_commands"); +} + + +static int +mpt_enable_lun(struct mpt_softc *mpt, target_id_t tgt, lun_id_t lun) +{ + if (tgt == CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { + mpt->twildcard = 1; + } else if (lun >= MPT_MAX_LUNS) { + return (EINVAL); + } else if (tgt != CAM_TARGET_WILDCARD && tgt != 0) { + return (EINVAL); + } + if (mpt->tenabled == 0) { /* - * TMF is complete. + * Try to add some target command resources */ - mpt->tmf_req->state = REQ_STATE_FREE; - if ((status & MPI_IOCSTATUS_MASK) == MPI_SCSI_STATUS_SUCCESS) - continue; + if (mpt_add_target_commands(mpt) == FALSE) { + mpt_free_els_buffers(mpt); + return (ENOMEM); + } + if (mpt->is_fc) { + (void) mpt_fc_reset_link(mpt, 0); + } + mpt->tenabled = 1; + } + if (lun == CAM_LUN_WILDCARD) { + mpt->trt_wildcard.enabled = 1; + } else { + mpt->trt[lun].enabled = 1; + } + return (0); +} - mpt_lprt(mpt, MPT_PRT_DEBUG, - "mpt_recover_commands: Abort Failed " - "with status 0x%x\n. Resetting bus", status); +static int +mpt_disable_lun(struct mpt_softc *mpt, target_id_t tgt, lun_id_t lun) +{ + int i; + if (tgt == CAM_TARGET_WILDCARD && lun == CAM_LUN_WILDCARD) { + mpt->twildcard = 0; + } else if (lun >= MPT_MAX_LUNS) { + return (EINVAL); + } else if (tgt != CAM_TARGET_WILDCARD && tgt != 0) { + return (EINVAL); + } + if (lun == CAM_LUN_WILDCARD) { + mpt->trt_wildcard.enabled = 0; + } else { + mpt->trt[lun].enabled = 0; + } + for (i = 0; i < MPT_MAX_LUNS; i++) { + if (mpt->trt[lun].enabled) { + break; + } + } + if (i == MPT_MAX_LUNS && mpt->twildcard == 0) { + mpt_free_els_buffers(mpt); + mpt_free_target_commands(mpt); + if (mpt->is_fc) { + (void) mpt_fc_reset_link(mpt, 0); + } + mpt->tenabled = 0; + } + return (0); +} + +/* + * Called with MPT lock held + */ +static void +mpt_target_start_io(struct mpt_softc *mpt, union ccb *ccb) +{ + struct ccb_scsiio *csio = &ccb->csio; + request_t *cmd_req = MPT_TAG_2_REQ(mpt, csio->tag_id); + mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, cmd_req); + + switch (tgt->state) { + case TGT_STATE_IN_CAM: + break; + case TGT_STATE_MOVING_DATA: + mpt_set_ccb_status(ccb, CAM_REQUEUE_REQ); + xpt_freeze_simq(mpt->sim, 1); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + tgt->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + MPTLOCK_2_CAMLOCK(mpt); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + return; + default: + mpt_prt(mpt, "ccb %p flags 0x%x tag 0x%08x had bad request " + "starting I/O\n", ccb, csio->ccb_h.flags, csio->tag_id); + mpt_tgt_dump_req_state(mpt, cmd_req); + mpt_set_ccb_status(ccb, CAM_REQ_CMP_ERR); + MPTLOCK_2_CAMLOCK(mpt); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + return; + } + + if (csio->dxfer_len) { + bus_dmamap_callback_t *cb; + PTR_MSG_TARGET_ASSIST_REQUEST ta; + request_t *req; + + KASSERT((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE, + ("dxfer_len %u but direction is NONE\n", csio->dxfer_len)); + + if ((req = mpt_get_request(mpt, FALSE)) == NULL) { + if (mpt->outofbeer == 0) { + mpt->outofbeer = 1; + xpt_freeze_simq(mpt->sim, 1); + mpt_lprt(mpt, MPT_PRT_DEBUG, "FREEZEQ\n"); + } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + mpt_set_ccb_status(ccb, CAM_REQUEUE_REQ); + MPTLOCK_2_CAMLOCK(mpt); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + return; + } + ccb->ccb_h.status = CAM_SIM_QUEUED | CAM_REQ_INPROG; + if (sizeof (bus_addr_t) > 4) { + cb = mpt_execute_req_a64; + } else { + cb = mpt_execute_req; + } + + req->ccb = ccb; + ccb->ccb_h.ccb_req_ptr = req; + + /* + * Record the currently active ccb and the + * request for it in our target state area. + */ + tgt->ccb = ccb; + tgt->req = req; + + memset(req->req_vbuf, 0, MPT_RQSL(mpt)); + ta = req->req_vbuf; + + if (mpt->is_sas == 0) { + PTR_MPI_TARGET_SSP_CMD_BUFFER ssp = + cmd_req->req_vbuf; + ta->QueueTag = ssp->InitiatorTag; + } else if (mpt->is_spi) { + PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER sp = + cmd_req->req_vbuf; + ta->QueueTag = sp->Tag; + } + ta->Function = MPI_FUNCTION_TARGET_ASSIST; + ta->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); + ta->ReplyWord = htole32(tgt->reply_desc); + if (csio->ccb_h.target_lun > 256) { + ta->LUN[0] = + 0x40 | ((csio->ccb_h.target_lun >> 8) & 0x3f); + ta->LUN[1] = csio->ccb_h.target_lun & 0xff; + } else { + ta->LUN[1] = csio->ccb_h.target_lun; + } + + ta->RelativeOffset = tgt->bytes_xfered; + ta->DataLength = ccb->csio.dxfer_len; + if (ta->DataLength > tgt->resid) { + ta->DataLength = tgt->resid; + } + + /* + * XXX Should be done after data transfer completes? + */ + tgt->resid -= csio->dxfer_len; + tgt->bytes_xfered += csio->dxfer_len; + + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { + ta->TargetAssistFlags |= + TARGET_ASSIST_FLAGS_DATA_DIRECTION; + } + +#ifdef WE_TRUST_AUTO_GOOD_STATUS + if ((ccb->ccb_h.flags & CAM_SEND_STATUS) && + csio->scsi_status == SCSI_STATUS_OK && tgt->resid == 0) { + ta->TargetAssistFlags |= + TARGET_ASSIST_FLAGS_AUTO_STATUS; + } +#endif + tgt->state = TGT_STATE_SETTING_UP_FOR_DATA; + + mpt_lprt(mpt, MPT_PRT_DEBUG, + "DATA_CCB %p tag %x %u bytes %u resid flg %x req %p:%u " + "nxtstate=%d\n", csio, csio->tag_id, csio->dxfer_len, + tgt->resid, ccb->ccb_h.flags, req, req->serno, tgt->state); + + MPTLOCK_2_CAMLOCK(mpt); + if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) { + if ((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) { + int error; + int s = splsoftvm(); + error = bus_dmamap_load(mpt->buffer_dmat, + req->dmap, csio->data_ptr, csio->dxfer_len, + cb, req, 0); + splx(s); + if (error == EINPROGRESS) { + xpt_freeze_simq(mpt->sim, 1); + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + } + } else { + /* + * We have been given a pointer to single + * physical buffer. + */ + struct bus_dma_segment seg; + seg.ds_addr = (bus_addr_t) + (vm_offset_t)csio->data_ptr; + seg.ds_len = csio->dxfer_len; + (*cb)(req, &seg, 1, 0); + } + } else { + /* + * We have been given a list of addresses. + * This case could be easily supported but they are not + * currently generated by the CAM subsystem so there + * is no point in wasting the time right now. + */ + struct bus_dma_segment *sgs; + if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) { + (*cb)(req, NULL, 0, EFAULT); + } else { + /* Just use the segments provided */ + sgs = (struct bus_dma_segment *)csio->data_ptr; + (*cb)(req, sgs, csio->sglist_cnt, 0); + } + } + CAMLOCK_2_MPTLOCK(mpt); + } else { + uint8_t *sp = NULL, sense[MPT_SENSE_SIZE]; /* - * If the abort attempt fails for any reason, reset the bus. - * We should find all of the timed-out commands on our - * list are in the done state after this completes. + * XXX: I don't know why this seems to happen, but + * XXX: completing the CCB seems to make things happy. + * XXX: This seems to happen if the initiator requests + * XXX: enough data that we have to do multiple CTIOs. */ - mpt_bus_reset(mpt, /*sleep_ok*/TRUE); + if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) { + mpt_lprt(mpt, MPT_PRT_DEBUG, + "Meaningless STATUS CCB (%p): flags %x status %x " + "resid %d bytes_xfered %u\n", ccb, ccb->ccb_h.flags, + ccb->ccb_h.status, tgt->resid, tgt->bytes_xfered); + mpt_set_ccb_status(ccb, CAM_REQ_CMP); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + MPTLOCK_2_CAMLOCK(mpt); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + return; + } + if (ccb->ccb_h.flags & CAM_SEND_SENSE) { + sp = sense; + memcpy(sp, &csio->sense_data, + min(csio->sense_len, MPT_SENSE_SIZE)); + } + mpt_scsi_tgt_status(mpt, ccb, cmd_req, csio->scsi_status, sp); + } +} + +/* + * Abort queued up CCBs + */ +static cam_status +mpt_abort_target_ccb(struct mpt_softc *mpt, union ccb *ccb) +{ + struct mpt_hdr_stailq *lp; + struct ccb_hdr *srch; + int found = 0; + union ccb *accb = ccb->cab.abort_ccb; + tgt_resource_t *trtp; + + mpt_lprt(mpt, MPT_PRT_DEBUG, "aborting ccb %p\n", accb); + + if (ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { + trtp = &mpt->trt_wildcard; + } else { + trtp = &mpt->trt[ccb->ccb_h.target_lun]; + } + + if (accb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { + lp = &trtp->atios; + } else if (accb->ccb_h.func_code == XPT_IMMED_NOTIFY) { + lp = &trtp->inots; + } else { + return (CAM_REQ_INVALID); + } + + STAILQ_FOREACH(srch, lp, sim_links.stqe) { + if (srch == &accb->ccb_h) { + found = 1; + STAILQ_REMOVE(lp, srch, ccb_hdr, sim_links.stqe); + break; + } + } + if (found) { + accb->ccb_h.status = CAM_REQ_ABORTED; + xpt_done(accb); + return (CAM_REQ_CMP); + } + mpt_prt(mpt, "mpt_abort_tgt_ccb: CCB %p not found\n", ccb); + return (CAM_PATH_INVALID); +} + +/* + * Ask the MPT to abort the current target command + */ +static int +mpt_abort_target_cmd(struct mpt_softc *mpt, request_t *cmd_req) +{ + int error; + request_t *req; + PTR_MSG_TARGET_MODE_ABORT abtp; + + req = mpt_get_request(mpt, FALSE); + if (req == NULL) { + return (-1); + } + abtp = req->req_vbuf; + memset(abtp, 0, sizeof (*abtp)); + + abtp->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); + abtp->AbortType = TARGET_MODE_ABORT_TYPE_EXACT_IO; + abtp->Function = MPI_FUNCTION_TARGET_MODE_ABORT; + abtp->ReplyWord = htole32(MPT_TGT_STATE(mpt, cmd_req)->reply_desc); + error = 0; + if (mpt->is_fc || mpt->is_sas) { + mpt_send_cmd(mpt, req); + } else { + error = mpt_send_handshake_cmd(mpt, sizeof(*req), req); + } + return (error); +} + +/* + * WE_TRUST_AUTO_GOOD_STATUS- I've found that setting + * TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS leads the + * FC929 to set bogus FC_RSP fields (nonzero residuals + * but w/o RESID fields set). This causes QLogic initiators + * to think maybe that a frame was lost. + * + * WE_CAN_USE_AUTO_REPOST- we can't use AUTO_REPOST because + * we use allocated requests to do TARGET_ASSIST and we + * need to know when to release them. + */ + +static void +mpt_scsi_tgt_status(struct mpt_softc *mpt, union ccb *ccb, request_t *cmd_req, + uint8_t status, uint8_t const *sense_data) +{ + uint8_t *cmd_vbuf; + mpt_tgt_state_t *tgt; + PTR_MSG_TARGET_STATUS_SEND_REQUEST tp; + request_t *req; + bus_addr_t paddr; + int resplen = 0; + + cmd_vbuf = cmd_req->req_vbuf; + cmd_vbuf += MPT_RQSL(mpt); + tgt = MPT_TGT_STATE(mpt, cmd_req); + + if ((req = mpt_get_request(mpt, FALSE)) == NULL) { + if (mpt->outofbeer == 0) { + mpt->outofbeer = 1; + xpt_freeze_simq(mpt->sim, 1); + mpt_lprt(mpt, MPT_PRT_DEBUG, "FREEZEQ\n"); + } + if (ccb) { + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + mpt_set_ccb_status(ccb, CAM_REQUEUE_REQ); + MPTLOCK_2_CAMLOCK(mpt); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + } else { + mpt_prt(mpt, + "XXXX could not allocate status req- dropping\n"); + } + return; + } + req->ccb = ccb; + if (ccb) { + ccb->ccb_h.ccb_mpt_ptr = mpt; + ccb->ccb_h.ccb_req_ptr = req; + } + + /* + * Record the currently active ccb, if any, and the + * request for it in our target state area. + */ + tgt->ccb = ccb; + tgt->req = req; + tgt->state = TGT_STATE_SENDING_STATUS; + + tp = req->req_vbuf; + paddr = req->req_pbuf; + paddr += MPT_RQSL(mpt); + + memset(tp, 0, sizeof (*tp)); + tp->Function = MPI_FUNCTION_TARGET_STATUS_SEND; + if (mpt->is_fc) { + PTR_MPI_TARGET_FCP_CMD_BUFFER fc = + (PTR_MPI_TARGET_FCP_CMD_BUFFER) cmd_vbuf; + uint8_t *sts_vbuf; + uint32_t *rsp; + + sts_vbuf = req->req_vbuf; + sts_vbuf += MPT_RQSL(mpt); + rsp = (uint32_t *) sts_vbuf; + memcpy(tp->LUN, fc->FcpLun, sizeof (tp->LUN)); + + /* + * The MPI_TARGET_FCP_RSP_BUFFER define is unfortunate. + * It has to be big-endian in memory and is organized + * in 32 bit words, which are much easier to deal with + * as words which are swizzled as needed. + * + * All we're filling here is the FC_RSP payload. + * We may just have the chip synthesize it if + * we have no residual and an OK status. + * + */ + memset(rsp, 0, sizeof (MPI_TARGET_FCP_RSP_BUFFER)); + + rsp[2] = status; + if (tgt->resid) { + rsp[2] |= 0x800; /* XXXX NEED MNEMONIC!!!! */ + rsp[3] = htobe32(tgt->resid); +#ifdef WE_TRUST_AUTO_GOOD_STATUS + resplen = sizeof (MPI_TARGET_FCP_RSP_BUFFER); +#endif + } + if (status == SCSI_STATUS_CHECK_COND) { + int i; + + rsp[2] |= 0x200; /* XXXX NEED MNEMONIC!!!! */ + rsp[4] = htobe32(MPT_SENSE_SIZE); + if (sense_data) { + memcpy(&rsp[8], sense_data, MPT_SENSE_SIZE); + } else { + mpt_prt(mpt, "mpt_scsi_tgt_status: CHECK CONDI" + "TION but no sense data?\n"); + memset(&rsp, 0, MPT_SENSE_SIZE); + } + for (i = 8; i < (8 + (MPT_SENSE_SIZE >> 2)); i++) { + rsp[i] = htobe32(rsp[i]); + } +#ifdef WE_TRUST_AUTO_GOOD_STATUS + resplen = sizeof (MPI_TARGET_FCP_RSP_BUFFER); +#endif + } +#ifndef WE_TRUST_AUTO_GOOD_STATUS + resplen = sizeof (MPI_TARGET_FCP_RSP_BUFFER); +#endif + rsp[2] = htobe32(rsp[2]); + } else if (mpt->is_sas) { + PTR_MPI_TARGET_SSP_CMD_BUFFER ssp = + (PTR_MPI_TARGET_SSP_CMD_BUFFER) cmd_vbuf; + memcpy(tp->LUN, ssp->LogicalUnitNumber, sizeof (tp->LUN)); + } else { + PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER sp = + (PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER) cmd_vbuf; + tp->StatusCode = status; + tp->QueueTag = htole16(sp->Tag); + memcpy(tp->LUN, sp->LogicalUnitNumber, sizeof (tp->LUN)); + } + + tp->ReplyWord = htole32(tgt->reply_desc); + tp->MsgContext = htole32(req->index | mpt->scsi_tgt_handler_id); + +#ifdef WE_CAN_USE_AUTO_REPOST + tp->MsgFlags = TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER; +#endif + if (status == SCSI_STATUS_OK && resplen == 0) { + tp->MsgFlags |= TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS; + } else { + tp->StatusDataSGE.u.Address32 = (uint32_t) paddr; + tp->StatusDataSGE.FlagsLength = + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_LAST_ELEMENT | + MPI_SGE_FLAGS_END_OF_LIST | + MPI_SGE_FLAGS_END_OF_BUFFER; + tp->StatusDataSGE.FlagsLength <<= MPI_SGE_FLAGS_SHIFT; + tp->StatusDataSGE.FlagsLength |= resplen; + } + + mpt_lprt(mpt, MPT_PRT_DEBUG, + "STATUS_CCB %p (wit%s sense) tag %x req %p:%u resid %u\n", + ccb, sense_data?"h" : "hout", ccb? ccb->csio.tag_id : -1, req, + req->serno, tgt->resid); + if (ccb) { + ccb->ccb_h.status = CAM_SIM_QUEUED | CAM_REQ_INPROG; + ccb->ccb_h.timeout_ch = timeout(mpt_timeout, ccb, 60 * hz); + } + mpt_send_cmd(mpt, req); +} + +static void +mpt_scsi_tgt_tsk_mgmt(struct mpt_softc *mpt, request_t *req, mpt_task_mgmt_t fc, + tgt_resource_t *trtp, int init_id) +{ + struct ccb_immed_notify *inot; + mpt_tgt_state_t *tgt; + + tgt = MPT_TGT_STATE(mpt, req); + inot = (struct ccb_immed_notify *) STAILQ_FIRST(&trtp->inots); + if (inot == NULL) { + mpt_lprt(mpt, MPT_PRT_WARN, "no INOTSs- sending back BSY\n"); + mpt_scsi_tgt_status(mpt, NULL, req, SCSI_STATUS_BUSY, NULL); + return; + } + STAILQ_REMOVE_HEAD(&trtp->inots, sim_links.stqe); + mpt_lprt(mpt, MPT_PRT_DEBUG1, + "Get FREE INOT %p lun %d\n", inot, inot->ccb_h.target_lun); + + memset(&inot->sense_data, 0, sizeof (inot->sense_data)); + inot->sense_len = 0; + memset(inot->message_args, 0, sizeof (inot->message_args)); + inot->initiator_id = init_id; /* XXX */ + + /* + * This is a somewhat grotesque attempt to map from task management + * to old style SCSI messages. God help us all. + */ + switch (fc) { + case MPT_ABORT_TASK_SET: + inot->message_args[0] = MSG_ABORT_TAG; + break; + case MPT_CLEAR_TASK_SET: + inot->message_args[0] = MSG_CLEAR_TASK_SET; + break; + case MPT_TARGET_RESET: + inot->message_args[0] = MSG_TARGET_RESET; + break; + case MPT_CLEAR_ACA: + inot->message_args[0] = MSG_CLEAR_ACA; + break; + case MPT_TERMINATE_TASK: + inot->message_args[0] = MSG_ABORT_TAG; + break; + default: + inot->message_args[0] = MSG_NOOP; + break; + } + tgt->ccb = (union ccb *) inot; + inot->ccb_h.status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; + MPTLOCK_2_CAMLOCK(mpt); + xpt_done((union ccb *)inot); + CAMLOCK_2_MPTLOCK(mpt); +} + +static void +mpt_scsi_tgt_atio(struct mpt_softc *mpt, request_t *req, uint32_t reply_desc) +{ + struct ccb_accept_tio *atiop; + lun_id_t lun; + int tag_action = 0; + mpt_tgt_state_t *tgt; + tgt_resource_t *trtp = NULL; + U8 *lunptr; + U8 *vbuf; + U16 itag; + U16 ioindex; + mpt_task_mgmt_t fct = MPT_NIL_TMT_VALUE; + uint8_t *cdbp; + + /* + * First, DMA sync the received command- which is in the *request* + * phys area. + * XXX: We could optimize this for a range + */ + bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, + BUS_DMASYNC_POSTREAD); + + /* + * Stash info for the current command where we can get at it later. + */ + vbuf = req->req_vbuf; + vbuf += MPT_RQSL(mpt); + + /* + * Get our state pointer set up. + */ + tgt = MPT_TGT_STATE(mpt, req); + if (tgt->state != TGT_STATE_LOADED) { + mpt_tgt_dump_req_state(mpt, req); + panic("bad target state in mpt_scsi_tgt_atio"); + } + memset(tgt, 0, sizeof (mpt_tgt_state_t)); + tgt->state = TGT_STATE_IN_CAM; + tgt->reply_desc = reply_desc; + ioindex = GET_IO_INDEX(reply_desc); + + if (mpt->is_fc) { + PTR_MPI_TARGET_FCP_CMD_BUFFER fc; + fc = (PTR_MPI_TARGET_FCP_CMD_BUFFER) vbuf; + if (fc->FcpCntl[2]) { + /* + * Task Management Request + */ + switch (fc->FcpCntl[2]) { + case 0x2: + fct = MPT_ABORT_TASK_SET; + break; + case 0x4: + fct = MPT_CLEAR_TASK_SET; + break; + case 0x20: + fct = MPT_TARGET_RESET; + break; + case 0x40: + fct = MPT_CLEAR_ACA; + break; + case 0x80: + fct = MPT_TERMINATE_TASK; + break; + default: + mpt_prt(mpt, "CORRUPTED TASK MGMT BITS: 0x%x\n", + fc->FcpCntl[2]); + mpt_scsi_tgt_status(mpt, 0, req, + SCSI_STATUS_OK, 0); + return; + } + } else { + switch (fc->FcpCntl[1]) { + case 0: + tag_action = MSG_SIMPLE_Q_TAG; + break; + case 1: + tag_action = MSG_HEAD_OF_Q_TAG; + break; + case 2: + tag_action = MSG_ORDERED_Q_TAG; + break; + default: + /* + * Bah. Ignore Untagged Queing and ACA + */ + tag_action = MSG_SIMPLE_Q_TAG; + break; + } + } + tgt->resid = be32toh(fc->FcpDl); + cdbp = fc->FcpCdb; + lunptr = fc->FcpLun; + itag = be16toh(fc->OptionalOxid); + } else if (mpt->is_sas) { + PTR_MPI_TARGET_SSP_CMD_BUFFER ssp; + ssp = (PTR_MPI_TARGET_SSP_CMD_BUFFER) vbuf; + cdbp = ssp->CDB; + lunptr = ssp->LogicalUnitNumber; + itag = ssp->InitiatorTag; + } else { + PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER sp; + sp = (PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER) vbuf; + cdbp = sp->CDB; + lunptr = sp->LogicalUnitNumber; + itag = sp->Tag; + } + + /* + * Generate a simple lun + */ + switch (lunptr[0] & 0xc0) { + case 0x40: + lun = ((lunptr[0] & 0x3f) << 8) | lunptr[1]; + break; + case 0: + lun = lunptr[1]; + break; + default: + mpt_lprt(mpt, MPT_PRT_ERROR, "cannot handle this type lun\n"); + lun = 0xffff; + break; + } + + /* + * Deal with non-enabled or bad luns here. + */ + if (lun >= MPT_MAX_LUNS || mpt->tenabled == 0 || + mpt->trt[lun].enabled == 0) { + if (mpt->twildcard) { + trtp = &mpt->trt_wildcard; + } else if (fct != MPT_NIL_TMT_VALUE) { + const uint8_t sp[MPT_SENSE_SIZE] = { + 0xf0, 0, 0x5, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0x25 + }; + mpt_scsi_tgt_status(mpt, NULL, req, + SCSI_STATUS_CHECK_COND, sp); + return; + } + } else { + trtp = &mpt->trt[lun]; + } + + /* + * Deal with any task management + */ + if (fct != MPT_NIL_TMT_VALUE) { + if (trtp == NULL) { + mpt_prt(mpt, "task mgmt function %x but no listener\n", + fct); + mpt_scsi_tgt_status(mpt, 0, req, + SCSI_STATUS_OK, 0); + } else { + mpt_scsi_tgt_tsk_mgmt(mpt, req, fct, trtp, + GET_INITIATOR_INDEX(reply_desc)); + } + return; + } + + + atiop = (struct ccb_accept_tio *) STAILQ_FIRST(&trtp->atios); + if (atiop == NULL) { + mpt_lprt(mpt, MPT_PRT_WARN, + "no ATIOs for lun %u- sending back %s\n", lun, + mpt->tenabled? "QUEUE FULL" : "BUSY"); + mpt_scsi_tgt_status(mpt, NULL, req, + mpt->tenabled? SCSI_STATUS_QUEUE_FULL : SCSI_STATUS_BUSY, + NULL); + return; + } + STAILQ_REMOVE_HEAD(&trtp->atios, sim_links.stqe); + mpt_lprt(mpt, MPT_PRT_DEBUG1, + "Get FREE ATIO %p lun %d\n", atiop, atiop->ccb_h.target_lun); + atiop->ccb_h.ccb_mpt_ptr = mpt; + atiop->ccb_h.status = CAM_CDB_RECVD; + atiop->ccb_h.target_lun = lun; + atiop->sense_len = 0; + atiop->init_id = GET_INITIATOR_INDEX(reply_desc); + atiop->cdb_len = mpt_cdblen(cdbp[0], 16); + memcpy(atiop->cdb_io.cdb_bytes, cdbp, atiop->cdb_len); + + /* + * The tag we construct here allows us to find the + * original request that the command came in with. + * + * This way we don't have to depend on anything but the + * tag to find things when CCBs show back up from CAM. + */ + atiop->tag_id = MPT_MAKE_TAGID(mpt, req, ioindex); + tgt->tag_id = atiop->tag_id; + if (tag_action) { + atiop->tag_action = tag_action; + atiop->ccb_h.flags = CAM_TAG_ACTION_VALID; + } + if (mpt->verbose >= MPT_PRT_DEBUG) { + int i; + mpt_prt(mpt, "START_CCB %p for lun %u CDB=<", atiop, + atiop->ccb_h.target_lun); + for (i = 0; i < atiop->cdb_len; i++) { + mpt_prtc(mpt, "%02x%c", cdbp[i] & 0xff, + (i == (atiop->cdb_len - 1))? '>' : ' '); + } + mpt_prtc(mpt, " itag %x tag %x rdesc %x dl=%u\n", + itag, atiop->tag_id, tgt->reply_desc, tgt->resid); } - MPT_UNLOCK(mpt); + MPTLOCK_2_CAMLOCK(mpt); + xpt_done((union ccb *)atiop); + CAMLOCK_2_MPTLOCK(mpt); +} + +static void +mpt_tgt_dump_tgt_state(struct mpt_softc *mpt, request_t *req) +{ + mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, req); + + mpt_prt(mpt, "req %p:%u tgt:rdesc 0x%x resid %u xfrd %u ccb %p treq %p " + "nx %d tag 0x%08x state=%d\n", req, req->serno, tgt->reply_desc, + tgt->resid, tgt->bytes_xfered, tgt->ccb, tgt->req, tgt->nxfers, + tgt->tag_id, tgt->state); +} + +static void +mpt_tgt_dump_req_state(struct mpt_softc *mpt, request_t *req) +{ + mpt_prt(mpt, "req %p:%u index %u (%x) state %x\n", req, req->serno, + req->index, req->index, req->state); + mpt_tgt_dump_tgt_state(mpt, req); +} + +static int +mpt_scsi_tgt_reply_handler(struct mpt_softc *mpt, request_t *req, + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) +{ + int dbg; + union ccb *ccb; + U16 status; + + if (reply_frame == NULL) { + /* + * Figure out what the state of the command is. + */ + mpt_tgt_state_t *tgt = MPT_TGT_STATE(mpt, req); + +#ifdef INVARIANTS + mpt_req_spcl(mpt, req, "turbo scsi_tgt_reply", __LINE__); + if (tgt->req) { + mpt_req_not_spcl(mpt, tgt->req, + "turbo scsi_tgt_reply associated req", __LINE__); + } +#endif + switch(tgt->state) { + case TGT_STATE_LOADED: + /* + * This is a new command starting. + */ + mpt_scsi_tgt_atio(mpt, req, reply_desc); + break; + case TGT_STATE_MOVING_DATA: + { + uint8_t *sp = NULL, sense[MPT_SENSE_SIZE]; + + ccb = tgt->ccb; + if (tgt->req == NULL) { + panic("mpt: turbo target reply with null " + "associated request moving data"); + /* NOTREACHED */ + } + if (ccb == NULL) { + panic("mpt: turbo target reply with null " + "associated ccb moving data"); + /* NOTREACHED */ + } + tgt->ccb = NULL; + tgt->nxfers++; + untimeout(mpt_timeout, ccb, ccb->ccb_h.timeout_ch); + mpt_lprt(mpt, MPT_PRT_DEBUG, + "TARGET_ASSIST %p (req %p:%u) done tag 0x%x\n", + ccb, tgt->req, tgt->req->serno, ccb->csio.tag_id); + /* + * Free the Target Assist Request + */ + KASSERT(tgt->req->ccb == ccb, + ("tgt->req %p:%u tgt->req->ccb %p", tgt->req, + tgt->req->serno, tgt->req->ccb)); + TAILQ_REMOVE(&mpt->request_pending_list, + tgt->req, links); + mpt_free_request(mpt, tgt->req); + tgt->req = NULL; + + /* + * Do we need to send status now? That is, are + * we done with all our data transfers? + */ + if ((ccb->ccb_h.flags & CAM_SEND_STATUS) == 0) { + mpt_set_ccb_status(ccb, CAM_REQ_CMP); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + KASSERT(ccb->ccb_h.status, + ("zero ccb sts at %d\n", __LINE__)); + tgt->state = TGT_STATE_IN_CAM; + if (mpt->outofbeer) { + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + mpt->outofbeer = 0; + mpt_lprt(mpt, MPT_PRT_DEBUG, "THAWQ\n"); + } + MPTLOCK_2_CAMLOCK(mpt); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + break; + } + /* + * Otherwise, send status (and sense) + */ + if (ccb->ccb_h.flags & CAM_SEND_SENSE) { + sp = sense; + memcpy(sp, &ccb->csio.sense_data, + min(ccb->csio.sense_len, MPT_SENSE_SIZE)); + } + mpt_scsi_tgt_status(mpt, ccb, req, + ccb->csio.scsi_status, sp); + break; + } + case TGT_STATE_SENDING_STATUS: + case TGT_STATE_MOVING_DATA_AND_STATUS: + { + int ioindex; + ccb = tgt->ccb; + + if (tgt->req == NULL) { + panic("mpt: turbo target reply with null " + "associated request sending status"); + /* NOTREACHED */ + } + + if (ccb) { + tgt->ccb = NULL; + if (tgt->state == + TGT_STATE_MOVING_DATA_AND_STATUS) { + tgt->nxfers++; + } + untimeout(mpt_timeout, ccb, + ccb->ccb_h.timeout_ch); + if (ccb->ccb_h.flags & CAM_SEND_SENSE) { + ccb->ccb_h.status |= CAM_SENT_SENSE; + } + mpt_lprt(mpt, MPT_PRT_DEBUG, + "TARGET_STATUS tag %x sts %x flgs %x req " + "%p\n", ccb->csio.tag_id, ccb->ccb_h.status, + ccb->ccb_h.flags, tgt->req); + /* + * Free the Target Send Status Request + */ + KASSERT(tgt->req->ccb == ccb, + ("tgt->req %p:%u tgt->req->ccb %p", + tgt->req, tgt->req->serno, tgt->req->ccb)); + /* + * Notify CAM that we're done + */ + mpt_set_ccb_status(ccb, CAM_REQ_CMP); + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + KASSERT(ccb->ccb_h.status, + ("ZERO ccb sts at %d\n", __LINE__)); + tgt->ccb = NULL; + } else { + mpt_lprt(mpt, MPT_PRT_DEBUG, + "TARGET_STATUS non-CAM for req %p:%u\n", + tgt->req, tgt->req->serno); + } + TAILQ_REMOVE(&mpt->request_pending_list, + tgt->req, links); + mpt_free_request(mpt, tgt->req); + tgt->req = NULL; + + /* + * And re-post the Command Buffer. + * This wil reset the state. + */ + ioindex = GET_IO_INDEX(reply_desc); + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + mpt_post_target_command(mpt, req, ioindex); + + /* + * And post a done for anyone who cares + */ + if (ccb) { + if (mpt->outofbeer) { + ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + mpt->outofbeer = 0; + mpt_lprt(mpt, MPT_PRT_DEBUG, "THAWQ\n"); + } + MPTLOCK_2_CAMLOCK(mpt); + xpt_done(ccb); + CAMLOCK_2_MPTLOCK(mpt); + } + break; + } + case TGT_STATE_NIL: /* XXX This Never Happens XXX */ + tgt->state = TGT_STATE_LOADED; + break; + default: + mpt_prt(mpt, "Unknown Target State 0x%x in Context " + "Reply Function\n", tgt->state); + } + return (TRUE); + } + + status = le16toh(reply_frame->IOCStatus); + if (status != MPI_IOCSTATUS_SUCCESS) { + dbg = MPT_PRT_ERROR; + } else { + dbg = MPT_PRT_DEBUG1; + } + + mpt_lprt(mpt, dbg, + "SCSI_TGT REPLY: req=%p:%u reply=%p func=%x IOCstatus 0x%x\n", + req, req->serno, reply_frame, reply_frame->Function, status); + + switch (reply_frame->Function) { + case MPI_FUNCTION_TARGET_CMD_BUFFER_POST: + { + mpt_tgt_state_t *tgt; +#ifdef INVARIANTS + mpt_req_spcl(mpt, req, "tgt reply BUFFER POST", __LINE__); +#endif + if (status != MPI_IOCSTATUS_SUCCESS) { + /* + * XXX What to do? + */ + break; + } + tgt = MPT_TGT_STATE(mpt, req); + KASSERT(tgt->state == TGT_STATE_LOADING, + ("bad state 0x%x on reply to buffer post\n", tgt->state)); + mpt_assign_serno(mpt, req); + tgt->state = TGT_STATE_LOADED; + break; + } + case MPI_FUNCTION_TARGET_ASSIST: +#ifdef INVARIANTS + mpt_req_not_spcl(mpt, req, "tgt reply TARGET ASSIST", __LINE__); +#endif + mpt_prt(mpt, "target assist completion\n"); + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + mpt_free_request(mpt, req); + break; + case MPI_FUNCTION_TARGET_STATUS_SEND: +#ifdef INVARIANTS + mpt_req_not_spcl(mpt, req, "tgt reply STATUS SEND", __LINE__); +#endif + mpt_prt(mpt, "status send completion\n"); + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + mpt_free_request(mpt, req); + break; + case MPI_FUNCTION_TARGET_MODE_ABORT: + { + PTR_MSG_TARGET_MODE_ABORT_REPLY abtrp = + (PTR_MSG_TARGET_MODE_ABORT_REPLY) reply_frame; + PTR_MSG_TARGET_MODE_ABORT abtp = + (PTR_MSG_TARGET_MODE_ABORT) req->req_vbuf; + uint32_t cc = GET_IO_INDEX(le32toh(abtp->ReplyWord)); +#ifdef INVARIANTS + mpt_req_not_spcl(mpt, req, "tgt reply TMODE ABORT", __LINE__); +#endif + mpt_prt(mpt, "ABORT RX_ID 0x%x Complete; status 0x%x cnt %u\n", + cc, le16toh(abtrp->IOCStatus), le32toh(abtrp->AbortCount)); + TAILQ_REMOVE(&mpt->request_pending_list, req, links); + mpt_free_request(mpt, req); + break; + } + default: + mpt_prt(mpt, "Unknown Target Address Reply Function code: " + "0x%x\n", reply_frame->Function); + break; + } + return (TRUE); } diff --git a/sys/dev/mpt/mpt_cam.h b/sys/dev/mpt/mpt_cam.h index 39492c9e5246..0bb6eb2e9e1a 100644 --- a/sys/dev/mpt/mpt_cam.h +++ b/sys/dev/mpt/mpt_cam.h @@ -24,8 +24,42 @@ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + */ +/*- + * Copyright (c) 2002, 2006 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon including + * a substantially similar Disclaimer requirement for further binary + * redistribution. + * 3. Neither the names of the above listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT + * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Support from Chris Ellsworth in order to make SAS adapters work + * is gratefully acknowledged. * - * Additional Copyright (c) 2002 by Matthew Jacob under same license. + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. */ /*- * Copyright (c) 2004, Avid Technology, Inc. and its contributors. diff --git a/sys/dev/mpt/mpt_debug.c b/sys/dev/mpt/mpt_debug.c index 0dce5f77834c..f5546ad0303b 100644 --- a/sys/dev/mpt/mpt_debug.c +++ b/sys/dev/mpt/mpt_debug.c @@ -25,7 +25,42 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Additional Copyright (c) 2002 by Matthew Jacob under same license. + */ +/*- + * Copyright (c) 2002, 2006 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon including + * a substantially similar Disclaimer requirement for further binary + * redistribution. + * 3. Neither the names of the above listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT + * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Support from Chris Ellsworth in order to make SAS adapters work + * is gratefully acknowledged. + * + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. */ #include <sys/cdefs.h> @@ -36,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include <dev/mpt/mpilib/mpi_ioc.h> #include <dev/mpt/mpilib/mpi_init.h> #include <dev/mpt/mpilib/mpi_fc.h> +#include <dev/mpt/mpilib/mpi_targ.h> #include <cam/scsi/scsi_all.h> @@ -112,29 +148,6 @@ static const struct Error_Map IOC_Func[] = { { MPI_FUNCTION_TARGET_ASSIST, "Target Assist" }, { MPI_FUNCTION_TARGET_STATUS_SEND, "Target Status Send" }, { MPI_FUNCTION_TARGET_MODE_ABORT, "Target Mode Abort" }, -{ MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC, "FC: Link Service Buffers" }, -{ MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC, "FC: Link Service Response" }, -{ MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC, "FC: Send Extended Link Service" }, -{ MPI_FUNCTION_TARGET_FC_ABORT, "FC: Abort" }, -{ MPI_FUNCTION_FC_LINK_SRVC_BUF_POST, "FC: Link Service Buffers" }, -{ MPI_FUNCTION_FC_LINK_SRVC_RSP, "FC: Link Server Response" }, -{ MPI_FUNCTION_FC_EX_LINK_SRVC_SEND, "FC: Send Extended Link Service" }, -{ MPI_FUNCTION_FC_ABORT, "FC: Abort" }, -{ MPI_FUNCTION_FW_UPLOAD, "FW Upload" }, -{ MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND, "FC: Send Common Transport" }, -{ MPI_FUNCTION_FC_PRIMITIVE_SEND, "FC: Send Primitive" }, -{ MPI_FUNCTION_RAID_ACTION, "RAID Action" }, -{ MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH, "RAID SCSI Pass-Through" }, -{ MPI_FUNCTION_TOOLBOX, "Toolbox Command" }, -{ MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR, "SCSI Enclosure Proc. Command" }, -{ MPI_FUNCTION_MAILBOX, "Mailbox Command" }, -{ MPI_FUNCTION_LAN_SEND, "LAN Send" }, -{ MPI_FUNCTION_LAN_RECEIVE, "LAN Recieve" }, -{ MPI_FUNCTION_LAN_RESET, "LAN Reset" }, -{ MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, "IOC Message Unit Reset" }, -{ MPI_FUNCTION_IO_UNIT_RESET, "IO Unit Reset" }, -{ MPI_FUNCTION_HANDSHAKE, "Handshake" }, -{ MPI_FUNCTION_REPLY_FRAME_REMOVAL, "Reply Frame Removal" }, { -1, 0}, }; @@ -195,8 +208,6 @@ static const struct Error_Map IOC_SCSITMType[] = { { -1, 0 }, }; -static void mpt_dump_sgl(SGE_IO_UNION *sgl); - static char * mpt_ioc_status(int code) { @@ -242,6 +253,7 @@ mpt_ioc_function(int code) snprintf(buf, sizeof buf, "Unknown (0x%08x)", code); return buf; } + static char * mpt_ioc_event(int code) { @@ -255,6 +267,7 @@ mpt_ioc_event(int code) snprintf(buf, sizeof buf, "Unknown (0x%08x)", code); return buf; } + static char * mpt_scsi_state(int code) { @@ -483,6 +496,7 @@ mpt_print_reply(void *vmsg) mpt_print_init_reply((MSG_IOC_INIT_REPLY *)msg); break; case MPI_FUNCTION_SCSI_IO_REQUEST: + case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: mpt_print_scsi_io_reply((MSG_SCSI_IO_REPLY *)msg); break; default: @@ -550,7 +564,12 @@ mpt_print_scsi_io_request(MSG_SCSI_IO_REQUEST *orig_msg) for (i = 0; i < msg->CDBLength; i++) printf("%02x ", msg->CDB[i]); printf("\n"); - mpt_dump_sgl(&orig_msg->SGL); + + if ((msg->Control & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK) != + MPI_SCSIIO_CONTROL_NODATATRANSFER ) { + mpt_dump_sgl(&orig_msg->SGL, + ((char *)&orig_msg->SGL)-(char *)orig_msg); + } } static void @@ -562,6 +581,35 @@ mpt_print_scsi_tmf_request(MSG_SCSI_TASK_MGMT *msg) printf("\tTaskMsgContext 0x%08x\n", msg->TaskMsgContext); } + +static void +mpt_print_scsi_target_assist_request(PTR_MSG_TARGET_ASSIST_REQUEST msg) +{ + mpt_print_request_hdr((MSG_REQUEST_HEADER *)msg); + printf("\tStatusCode 0x%02x\n", msg->StatusCode); + printf("\tTargetAssist 0x%02x\n", msg->TargetAssistFlags); + printf("\tQueueTag 0x%04x\n", msg->QueueTag); + printf("\tReplyWord 0x%08x\n", msg->ReplyWord); + printf("\tLun 0x%02x\n", msg->LUN[1]); + printf("\tRelativeOff 0x%08x\n", msg->RelativeOffset); + printf("\tDataLength 0x%08x\n", msg->DataLength); + mpt_dump_sgl(msg->SGL, 0); +} + +static void +mpt_print_scsi_target_status_send_request(MSG_TARGET_STATUS_SEND_REQUEST *msg) +{ + SGE_IO_UNION x; + mpt_print_request_hdr((MSG_REQUEST_HEADER *)msg); + printf("\tStatusCode 0x%02x\n", msg->StatusCode); + printf("\tStatusFlags 0x%02x\n", msg->StatusFlags); + printf("\tQueueTag 0x%04x\n", msg->QueueTag); + printf("\tReplyWord 0x%08x\n", msg->ReplyWord); + printf("\tLun 0x%02x\n", msg->LUN[1]); + x.u.Simple = msg->StatusDataSGE; + mpt_dump_sgl(&x, 0); +} + void mpt_print_request(void *vreq) { @@ -569,10 +617,20 @@ mpt_print_request(void *vreq) switch (req->Function) { case MPI_FUNCTION_SCSI_IO_REQUEST: + case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: mpt_print_scsi_io_request((MSG_SCSI_IO_REQUEST *)req); break; case MPI_FUNCTION_SCSI_TASK_MGMT: mpt_print_scsi_tmf_request((MSG_SCSI_TASK_MGMT *)req); + break; + case MPI_FUNCTION_TARGET_ASSIST: + mpt_print_scsi_target_assist_request( + (PTR_MSG_TARGET_ASSIST_REQUEST)req); + break; + case MPI_FUNCTION_TARGET_STATUS_SEND: + mpt_print_scsi_target_status_send_request( + (MSG_TARGET_STATUS_SEND_REQUEST *)req); + break; default: mpt_print_request_hdr(req); break; @@ -648,35 +706,69 @@ mpt_req_state(mpt_req_state_t state) "REQ_STATE", state, NULL, 80); } -static void -mpt_dump_sgl(SGE_IO_UNION *su) +#define LAST_SGE ( \ + MPI_SGE_FLAGS_END_OF_LIST | \ + MPI_SGE_FLAGS_END_OF_BUFFER| \ + MPI_SGE_FLAGS_LAST_ELEMENT) +void +mpt_dump_sgl(SGE_IO_UNION *su, int offset) { SGE_SIMPLE32 *se = (SGE_SIMPLE32 *) su; - int iCount, flags; + const char allfox[4] = { 0xff, 0xff, 0xff, 0xff }; + void *nxtaddr = se; + void *lim; + int flags; + + /* + * Can't be any bigger than this. + */ + lim = &((char *)se)[MPT_REQUEST_AREA - offset]; - iCount = MPT_SGL_MAX; do { int iprt; printf("\t"); + if (memcmp(se, allfox, 4) == 0) { + uint32_t *nxt = (uint32_t *)se; + printf("PAD %p\n", se); + nxtaddr = nxt + 1; + se = nxtaddr; + flags = 0; + continue; + } + nxtaddr = se + 1; flags = MPI_SGE_GET_FLAGS(se->FlagsLength); switch (flags & MPI_SGE_FLAGS_ELEMENT_MASK) { case MPI_SGE_FLAGS_SIMPLE_ELEMENT: - { - printf("SE32 %p: Addr=0x%0x FlagsLength=0x%0x\n", - se, se->Address, se->FlagsLength); + if (flags & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { + SGE_SIMPLE64 *se64 = (SGE_SIMPLE64 *)se; + printf("SE64 %p: Addr=0x%08x%08x FlagsLength" + "=0x%0x\n", se64, se64->Address.High, + se64->Address.Low, se64->FlagsLength); + nxtaddr = se64 + 1; + } else { + printf("SE32 %p: Addr=0x%0x FlagsLength=0x%0x" + "\n", se, se->Address, se->FlagsLength); + } printf(" "); break; - } case MPI_SGE_FLAGS_CHAIN_ELEMENT: - { - SGE_CHAIN32 *ce = (SGE_CHAIN32 *) se; - printf("CE32 %p: Addr=0x%0x NxtChnO=0x%x Flgs=0x%x " - "Len=0x%0x\n", ce, ce->Address, ce->NextChainOffset, - ce->Flags, ce->Length); + if (flags & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { + SGE_CHAIN64 *ce64 = (SGE_CHAIN64 *) se; + printf("CE64 %p: Addr=0x%08x%08x NxtChnO=0x%x " + "Flgs=0x%x Len=0x%0x\n", ce64, + ce64->Address.High, ce64->Address.Low, + ce64->NextChainOffset, + ce64->Flags, ce64->Length); + nxtaddr = ce64 + 1; + } else { + SGE_CHAIN32 *ce = (SGE_CHAIN32 *) se; + printf("CE32 %p: Addr=0x%0x NxtChnO=0x%x " + " Flgs=0x%x Len=0x%0x\n", ce, ce->Address, + ce->NextChainOffset, ce->Flags, ce->Length); + } flags = 0; break; - } case MPI_SGE_FLAGS_TRANSACTION_ELEMENT: printf("TE32 @ %p\n", se); flags = 0; @@ -701,10 +793,59 @@ mpt_dump_sgl(SGE_IO_UNION *su) #undef MPT_PRINT_FLAG if (iprt) printf("\n"); - se++; - iCount -= 1; - } while ((flags & MPI_SGE_FLAGS_END_OF_LIST) == 0 && iCount != 0); + se = nxtaddr; + if ((flags & LAST_SGE) == LAST_SGE) { + break; + } + } while ((flags & MPI_SGE_FLAGS_END_OF_LIST) == 0 && nxtaddr < lim); +} + +void +mpt_dump_request(struct mpt_softc *mpt, request_t *req) +{ + uint32_t *pReq = req->req_vbuf; + int offset; +#if __FreeBSD_version >= 500000 + mpt_prt(mpt, "Send Request %d (%jx):", + req->index, (uintmax_t) req->req_pbuf); +#else + mpt_prt(mpt, "Send Request %d (%llx):", + req->index, (unsigned long long) req->req_pbuf); +#endif + for (offset = 0; offset < mpt->request_frame_size; offset++) { + if ((offset & 0x7) == 0) { + mpt_prtc(mpt, "\n"); + mpt_prt(mpt, " "); + } + mpt_prtc(mpt, " %08x", pReq[offset]); + } + mpt_prtc(mpt, "\n"); +} + +#if __FreeBSD_version < 500000 +void +mpt_lprt(struct mpt_softc *mpt, int level, const char *fmt, ...) +{ + va_list ap; + if (level <= mpt->verbose) { + printf("%s: ", device_get_nameunit(mpt->dev)); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + } +} + +void +mpt_lprtc(struct mpt_softc *mpt, int level, const char *fmt, ...) +{ + va_list ap; + if (level <= mpt->verbose) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + } } +#endif void mpt_prt(struct mpt_softc *mpt, const char *fmt, ...) diff --git a/sys/dev/mpt/mpt_pci.c b/sys/dev/mpt/mpt_pci.c index ebc1ac31f203..aeffb5c58a26 100644 --- a/sys/dev/mpt/mpt_pci.c +++ b/sys/dev/mpt/mpt_pci.c @@ -29,6 +29,42 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +/*- + * Copyright (c) 2002, 2006 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon including + * a substantially similar Disclaimer requirement for further binary + * redistribution. + * 3. Neither the names of the above listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT + * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Support from Chris Ellsworth in order to make SAS adapters work + * is gratefully acknowledged. + * + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. + */ /* * Copyright (c) 2004, Avid Technology, Inc. and its contributors. * Copyright (c) 2005, WHEEL Sp. z o.o. @@ -69,13 +105,6 @@ __FBSDID("$FreeBSD$"); #include <dev/mpt/mpt_cam.h> #include <dev/mpt/mpt_raid.h> -#if __FreeBSD_version < 500000 -#include <pci/pcireg.h> -#include <pci/pcivar.h> -#else -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.h> -#endif #ifndef PCI_VENDOR_LSI #define PCI_VENDOR_LSI 0x1000 @@ -101,16 +130,51 @@ __FBSDID("$FreeBSD$"); #define PCI_PRODUCT_LSI_FC929X 0x0626 #endif +#ifndef PCI_PRODUCT_LSI_FC7X04X +#define PCI_PRODUCT_LSI_FC7X04X 0x0640 +#endif + #ifndef PCI_PRODUCT_LSI_1030 #define PCI_PRODUCT_LSI_1030 0x0030 #endif +#ifndef PCI_PRODUCT_LSI_SAS1064 +#define PCI_PRODUCT_LSI_SAS1064 0x0050 +#endif + +#ifndef PCI_PRODUCT_LSI_SAS1064A +#define PCI_PRODUCT_LSI_SAS1064A 0x005C +#endif + +#ifndef PCI_PRODUCT_LSI_SAS1064E +#define PCI_PRODUCT_LSI_SAS1064E 0x0056 +#endif + +#ifndef PCI_PRODUCT_LSI_SAS1066 +#define PCI_PRODUCT_LSI_SAS1066 0x005E +#endif + +#ifndef PCI_PRODUCT_LSI_SAS1066E +#define PCI_PRODUCT_LSI_SAS1066E 0x005A +#endif + +#ifndef PCI_PRODUCT_LSI_SAS1068 +#define PCI_PRODUCT_LSI_SAS1068 0x0054 +#endif + +#ifndef PCI_PRODUCT_LSI_SAS1068E +#define PCI_PRODUCT_LSI_SAS1068E 0x0058 +#endif + +#ifndef PCI_PRODUCT_LSI_SAS1078 +#define PCI_PRODUCT_LSI_SAS1078 0x0060 +#endif + #ifndef PCIM_CMD_SERRESPEN #define PCIM_CMD_SERRESPEN 0x0100 #endif - #define MPT_IO_BAR 0 #define MPT_MEM_BAR 1 @@ -162,11 +226,24 @@ mpt_pci_probe(device_t dev) desc = "LSILogic FC929 FC Adapter"; break; case PCI_PRODUCT_LSI_FC929X: - desc = "LSILogic FC929X FC Adapter"; + desc = "LSILogic FC929X 2Gb/s FC Adapter"; + break; + case PCI_PRODUCT_LSI_FC7X04X: + desc = "LSILogic FC7X04X 4Gb/s FC Adapter"; break; case PCI_PRODUCT_LSI_1030: desc = "LSILogic 1030 Ultra4 Adapter"; break; + case PCI_PRODUCT_LSI_SAS1064: + case PCI_PRODUCT_LSI_SAS1064A: + case PCI_PRODUCT_LSI_SAS1064E: + case PCI_PRODUCT_LSI_SAS1066: + case PCI_PRODUCT_LSI_SAS1066E: + case PCI_PRODUCT_LSI_SAS1068: + case PCI_PRODUCT_LSI_SAS1068E: + case PCI_PRODUCT_LSI_SAS1078: + desc = "LSILogic SAS Adapter"; + break; default: return (ENXIO); } @@ -175,7 +252,7 @@ mpt_pci_probe(device_t dev) return (0); } -#ifdef RELENG_4 +#if __FreeBSD_version < 500000 static void mpt_set_options(struct mpt_softc *mpt) { @@ -187,14 +264,30 @@ mpt_set_options(struct mpt_softc *mpt) mpt->disabled = 1; } } - bitmap = 0; if (getenv_int("mpt_debug", &bitmap)) { if (bitmap & (1 << mpt->unit)) { mpt->verbose = MPT_PRT_DEBUG; } } - + bitmap = 0; + if (getenv_int("mpt_debug1", &bitmap)) { + if (bitmap & (1 << mpt->unit)) { + mpt->verbose = MPT_PRT_DEBUG1; + } + } + bitmap = 0; + if (getenv_int("mpt_debug2", &bitmap)) { + if (bitmap & (1 << mpt->unit)) { + mpt->verbose = MPT_PRT_DEBUG2; + } + } + bitmap = 0; + if (getenv_int("mpt_debug3", &bitmap)) { + if (bitmap & (1 << mpt->unit)) { + mpt->verbose = MPT_PRT_DEBUG3; + } + } } #else static void @@ -210,7 +303,13 @@ mpt_set_options(struct mpt_softc *mpt) tval = 0; if (resource_int_value(device_get_name(mpt->dev), device_get_unit(mpt->dev), "debug", &tval) == 0 && tval != 0) { - mpt->verbose += tval; + mpt->verbose = tval; + } + tval = 0; + if (resource_int_value(device_get_name(mpt->dev), + device_get_unit(mpt->dev), "role", &tval) == 0 && tval != 0 && + tval <= 3) { + mpt->role = tval; } } #endif @@ -221,9 +320,9 @@ mpt_link_peer(struct mpt_softc *mpt) { struct mpt_softc *mpt2; - if (mpt->unit == 0) + if (mpt->unit == 0) { return; - + } /* * XXX: depends on probe order */ @@ -246,6 +345,14 @@ mpt_link_peer(struct mpt_softc *mpt) } } +static void +mpt_unlink_peer(struct mpt_softc *mpt) +{ + if (mpt->mpt2) { + mpt->mpt2->mpt2 = NULL; + } +} + static int mpt_pci_attach(device_t dev) @@ -260,15 +367,27 @@ mpt_pci_attach(device_t dev) device_printf(dev, "cannot allocate softc\n"); return (ENOMEM); } - bzero(mpt, sizeof(struct mpt_softc)); + memset(mpt, 0, sizeof(struct mpt_softc)); switch ((pci_get_device(dev) & ~1)) { case PCI_PRODUCT_LSI_FC909: case PCI_PRODUCT_LSI_FC909A: case PCI_PRODUCT_LSI_FC919: case PCI_PRODUCT_LSI_FC929: + case PCI_PRODUCT_LSI_FC7X04X: mpt->is_fc = 1; break; + case PCI_PRODUCT_LSI_SAS1064: + case PCI_PRODUCT_LSI_SAS1064A: + case PCI_PRODUCT_LSI_SAS1064E: + case PCI_PRODUCT_LSI_SAS1066: + case PCI_PRODUCT_LSI_SAS1066E: + case PCI_PRODUCT_LSI_SAS1068: + case PCI_PRODUCT_LSI_SAS1068E: + case PCI_PRODUCT_LSI_SAS1078: + mpt->is_sas = 1; + break; default: + mpt->is_spi = 1; break; } mpt->dev = dev; @@ -276,15 +395,19 @@ mpt_pci_attach(device_t dev) mpt->raid_resync_rate = MPT_RAID_RESYNC_RATE_DEFAULT; mpt->raid_mwce_setting = MPT_RAID_MWCE_DEFAULT; mpt->raid_queue_depth = MPT_RAID_QUEUE_DEPTH_DEFAULT; + mpt->verbose = MPT_PRT_NONE; + mpt->role = MPT_ROLE_NONE; mpt_set_options(mpt); - mpt->verbose = MPT_PRT_INFO; - mpt->verbose += (bootverbose != 0)? 1 : 0; - + if (mpt->verbose == MPT_PRT_NONE) { + mpt->verbose = MPT_PRT_WARN; + /* Print INFO level (if any) if bootverbose is set */ + mpt->verbose += (bootverbose != 0)? 1 : 0; + } /* Make sure memory access decoders are enabled */ cmd = pci_read_config(dev, PCIR_COMMAND, 2); if ((cmd & PCIM_CMD_MEMEN) == 0) { device_printf(dev, "Memory accesses disabled"); - goto bad; + return (ENXIO); } /* @@ -307,13 +430,15 @@ mpt_pci_attach(device_t dev) * If so, link with our partner (around yet) */ if ((pci_get_device(dev) & ~1) == PCI_PRODUCT_LSI_FC929 || + (pci_get_device(dev) & ~1) == PCI_PRODUCT_LSI_FC7X04X || (pci_get_device(dev) & ~1) == PCI_PRODUCT_LSI_1030) { mpt_link_peer(mpt); } /* * Set up register access. PIO mode is required for - * certain reset operations. + * certain reset operations (but must be disabled for + * some cards otherwise). */ mpt->pci_pio_rid = PCIR_BAR(MPT_IO_BAR); mpt->pci_pio_reg = bus_alloc_resource(dev, SYS_RES_IOPORT, @@ -331,6 +456,10 @@ mpt_pci_attach(device_t dev) &mpt->pci_mem_rid, 0, ~0, 0, RF_ACTIVE); if (mpt->pci_reg == NULL) { device_printf(dev, "Unable to memory map registers.\n"); + if (mpt->is_sas) { + device_printf(dev, "Giving Up.\n"); + goto bad; + } device_printf(dev, "Falling back to PIO mode.\n"); mpt->pci_st = mpt->pci_pio_st; mpt->pci_sh = mpt->pci_pio_sh; @@ -368,7 +497,7 @@ mpt_pci_attach(device_t dev) /* Allocate dma memory */ /* XXX JGibbs -Should really be done based on IOCFacts. */ if (mpt_dma_mem_alloc(mpt)) { - device_printf(dev, "Could not allocate DMA memory\n"); + mpt_prt(mpt, "Could not allocate DMA memory\n"); goto bad; } @@ -384,6 +513,11 @@ mpt_pci_attach(device_t dev) mpt_read_config_regs(mpt); + /* + * Disable PIO until we need it + */ + pci_disable_io(dev, SYS_RES_IOPORT); + /* Initialize the hardware */ if (mpt->disabled == 0) { MPT_LOCK(mpt); @@ -391,13 +525,31 @@ mpt_pci_attach(device_t dev) MPT_UNLOCK(mpt); goto bad; } + MPT_UNLOCK(mpt); + } else { + mpt_prt(mpt, "device disabled at user request\n"); + goto bad; } + mpt->eh = EVENTHANDLER_REGISTER(shutdown_post_sync, mpt_pci_shutdown, + dev, SHUTDOWN_PRI_DEFAULT); + + if (mpt->eh == NULL) { + mpt_prt(mpt, "shutdown event registration failed\n"); + MPT_LOCK(mpt); + (void) mpt_detach(mpt); + MPT_UNLOCK(mpt); + goto bad; + } + KASSERT(MPT_OWNED(mpt) == 0, ("leaving attach with device locked")); return (0); bad: mpt_dma_mem_free(mpt); mpt_free_bus_resources(mpt); + mpt_unlink_peer(mpt); + + MPT_LOCK_DESTROY(mpt); /* * but return zero to preserve unit numbering @@ -444,36 +596,19 @@ mpt_pci_detach(device_t dev) struct mpt_softc *mpt; mpt = (struct mpt_softc*)device_get_softc(dev); - mpt_prt(mpt, "mpt_detach\n"); if (mpt) { + MPT_LOCK(mpt); mpt_disable_ints(mpt); mpt_detach(mpt); mpt_reset(mpt, /*reinit*/FALSE); mpt_dma_mem_free(mpt); mpt_free_bus_resources(mpt); - if (mpt->raid_volumes != NULL - && mpt->ioc_page2 != NULL) { - int i; - - for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) { - struct mpt_raid_volume *mpt_vol; - - mpt_vol = &mpt->raid_volumes[i]; - if (mpt_vol->config_page) - free(mpt_vol->config_page, M_DEVBUF); - } - } - if (mpt->ioc_page2 != NULL) - free(mpt->ioc_page2, M_DEVBUF); - if (mpt->ioc_page3 != NULL) - free(mpt->ioc_page3, M_DEVBUF); - if (mpt->raid_volumes != NULL) - free(mpt->raid_volumes, M_DEVBUF); - if (mpt->raid_disks != NULL) - free(mpt->raid_disks, M_DEVBUF); - if (mpt->eh != NULL) + mpt_raid_free_mem(mpt); + if (mpt->eh != NULL) { EVENTHANDLER_DEREGISTER(shutdown_final, mpt->eh); + } + MPT_UNLOCK(mpt); } return(0); } @@ -481,7 +616,6 @@ mpt_pci_detach(device_t dev) /* * Disable the hardware - * XXX - Called too early by New Bus!!! ??? */ static int mpt_pci_shutdown(device_t dev) @@ -489,20 +623,24 @@ mpt_pci_shutdown(device_t dev) struct mpt_softc *mpt; mpt = (struct mpt_softc *)device_get_softc(dev); - if (mpt) - return (mpt_shutdown(mpt)); + if (mpt) { + int r; + MPT_LOCK(mpt); + r = mpt_shutdown(mpt); + MPT_UNLOCK(mpt); + return (r); + } return(0); } static int mpt_dma_mem_alloc(struct mpt_softc *mpt) { - int i, error; + int i, error, nsegs; uint8_t *vptr; uint32_t pptr, end; size_t len; struct mpt_map_info mi; - device_t dev = mpt->dev; /* Check if we alreay have allocated the reply memory */ if (mpt->reply_phys != 0) { @@ -513,49 +651,49 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt) #ifdef RELENG_4 mpt->request_pool = (request_t *)malloc(len, M_DEVBUF, M_WAITOK); if (mpt->request_pool == NULL) { - device_printf(dev, "cannot allocate request pool\n"); + mpt_prt(mpt, "cannot allocate request pool\n"); return (1); } - bzero(mpt->request_pool, len); + memset(mpt->request_pool, 0, len); #else mpt->request_pool = (request_t *)malloc(len, M_DEVBUF, M_WAITOK|M_ZERO); if (mpt->request_pool == NULL) { - device_printf(dev, "cannot allocate request pool\n"); + mpt_prt(mpt, "cannot allocate request pool\n"); return (1); } #endif /* - * Create a parent dma tag for this device + * Create a parent dma tag for this device. * - * Align at byte boundaries, limit to 32-bit addressing - * (The chip supports 64-bit addressing, but this driver doesn't) + * Align at byte boundaries, + * Limit to 32-bit addressing for request/reply queues. */ if (mpt_dma_tag_create(mpt, /*parent*/NULL, /*alignment*/1, - /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, + /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, /*nsegments*/BUS_SPACE_MAXSIZE_32BIT, /*maxsegsz*/BUS_SPACE_UNRESTRICTED, /*flags*/0, &mpt->parent_dmat) != 0) { - device_printf(dev, "cannot create parent dma tag\n"); + mpt_prt(mpt, "cannot create parent dma tag\n"); return (1); } /* Create a child tag for reply buffers */ - if (mpt_dma_tag_create(mpt, mpt->parent_dmat, PAGE_SIZE, - 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, - NULL, NULL, PAGE_SIZE, 1, BUS_SPACE_MAXSIZE_32BIT, 0, + if (mpt_dma_tag_create(mpt, mpt->parent_dmat, PAGE_SIZE, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, + NULL, NULL, 2 * PAGE_SIZE, 1, BUS_SPACE_MAXSIZE_32BIT, 0, &mpt->reply_dmat) != 0) { - device_printf(dev, "cannot create a dma tag for replies\n"); + mpt_prt(mpt, "cannot create a dma tag for replies\n"); return (1); } /* Allocate some DMA accessable memory for replies */ if (bus_dmamem_alloc(mpt->reply_dmat, (void **)&mpt->reply, BUS_DMA_NOWAIT, &mpt->reply_dmap) != 0) { - device_printf(dev, "cannot allocate %lu bytes of reply memory\n", - (u_long)PAGE_SIZE); + mpt_prt(mpt, "cannot allocate %lu bytes of reply memory\n", + (u_long) (2 * PAGE_SIZE)); return (1); } @@ -564,39 +702,44 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt) /* Load and lock it into "bus space" */ bus_dmamap_load(mpt->reply_dmat, mpt->reply_dmap, mpt->reply, - PAGE_SIZE, mpt_map_rquest, &mi, 0); + 2 * PAGE_SIZE, mpt_map_rquest, &mi, 0); if (mi.error) { - device_printf(dev, - "error %d loading dma map for DMA reply queue\n", mi.error); + mpt_prt(mpt, "error %d loading dma map for DMA reply queue\n", + mi.error); return (1); } mpt->reply_phys = mi.phys; /* Create a child tag for data buffers */ + + /* + * XXX: we should say that nsegs is 'unrestricted, but that + * XXX: tickles a horrible bug in the busdma code. Instead, + * XXX: we'll derive a reasonable segment limit from MAXPHYS + */ + nsegs = (MAXPHYS / PAGE_SIZE) + 1; if (mpt_dma_tag_create(mpt, mpt->parent_dmat, 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, - NULL, NULL, MAXBSIZE, MPT_SGL_MAX, BUS_SPACE_MAXSIZE_32BIT, 0, + NULL, NULL, MAXBSIZE, nsegs, BUS_SPACE_MAXSIZE_32BIT, 0, &mpt->buffer_dmat) != 0) { - device_printf(dev, - "cannot create a dma tag for data buffers\n"); + mpt_prt(mpt, "cannot create a dma tag for data buffers\n"); return (1); } /* Create a child tag for request buffers */ - if (mpt_dma_tag_create(mpt, mpt->parent_dmat, PAGE_SIZE, - 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, + if (mpt_dma_tag_create(mpt, mpt->parent_dmat, PAGE_SIZE, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MPT_REQ_MEM_SIZE(mpt), 1, BUS_SPACE_MAXSIZE_32BIT, 0, &mpt->request_dmat) != 0) { - device_printf(dev, "cannot create a dma tag for requests\n"); + mpt_prt(mpt, "cannot create a dma tag for requests\n"); return (1); } /* Allocate some DMA accessable memory for requests */ if (bus_dmamem_alloc(mpt->request_dmat, (void **)&mpt->request, BUS_DMA_NOWAIT, &mpt->request_dmap) != 0) { - device_printf(dev, - "cannot allocate %d bytes of request memory\n", + mpt_prt(mpt, "cannot allocate %d bytes of request memory\n", MPT_REQ_MEM_SIZE(mpt)); return (1); } @@ -609,13 +752,15 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt) MPT_REQ_MEM_SIZE(mpt), mpt_map_rquest, &mi, 0); if (mi.error) { - device_printf(dev, - "error %d loading dma map for DMA request queue\n", + mpt_prt(mpt, "error %d loading dma map for DMA request queue\n", mi.error); return (1); } mpt->request_phys = mi.phys; + /* + * Now create per-request dma maps + */ i = 0; pptr = mpt->request_phys; vptr = mpt->request; @@ -636,11 +781,12 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt) error = bus_dmamap_create(mpt->buffer_dmat, 0, &req->dmap); if (error) { - device_printf(dev, - "error %d creating per-cmd DMA maps\n", error); + mpt_prt(mpt, "error %d creating per-cmd DMA maps\n", + error); return (1); } } + return (0); } @@ -655,8 +801,7 @@ mpt_dma_mem_free(struct mpt_softc *mpt) /* Make sure we aren't double destroying */ if (mpt->reply_dmat == 0) { - if (mpt->verbose >= MPT_PRT_DEBUG) - device_printf(mpt->dev,"Already released dma memory\n"); + mpt_lprt(mpt, MPT_PRT_DEBUG, "already released dma memory\n"); return; } diff --git a/sys/dev/mpt/mpt_raid.c b/sys/dev/mpt/mpt_raid.c index c62b3af1d3da..201cc0d1a5af 100644 --- a/sys/dev/mpt/mpt_raid.c +++ b/sys/dev/mpt/mpt_raid.c @@ -31,6 +31,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*- + * Some Breakage and Bug Fixing added later. + * Copyright (c) 2006, by Matthew Jacob + * All Rights Reserved + * + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. + */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -46,6 +54,10 @@ __FBSDID("$FreeBSD$"); #include <cam/cam_sim.h> #include <cam/cam_xpt_sim.h> +#if __FreeBSD_version < 500000 +#include <sys/devicestat.h> +#define GIANT_REQUIRED +#endif #include <cam/cam_periph.h> #include <sys/callout.h> @@ -72,6 +84,7 @@ struct mpt_raid_action_result static mpt_probe_handler_t mpt_raid_probe; static mpt_attach_handler_t mpt_raid_attach; +static mpt_enable_handler_t mpt_raid_enable; static mpt_event_handler_t mpt_raid_event; static mpt_shutdown_handler_t mpt_raid_shutdown; static mpt_reset_handler_t mpt_raid_ioc_reset; @@ -82,6 +95,7 @@ static struct mpt_personality mpt_raid_personality = .name = "mpt_raid", .probe = mpt_raid_probe, .attach = mpt_raid_attach, + .enable = mpt_raid_enable, .event = mpt_raid_event, .reset = mpt_raid_ioc_reset, .shutdown = mpt_raid_shutdown, @@ -99,7 +113,7 @@ static void mpt_terminate_raid_thread(struct mpt_softc *mpt); static void mpt_raid_thread(void *arg); static timeout_t mpt_raid_timer; static timeout_t mpt_raid_quiesce_timeout; -#if UNUSED +#if 0 static void mpt_enable_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol, int enable); #endif @@ -216,10 +230,11 @@ mpt_raid_async(void *callback_arg, u_int32_t code, struct mpt_raid_volume *mpt_vol; cgd = (struct ccb_getdev *)arg; - if (cgd == NULL) + if (cgd == NULL) { break; + } - mpt_lprt(mpt, MPT_PRT_DEBUG, " Callback for %d\n", + mpt_lprt(mpt, MPT_PRT_DEBUG, "Callback for %d\n", cgd->ccb_h.target_id); RAID_VOL_FOREACH(mpt, mpt_vol) { @@ -241,9 +256,9 @@ mpt_raid_async(void *callback_arg, u_int32_t code, int mpt_raid_probe(struct mpt_softc *mpt) { - if (mpt->ioc_page2 == NULL - || mpt->ioc_page2->MaxPhysDisks == 0) + if (mpt->ioc_page2 == NULL || mpt->ioc_page2->MaxPhysDisks == 0) { return (ENODEV); + } return (0); } @@ -259,8 +274,10 @@ mpt_raid_attach(struct mpt_softc *mpt) handler.reply_handler = mpt_raid_reply_handler; error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, &raid_handler_id); - if (error != 0) + if (error != 0) { + mpt_prt(mpt, "Unable to register RAID haandler!\n"); goto cleanup; + } error = mpt_spawn_raid_thread(mpt); if (error != 0) { @@ -268,12 +285,14 @@ mpt_raid_attach(struct mpt_softc *mpt) goto cleanup; } - xpt_setup_ccb(&csa.ccb_h, mpt->path, /*priority*/5); + xpt_setup_ccb(&csa.ccb_h, mpt->path, 5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = AC_FOUND_DEVICE; csa.callback = mpt_raid_async; csa.callback_arg = mpt; + MPTLOCK_2_CAMLOCK(mpt); xpt_action((union ccb *)&csa); + CAMLOCK_2_MPTLOCK(mpt); if (csa.ccb_h.status != CAM_REQ_CMP) { mpt_prt(mpt, "mpt_raid_attach: Unable to register " "CAM async handler.\n"); @@ -286,6 +305,12 @@ cleanup: return (error); } +int +mpt_raid_enable(struct mpt_softc *mpt) +{ + return (0); +} + void mpt_raid_detach(struct mpt_softc *mpt) { @@ -303,7 +328,9 @@ mpt_raid_detach(struct mpt_softc *mpt) csa.event_enable = 0; csa.callback = mpt_raid_async; csa.callback_arg = mpt; + MPTLOCK_2_CAMLOCK(mpt); xpt_action((union ccb *)&csa); + CAMLOCK_2_MPTLOCK(mpt); } static void @@ -339,11 +366,12 @@ mpt_raid_event(struct mpt_softc *mpt, request_t *req, int i; int print_event; - if (msg->Event != MPI_EVENT_INTEGRATED_RAID) - return (/*handled*/0); + if (msg->Event != MPI_EVENT_INTEGRATED_RAID) { + return (0); + } raid_event = (EVENT_DATA_RAID *)&msg->Data; - + mpt_vol = NULL; vol_pg = NULL; if (mpt->raid_volumes != NULL && mpt->ioc_page2 != NULL) { @@ -365,12 +393,11 @@ mpt_raid_event(struct mpt_softc *mpt, request_t *req, } mpt_disk = NULL; - if (raid_event->PhysDiskNum != 0xFF - && mpt->raid_disks != NULL) { - mpt_disk = mpt->raid_disks - + raid_event->PhysDiskNum; - if ((mpt_disk->flags & MPT_RDF_ACTIVE) == 0) + if (raid_event->PhysDiskNum != 0xFF && mpt->raid_disks != NULL) { + mpt_disk = mpt->raid_disks + raid_event->PhysDiskNum; + if ((mpt_disk->flags & MPT_RDF_ACTIVE) == 0) { mpt_disk = NULL; + } } print_event = 1; @@ -396,8 +423,9 @@ mpt_raid_event(struct mpt_softc *mpt, request_t *req, case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED: case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED: mpt->raid_rescan++; - if (mpt_vol != NULL) + if (mpt_vol != NULL) { mpt_vol->flags &= ~(MPT_RVF_UP2DATE|MPT_RVF_ANNOUNCED); + } break; case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: @@ -406,8 +434,9 @@ mpt_raid_event(struct mpt_softc *mpt, request_t *req, case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED: case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: mpt->raid_rescan++; - if (mpt_disk != NULL) + if (mpt_disk != NULL) { mpt_disk->flags &= ~MPT_RDF_UP2DATE; + } break; case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED: mpt->raid_rescan++; @@ -446,13 +475,15 @@ mpt_raid_event(struct mpt_softc *mpt, request_t *req, if (mpt_disk != NULL) mpt_disk_prt(mpt, mpt_disk, ""); else - mpt_prt(mpt, "Volume(%d:%d:%d: "); - mpt_prtc(mpt, "ASC 0x%x, ASCQ 0x%x\n", + mpt_prt(mpt, "Volume(%d:%d:%d: ", + raid_event->VolumeBus, raid_event->VolumeID, + raid_event->PhysDiskNum); + mpt_prtc(mpt, "ASC 0x%x, ASCQ 0x%x)\n", raid_event->ASC, raid_event->ASCQ); } mpt_raid_wakeup(mpt); - return (/*handled*/1); + return (1); } static void @@ -460,29 +491,29 @@ mpt_raid_shutdown(struct mpt_softc *mpt) { struct mpt_raid_volume *mpt_vol; - if (mpt->raid_mwce_setting != MPT_RAID_MWCE_REBUILD_ONLY) + if (mpt->raid_mwce_setting != MPT_RAID_MWCE_REBUILD_ONLY) { return; + } mpt->raid_mwce_setting = MPT_RAID_MWCE_OFF; RAID_VOL_FOREACH(mpt, mpt_vol) { - mpt_verify_mwce(mpt, mpt_vol); } } static int mpt_raid_reply_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame) + uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) { int free_req; if (req == NULL) - return (/*free_reply*/TRUE); + return (TRUE); free_req = TRUE; if (reply_frame != NULL) free_req = mpt_raid_reply_frame_handler(mpt, req, reply_frame); -#if NOTYET +#ifdef NOTYET else if (req->ccb != NULL) { /* Complete Quiesce CCB with error... */ } @@ -498,7 +529,7 @@ mpt_raid_reply_handler(struct mpt_softc *mpt, request_t *req, mpt_free_request(mpt, req); } - return (/*free_reply*/TRUE); + return (TRUE); } /* @@ -507,7 +538,7 @@ mpt_raid_reply_handler(struct mpt_softc *mpt, request_t *req, */ static int mpt_raid_reply_frame_handler(struct mpt_softc *mpt, request_t *req, - MSG_DEFAULT_REPLY *reply_frame) + MSG_DEFAULT_REPLY *reply_frame) { MSG_RAID_ACTION_REPLY *reply; struct mpt_raid_action_result *action_result; @@ -519,27 +550,19 @@ mpt_raid_reply_frame_handler(struct mpt_softc *mpt, request_t *req, switch (rap->Action) { case MPI_RAID_ACTION_QUIESCE_PHYS_IO: - /* - * Parse result, call mpt_start with ccb, - * release device queue. - * COWWWWW - */ + mpt_prt(mpt, "QUIESCE PHYSIO DONE\n"); break; case MPI_RAID_ACTION_ENABLE_PHYS_IO: - /* - * Need additional state for transition to enabled to - * protect against attempts to disable?? - */ + mpt_prt(mpt, "ENABLY PHYSIO DONE\n"); break; default: - action_result = REQ_TO_RAID_ACTION_RESULT(req); - memcpy(&action_result->action_data, &reply->ActionData, - sizeof(action_result->action_data)); - action_result->action_status = reply->ActionStatus; break; } - - return (/*Free Request*/TRUE); + action_result = REQ_TO_RAID_ACTION_RESULT(req); + memcpy(&action_result->action_data, &reply->ActionData, + sizeof(action_result->action_data)); + action_result->action_status = reply->ActionStatus; + return (TRUE); } /* @@ -607,16 +630,11 @@ mpt_spawn_raid_thread(struct mpt_softc *mpt) return (error); } -/* - * Lock is not held on entry. - */ static void mpt_terminate_raid_thread(struct mpt_softc *mpt) { - MPT_LOCK(mpt); if (mpt->raid_thread == NULL) { - MPT_UNLOCK(mpt); return; } mpt->shutdwn_raid = 1; @@ -626,7 +644,6 @@ mpt_terminate_raid_thread(struct mpt_softc *mpt) * for this interlock just for added safety. */ mpt_sleep(mpt, &mpt->raid_thread, PUSER, "thtrm", 0); - MPT_UNLOCK(mpt); } static void @@ -657,7 +674,10 @@ mpt_raid_thread(void *arg) mpt->raid_wakeup = 0; - mpt_refresh_raid_data(mpt); + if (mpt_refresh_raid_data(mpt)) { + mpt_schedule_raid_refresh(mpt); /* XX NOT QUITE RIGHT */ + continue; + } /* * Now that we have our first snapshot of RAID data, @@ -665,7 +685,9 @@ mpt_raid_thread(void *arg) */ if (firstrun) { firstrun = 0; - xpt_release_simq(mpt->phydisk_sim, /*run_queue*/TRUE); + MPTLOCK_2_CAMLOCK(mpt); + xpt_release_simq(mpt->phydisk_sim, TRUE); + CAMLOCK_2_MPTLOCK(mpt); } if (mpt->raid_rescan != 0) { @@ -677,18 +699,19 @@ mpt_raid_thread(void *arg) ccb = malloc(sizeof(*ccb), M_DEVBUF, M_WAITOK); error = xpt_create_path(&path, xpt_periph, - cam_sim_path(mpt->phydisk_sim), - CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD); + cam_sim_path(mpt->phydisk_sim), + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); if (error != CAM_REQ_CMP) { free(ccb, M_DEVBUF); mpt_prt(mpt, "Unable to rescan RAID Bus!\n"); } else { - xpt_setup_ccb(&ccb->ccb_h, path, /*priority*/5); + xpt_setup_ccb(&ccb->ccb_h, path, 5); ccb->ccb_h.func_code = XPT_SCAN_BUS; ccb->ccb_h.cbfcnp = mpt_cam_rescan_callback; ccb->crcn.flags = CAM_FLAG_NONE; + MPTLOCK_2_CAMLOCK(mpt); xpt_action(ccb); + CAMLOCK_2_MPTLOCK(mpt); } } } @@ -764,12 +787,29 @@ mpt_map_physdisk(struct mpt_softc *mpt, union ccb *ccb, u_int *tgt) *tgt = mpt_disk->config_page.PhysDiskID; return (0); } - mpt_lprt(mpt, MPT_PRT_DEBUG, "mpt_map_physdisk(%d) - Not Active\n", + mpt_lprt(mpt, MPT_PRT_DEBUG1, "mpt_map_physdisk(%d) - Not Active\n", ccb->ccb_h.target_id); return (-1); } -#if UNUSED +/* XXX Ignores that there may be multiple busses/IOCs involved. */ +int +mpt_is_raid_volume(struct mpt_softc *mpt, int tgt) +{ + CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol; + CONFIG_PAGE_IOC_2_RAID_VOL *ioc_last_vol; + + ioc_vol = mpt->ioc_page2->RaidVolume; + ioc_last_vol = ioc_vol + mpt->ioc_page2->NumActiveVolumes; + for (;ioc_vol != ioc_last_vol; ioc_vol++) { + if (ioc_vol->VolumeID == tgt) { + return (1); + } + } + return (0); +} + +#if 0 static void mpt_enable_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol, int enable) @@ -845,10 +885,9 @@ mpt_verify_mwce(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol) */ switch (mpt->raid_mwce_setting) { case MPT_RAID_MWCE_REBUILD_ONLY: - if ((resyncing && mwce) - || (!resyncing && !mwce)) + if ((resyncing && mwce) || (!resyncing && !mwce)) { return; - + } mpt_vol->flags ^= MPT_RVF_WCE_CHANGED; if ((mpt_vol->flags & MPT_RVF_WCE_CHANGED) == 0) { /* @@ -903,7 +942,6 @@ mpt_verify_mwce(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol) vol_pg->VolumeSettings.Settings ^= MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE; } - mpt_free_request(mpt, req); } @@ -1215,7 +1253,7 @@ mpt_refresh_raid_vol(struct mpt_softc *mpt, struct mpt_raid_volume *mpt_vol, * be updated by our event handler. Interesting changes are displayed * to the console. */ -void +int mpt_refresh_raid_data(struct mpt_softc *mpt) { CONFIG_PAGE_IOC_2_RAID_VOL *ioc_vol; @@ -1226,19 +1264,23 @@ mpt_refresh_raid_data(struct mpt_softc *mpt) size_t len; int rv; int i; + u_int nonopt_volumes; - if (mpt->ioc_page2 == NULL || mpt->ioc_page3 == NULL) - return; + if (mpt->ioc_page2 == NULL || mpt->ioc_page3 == NULL) { + return (0); + } /* - * Mark all items as unreferrened by the configuration. + * Mark all items as unreferenced by the configuration. * This allows us to find, report, and discard stale * entries. */ - for (i = 0; i < mpt->ioc_page2->MaxPhysDisks; i++) + for (i = 0; i < mpt->ioc_page2->MaxPhysDisks; i++) { mpt->raid_disks[i].flags &= ~MPT_RDF_REFERENCED; - for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) + } + for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) { mpt->raid_volumes[i].flags &= ~MPT_RVF_REFERENCED; + } /* * Get Physical Disk information. @@ -1248,9 +1290,9 @@ mpt_refresh_raid_data(struct mpt_softc *mpt) &mpt->ioc_page3->Header, len, /*sleep_ok*/TRUE, /*timeout_ms*/5000); if (rv) { - mpt_prt(mpt, "mpt_refresh_raid_data: " - "Failed to read IOC Page 3\n"); - return; + mpt_prt(mpt, + "mpt_refresh_raid_data: Failed to read IOC Page 3\n"); + return (-1); } ioc_disk = mpt->ioc_page3->PhysDisk; @@ -1280,7 +1322,7 @@ mpt_refresh_raid_data(struct mpt_softc *mpt) if (rv) { mpt_prt(mpt, "mpt_refresh_raid_data: " "Failed to read IOC Page 2\n"); - return; + return (-1); } ioc_vol = mpt->ioc_page2->RaidVolume; @@ -1303,6 +1345,7 @@ mpt_refresh_raid_data(struct mpt_softc *mpt) mpt_vol->flags |= MPT_RVF_ACTIVE; } + nonopt_volumes = 0; for (i = 0; i < mpt->ioc_page2->MaxVolumes; i++) { struct mpt_raid_volume *mpt_vol; uint64_t total; @@ -1329,6 +1372,10 @@ mpt_refresh_raid_data(struct mpt_softc *mpt) mpt_vol->flags |= MPT_RVF_ANNOUNCED; } + if (vol_pg->VolumeStatus.State != + MPI_RAIDVOL0_STATUS_STATE_OPTIMAL) + nonopt_volumes++; + if ((mpt_vol->flags & MPT_RVF_UP2DATE) != 0) continue; @@ -1380,9 +1427,15 @@ mpt_refresh_raid_data(struct mpt_softc *mpt) mpt_vol_prt(mpt, mpt_vol, "%s Priority Re-Sync\n", prio ? "High" : "Low"); } +#if __FreeBSD_version >= 500000 mpt_vol_prt(mpt, mpt_vol, "%ju of %ju " "blocks remaining\n", (uintmax_t)left, (uintmax_t)total); +#else + mpt_vol_prt(mpt, mpt_vol, "%llu of %llu " + "blocks remaining\n", (uint64_t)left, + (uint64_t)total); +#endif /* Periodically report on sync progress. */ mpt_schedule_raid_refresh(mpt); @@ -1436,6 +1489,9 @@ mpt_refresh_raid_data(struct mpt_softc *mpt) } mpt_prtc(mpt, " )\n"); } + + mpt->raid_nonopt_volumes = nonopt_volumes; + return (0); } static void @@ -1463,6 +1519,39 @@ mpt_schedule_raid_refresh(struct mpt_softc *mpt) mpt_raid_timer, mpt); } +void +mpt_raid_free_mem(struct mpt_softc *mpt) +{ + + if (mpt->raid_volumes) { + struct mpt_raid_volume *mpt_raid; + int i; + for (i = 0; i < mpt->raid_max_volumes; i++) { + mpt_raid = &mpt->raid_volumes[i]; + if (mpt_raid->config_page) { + free(mpt_raid->config_page, M_DEVBUF); + mpt_raid->config_page = NULL; + } + } + free(mpt->raid_volumes, M_DEVBUF); + mpt->raid_volumes = NULL; + } + if (mpt->raid_disks) { + free(mpt->raid_disks, M_DEVBUF); + mpt->raid_disks = NULL; + } + if (mpt->ioc_page2) { + free(mpt->ioc_page2, M_DEVBUF); + mpt->ioc_page2 = NULL; + } + if (mpt->ioc_page3) { + free(mpt->ioc_page3, M_DEVBUF); + mpt->ioc_page3 = NULL; + } + mpt->raid_max_volumes = 0; + mpt->raid_max_disks = 0; +} + static int mpt_raid_set_vol_resync_rate(struct mpt_softc *mpt, u_int rate) { @@ -1476,8 +1565,9 @@ mpt_raid_set_vol_resync_rate(struct mpt_softc *mpt, u_int rate) MPT_LOCK(mpt); mpt->raid_resync_rate = rate; RAID_VOL_FOREACH(mpt, mpt_vol) { - if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0) + if ((mpt_vol->flags & MPT_RVF_ACTIVE) == 0) { continue; + } mpt_verify_resync_rate(mpt, mpt_vol); } MPT_UNLOCK(mpt); @@ -1489,8 +1579,7 @@ mpt_raid_set_vol_queue_depth(struct mpt_softc *mpt, u_int vol_queue_depth) { struct mpt_raid_volume *mpt_vol; - if (vol_queue_depth > 255 - || vol_queue_depth < 1) + if (vol_queue_depth > 255 || vol_queue_depth < 1) return (EINVAL); MPT_LOCK(mpt); @@ -1593,24 +1682,28 @@ mpt_raid_sysctl_vol_member_wce(SYSCTL_HANDLER_ARGS) u_int i; GIANT_REQUIRED; + mpt = (struct mpt_softc *)arg1; str = mpt_vol_mwce_strs[mpt->raid_mwce_setting]; error = SYSCTL_OUT(req, str, strlen(str) + 1); - if (error || !req->newptr) + if (error || !req->newptr) { return (error); + } size = req->newlen - req->newidx; - if (size >= sizeof(inbuf)) + if (size >= sizeof(inbuf)) { return (EINVAL); + } error = SYSCTL_IN(req, inbuf, size); - if (error) + if (error) { return (error); + } inbuf[size] = '\0'; for (i = 0; i < NUM_ELEMENTS(mpt_vol_mwce_strs); i++) { - - if (strcmp(mpt_vol_mwce_strs[i], inbuf) == 0) + if (strcmp(mpt_vol_mwce_strs[i], inbuf) == 0) { return (mpt_raid_set_vol_mwce(mpt, i)); + } } return (EINVAL); } @@ -1623,12 +1716,14 @@ mpt_raid_sysctl_vol_resync_rate(SYSCTL_HANDLER_ARGS) int error; GIANT_REQUIRED; + mpt = (struct mpt_softc *)arg1; raid_resync_rate = mpt->raid_resync_rate; error = sysctl_handle_int(oidp, &raid_resync_rate, 0, req); - if (error || !req->newptr) + if (error || !req->newptr) { return error; + } return (mpt_raid_set_vol_resync_rate(mpt, raid_resync_rate)); } @@ -1641,12 +1736,14 @@ mpt_raid_sysctl_vol_queue_depth(SYSCTL_HANDLER_ARGS) int error; GIANT_REQUIRED; + mpt = (struct mpt_softc *)arg1; raid_queue_depth = mpt->raid_queue_depth; error = sysctl_handle_int(oidp, &raid_queue_depth, 0, req); - if (error || !req->newptr) + if (error || !req->newptr) { return error; + } return (mpt_raid_set_vol_queue_depth(mpt, raid_queue_depth)); } @@ -1654,6 +1751,7 @@ mpt_raid_sysctl_vol_queue_depth(SYSCTL_HANDLER_ARGS) static void mpt_raid_sysctl_attach(struct mpt_softc *mpt) { +#if __FreeBSD_version >= 500000 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(mpt->dev); struct sysctl_oid *tree = device_get_sysctl_tree(mpt->dev); @@ -1671,4 +1769,9 @@ mpt_raid_sysctl_attach(struct mpt_softc *mpt) "vol_resync_rate", CTLTYPE_INT | CTLFLAG_RW, mpt, 0, mpt_raid_sysctl_vol_resync_rate, "I", "volume resync priority (0 == NC, 1 - 255)"); + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "nonoptimal_volumes", CTLFLAG_RD, + &mpt->raid_nonopt_volumes, 0, + "number of nonoptimal volumes"); +#endif } diff --git a/sys/dev/mpt/mpt_raid.h b/sys/dev/mpt/mpt_raid.h index 310ac6df6d8c..1bd41018ef9c 100644 --- a/sys/dev/mpt/mpt_raid.h +++ b/sys/dev/mpt/mpt_raid.h @@ -32,6 +32,14 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*- + * Some Breakage and Bug Fixing added later. + * Copyright (c) 2006, by Matthew Jacob + * All Rights Reserved + * + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. + */ #ifndef _MPT_RAID_H_ #define _MPT_RAID_H_ @@ -45,30 +53,28 @@ typedef enum { MPT_RAID_MWCE_NC } mpt_raid_mwce_t; -const char * - mpt_vol_type(struct mpt_raid_volume *); -const char * - mpt_vol_state(struct mpt_raid_volume *); -const char * - mpt_disk_state(struct mpt_raid_disk *); -void mpt_vol_prt(struct mpt_softc *, struct mpt_raid_volume *, - const char *fmt, ...); -void mpt_disk_prt(struct mpt_softc *mpt, struct mpt_raid_disk *disk, - const char *fmt, ...); +const char *mpt_vol_type(struct mpt_raid_volume *); +const char *mpt_vol_state(struct mpt_raid_volume *); +const char *mpt_disk_state(struct mpt_raid_disk *); +void +mpt_vol_prt(struct mpt_softc *, struct mpt_raid_volume *, const char *fmt, ...); +void +mpt_disk_prt(struct mpt_softc *, struct mpt_raid_disk *, const char *, ...); + +int +mpt_issue_raid_req(struct mpt_softc *, struct mpt_raid_volume *, + struct mpt_raid_disk *, request_t *, u_int, uint32_t, bus_addr_t, + bus_size_t, int, int); -int mpt_issue_raid_req(struct mpt_softc *mpt, struct mpt_raid_volume *vol, - struct mpt_raid_disk *disk, request_t *req, - u_int Action, uint32_t ActionDataWord, - bus_addr_t addr, bus_size_t len, int write, - int wait); cam_status - mpt_map_physdisk(struct mpt_softc *mpt, union ccb *, u_int *tgt); +mpt_map_physdisk(struct mpt_softc *, union ccb *, target_id_t *); +int mpt_is_raid_volume(struct mpt_softc *, int); cam_status - mpt_raid_quiesce_disk(struct mpt_softc *mpt, - struct mpt_raid_disk *mpt_disk, - request_t *req); -void mpt_refresh_raid_data(struct mpt_softc *); -void mpt_schedule_raid_refresh(struct mpt_softc *mpt); +mpt_raid_quiesce_disk(struct mpt_softc *, struct mpt_raid_disk *, request_t *); + +int mpt_refresh_raid_data(struct mpt_softc *); +void mpt_schedule_raid_refresh(struct mpt_softc *); +void mpt_raid_free_mem(struct mpt_softc *); static __inline void mpt_raid_wakeup(struct mpt_softc *mpt) diff --git a/sys/dev/mpt/mpt_reg.h b/sys/dev/mpt/mpt_reg.h index 6403b527c596..dca924c84569 100644 --- a/sys/dev/mpt/mpt_reg.h +++ b/sys/dev/mpt/mpt_reg.h @@ -25,8 +25,42 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + */ +/*- + * Copyright (c) 2002, 2006 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon including + * a substantially similar Disclaimer requirement for further binary + * redistribution. + * 3. Neither the names of the above listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF THE COPYRIGHT + * OWNER OR CONTRIBUTOR IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Support from Chris Ellsworth in order to make SAS adapters work + * is gratefully acknowledged. * - * Additional Copyright (c) 2002 by Matthew Jacob under same license. + * Support from LSI-Logic has also gone a great deal toward making this a + * workable subsystem and is gratefully acknowledged. */ #ifndef _MPT_REG_H_ #define _MPT_REG_H_ @@ -94,7 +128,7 @@ enum _MPT_INTR_REQ_BITS { #define MPT_DB_INTR(v) (((v) & MPT_INTR_DB_READY) != 0) #define MPT_REPLY_INTR(v) (((v) & MPT_INTR_REPLY_READY) != 0) -/* Function Maps for INTERRUPT make register */ +/* Function Maps for INTERRUPT mask register */ enum _MPT_INTR_MASK_BITS { MPT_INTR_REPLY_MASK = 0x00000008, MPT_INTR_DB_MASK = 0x00000001 |
