aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/mpt
diff options
context:
space:
mode:
authorMatt Jacob <mjacob@FreeBSD.org>2006-06-08 17:48:35 +0000
committerMatt Jacob <mjacob@FreeBSD.org>2006-06-08 17:48:35 +0000
commit6b80f42341b02a37104092ae84a0614d6b1596f5 (patch)
tree7bc783f955a4e3ddfcc5e2e04685d10fc53caf80 /sys/dev/mpt
parentb803b3447aa4b676c6740e39903d0cbc0fe33593 (diff)
Notes
Diffstat (limited to 'sys/dev/mpt')
-rw-r--r--sys/dev/mpt/mpilib/fc_log.h117
-rw-r--r--sys/dev/mpt/mpilib/mpi.h136
-rw-r--r--sys/dev/mpt/mpilib/mpi_cnfg.h1261
-rw-r--r--sys/dev/mpt/mpilib/mpi_fc.h12
-rw-r--r--sys/dev/mpt/mpilib/mpi_init.h262
-rw-r--r--sys/dev/mpt/mpilib/mpi_ioc.h379
-rw-r--r--sys/dev/mpt/mpilib/mpi_lan.h10
-rw-r--r--sys/dev/mpt/mpilib/mpi_raid.h21
-rw-r--r--sys/dev/mpt/mpilib/mpi_targ.h232
-rw-r--r--sys/dev/mpt/mpilib/mpi_type.h38
-rw-r--r--sys/dev/mpt/mpt.c1158
-rw-r--r--sys/dev/mpt/mpt.h498
-rw-r--r--sys/dev/mpt/mpt_cam.c4144
-rw-r--r--sys/dev/mpt/mpt_cam.h36
-rw-r--r--sys/dev/mpt/mpt_debug.c229
-rw-r--r--sys/dev/mpt/mpt_pci.c305
-rw-r--r--sys/dev/mpt/mpt_raid.c263
-rw-r--r--sys/dev/mpt/mpt_raid.h48
-rw-r--r--sys/dev/mpt/mpt_reg.h38
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