--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Tue Jun 17 10:45:12 2014
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Tue Jun 17 10:45:12 2014
@@ -24,6 +24,7 @@
  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
  */
 
 /*
@@ -245,7 +246,7 @@
 static void mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd);
 static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply,
     uint8_t *data, uint32_t request_size, uint32_t reply_size,
-    uint32_t data_size, uint32_t direction, uint8_t *dataout,
+    uint32_t data_size, uint8_t direction, uint8_t *dataout,
     uint32_t dataout_size, short timeout, int mode);
 static int mptsas_free_devhdl(mptsas_t *mpt, uint16_t devhdl);
 
@@ -491,7 +492,7 @@
 	0xffffffffull,	/* max segment size (DMA boundary)	*/
 	MPTSAS_MAX_DMA_SEGS, /* scatter/gather list length	*/
 	512,		/* granularity - device transfer size	*/
-	DDI_DMA_RELAXED_ORDERING	/* flags, enable relaxed ordering */
+	0		/* flags, set to 0 */
 };
 
 ddi_device_acc_attr_t mptsas_dev_attr = {
@@ -569,7 +570,7 @@
  * Local static data
  */
 #if defined(MPTSAS_DEBUG)
-uint32_t mptsas_debug_flags = 0;
+uint32_t mptsas_debug_flags = 0x0;
 #endif	/* defined(MPTSAS_DEBUG) */
 uint32_t mptsas_debug_resets = 0;
 
@@ -587,7 +588,21 @@
 static timeout_id_t mptsas_reset_watch;
 static timeout_id_t mptsas_timeout_id;
 static int mptsas_timeouts_enabled = 0;
+
 /*
+ * The only software retriction on switching msg buffers to 64 bit seems to
+ * be the Auto Request Sense interface. The high 32 bits for all such
+ * requests appear to be required to sit in the same 4G segment.
+ * See initialization of SenseBufferAddressHigh in mptsas_init.c, and
+ * the use of SenseBufferLowAddress in requests. Note that there is
+ * currently a dependency on scsi_alloc_consistent_buf() adhering to
+ * this requirement.
+ * There is also a question about improved performance over PCI/PCIX
+ * if transfers are within the first 4Gb.
+ */
+static int mptsas_use_64bit_msgaddr = 0;
+
+/*
  * warlock directives
  */
 _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt \
@@ -1165,7 +1180,11 @@
 
 	/* Make a per-instance copy of the structures */
 	mpt->m_io_dma_attr = mptsas_dma_attrs64;
-	mpt->m_msg_dma_attr = mptsas_dma_attrs;
+	if (mptsas_use_64bit_msgaddr) {
+		mpt->m_msg_dma_attr = mptsas_dma_attrs64;
+	} else {
+		mpt->m_msg_dma_attr = mptsas_dma_attrs;
+	}
 	mpt->m_reg_acc_attr = mptsas_dev_attr;
 	mpt->m_dev_acc_attr = mptsas_dev_attr;
 
@@ -1261,6 +1280,15 @@
 		doneq_thread_create++;
 	}
 
+	/*
+	 * Disable hardware interrupt since we're not ready to
+	 * handle it yet.
+	 */
+	MPTSAS_DISABLE_INTR(mpt);
+	if (mptsas_register_intrs(mpt) == FALSE)
+		goto fail;
+	intr_added++;
+
 	/* Initialize mutex used in interrupt handler */
 	mutex_init(&mpt->m_mutex, NULL, MUTEX_DRIVER,
 	    DDI_INTR_PRI(mpt->m_intr_pri));
@@ -1280,15 +1308,6 @@
 	cv_init(&mpt->m_fw_diag_cv, NULL, CV_DRIVER, NULL);
 	mutex_init_done++;
 
-	/*
-	 * Disable hardware interrupt since we're not ready to
-	 * handle it yet.
-	 */
-	MPTSAS_DISABLE_INTR(mpt);
-	if (mptsas_register_intrs(mpt) == FALSE)
-		goto fail;
-	intr_added++;
-
 	mutex_enter(&mpt->m_mutex);
 	/*
 	 * Initialize power management component
@@ -2222,7 +2241,7 @@
 	 */
 	(void) sprintf(buf, "mptsas%d_cache", instance);
 	mpt->m_kmem_cache = kmem_cache_create(buf,
-	    sizeof (struct mptsas_cmd) + scsi_pkt_size(), 8,
+	    sizeof (struct mptsas_cmd) + scsi_pkt_size(), 16,
 	    mptsas_kmem_cache_constructor, mptsas_kmem_cache_destructor,
 	    NULL, (void *)mpt, NULL, 0);
 
@@ -2237,7 +2256,7 @@
 	 */
 	(void) sprintf(buf, "mptsas%d_cache_frames", instance);
 	mpt->m_cache_frames = kmem_cache_create(buf,
-	    sizeof (mptsas_cache_frames_t), 8,
+	    sizeof (mptsas_cache_frames_t), 16,
 	    mptsas_cache_frames_constructor, mptsas_cache_frames_destructor,
 	    NULL, (void *)mpt, NULL, 0);
 
@@ -3971,7 +3990,7 @@
 	 * address to dma to and from the driver.  The second
 	 * address is the address mpt uses to fill in the SGL.
 	 */
-	p->m_phys_addr = cookie.dmac_address;
+	p->m_phys_addr = cookie.dmac_laddress;
 
 	return (DDI_SUCCESS);
 }
@@ -4178,167 +4197,324 @@
 }
 
 static void
-mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control,
-	pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+mptsas_sge_mainframe(mptsas_cmd_t *cmd, pMpi2SCSIIORequest_t frame,
+		ddi_acc_handle_t acc_hdl, uint_t cookiec,
+		uint32_t end_flags)
 {
-	uint_t			cookiec;
+	pMpi2SGESimple64_t	sge;
 	mptti_t			*dmap;
 	uint32_t		flags;
+
+	dmap = cmd->cmd_sg;
+
+	sge = (pMpi2SGESimple64_t)(&frame->SGL);
+	while (cookiec--) {
+		ddi_put32(acc_hdl, &sge->Address.Low,
+		    dmap->addr.address64.Low);
+		ddi_put32(acc_hdl, &sge->Address.High,
+		    dmap->addr.address64.High);
+		ddi_put32(acc_hdl, &sge->FlagsLength, dmap->count);
+		flags = ddi_get32(acc_hdl, &sge->FlagsLength);
+		flags |= ((uint32_t)
+		    (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+		    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+		    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+		    MPI2_SGE_FLAGS_SHIFT);
+
+		/*
+		 * If this is the last cookie, we set the flags
+		 * to indicate so
+		 */
+		if (cookiec == 0) {
+			flags |= end_flags;
+		}
+		if (cmd->cmd_flags & CFLAG_DMASEND) {
+			flags |= (MPI2_SGE_FLAGS_HOST_TO_IOC <<
+			    MPI2_SGE_FLAGS_SHIFT);
+		} else {
+			flags |= (MPI2_SGE_FLAGS_IOC_TO_HOST <<
+			    MPI2_SGE_FLAGS_SHIFT);
+		}
+		ddi_put32(acc_hdl, &sge->FlagsLength, flags);
+		dmap++;
+		sge++;
+	}
+}
+
+static void
+mptsas_sge_chain(mptsas_t *mpt, mptsas_cmd_t *cmd,
+    pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+{
 	pMpi2SGESimple64_t	sge;
 	pMpi2SGEChain64_t	sgechain;
-	ASSERT(cmd->cmd_flags & CFLAG_DMAVALID);
+	uint64_t		nframe_phys_addr;
+	uint_t			cookiec;
+	mptti_t			*dmap;
+	uint32_t		flags;
+	int			i, j, k, l, frames, sgemax;
+	int			temp, maxframe_sges;
+	uint8_t			chainflags;
+	uint16_t		chainlength;
+	mptsas_cache_frames_t	*p;
 
+	cookiec = cmd->cmd_cookiec;
+
 	/*
-	 * Save the number of entries in the DMA
-	 * Scatter/Gather list
+	 * Hereby we start to deal with multiple frames.
+	 * The process is as follows:
+	 * 1. Determine how many frames are needed for SGL element
+	 *    storage; Note that all frames are stored in contiguous
+	 *    memory space and in 64-bit DMA mode each element is
+	 *    3 double-words (12 bytes) long.
+	 * 2. Fill up the main frame. We need to do this separately
+	 *    since it contains the SCSI IO request header and needs
+	 *    dedicated processing. Note that the last 4 double-words
+	 *    of the SCSI IO header is for SGL element storage
+	 *    (MPI2_SGE_IO_UNION).
+	 * 3. Fill the chain element in the main frame, so the DMA
+	 *    engine can use the following frames.
+	 * 4. Enter a loop to fill the remaining frames. Note that the
+	 *    last frame contains no chain element.  The remaining
+	 *    frames go into the mpt SGL buffer allocated on the fly,
+	 *    not immediately following the main message frame, as in
+	 *    Gen1.
+	 * Some restrictions:
+	 * 1. For 64-bit DMA, the simple element and chain element
+	 *    are both of 3 double-words (12 bytes) in size, even
+	 *    though all frames are stored in the first 4G of mem
+	 *    range and the higher 32-bits of the address are always 0.
+	 * 2. On some controllers (like the 1064/1068), a frame can
+	 *    hold SGL elements with the last 1 or 2 double-words
+	 *    (4 or 8 bytes) un-used. On these controllers, we should
+	 *    recognize that there's not enough room for another SGL
+	 *    element and move the sge pointer to the next frame.
 	 */
-	cookiec = cmd->cmd_cookiec;
 
-	NDBG1(("mptsas_sge_setup: cookiec=%d", cookiec));
+	/*
+	 * Sgemax is the number of SGE's that will fit
+	 * each extra frame and frames is total
+	 * number of frames we'll need.  1 sge entry per
+	 * frame is reseverd for the chain element thus the -1 below.
+	 */
+	sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_SGE_SIMPLE64)) - 1);
+	maxframe_sges = MPTSAS_MAX_FRAME_SGES64(mpt);
+	temp = (cookiec - (maxframe_sges - 1)) / sgemax;
 
 	/*
-	 * Set read/write bit in control.
+	 * A little check to see if we need to round up the number
+	 * of frames we need
 	 */
-	if (cmd->cmd_flags & CFLAG_DMASEND) {
-		*control |= MPI2_SCSIIO_CONTROL_WRITE;
+	if ((cookiec - (maxframe_sges - 1)) - (temp * sgemax) > 1) {
+		frames = (temp + 1);
 	} else {
-		*control |= MPI2_SCSIIO_CONTROL_READ;
+		frames = temp;
 	}
+	dmap = cmd->cmd_sg;
+	sge = (pMpi2SGESimple64_t)(&frame->SGL);
 
-	ddi_put32(acc_hdl, &frame->DataLength, cmd->cmd_dmacount);
+	/*
+	 * First fill in the main frame
+	 */
+	j = maxframe_sges - 1;
+	mptsas_sge_mainframe(cmd, frame, acc_hdl, j,
+	    ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT) <<
+	    MPI2_SGE_FLAGS_SHIFT));
+	dmap += j;
+	sge += j;
+	j++;
 
 	/*
-	 * We have 2 cases here.  First where we can fit all the
-	 * SG elements into the main frame, and the case
-	 * where we can't.
-	 * If we have more cookies than we can attach to a frame
-	 * we will need to use a chain element to point
-	 * a location of memory where the rest of the S/G
-	 * elements reside.
+	 * Fill in the chain element in the main frame.
+	 * About calculation on ChainOffset:
+	 * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes)
+	 *    in the end reserved for SGL element storage
+	 *    (MPI2_SGE_IO_UNION); we should count it in our
+	 *    calculation.  See its definition in the header file.
+	 * 2. Constant j is the counter of the current SGL element
+	 *    that will be processed, and (j - 1) is the number of
+	 *    SGL elements that have been processed (stored in the
+	 *    main frame).
+	 * 3. ChainOffset value should be in units of double-words (4
+	 *    bytes) so the last value should be divided by 4.
 	 */
-	if (cookiec <= MPTSAS_MAX_FRAME_SGES64(mpt)) {
-		dmap = cmd->cmd_sg;
-		sge = (pMpi2SGESimple64_t)(&frame->SGL);
-		while (cookiec--) {
-			ddi_put32(acc_hdl,
-			    &sge->Address.Low, dmap->addr.address64.Low);
-			ddi_put32(acc_hdl,
-			    &sge->Address.High, dmap->addr.address64.High);
-			ddi_put32(acc_hdl, &sge->FlagsLength,
-			    dmap->count);
-			flags = ddi_get32(acc_hdl, &sge->FlagsLength);
-			flags |= ((uint32_t)
-			    (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
-			    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
-			    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
-			    MPI2_SGE_FLAGS_SHIFT);
+	ddi_put8(acc_hdl, &frame->ChainOffset,
+	    (sizeof (MPI2_SCSI_IO_REQUEST) -
+	    sizeof (MPI2_SGE_IO_UNION) +
+	    (j - 1) * sizeof (MPI2_SGE_SIMPLE64)) >> 2);
+	sgechain = (pMpi2SGEChain64_t)sge;
+	chainflags = (MPI2_SGE_FLAGS_CHAIN_ELEMENT |
+	    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+	    MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
+	ddi_put8(acc_hdl, &sgechain->Flags, chainflags);
 
+	/*
+	 * The size of the next frame is the accurate size of space
+	 * (in bytes) used to store the SGL elements. j is the counter
+	 * of SGL elements. (j - 1) is the number of SGL elements that
+	 * have been processed (stored in frames).
+	 */
+	if (frames >= 2) {
+		chainlength = mpt->m_req_frame_size /
+		    sizeof (MPI2_SGE_SIMPLE64) *
+		    sizeof (MPI2_SGE_SIMPLE64);
+	} else {
+		chainlength = ((cookiec - (j - 1)) *
+		    sizeof (MPI2_SGE_SIMPLE64));
+	}
+
+	p = cmd->cmd_extra_frames;
+
+	ddi_put16(acc_hdl, &sgechain->Length, chainlength);
+	ddi_put32(acc_hdl, &sgechain->Address.Low,
+	    (p->m_phys_addr&0xffffffffull));
+	ddi_put32(acc_hdl, &sgechain->Address.High, p->m_phys_addr>>32);
+
+	/*
+	 * If there are more than 2 frames left we have to
+	 * fill in the next chain offset to the location of
+	 * the chain element in the next frame.
+	 * sgemax is the number of simple elements in an extra
+	 * frame. Note that the value NextChainOffset should be
+	 * in double-words (4 bytes).
+	 */
+	if (frames >= 2) {
+		ddi_put8(acc_hdl, &sgechain->NextChainOffset,
+		    (sgemax * sizeof (MPI2_SGE_SIMPLE64)) >> 2);
+	} else {
+		ddi_put8(acc_hdl, &sgechain->NextChainOffset, 0);
+	}
+
+	/*
+	 * Jump to next frame;
+	 * Starting here, chain buffers go into the per command SGL.
+	 * This buffer is allocated when chain buffers are needed.
+	 */
+	sge = (pMpi2SGESimple64_t)p->m_frames_addr;
+	i = cookiec;
+
+	/*
+	 * Start filling in frames with SGE's.  If we
+	 * reach the end of frame and still have SGE's
+	 * to fill we need to add a chain element and
+	 * use another frame.  j will be our counter
+	 * for what cookie we are at and i will be
+	 * the total cookiec. k is the current frame
+	 */
+	for (k = 1; k <= frames; k++) {
+		for (l = 1; (l <= (sgemax + 1)) && (j <= i); j++, l++) {
+
 			/*
-			 * If this is the last cookie, we set the flags
-			 * to indicate so
+			 * If we have reached the end of frame
+			 * and we have more SGE's to fill in
+			 * we have to fill the final entry
+			 * with a chain element and then
+			 * continue to the next frame
 			 */
-			if (cookiec == 0) {
-				flags |=
-				    ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT
-				    | MPI2_SGE_FLAGS_END_OF_BUFFER
-				    | MPI2_SGE_FLAGS_END_OF_LIST) <<
-				    MPI2_SGE_FLAGS_SHIFT);
-			}
-			if (cmd->cmd_flags & CFLAG_DMASEND) {
-				flags |= (MPI2_SGE_FLAGS_HOST_TO_IOC <<
-				    MPI2_SGE_FLAGS_SHIFT);
-			} else {
-				flags |= (MPI2_SGE_FLAGS_IOC_TO_HOST <<
-				    MPI2_SGE_FLAGS_SHIFT);
-			}
-			ddi_put32(acc_hdl, &sge->FlagsLength, flags);
-			dmap++;
-			sge++;
-		}
-	} else {
-		/*
-		 * Hereby we start to deal with multiple frames.
-		 * The process is as follows:
-		 * 1. Determine how many frames are needed for SGL element
-		 *    storage; Note that all frames are stored in contiguous
-		 *    memory space and in 64-bit DMA mode each element is
-		 *    3 double-words (12 bytes) long.
-		 * 2. Fill up the main frame. We need to do this separately
-		 *    since it contains the SCSI IO request header and needs
-		 *    dedicated processing. Note that the last 4 double-words
-		 *    of the SCSI IO header is for SGL element storage
-		 *    (MPI2_SGE_IO_UNION).
-		 * 3. Fill the chain element in the main frame, so the DMA
-		 *    engine can use the following frames.
-		 * 4. Enter a loop to fill the remaining frames. Note that the
-		 *    last frame contains no chain element.  The remaining
-		 *    frames go into the mpt SGL buffer allocated on the fly,
-		 *    not immediately following the main message frame, as in
-		 *    Gen1.
-		 * Some restrictions:
-		 * 1. For 64-bit DMA, the simple element and chain element
-		 *    are both of 3 double-words (12 bytes) in size, even
-		 *    though all frames are stored in the first 4G of mem
-		 *    range and the higher 32-bits of the address are always 0.
-		 * 2. On some controllers (like the 1064/1068), a frame can
-		 *    hold SGL elements with the last 1 or 2 double-words
-		 *    (4 or 8 bytes) un-used. On these controllers, we should
-		 *    recognize that there's not enough room for another SGL
-		 *    element and move the sge pointer to the next frame.
-		 */
-		int		i, j, k, l, frames, sgemax;
-		int		temp;
-		uint8_t		chainflags;
-		uint16_t	chainlength;
-		mptsas_cache_frames_t *p;
+			if ((l == (sgemax + 1)) && (k != frames)) {
+				sgechain = (pMpi2SGEChain64_t)sge;
+				j--;
+				chainflags = (
+				    MPI2_SGE_FLAGS_CHAIN_ELEMENT |
+				    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
+				    MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
+				ddi_put8(p->m_acc_hdl,
+				    &sgechain->Flags, chainflags);
+				/*
+				 * k is the frame counter and (k + 1)
+				 * is the number of the next frame.
+				 * Note that frames are in contiguous
+				 * memory space.
+				 */
+				nframe_phys_addr = p->m_phys_addr +
+				    (mpt->m_req_frame_size * k);
+				ddi_put32(p->m_acc_hdl,
+				    &sgechain->Address.Low,
+				    nframe_phys_addr&0xffffffffull);
+				ddi_put32(p->m_acc_hdl,
+				    &sgechain->Address.High,
+				    nframe_phys_addr>>32);
 
-		/*
-		 * Sgemax is the number of SGE's that will fit
-		 * each extra frame and frames is total
-		 * number of frames we'll need.  1 sge entry per
-		 * frame is reseverd for the chain element thus the -1 below.
-		 */
-		sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_SGE_SIMPLE64))
-		    - 1);
-		temp = (cookiec - (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) / sgemax;
+				/*
+				 * If there are more than 2 frames left
+				 * we have to next chain offset to
+				 * the location of the chain element
+				 * in the next frame and fill in the
+				 * length of the next chain
+				 */
+				if ((frames - k) >= 2) {
+					ddi_put8(p->m_acc_hdl,
+					    &sgechain->NextChainOffset,
+					    (sgemax *
+					    sizeof (MPI2_SGE_SIMPLE64))
+					    >> 2);
+					ddi_put16(p->m_acc_hdl,
+					    &sgechain->Length,
+					    mpt->m_req_frame_size /
+					    sizeof (MPI2_SGE_SIMPLE64) *
+					    sizeof (MPI2_SGE_SIMPLE64));
+				} else {
+					/*
+					 * This is the last frame. Set
+					 * the NextChainOffset to 0 and
+					 * Length is the total size of
+					 * all remaining simple elements
+					 */
+					ddi_put8(p->m_acc_hdl,
+					    &sgechain->NextChainOffset,
+					    0);
+					ddi_put16(p->m_acc_hdl,
+					    &sgechain->Length,
+					    (cookiec - j) *
+					    sizeof (MPI2_SGE_SIMPLE64));
+				}
 
-		/*
-		 * A little check to see if we need to round up the number
-		 * of frames we need
-		 */
-		if ((cookiec - (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) - (temp *
-		    sgemax) > 1) {
-			frames = (temp + 1);
-		} else {
-			frames = temp;
-		}
-		dmap = cmd->cmd_sg;
-		sge = (pMpi2SGESimple64_t)(&frame->SGL);
+				/* Jump to the next frame */
+				sge = (pMpi2SGESimple64_t)
+				    ((char *)p->m_frames_addr +
+				    (int)mpt->m_req_frame_size * k);
 
-		/*
-		 * First fill in the main frame
-		 */
-		for (j = 1; j < MPTSAS_MAX_FRAME_SGES64(mpt); j++) {
-			ddi_put32(acc_hdl, &sge->Address.Low,
+				continue;
+			}
+
+			ddi_put32(p->m_acc_hdl,
+			    &sge->Address.Low,
 			    dmap->addr.address64.Low);
-			ddi_put32(acc_hdl, &sge->Address.High,
+			ddi_put32(p->m_acc_hdl,
+			    &sge->Address.High,
 			    dmap->addr.address64.High);
-			ddi_put32(acc_hdl, &sge->FlagsLength, dmap->count);
-			flags = ddi_get32(acc_hdl, &sge->FlagsLength);
-			flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+			ddi_put32(p->m_acc_hdl,
+			    &sge->FlagsLength, dmap->count);
+			flags = ddi_get32(p->m_acc_hdl,
+			    &sge->FlagsLength);
+			flags |= ((uint32_t)(
+			    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
 			    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
 			    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
 			    MPI2_SGE_FLAGS_SHIFT);
 
 			/*
-			 * If this is the last SGE of this frame
-			 * we set the end of list flag
+			 * If we are at the end of the frame and
+			 * there is another frame to fill in
+			 * we set the last simple element as last
+			 * element
 			 */
-			if (j == (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) {
+			if ((l == sgemax) && (k != frames)) {
 				flags |= ((uint32_t)
 				    (MPI2_SGE_FLAGS_LAST_ELEMENT) <<
 				    MPI2_SGE_FLAGS_SHIFT);
 			}
+
+			/*
+			 * If this is the final cookie we
+			 * indicate it by setting the flags
+			 */
+			if (j == i) {
+				flags |= ((uint32_t)
+				    (MPI2_SGE_FLAGS_LAST_ELEMENT |
+				    MPI2_SGE_FLAGS_END_OF_BUFFER |
+				    MPI2_SGE_FLAGS_END_OF_LIST) <<
+				    MPI2_SGE_FLAGS_SHIFT);
+			}
 			if (cmd->cmd_flags & CFLAG_DMASEND) {
 				flags |=
 				    (MPI2_SGE_FLAGS_HOST_TO_IOC <<
@@ -4348,223 +4524,384 @@
 				    (MPI2_SGE_FLAGS_IOC_TO_HOST <<
 				    MPI2_SGE_FLAGS_SHIFT);
 			}
-			ddi_put32(acc_hdl, &sge->FlagsLength, flags);
+			ddi_put32(p->m_acc_hdl,
+			    &sge->FlagsLength, flags);
 			dmap++;
 			sge++;
 		}
+	}
 
-		/*
-		 * Fill in the chain element in the main frame.
-		 * About calculation on ChainOffset:
-		 * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes)
-		 *    in the end reserved for SGL element storage
-		 *    (MPI2_SGE_IO_UNION); we should count it in our
-		 *    calculation.  See its definition in the header file.
-		 * 2. Constant j is the counter of the current SGL element
-		 *    that will be processed, and (j - 1) is the number of
-		 *    SGL elements that have been processed (stored in the
-		 *    main frame).
-		 * 3. ChainOffset value should be in units of double-words (4
-		 *    bytes) so the last value should be divided by 4.
-		 */
-		ddi_put8(acc_hdl, &frame->ChainOffset,
-		    (sizeof (MPI2_SCSI_IO_REQUEST) -
-		    sizeof (MPI2_SGE_IO_UNION) +
-		    (j - 1) * sizeof (MPI2_SGE_SIMPLE64)) >> 2);
-		sgechain = (pMpi2SGEChain64_t)sge;
-		chainflags = (MPI2_SGE_FLAGS_CHAIN_ELEMENT |
-		    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
-		    MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
-		ddi_put8(acc_hdl, &sgechain->Flags, chainflags);
+	/*
+	 * Sync DMA with the chain buffers that were just created
+	 */
+	(void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
 
-		/*
-		 * The size of the next frame is the accurate size of space
-		 * (in bytes) used to store the SGL elements. j is the counter
-		 * of SGL elements. (j - 1) is the number of SGL elements that
-		 * have been processed (stored in frames).
-		 */
-		if (frames >= 2) {
-			chainlength = mpt->m_req_frame_size /
-			    sizeof (MPI2_SGE_SIMPLE64) *
-			    sizeof (MPI2_SGE_SIMPLE64);
-		} else {
-			chainlength = ((cookiec - (j - 1)) *
-			    sizeof (MPI2_SGE_SIMPLE64));
-		}
+static void
+mptsas_ieee_sge_mainframe(mptsas_cmd_t *cmd, pMpi2SCSIIORequest_t frame,
+    ddi_acc_handle_t acc_hdl, uint_t cookiec,
+    uint8_t end_flag)
+{
+	pMpi2IeeeSgeSimple64_t	ieeesge;
+	mptti_t			*dmap;
+	uint8_t			flags;
 
-		p = cmd->cmd_extra_frames;
+	dmap = cmd->cmd_sg;
 
-		ddi_put16(acc_hdl, &sgechain->Length, chainlength);
-		ddi_put32(acc_hdl, &sgechain->Address.Low,
-		    p->m_phys_addr);
-		/* SGL is allocated in the first 4G mem range */
-		ddi_put32(acc_hdl, &sgechain->Address.High, 0);
+	NDBG1(("mptsas_ieee_sge_mainframe: cookiec=%d, %s", cookiec,
+	    cmd->cmd_flags & CFLAG_DMASEND?"Out":"In"));
 
+	ieeesge = (pMpi2IeeeSgeSimple64_t)(&frame->SGL);
+	while (cookiec--) {
+		ddi_put32(acc_hdl, &ieeesge->Address.Low,
+		    dmap->addr.address64.Low);
+		ddi_put32(acc_hdl, &ieeesge->Address.High,
+		    dmap->addr.address64.High);
+		ddi_put32(acc_hdl, &ieeesge->Length, dmap->count);
+		NDBG1(("mptsas_ieee_sge_mainframe: len=%d", dmap->count));
+		flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+		    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+
 		/*
-		 * If there are more than 2 frames left we have to
-		 * fill in the next chain offset to the location of
-		 * the chain element in the next frame.
-		 * sgemax is the number of simple elements in an extra
-		 * frame. Note that the value NextChainOffset should be
-		 * in double-words (4 bytes).
+		 * If this is the last cookie, we set the flags
+		 * to indicate so
 		 */
-		if (frames >= 2) {
-			ddi_put8(acc_hdl, &sgechain->NextChainOffset,
-			    (sgemax * sizeof (MPI2_SGE_SIMPLE64)) >> 2);
-		} else {
-			ddi_put8(acc_hdl, &sgechain->NextChainOffset, 0);
+		if (cookiec == 0) {
+			flags |= end_flag;
 		}
 
 		/*
-		 * Jump to next frame;
-		 * Starting here, chain buffers go into the per command SGL.
-		 * This buffer is allocated when chain buffers are needed.
+		 * XXX: Hmmm, what about the direction based on
+		 * cmd->cmd_flags & CFLAG_DMASEND?
 		 */
-		sge = (pMpi2SGESimple64_t)p->m_frames_addr;
-		i = cookiec;
+		ddi_put8(acc_hdl, &ieeesge->Flags, flags);
+		dmap++;
+		ieeesge++;
+	}
+}
 
-		/*
-		 * Start filling in frames with SGE's.  If we
-		 * reach the end of frame and still have SGE's
-		 * to fill we need to add a chain element and
-		 * use another frame.  j will be our counter
-		 * for what cookie we are at and i will be
-		 * the total cookiec. k is the current frame
-		 */
-		for (k = 1; k <= frames; k++) {
-			for (l = 1; (l <= (sgemax + 1)) && (j <= i); j++, l++) {
+static void
+mptsas_ieee_sge_chain(mptsas_t *mpt, mptsas_cmd_t *cmd,
+    pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+{
+	pMpi2IeeeSgeSimple64_t	ieeesge;
+	pMpi25IeeeSgeChain64_t	ieeesgechain;
+	uint64_t		nframe_phys_addr;
+	uint_t			cookiec;
+	mptti_t			*dmap;
+	uint8_t			flags;
+	int			i, j, k, l, frames, sgemax;
+	int			temp, maxframe_sges;
+	uint8_t			chainflags;
+	uint32_t		chainlength;
+	mptsas_cache_frames_t	*p;
 
-				/*
-				 * If we have reached the end of frame
-				 * and we have more SGE's to fill in
-				 * we have to fill the final entry
-				 * with a chain element and then
-				 * continue to the next frame
-				 */
-				if ((l == (sgemax + 1)) && (k != frames)) {
-					sgechain = (pMpi2SGEChain64_t)sge;
-					j--;
-					chainflags = (
-					    MPI2_SGE_FLAGS_CHAIN_ELEMENT |
-					    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
-					    MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
-					ddi_put8(p->m_acc_hdl,
-					    &sgechain->Flags, chainflags);
-					/*
-					 * k is the frame counter and (k + 1)
-					 * is the number of the next frame.
-					 * Note that frames are in contiguous
-					 * memory space.
-					 */
-					ddi_put32(p->m_acc_hdl,
-					    &sgechain->Address.Low,
-					    (p->m_phys_addr +
-					    (mpt->m_req_frame_size * k)));
-					ddi_put32(p->m_acc_hdl,
-					    &sgechain->Address.High, 0);
+	cookiec = cmd->cmd_cookiec;
 
-					/*
-					 * If there are more than 2 frames left
-					 * we have to next chain offset to
-					 * the location of the chain element
-					 * in the next frame and fill in the
-					 * length of the next chain
-					 */
-					if ((frames - k) >= 2) {
-						ddi_put8(p->m_acc_hdl,
-						    &sgechain->NextChainOffset,
-						    (sgemax *
-						    sizeof (MPI2_SGE_SIMPLE64))
-						    >> 2);
-						ddi_put16(p->m_acc_hdl,
-						    &sgechain->Length,
-						    mpt->m_req_frame_size /
-						    sizeof (MPI2_SGE_SIMPLE64) *
-						    sizeof (MPI2_SGE_SIMPLE64));
-					} else {
-						/*
-						 * This is the last frame. Set
-						 * the NextChainOffset to 0 and
-						 * Length is the total size of
-						 * all remaining simple elements
-						 */
-						ddi_put8(p->m_acc_hdl,
-						    &sgechain->NextChainOffset,
-						    0);
-						ddi_put16(p->m_acc_hdl,
-						    &sgechain->Length,
-						    (cookiec - j) *
-						    sizeof (MPI2_SGE_SIMPLE64));
-					}
+	NDBG1(("mptsas_ieee_sge_chain: cookiec=%d", cookiec));
 
-					/* Jump to the next frame */
-					sge = (pMpi2SGESimple64_t)
-					    ((char *)p->m_frames_addr +
-					    (int)mpt->m_req_frame_size * k);
+	/*
+	 * Hereby we start to deal with multiple frames.
+	 * The process is as follows:
+	 * 1. Determine how many frames are needed for SGL element
+	 *    storage; Note that all frames are stored in contiguous
+	 *    memory space and in 64-bit DMA mode each element is
+	 *    4 double-words (16 bytes) long.
+	 * 2. Fill up the main frame. We need to do this separately
+	 *    since it contains the SCSI IO request header and needs
+	 *    dedicated processing. Note that the last 4 double-words
+	 *    of the SCSI IO header is for SGL element storage
+	 *    (MPI2_SGE_IO_UNION).
+	 * 3. Fill the chain element in the main frame, so the DMA
+	 *    engine can use the following frames.
+	 * 4. Enter a loop to fill the remaining frames. Note that the
+	 *    last frame contains no chain element.  The remaining
+	 *    frames go into the mpt SGL buffer allocated on the fly,
+	 *    not immediately following the main message frame, as in
+	 *    Gen1.
+	 * Some restrictions:
+	 * 1. For 64-bit DMA, the simple element and chain element
+	 *    are both of 4 double-words (16 bytes) in size, even
+	 *    though all frames are stored in the first 4G of mem
+	 *    range and the higher 32-bits of the address are always 0.
+	 * 2. On some controllers (like the 1064/1068), a frame can
+	 *    hold SGL elements with the last 1 or 2 double-words
+	 *    (4 or 8 bytes) un-used. On these controllers, we should
+	 *    recognize that there's not enough room for another SGL
+	 *    element and move the sge pointer to the next frame.
+	 */
 
-					continue;
-				}
+	/*
+	 * Sgemax is the number of SGE's that will fit
+	 * each extra frame and frames is total
+	 * number of frames we'll need.  1 sge entry per
+	 * frame is reseverd for the chain element thus the -1 below.
+	 */
+	sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_IEEE_SGE_SIMPLE64))
+	    - 1);
+	maxframe_sges = MPTSAS_MAX_FRAME_SGES64(mpt);
+	temp = (cookiec - (maxframe_sges - 1)) / sgemax;
 
-				ddi_put32(p->m_acc_hdl,
-				    &sge->Address.Low,
-				    dmap->addr.address64.Low);
-				ddi_put32(p->m_acc_hdl,
-				    &sge->Address.High,
-				    dmap->addr.address64.High);
-				ddi_put32(p->m_acc_hdl,
-				    &sge->FlagsLength, dmap->count);
-				flags = ddi_get32(p->m_acc_hdl,
-				    &sge->FlagsLength);
-				flags |= ((uint32_t)(
-				    MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
-				    MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
-				    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
-				    MPI2_SGE_FLAGS_SHIFT);
+	/*
+	 * A little check to see if we need to round up the number
+	 * of frames we need
+	 */
+	if ((cookiec - (maxframe_sges - 1)) - (temp * sgemax) > 1) {
+		frames = (temp + 1);
+	} else {
+		frames = temp;
+	}
+	NDBG1(("mptsas_ieee_sge_chain: temp=%d, frames=%d", temp, frames));
+	dmap = cmd->cmd_sg;
+	ieeesge = (pMpi2IeeeSgeSimple64_t)(&frame->SGL);
 
+	/*
+	 * First fill in the main frame
+	 */
+	j = maxframe_sges - 1;
+	mptsas_ieee_sge_mainframe(cmd, frame, acc_hdl, j, 0);
+	dmap += j;
+	ieeesge += j;
+	j++;
+
+	/*
+	 * Fill in the chain element in the main frame.
+	 * About calculation on ChainOffset:
+	 * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes)
+	 *    in the end reserved for SGL element storage
+	 *    (MPI2_SGE_IO_UNION); we should count it in our
+	 *    calculation.  See its definition in the header file.
+	 * 2. Constant j is the counter of the current SGL element
+	 *    that will be processed, and (j - 1) is the number of
+	 *    SGL elements that have been processed (stored in the
+	 *    main frame).
+	 * 3. ChainOffset value should be in units of quad-words (16
+	 *    bytes) so the last value should be divided by 16.
+	 */
+	ddi_put8(acc_hdl, &frame->ChainOffset,
+	    (sizeof (MPI2_SCSI_IO_REQUEST) -
+	    sizeof (MPI2_SGE_IO_UNION) +
+	    (j - 1) * sizeof (MPI2_IEEE_SGE_SIMPLE64)) >> 4);
+	ieeesgechain = (pMpi25IeeeSgeChain64_t)ieeesge;
+	chainflags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+	    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+	ddi_put8(acc_hdl, &ieeesgechain->Flags, chainflags);
+
+	/*
+	 * The size of the next frame is the accurate size of space
+	 * (in bytes) used to store the SGL elements. j is the counter
+	 * of SGL elements. (j - 1) is the number of SGL elements that
+	 * have been processed (stored in frames).
+	 */
+	if (frames >= 2) {
+		chainlength = mpt->m_req_frame_size /
+		    sizeof (MPI2_IEEE_SGE_SIMPLE64) *
+		    sizeof (MPI2_IEEE_SGE_SIMPLE64);
+	} else {
+		chainlength = ((cookiec - (j - 1)) *
+		    sizeof (MPI2_IEEE_SGE_SIMPLE64));
+	}
+
+	p = cmd->cmd_extra_frames;
+
+	ddi_put32(acc_hdl, &ieeesgechain->Length, chainlength);
+	ddi_put32(acc_hdl, &ieeesgechain->Address.Low,
+	    p->m_phys_addr&0xffffffffull);
+	ddi_put32(acc_hdl, &ieeesgechain->Address.High, p->m_phys_addr>>32);
+
+	/*
+	 * If there are more than 2 frames left we have to
+	 * fill in the next chain offset to the location of
+	 * the chain element in the next frame.
+	 * sgemax is the number of simple elements in an extra
+	 * frame. Note that the value NextChainOffset should be
+	 * in double-words (4 bytes).
+	 */
+	if (frames >= 2) {
+		ddi_put8(acc_hdl, &ieeesgechain->NextChainOffset,
+		    (sgemax * sizeof (MPI2_IEEE_SGE_SIMPLE64)) >> 4);
+	} else {
+		ddi_put8(acc_hdl, &ieeesgechain->NextChainOffset, 0);
+	}
+
+	/*
+	 * Jump to next frame;
+	 * Starting here, chain buffers go into the per command SGL.
+	 * This buffer is allocated when chain buffers are needed.
+	 */
+	ieeesge = (pMpi2IeeeSgeSimple64_t)p->m_frames_addr;
+	i = cookiec;
+
+	/*
+	 * Start filling in frames with SGE's.  If we
+	 * reach the end of frame and still have SGE's
+	 * to fill we need to add a chain element and
+	 * use another frame.  j will be our counter
+	 * for what cookie we are at and i will be
+	 * the total cookiec. k is the current frame
+	 */
+	for (k = 1; k <= frames; k++) {
+		for (l = 1; (l <= (sgemax + 1)) && (j <= i); j++, l++) {
+
+			/*
+			 * If we have reached the end of frame
+			 * and we have more SGE's to fill in
+			 * we have to fill the final entry
+			 * with a chain element and then
+			 * continue to the next frame
+			 */
+			if ((l == (sgemax + 1)) && (k != frames)) {
+				ieeesgechain = (pMpi25IeeeSgeChain64_t)ieeesge;
+				j--;
+				chainflags =
+				    MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+				    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
+				ddi_put8(p->m_acc_hdl,
+				    &ieeesgechain->Flags, chainflags);
 				/*
-				 * If we are at the end of the frame and
-				 * there is another frame to fill in
-				 * we set the last simple element as last
-				 * element
+				 * k is the frame counter and (k + 1)
+				 * is the number of the next frame.
+				 * Note that frames are in contiguous
+				 * memory space.
 				 */
-				if ((l == sgemax) && (k != frames)) {
-					flags |= ((uint32_t)
-					    (MPI2_SGE_FLAGS_LAST_ELEMENT) <<
-					    MPI2_SGE_FLAGS_SHIFT);
-				}
+				nframe_phys_addr = p->m_phys_addr +
+				    (mpt->m_req_frame_size * k);
+				ddi_put32(p->m_acc_hdl,
+				    &ieeesgechain->Address.Low,
+				    nframe_phys_addr&0xffffffffull);
+				ddi_put32(p->m_acc_hdl,
+				    &ieeesgechain->Address.High,
+				    nframe_phys_addr>>32);
 
 				/*
-				 * If this is the final cookie we
-				 * indicate it by setting the flags
+				 * If there are more than 2 frames left
+				 * we have to next chain offset to
+				 * the location of the chain element
+				 * in the next frame and fill in the
+				 * length of the next chain
 				 */
-				if (j == i) {
-					flags |= ((uint32_t)
-					    (MPI2_SGE_FLAGS_LAST_ELEMENT |
-					    MPI2_SGE_FLAGS_END_OF_BUFFER |
-					    MPI2_SGE_FLAGS_END_OF_LIST) <<
-					    MPI2_SGE_FLAGS_SHIFT);
-				}
-				if (cmd->cmd_flags & CFLAG_DMASEND) {
-					flags |=
-					    (MPI2_SGE_FLAGS_HOST_TO_IOC <<
-					    MPI2_SGE_FLAGS_SHIFT);
+				if ((frames - k) >= 2) {
+					ddi_put8(p->m_acc_hdl,
+					    &ieeesgechain->NextChainOffset,
+					    (sgemax *
+					    sizeof (MPI2_IEEE_SGE_SIMPLE64))
+					    >> 4);
+					ddi_put32(p->m_acc_hdl,
+					    &ieeesgechain->Length,
+					    mpt->m_req_frame_size /
+					    sizeof (MPI2_IEEE_SGE_SIMPLE64) *
+					    sizeof (MPI2_IEEE_SGE_SIMPLE64));
 				} else {
-					flags |=
-					    (MPI2_SGE_FLAGS_IOC_TO_HOST <<
-					    MPI2_SGE_FLAGS_SHIFT);
+					/*
+					 * This is the last frame. Set
+					 * the NextChainOffset to 0 and
+					 * Length is the total size of
+					 * all remaining simple elements
+					 */
+					ddi_put8(p->m_acc_hdl,
+					    &ieeesgechain->NextChainOffset,
+					    0);
+					ddi_put32(p->m_acc_hdl,
+					    &ieeesgechain->Length,
+					    (cookiec - j) *
+					    sizeof (MPI2_IEEE_SGE_SIMPLE64));
 				}
-				ddi_put32(p->m_acc_hdl,
-				    &sge->FlagsLength, flags);
-				dmap++;
-				sge++;
+
+				/* Jump to the next frame */
+				ieeesge = (pMpi2IeeeSgeSimple64_t)
+				    ((char *)p->m_frames_addr +
+				    (int)mpt->m_req_frame_size * k);
+
+				continue;
 			}
+
+			ddi_put32(p->m_acc_hdl,
+			    &ieeesge->Address.Low,
+			    dmap->addr.address64.Low);
+			ddi_put32(p->m_acc_hdl,
+			    &ieeesge->Address.High,
+			    dmap->addr.address64.High);
+			ddi_put32(p->m_acc_hdl,
+			    &ieeesge->Length, dmap->count);
+			flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+			    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+
+			/*
+			 * If we are at the end of the frame and
+			 * there is another frame to fill in
+			 * do we need to do anything?
+			 * if ((l == sgemax) && (k != frames)) {
+			 * }
+			 */
+
+			/*
+			 * If this is the final cookie set end of list.
+			 */
+			if (j == i) {
+				flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
+			}
+
+			ddi_put8(p->m_acc_hdl, &ieeesge->Flags, flags);
+			dmap++;
+			ieeesge++;
 		}
+	}
 
-		/*
-		 * Sync DMA with the chain buffers that were just created
-		 */
-		(void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+	/*
+	 * Sync DMA with the chain buffers that were just created
+	 */
+	(void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
+
+static void
+mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control,
+    pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl)
+{
+	ASSERT(cmd->cmd_flags & CFLAG_DMAVALID);
+
+	NDBG1(("mptsas_sge_setup: cookiec=%d", cmd->cmd_cookiec));
+
+	/*
+	 * Set read/write bit in control.
+	 */
+	if (cmd->cmd_flags & CFLAG_DMASEND) {
+		*control |= MPI2_SCSIIO_CONTROL_WRITE;
+	} else {
+		*control |= MPI2_SCSIIO_CONTROL_READ;
 	}
+
+	ddi_put32(acc_hdl, &frame->DataLength, cmd->cmd_dmacount);
+
+	/*
+	 * We have 4 cases here.  First where we can fit all the
+	 * SG elements into the main frame, and the case
+	 * where we can't. The SG element is also different when using
+	 * MPI2.5 interface.
+	 * If we have more cookies than we can attach to a frame
+	 * we will need to use a chain element to point
+	 * a location of memory where the rest of the S/G
+	 * elements reside.
+	 */
+	if (cmd->cmd_cookiec <= MPTSAS_MAX_FRAME_SGES64(mpt)) {
+		if (mpt->m_MPI25) {
+			mptsas_ieee_sge_mainframe(cmd, frame, acc_hdl,
+			    cmd->cmd_cookiec,
+			    MPI25_IEEE_SGE_FLAGS_END_OF_LIST);
+		} else {
+			mptsas_sge_mainframe(cmd, frame, acc_hdl,
+			    cmd->cmd_cookiec,
+			    ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT
+			    | MPI2_SGE_FLAGS_END_OF_BUFFER
+			    | MPI2_SGE_FLAGS_END_OF_LIST) <<
+			    MPI2_SGE_FLAGS_SHIFT));
+		}
+	} else {
+		if (mpt->m_MPI25) {
+			mptsas_ieee_sge_chain(mpt, cmd, frame, acc_hdl);
+		} else {
+			mptsas_sge_chain(mpt, cmd, frame, acc_hdl);
+		}
+	}
 }
 
 /*
@@ -5491,7 +5828,8 @@
 	reply_type = ddi_get8(mpt->m_acc_post_queue_hdl,
 	    &reply_desc_union->Default.ReplyFlags);
 	reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
-	if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) {
+	if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS ||
+	    reply_type == MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS) {
 		mptsas_handle_scsi_io_success(mpt, reply_desc_union);
 	} else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
 		mptsas_handle_address_reply(mpt, reply_desc_union);
@@ -9305,7 +9643,7 @@
 #ifdef PROM_PRINTF
 	prom_printf("%s:\t%s\n", mptsas_label, mptsas_log_buf);
 #else
-	scsi_log(dev, mptsas_label, SCSI_DEBUG, "%s\n", mptsas_log_buf);
+	scsi_log(dev, mptsas_label, CE_CONT, "!%s\n", mptsas_log_buf);
 #endif
 	mutex_exit(&mptsas_log_mutex);
 }
@@ -9667,6 +10005,90 @@
 }
 
 static void
+mptsas_passthru_sge(ddi_acc_handle_t acc_hdl, mptsas_pt_request_t *pt,
+    pMpi2SGESimple64_t sgep)
+{
+	uint32_t		sge_flags;
+	uint32_t		data_size, dataout_size;
+	ddi_dma_cookie_t	data_cookie;
+	ddi_dma_cookie_t	dataout_cookie;
+
+	data_size = pt->data_size;
+	dataout_size = pt->dataout_size;
+	data_cookie = pt->data_cookie;
+	dataout_cookie = pt->dataout_cookie;
+
+	if (dataout_size) {
+		sge_flags = dataout_size |
+		    ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+		    MPI2_SGE_FLAGS_END_OF_BUFFER |
+		    MPI2_SGE_FLAGS_HOST_TO_IOC |
+		    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+		    MPI2_SGE_FLAGS_SHIFT);
+		ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags);
+		ddi_put32(acc_hdl, &sgep->Address.Low,
+		    (uint32_t)(dataout_cookie.dmac_laddress & 0xffffffffull));
+		ddi_put32(acc_hdl, &sgep->Address.High,
+		    (uint32_t)(dataout_cookie.dmac_laddress >> 32));
+		sgep++;
+	}
+	sge_flags = data_size;
+	sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_SGE_FLAGS_LAST_ELEMENT |
+	    MPI2_SGE_FLAGS_END_OF_BUFFER |
+	    MPI2_SGE_FLAGS_END_OF_LIST |
+	    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+	    MPI2_SGE_FLAGS_SHIFT);
+	if (pt->direction == MPTSAS_PASS_THRU_DIRECTION_WRITE) {
+		sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
+		    MPI2_SGE_FLAGS_SHIFT);
+	} else {
+		sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
+		    MPI2_SGE_FLAGS_SHIFT);
+	}
+	ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags);
+	ddi_put32(acc_hdl, &sgep->Address.Low,
+	    (uint32_t)(data_cookie.dmac_laddress & 0xffffffffull));
+	ddi_put32(acc_hdl, &sgep->Address.High,
+	    (uint32_t)(data_cookie.dmac_laddress >> 32));
+}
+
+static void
+mptsas_passthru_ieee_sge(ddi_acc_handle_t acc_hdl, mptsas_pt_request_t *pt,
+    pMpi2IeeeSgeSimple64_t ieeesgep)
+{
+	uint8_t			sge_flags;
+	uint32_t		data_size, dataout_size;
+	ddi_dma_cookie_t	data_cookie;
+	ddi_dma_cookie_t	dataout_cookie;
+
+	data_size = pt->data_size;
+	dataout_size = pt->dataout_size;
+	data_cookie = pt->data_cookie;
+	dataout_cookie = pt->dataout_cookie;
+
+	sge_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
+	    MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR);
+	if (dataout_size) {
+		ddi_put32(acc_hdl, &ieeesgep->Length, dataout_size);
+		ddi_put32(acc_hdl, &ieeesgep->Address.Low,
+		    (uint32_t)(dataout_cookie.dmac_laddress &
+		    0xffffffffull));
+		ddi_put32(acc_hdl, &ieeesgep->Address.High,
+		    (uint32_t)(dataout_cookie.dmac_laddress >> 32));
+		ddi_put8(acc_hdl, &ieeesgep->Flags, sge_flags);
+		ieeesgep++;
+	}
+	sge_flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
+	ddi_put32(acc_hdl, &ieeesgep->Length, data_size);
+	ddi_put32(acc_hdl, &ieeesgep->Address.Low,
+	    (uint32_t)(data_cookie.dmac_laddress & 0xffffffffull));
+	ddi_put32(acc_hdl, &ieeesgep->Address.High,
+	    (uint32_t)(data_cookie.dmac_laddress >> 32));
+	ddi_put8(acc_hdl, &ieeesgep->Flags, sge_flags);
+}
+
+static void
 mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd)
 {
 	caddr_t			memp;
@@ -9673,12 +10095,9 @@
 	pMPI2RequestHeader_t	request_hdrp;
 	struct scsi_pkt		*pkt = cmd->cmd_pkt;
 	mptsas_pt_request_t	*pt = pkt->pkt_ha_private;
-	uint32_t		request_size, data_size, dataout_size;
-	uint32_t		direction;
-	ddi_dma_cookie_t	data_cookie;
-	ddi_dma_cookie_t	dataout_cookie;
+	uint32_t		request_size;
 	uint32_t		request_desc_low, request_desc_high = 0;
-	uint32_t		i, sense_bufp;
+	uint64_t		sense_bufp;
 	uint8_t			desc_type;
 	uint8_t			*request, function;
 	ddi_dma_handle_t	dma_hdl = mpt->m_dma_req_frame_hdl;
@@ -9687,12 +10106,7 @@
 	desc_type = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 
 	request = pt->request;
-	direction = pt->direction;
 	request_size = pt->request_size;
-	data_size = pt->data_size;
-	dataout_size = pt->dataout_size;
-	data_cookie = pt->data_cookie;
-	dataout_cookie = pt->dataout_cookie;
 
 	/*
 	 * Store the passthrough message in memory location
@@ -9702,54 +10116,24 @@
 	request_hdrp = (pMPI2RequestHeader_t)memp;
 	bzero(memp, mpt->m_req_frame_size);
 
-	for (i = 0; i < request_size; i++) {
-		bcopy(request + i, memp + i, 1);
-	}
+	bcopy(request, memp, request_size);
 
-	if (data_size || dataout_size) {
-		pMpi2SGESimple64_t	sgep;
-		uint32_t		sge_flags;
+	NDBG15(("mptsas_start_passthru: Func 0x%x, MsgFlags 0x%x, "
+	    "size=%d, in %d, out %d", request_hdrp->Function,
+	    request_hdrp->MsgFlags, request_size,
+	    pt->data_size, pt->dataout_size));
 
-		sgep = (pMpi2SGESimple64_t)((uint8_t *)request_hdrp +
-		    request_size);
-		if (dataout_size) {
-
-			sge_flags = dataout_size |
-			    ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
-			    MPI2_SGE_FLAGS_END_OF_BUFFER |
-			    MPI2_SGE_FLAGS_HOST_TO_IOC |
-			    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
-			    MPI2_SGE_FLAGS_SHIFT);
-			ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags);
-			ddi_put32(acc_hdl, &sgep->Address.Low,
-			    (uint32_t)(dataout_cookie.dmac_laddress &
-			    0xffffffffull));
-			ddi_put32(acc_hdl, &sgep->Address.High,
-			    (uint32_t)(dataout_cookie.dmac_laddress
-			    >> 32));
-			sgep++;
-		}
-		sge_flags = data_size;
-		sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
-		    MPI2_SGE_FLAGS_LAST_ELEMENT |
-		    MPI2_SGE_FLAGS_END_OF_BUFFER |
-		    MPI2_SGE_FLAGS_END_OF_LIST |
-		    MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
-		    MPI2_SGE_FLAGS_SHIFT);
-		if (direction == MPTSAS_PASS_THRU_DIRECTION_WRITE) {
-			sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
-			    MPI2_SGE_FLAGS_SHIFT);
-		} else {
-			sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
-			    MPI2_SGE_FLAGS_SHIFT);
-		}
-		ddi_put32(acc_hdl, &sgep->FlagsLength,
-		    sge_flags);
-		ddi_put32(acc_hdl, &sgep->Address.Low,
-		    (uint32_t)(data_cookie.dmac_laddress &
-		    0xffffffffull));
-		ddi_put32(acc_hdl, &sgep->Address.High,
-		    (uint32_t)(data_cookie.dmac_laddress >> 32));
+	/*
+	 * Add an SGE, even if the length is zero.
+	 */
+	if (mpt->m_MPI25 && pt->simple == 0) {
+		mptsas_passthru_ieee_sge(acc_hdl, pt,
+		    (pMpi2IeeeSgeSimple64_t)
+		    ((uint8_t *)request_hdrp + pt->sgl_offset));
+	} else {
+		mptsas_passthru_sge(acc_hdl, pt,
+		    (pMpi2SGESimple64_t)
+		    ((uint8_t *)request_hdrp + pt->sgl_offset));
 	}
 
 	function = request_hdrp->Function;
@@ -9757,6 +10141,7 @@
 	    (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
 		pMpi2SCSIIORequest_t	scsi_io_req;
 
+		NDBG15(("mptsas_start_passthru: Is SCSI IO Req"));
 		scsi_io_req = (pMpi2SCSIIORequest_t)request_hdrp;
 		/*
 		 * Put SGE for data and data_out buffer at the end of
@@ -9768,8 +10153,8 @@
 		    &scsi_io_req->SenseBufferLength,
 		    (uint8_t)(request_size - 64));
 
-		sense_bufp = mpt->m_req_frame_dma_addr +
-		    (mpt->m_req_frame_size * cmd->cmd_slot);
+		sense_bufp = (uint32_t)(mpt->m_req_frame_dma_addr +
+		    (mpt->m_req_frame_size * cmd->cmd_slot) & 0xffffffffull);
 		sense_bufp += 64;
 		ddi_put32(acc_hdl,
 		    &scsi_io_req->SenseBufferLowAddress, sense_bufp);
@@ -9807,12 +10192,373 @@
 	}
 }
 
+typedef void (mptsas_pre_f)(mptsas_t *, mptsas_pt_request_t *);
+static mptsas_pre_f	mpi_pre_ioc_facts;
+static mptsas_pre_f	mpi_pre_port_facts;
+static mptsas_pre_f	mpi_pre_fw_download;
+static mptsas_pre_f	mpi_pre_fw_25_download;
+static mptsas_pre_f	mpi_pre_fw_upload;
+static mptsas_pre_f	mpi_pre_fw_25_upload;
+static mptsas_pre_f	mpi_pre_sata_passthrough;
+static mptsas_pre_f	mpi_pre_smp_passthrough;
+static mptsas_pre_f	mpi_pre_config;
+static mptsas_pre_f	mpi_pre_sas_io_unit_control;
+static mptsas_pre_f	mpi_pre_scsi_io_req;
 
+/*
+ * Prepare the pt for a SAS2 FW_DOWNLOAD request.
+ */
+static void
+mpi_pre_fw_download(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMpi2FWDownloadTCSGE_t tcsge;
+	pMpi2FWDownloadRequest req;
 
+	/*
+	 * If SAS3, call separate function.
+	 */
+	if (mpt->m_MPI25) {
+		mpi_pre_fw_25_download(mpt, pt);
+		return;
+	}
+
+	/*
+	 * User requests should come in with the Transaction
+	 * context element where the SGL will go. Putting the
+	 * SGL after that seems to work, but don't really know
+	 * why. Other drivers tend to create an extra SGL and
+	 * refer to the TCE through that.
+	 */
+	req = (pMpi2FWDownloadRequest)pt->request;
+	tcsge = (pMpi2FWDownloadTCSGE_t)&req->SGL;
+	if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 ||
+	    tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) {
+		mptsas_log(mpt, CE_WARN, "FW Download tce invalid!");
+	}
+
+	pt->sgl_offset = offsetof(MPI2_FW_DOWNLOAD_REQUEST, SGL) +
+	    sizeof (*tcsge);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_fw_download(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    (int)pt->request_size, (int)pt->sgl_offset,
+		    (int)pt->dataout_size));
+	if (pt->data_size < sizeof (MPI2_FW_DOWNLOAD_REPLY))
+		NDBG15(("mpi_pre_fw_download(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_FW_DOWNLOAD_REPLY)));
+}
+
+/*
+ * Prepare the pt for a SAS3 FW_DOWNLOAD request.
+ */
+static void
+mpi_pre_fw_25_download(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMpi2FWDownloadTCSGE_t tcsge;
+	pMpi2FWDownloadRequest req2;
+	pMpi25FWDownloadRequest req25;
+
+	/*
+	 * User requests should come in with the Transaction
+	 * context element where the SGL will go. The new firmware
+	 * Doesn't use TCE and has space in the main request for
+	 * this information. So move to the right place.
+	 */
+	req2 = (pMpi2FWDownloadRequest)pt->request;
+	req25 = (pMpi25FWDownloadRequest)pt->request;
+	tcsge = (pMpi2FWDownloadTCSGE_t)&req2->SGL;
+	if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 ||
+	    tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) {
+		mptsas_log(mpt, CE_WARN, "FW Download tce invalid!");
+	}
+	req25->ImageOffset = tcsge->ImageOffset;
+	req25->ImageSize = tcsge->ImageSize;
+
+	pt->sgl_offset = offsetof(MPI25_FW_DOWNLOAD_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_fw_25_download(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size < sizeof (MPI2_FW_DOWNLOAD_REPLY))
+		NDBG15(("mpi_pre_fw_25_download(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_FW_UPLOAD_REPLY)));
+}
+
+/*
+ * Prepare the pt for a SAS2 FW_UPLOAD request.
+ */
+static void
+mpi_pre_fw_upload(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMpi2FWUploadTCSGE_t tcsge;
+	pMpi2FWUploadRequest_t req;
+
+	/*
+	 * If SAS3, call separate function.
+	 */
+	if (mpt->m_MPI25) {
+		mpi_pre_fw_25_upload(mpt, pt);
+		return;
+	}
+
+	/*
+	 * User requests should come in with the Transaction
+	 * context element where the SGL will go. Putting the
+	 * SGL after that seems to work, but don't really know
+	 * why. Other drivers tend to create an extra SGL and
+	 * refer to the TCE through that.
+	 */
+	req = (pMpi2FWUploadRequest_t)pt->request;
+	tcsge = (pMpi2FWUploadTCSGE_t)&req->SGL;
+	if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 ||
+	    tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) {
+		mptsas_log(mpt, CE_WARN, "FW Upload tce invalid!");
+	}
+
+	pt->sgl_offset = offsetof(MPI2_FW_UPLOAD_REQUEST, SGL) +
+	    sizeof (*tcsge);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_fw_upload(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size < sizeof (MPI2_FW_UPLOAD_REPLY))
+		NDBG15(("mpi_pre_fw_upload(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_FW_UPLOAD_REPLY)));
+}
+
+/*
+ * Prepare the pt a SAS3 FW_UPLOAD request.
+ */
+static void
+mpi_pre_fw_25_upload(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMpi2FWUploadTCSGE_t tcsge;
+	pMpi2FWUploadRequest_t req2;
+	pMpi25FWUploadRequest_t req25;
+
+	/*
+	 * User requests should come in with the Transaction
+	 * context element where the SGL will go. The new firmware
+	 * Doesn't use TCE and has space in the main request for
+	 * this information. So move to the right place.
+	 */
+	req2 = (pMpi2FWUploadRequest_t)pt->request;
+	req25 = (pMpi25FWUploadRequest_t)pt->request;
+	tcsge = (pMpi2FWUploadTCSGE_t)&req2->SGL;
+	if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 ||
+	    tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) {
+		mptsas_log(mpt, CE_WARN, "FW Upload tce invalid!");
+	}
+	req25->ImageOffset = tcsge->ImageOffset;
+	req25->ImageSize = tcsge->ImageSize;
+
+	pt->sgl_offset = offsetof(MPI25_FW_UPLOAD_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_fw_25_upload(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size < sizeof (MPI2_FW_UPLOAD_REPLY))
+		NDBG15(("mpi_pre_fw_25_upload(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_FW_UPLOAD_REPLY)));
+}
+
+/*
+ * Prepare the pt for an IOC_FACTS request.
+ */
+static void
+mpi_pre_ioc_facts(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	if (pt->request_size != sizeof (MPI2_IOC_FACTS_REQUEST))
+		NDBG15(("mpi_pre_ioc_facts(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size,
+		    (int)sizeof (MPI2_IOC_FACTS_REQUEST),
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_IOC_FACTS_REPLY))
+		NDBG15(("mpi_pre_ioc_facts(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_IOC_FACTS_REPLY)));
+	pt->sgl_offset = (uint16_t)pt->request_size;
+}
+
+/*
+ * Prepare the pt for a PORT_FACTS request.
+ */
+static void
+mpi_pre_port_facts(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	if (pt->request_size != sizeof (MPI2_PORT_FACTS_REQUEST))
+		NDBG15(("mpi_pre_port_facts(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size,
+		    (int)sizeof (MPI2_PORT_FACTS_REQUEST),
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_PORT_FACTS_REPLY))
+		NDBG15(("mpi_pre_port_facts(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_PORT_FACTS_REPLY)));
+	pt->sgl_offset = (uint16_t)pt->request_size;
+}
+
+/*
+ * Prepare pt for a SATA_PASSTHROUGH request.
+ */
+static void
+mpi_pre_sata_passthrough(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = offsetof(MPI2_SATA_PASSTHROUGH_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_sata_passthrough(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_SATA_PASSTHROUGH_REPLY))
+		NDBG15(("mpi_pre_sata_passthrough(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_SATA_PASSTHROUGH_REPLY)));
+}
+
+static void
+mpi_pre_smp_passthrough(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = offsetof(MPI2_SMP_PASSTHROUGH_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_smp_passthrough(): Incorrect req size, "
+		    "0x%x, should be 0x%x, dataoutsz 0x%x",
+		    pt->request_size, pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_SMP_PASSTHROUGH_REPLY))
+		NDBG15(("mpi_pre_smp_passthrough(): Incorrect rep size, "
+		    "0x%x, should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_SMP_PASSTHROUGH_REPLY)));
+}
+
+/*
+ * Prepare pt for a CONFIG request.
+ */
+static void
+mpi_pre_config(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = offsetof(MPI2_CONFIG_REQUEST, PageBufferSGE);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_config(): Incorrect req size, 0x%x, "
+		    "should be 0x%x, dataoutsz 0x%x", pt->request_size,
+		    pt->sgl_offset, pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_CONFIG_REPLY))
+		NDBG15(("mpi_pre_config(): Incorrect rep size, 0x%x, "
+		    "should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_CONFIG_REPLY)));
+	pt->simple = 1;
+}
+
+/*
+ * Prepare pt for a SCSI_IO_REQ request.
+ */
+static void
+mpi_pre_scsi_io_req(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = offsetof(MPI2_SCSI_IO_REQUEST, SGL);
+	if (pt->request_size != pt->sgl_offset)
+		NDBG15(("mpi_pre_config(): Incorrect req size, 0x%x, "
+		    "should be 0x%x, dataoutsz 0x%x", pt->request_size,
+		    pt->sgl_offset,
+		    pt->dataout_size));
+	if (pt->data_size != sizeof (MPI2_SCSI_IO_REPLY))
+		NDBG15(("mpi_pre_config(): Incorrect rep size, 0x%x, "
+		    "should be 0x%x", pt->data_size,
+		    (int)sizeof (MPI2_SCSI_IO_REPLY)));
+}
+
+/*
+ * Prepare the mptsas_cmd for a SAS_IO_UNIT_CONTROL request.
+ */
+static void
+mpi_pre_sas_io_unit_control(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+#ifndef __lock_lint
+	_NOTE(ARGUNUSED(mpt))
+#endif
+	pt->sgl_offset = (uint16_t)pt->request_size;
+}
+
+/*
+ * A set of functions to prepare an mptsas_cmd for the various
+ * supported requests.
+ */
+static struct mptsas_func {
+	U8		Function;
+	char		*Name;
+	mptsas_pre_f	*f_pre;
+} mptsas_func_list[] = {
+	{ MPI2_FUNCTION_IOC_FACTS, "IOC_FACTS",		mpi_pre_ioc_facts },
+	{ MPI2_FUNCTION_PORT_FACTS, "PORT_FACTS",	mpi_pre_port_facts },
+	{ MPI2_FUNCTION_FW_DOWNLOAD, "FW_DOWNLOAD",	mpi_pre_fw_download },
+	{ MPI2_FUNCTION_FW_UPLOAD, "FW_UPLOAD",		mpi_pre_fw_upload },
+	{ MPI2_FUNCTION_SATA_PASSTHROUGH, "SATA_PASSTHROUGH",
+	    mpi_pre_sata_passthrough },
+	{ MPI2_FUNCTION_SMP_PASSTHROUGH, "SMP_PASSTHROUGH",
+	    mpi_pre_smp_passthrough},
+	{ MPI2_FUNCTION_SCSI_IO_REQUEST, "SCSI_IO_REQUEST",
+	    mpi_pre_scsi_io_req},
+	{ MPI2_FUNCTION_CONFIG, "CONFIG",		mpi_pre_config},
+	{ MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, "SAS_IO_UNIT_CONTROL",
+	    mpi_pre_sas_io_unit_control },
+	{ 0xFF, NULL,				NULL } /* list end */
+};
+
+static void
+mptsas_prep_sgl_offset(mptsas_t *mpt, mptsas_pt_request_t *pt)
+{
+	pMPI2RequestHeader_t	hdr;
+	struct mptsas_func	*f;
+
+	hdr = (pMPI2RequestHeader_t)pt->request;
+
+	for (f = mptsas_func_list; f->f_pre != NULL; f++) {
+		if (hdr->Function == f->Function) {
+			f->f_pre(mpt, pt);
+			NDBG15(("mptsas_prep_sgl_offset: Function %s,"
+			    " sgl_offset 0x%x", f->Name,
+			    pt->sgl_offset));
+			return;
+		}
+	}
+	NDBG15(("mptsas_prep_sgl_offset: Unknown Function 0x%02x,"
+	    " returning req_size 0x%x for sgl_offset",
+	    hdr->Function, pt->request_size));
+	pt->sgl_offset = (uint16_t)pt->request_size;
+}
+
+
 static int
 mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply,
     uint8_t *data, uint32_t request_size, uint32_t reply_size,
-    uint32_t data_size, uint32_t direction, uint8_t *dataout,
+    uint32_t data_size, uint8_t direction, uint8_t *dataout,
     uint32_t dataout_size, short timeout, int mode)
 {
 	mptsas_pt_request_t		pt;
@@ -9889,6 +10635,8 @@
 			mutex_enter(&mpt->m_mutex);
 		}
 	}
+	else
+		bzero(&data_dma_state, sizeof (data_dma_state));
 
 	if (dataout_size != 0) {
 		dataout_dma_state.size = dataout_size;
@@ -9912,6 +10660,8 @@
 		}
 		mutex_enter(&mpt->m_mutex);
 	}
+	else
+		bzero(&dataout_dma_state, sizeof (dataout_dma_state));
 
 	if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
 		status = EAGAIN;
@@ -9928,11 +10678,13 @@
 
 	pt.request = (uint8_t *)request_msg;
 	pt.direction = direction;
+	pt.simple = 0;
 	pt.request_size = request_size;
 	pt.data_size = data_size;
 	pt.dataout_size = dataout_size;
 	pt.data_cookie = data_dma_state.cookie;
 	pt.dataout_cookie = dataout_dma_state.cookie;
+	mptsas_prep_sgl_offset(mpt, &pt);
 
 	/*
 	 * Form a blank cmd/pkt to store the acknowledgement message
@@ -10145,7 +10897,7 @@
 		    (uint8_t *)((uintptr_t)data->PtrReply),
 		    (uint8_t *)((uintptr_t)data->PtrData),
 		    data->RequestSize, data->ReplySize,
-		    data->DataSize, data->DataDirection,
+		    data->DataSize, (uint8_t)data->DataDirection,
 		    (uint8_t *)((uintptr_t)data->PtrDataOut),
 		    data->DataOutSize, data->Timeout, mode));
 	} else {
@@ -11230,7 +11982,9 @@
 	char	*driver_verstr = MPTSAS_MOD_STRING;
 
 	mptsas_lookup_pci_data(mpt, adapter_data);
-	adapter_data->AdapterType = MPTIOCTL_ADAPTER_TYPE_SAS2;
+	adapter_data->AdapterType = mpt->m_MPI25 ?
+	    MPTIOCTL_ADAPTER_TYPE_SAS3 :
+	    MPTIOCTL_ADAPTER_TYPE_SAS2;
 	adapter_data->PCIDeviceHwId = (uint32_t)mpt->m_devid;
 	adapter_data->PCIDeviceHwRev = (uint32_t)mpt->m_revid;
 	adapter_data->SubSystemId = (uint32_t)mpt->m_ssid;
@@ -14982,7 +15736,7 @@
 	uint64_t			wwn;
 	Mpi2SmpPassthroughRequest_t	req;
 	Mpi2SmpPassthroughReply_t	rep;
-	uint32_t			direction = 0;
+	uint8_t				direction = 0;
 	mptsas_t			*mpt;
 	int				ret;
 	uint64_t			tmp64;
