changeset 10740:b13b4915cb81

PSARC/2009/461 Transport Layer Retries (TLR) Support 6647764 Solaris storage driver Transport Layer Retries (TLR) support
author jianfei wang - Sun Microsystems - Beijing China <Jianfei.Wang@Sun.COM>
date Thu, 08 Oct 2009 10:37:32 +0800
parents 01d875748398
children 26a74e07a95b
files usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c usr/src/uts/common/io/scsi/targets/st.c usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h usr/src/uts/common/sys/scsi/impl/services.h usr/src/uts/common/sys/scsi/scsi_pkt.h usr/src/uts/common/sys/scsi/targets/stdef.h
diffstat 7 files changed, 176 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Wed Oct 07 17:26:56 2009 -0700
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Thu Oct 08 10:37:32 2009 +0800
@@ -4829,7 +4829,7 @@
 {
 	uint8_t			scsi_status, scsi_state;
 	uint16_t		ioc_status;
-	uint32_t		xferred, sensecount, loginfo = 0;
+	uint32_t		xferred, sensecount, responsedata, loginfo = 0;
 	struct scsi_pkt		*pkt;
 	struct scsi_arq_status	*arqstat;
 	struct buf		*bp;
@@ -4848,6 +4848,8 @@
 	scsi_state = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->SCSIState);
 	xferred = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->TransferCount);
 	sensecount = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->SenseCount);
+	responsedata = ddi_get32(mpt->m_acc_reply_frame_hdl,
+	    &reply->ResponseInfo);
 
 	if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
 		loginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
@@ -4887,6 +4889,16 @@
 		return;
 	}
 
+	if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
+		responsedata &= 0x000000FF;
+		if (responsedata & MPTSAS_SCSI_RESPONSE_CODE_TLR_OFF) {
+			mptsas_log(mpt, CE_NOTE, "Do not support the TLR\n");
+			pkt->pkt_reason = CMD_TLR_OFF;
+			return;
+		}
+	}
+
+
 	switch (scsi_status) {
 	case MPI2_SCSI_STATUS_CHECK_CONDITION:
 		pkt->pkt_resid = (cmd->cmd_dmacount - xferred);
@@ -7520,6 +7532,10 @@
 		control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
 	}
 
+	if (cmd->cmd_pkt_flags & FLAG_TLR) {
+		control |= MPI2_SCSIIO_CONTROL_TLR_ON;
+	}
+
 	mem = mpt->m_req_frame + (mpt->m_req_frame_size * SMID);
 	io_request = (pMpi2SCSIIORequest_t)mem;
 
@@ -8618,6 +8634,13 @@
 	case SCSI_CAP_INTERCONNECT_TYPE:
 		rval = INTERCONNECT_SAS;
 		break;
+	case SCSI_CAP_TRAN_LAYER_RETRIES:
+		if (mpt->m_ioc_capabilities &
+		    MPI2_IOCFACTS_CAPABILITY_TLR)
+			rval = TRUE;
+		else
+			rval = FALSE;
+		break;
 	default:
 		rval = UNDEFINED;
 		break;
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c	Wed Oct 07 17:26:56 2009 -0700
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_init.c	Thu Oct 08 10:37:32 2009 +0800
@@ -267,6 +267,8 @@
 	 */
 	mpt->m_max_chain_depth = ddi_get8(accessp,
 	    &factsreply->MaxChainDepth);
+	mpt->m_ioc_capabilities = ddi_get32(accessp,
+	    &factsreply->IOCCapabilities);
 
 	/*
 	 * Calculate max frames per request based on DMA S/G length.
--- a/usr/src/uts/common/io/scsi/targets/st.c	Wed Oct 07 17:26:56 2009 -0700
+++ b/usr/src/uts/common/io/scsi/targets/st.c	Thu Oct 08 10:37:32 2009 +0800
@@ -646,6 +646,10 @@
 static void st_reset_notification(caddr_t arg);
 static const cmd_attribute *st_lookup_cmd_attribute(unsigned char cmd);
 
+static int st_set_target_TLR_mode(struct scsi_tape *un, ubufunc_t ubf);
+static int st_make_sure_mode_data_is_correct(struct scsi_tape *un,
+    ubufunc_t ubf);
+
 #ifdef	__x86
 /*
  * routines for I/O in big block size
@@ -1876,6 +1880,35 @@
 		}
 	}
 
+	if (un->un_dp->type != ST_TYPE_INVALID) {
+		int result;
+
+		/* try and enable TLR */
+		un->un_tlr_flag = TLR_SAS_ONE_DEVICE;
+		result = st_set_target_TLR_mode(un, st_uscsi_cmd);
+		if (result == EACCES) {
+			/*
+			 * From attach command failed.
+			 * Set dp type so is run again on open.
+			 */
+			un->un_dp->type = ST_TYPE_INVALID;
+			un->un_tlr_flag = TLR_NOT_KNOWN;
+		} else if (result == 0) {
+			if (scsi_ifgetcap(&un->un_sd->sd_address,
+			    "tran-layer-retries", 1) == -1) {
+				un->un_tlr_flag = TLR_NOT_SUPPORTED;
+				(void) st_set_target_TLR_mode(un, st_uscsi_cmd);
+			} else {
+				un->un_tlr_flag = TLR_SAS_ONE_DEVICE;
+			}
+		} else {
+			un->un_tlr_flag = TLR_NOT_SUPPORTED;
+		}
+	}
+
+
+
+
 	/*
 	 * If we didn't just make up this configuration and
 	 * all the density codes are the same..
@@ -9062,6 +9095,7 @@
 	} else {
 		pkt->pkt_comp = st_intr;
 	}
+
 	st_add_recovery_info_to_pkt(un, bp, pkt);
 exit:
 	ASSERT(mutex_owned(ST_MUTEX));
@@ -16866,11 +16900,7 @@
 			un->un_rsvd_status &= ~(ST_RELEASE | ST_LOST_RESERVE |
 			    ST_RESERVATION_CONFLICT | ST_INITIATED_RESET);
 		}
-		rval = st_check_mode_for_change(un, st_uscsi_rcmd);
-		if (rval) {
-			rval = st_gen_mode_select(un, st_uscsi_rcmd,
-			    un->un_mspl, sizeof (struct seq_mode));
-		}
+		rval = st_make_sure_mode_data_is_correct(un, st_uscsi_rcmd);
 		if (rval) {
 			st_recov_ret(un, errinfo, COMMAND_DONE_ERROR);
 			return;
@@ -16887,14 +16917,8 @@
 			/*
 			 * See if mode sense changed.
 			 */
-			rval = st_check_mode_for_change(un, st_uscsi_rcmd);
-			if (rval) {
-				/*
-				 * If so change it back.
-				 */
-				rval = st_gen_mode_select(un, st_uscsi_rcmd,
-				    un->un_mspl, sizeof (struct seq_mode));
-			}
+			rval = st_make_sure_mode_data_is_correct(un,
+			    st_uscsi_rcmd);
 			if (rval) {
 				st_recov_ret(un, errinfo, COMMAND_DONE_ERROR);
 				return;
@@ -17455,6 +17479,27 @@
 }
 
 static int
+st_make_sure_mode_data_is_correct(struct scsi_tape *un, ubufunc_t ubf)
+{
+	int rval;
+
+	ST_FUNC(ST_DEVINFO, st_make_sure_mode_data_is_correct);
+
+	/*
+	 * check to see if mode data has changed.
+	 */
+	rval = st_check_mode_for_change(un, ubf);
+	if (rval) {
+		rval = st_gen_mode_select(un, ubf, un->un_mspl,
+		    sizeof (struct seq_mode));
+	}
+	if (un->un_tlr_flag != TLR_NOT_SUPPORTED) {
+		rval |= st_set_target_TLR_mode(un, ubf);
+	}
+	return (rval);
+}
+
+static int
 st_check_mode_for_change(struct scsi_tape *un, ubufunc_t ubf)
 {
 	struct seq_mode *current;
@@ -18412,6 +18457,60 @@
 	return (rval);
 }
 
+#define	SAS_TLR_MOD_LEN sizeof (struct seq_mode)
+static int
+st_set_target_TLR_mode(struct scsi_tape *un, ubufunc_t ubf)
+{
+	int ret;
+	int amount = SAS_TLR_MOD_LEN;
+	struct seq_mode *mode_data;
+
+	ST_FUNC(ST_DEVINFO, st_set_target_TLR_mode);
+
+	mode_data = kmem_zalloc(SAS_TLR_MOD_LEN, KM_SLEEP);
+	ret = st_gen_mode_sense(un, ubf, 0x18, mode_data, amount);
+	if (ret != DDI_SUCCESS) {
+		if (ret != EACCES)
+			un->un_tlr_flag = TLR_NOT_SUPPORTED;
+		goto out;
+	}
+	if (mode_data->data_len != amount + 1) {
+		amount = mode_data->data_len + 1;
+	}
+	/* Must be SAS protocol */
+	if (mode_data->page.saslun.protocol_id != 6) {
+		un->un_tlr_flag = TLR_NOT_SUPPORTED;
+		ret = ENOTSUP;
+		goto out;
+	}
+	if (un->un_tlr_flag == TLR_SAS_ONE_DEVICE) {
+		if (mode_data->page.saslun.tran_layer_ret == 1)
+			goto out;
+		mode_data->page.saslun.tran_layer_ret = 1;
+	} else {
+		if (mode_data->page.saslun.tran_layer_ret == 0)
+			goto out;
+		mode_data->page.saslun.tran_layer_ret = 0;
+	}
+	ret = st_gen_mode_select(un, ubf, mode_data, amount);
+	if (ret != DDI_SUCCESS) {
+		if (ret != EACCES)
+			un->un_tlr_flag = TLR_NOT_SUPPORTED;
+	} else {
+		if (mode_data->page.saslun.tran_layer_ret == 0)
+			un->un_tlr_flag = TLR_NOT_KNOWN;
+		else
+			un->un_tlr_flag = TLR_SAS_ONE_DEVICE;
+	}
+#ifdef STDEBUG
+	st_clean_print(ST_DEVINFO, st_label, SCSI_DEBUG, "TLR data sent",
+	    (char *)mode_data, amount);
+#endif
+out:
+	kmem_free(mode_data, SAS_TLR_MOD_LEN);
+	return (ret);
+}
+
 
 static void
 st_reset_notification(caddr_t arg)
--- a/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Wed Oct 07 17:26:56 2009 -0700
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Thu Oct 08 10:37:32 2009 +0800
@@ -725,6 +725,7 @@
 	uint32_t	m_free_index;
 	uint32_t	m_post_index;
 	uint8_t		m_reply_frame_size;
+	uint32_t	m_ioc_capabilities;
 
 	/*
 	 * indicates if the firmware was upload by the driver
@@ -1135,6 +1136,11 @@
 #define	MPTSAS_CMD_TIMEOUT		0x0010
 
 /*
+ * response code tlr flag
+ */
+#define	MPTSAS_SCSI_RESPONSE_CODE_TLR_OFF	0x02
+
+/*
  * System Events
  */
 #ifndef	DDI_VENDOR_LSI
--- a/usr/src/uts/common/sys/scsi/impl/services.h	Wed Oct 07 17:26:56 2009 -0700
+++ b/usr/src/uts/common/sys/scsi/impl/services.h	Thu Oct 08 10:37:32 2009 +0800
@@ -127,6 +127,7 @@
 #define	SCSI_CAP_LUN_RESET		19
 #define	SCSI_CAP_CDB_LEN		20
 #define	SCSI_CAP_DMA_MAX_ARCH		21
+#define	SCSI_CAP_TRAN_LAYER_RETRIES	22
 #define	SCSI_CAP_ASCII		{					\
 		"dma-max", "msg-out", "disconnect", "synchronous",	\
 		"wide-xfer", "parity", "initiator-id", "untagged-qing",	\
@@ -135,7 +136,8 @@
 		"reset-notification", "qfull-retries",			\
 		"qfull-retry-interval", "scsi-version",			\
 		"interconnect-type", "lun-reset",			\
-		"max-cdb-length", "dma-max-arch", NULL }
+		"max-cdb-length", "dma-max-arch",			\
+		"tran-layer-retries", NULL }
 
 /*
  * Definitions used by some capabilities
--- a/usr/src/uts/common/sys/scsi/scsi_pkt.h	Wed Oct 07 17:26:56 2009 -0700
+++ b/usr/src/uts/common/sys/scsi/scsi_pkt.h	Thu Oct 08 10:37:32 2009 +0800
@@ -163,6 +163,12 @@
 #define	FLAG_ISOLATE		0x00040000
 
 /*
+ * pkg_flag for TLR
+ */
+#define	FLAG_TLR		0x00080000
+
+
+/*
  * Following define is for scsi_vhci.
  *   NOQUEUE            If pHCI cannot transport the command to the device,
  *                      do not queue the pkt in pHCI. Return immediately with
@@ -194,6 +200,7 @@
 #define	CMD_CMD_OVR	8	/* Command Overrun */
 #define	CMD_STS_OVR	9	/* Status Overrun */
 #define	CMD_TERMINATED	22	/* Command transport terminated on request */
+#define	CMD_TLR_OFF	23	/* don't support TLR */
 
 /*
  * Following defines are appropriate for SCSI parallel bus.
--- a/usr/src/uts/common/sys/scsi/targets/stdef.h	Wed Oct 07 17:26:56 2009 -0700
+++ b/usr/src/uts/common/sys/scsi/targets/stdef.h	Thu Oct 08 10:37:32 2009 +0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -508,9 +508,23 @@
 #endif
 };
 
+struct sas_lun_mode {
+#if defined(_BIT_FIELDS_HTOL)
+	uchar_t :		3,
+		tran_layer_ret:	1,
+		protocol_id:	4;
+	uchar_t reserved[5];
+#elif defined(_BIT_FIELDS_LTOH)
+	uchar_t protocol_id:	4,
+		tran_layer_ret:	1,
+		:		3;
+	uchar_t reserved[5];
+#endif
+};
 typedef union {
 	struct comp_mode_page	comp;
 	struct dev_mode_page	dev;
+	struct sas_lun_mode	saslun;
 }modepage;
 
 /*
@@ -926,6 +940,12 @@
 }st_states;
 
 typedef enum { RDWR, RDONLY, WORM, RDWORM, FAILED } writablity;
+typedef enum {
+	TLR_NOT_KNOWN,
+	TLR_NOT_SUPPORTED,
+	TLR_SAS_ONE_DEVICE,
+	TLR_SAS_TWO_DEVICE
+}st_tlr_state;
 
 
 /*
@@ -1023,7 +1043,6 @@
 	read_pos_data_t *un_read_pos_data;
 	struct mterror_entry_stack *un_error_entry_stk;
 					/* latest sense cmd buffer */
-
 #ifdef	__x86
 	ddi_dma_handle_t un_contig_mem_hdl;
 	struct contig_mem *un_contig_mem;
@@ -1048,6 +1067,7 @@
 	uchar_t un_unit_attention_flags;
 	uchar_t un_multipath;
 	ulong_t un_last_path_instance;
+	st_tlr_state un_tlr_flag;		/* tape support TLR flag */
 };
 
 typedef int (*bufunc_t)(struct scsi_tape *, int, int64_t, int);