changeset 11920:4618932f3ed5

6912010 Panic if hotspare is created during heavy I/O 6914638 RAID passthrough should use Default descriptor instead of SCSI IO descriptor 6918102 Solaris Sparc: Sas2flash shows wrong information for the PCI Address 6914674 Remove unnecessary diag reset logging (listing active commands) 6928627 Solaris showing messages for unknown "volume 0" 6920705 Diag reset fails - device is gone 6903574 Reply data for Task Management is not returned through IOCTL 6918666 MDC initiated after importing volumes 6931325 Multiple Encode devid failed for path target WANRING messages during M3000 system reboot test
author Ada <Ada.Feng@Sun.COM>
date Mon, 15 Mar 2010 08:36:17 +0800
parents 5b917481ad11
children 74c9e6232edb
files usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h
diffstat 5 files changed, 391 insertions(+), 175 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Sun Mar 14 17:27:54 2010 -0700
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Mon Mar 15 08:36:17 2010 +0800
@@ -25,7 +25,7 @@
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
+ * Copyright (c) 2000 to 2010, LSI Corporation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms of all code within
@@ -115,7 +115,9 @@
  */
 static int mptsas_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
 	cred_t *credp, int *rval);
-#ifndef	__sparc
+#ifdef __sparc
+static int mptsas_reset(dev_info_t *devi, ddi_reset_cmd_t cmd);
+#else  /* __sparc */
 static int mptsas_quiesce(dev_info_t *devi);
 #endif	/* __sparc */
 
@@ -507,7 +509,11 @@
 	nulldev,		/* probe */
 	mptsas_attach,		/* attach */
 	mptsas_detach,		/* detach */
+#ifdef  __sparc
+	mptsas_reset,
+#else
 	nodev,			/* reset */
+#endif  /* __sparc */
 	&mptsas_cb_ops,		/* driver operations */
 	NULL,			/* bus operations */
 	mptsas_power,		/* power management */
@@ -519,7 +525,7 @@
 };
 
 
-#define	MPTSAS_MOD_STRING "MPTSAS HBA Driver 00.00.00.21"
+#define	MPTSAS_MOD_STRING "MPTSAS HBA Driver 00.00.00.22"
 
 static struct modldrv modldrv = {
 	&mod_driverops,	/* Type of module. This one is a driver */
@@ -1537,11 +1543,6 @@
 
 	mutex_enter(&mpt->m_mutex);
 
-	/*
-	 * Send RAID action system shutdown to sync IR
-	 */
-	mptsas_raid_action_system_shutdown(mpt);
-
 	if (mpt->m_suspended++) {
 		mutex_exit(&mpt->m_mutex);
 		return (DDI_SUCCESS);
@@ -1625,6 +1626,10 @@
 
 	/* Disable HBA interrupts in hardware */
 	MPTSAS_DISABLE_INTR(mpt);
+	/*
+	 * Send RAID action system shutdown to sync IR
+	 */
+	mptsas_raid_action_system_shutdown(mpt);
 
 	mutex_exit(&mpt->m_mutex);
 
@@ -1635,6 +1640,36 @@
 	return (DDI_SUCCESS);
 }
 
+#ifdef	__sparc
+/*ARGSUSED*/
+static int
+mptsas_reset(dev_info_t *devi, ddi_reset_cmd_t cmd)
+{
+	mptsas_t	*mpt;
+	scsi_hba_tran_t *tran;
+
+	/*
+	 * If this call is for iport, just return.
+	 */
+	if (scsi_hba_iport_unit_address(devi))
+		return (DDI_SUCCESS);
+
+	if ((tran = ddi_get_driver_private(devi)) == NULL)
+		return (DDI_SUCCESS);
+
+	if ((mpt = TRAN2MPT(tran)) == NULL)
+		return (DDI_SUCCESS);
+
+	/*
+	 * Send RAID action system shutdown to sync IR.  Disable HBA
+	 * interrupts in hardware first.
+	 */
+	MPTSAS_DISABLE_INTR(mpt);
+	mptsas_raid_action_system_shutdown(mpt);
+
+	return (DDI_SUCCESS);
+}
+#else /* __sparc */
 /*
  * quiesce(9E) entry point.
  *
@@ -1645,13 +1680,18 @@
  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
  * DDI_FAILURE indicates an error condition and should almost never happen.
  */
-#ifndef	__sparc
 static int
 mptsas_quiesce(dev_info_t *devi)
 {
 	mptsas_t	*mpt;
 	scsi_hba_tran_t *tran;
 
+	/*
+	 * If this call is for iport, just return.
+	 */
+	if (scsi_hba_iport_unit_address(devi))
+		return (DDI_SUCCESS);
+
 	if ((tran = ddi_get_driver_private(devi)) == NULL)
 		return (DDI_SUCCESS);
 
@@ -1660,6 +1700,8 @@
 
 	/* Disable HBA interrupts in hardware */
 	MPTSAS_DISABLE_INTR(mpt);
+	/* Send RAID action system shutdonw to sync IR */
+	mptsas_raid_action_system_shutdown(mpt);
 
 	return (DDI_SUCCESS);
 }
@@ -1757,11 +1799,6 @@
 	}
 
 	mutex_enter(&mpt->m_mutex);
-
-	/*
-	 * Send RAID action system shutdown to sync IR
-	 */
-	mptsas_raid_action_system_shutdown(mpt);
 	MPTSAS_DISABLE_INTR(mpt);
 	mutex_exit(&mpt->m_mutex);
 	mptsas_rem_intrs(mpt);
@@ -3164,6 +3201,24 @@
 	}
 
 	/*
+	 * If HBA is being reset, the DevHandles are being re-initialized,
+	 * which means that they could be invalid even if the target is still
+	 * attached.  Check if being reset and if DevHandle is being
+	 * re-initialized.  If this is the case, return BUSY so the I/O can be
+	 * retried later.
+	 */
+	if ((ptgt->m_devhdl == MPTSAS_INVALID_DEVHDL) && mpt->m_in_reset) {
+		mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET);
+		if (cmd->cmd_flags & CFLAG_TXQ) {
+			mptsas_doneq_add(mpt, cmd);
+			mptsas_doneq_empty(mpt);
+			return (rval);
+		} else {
+			return (TRAN_BUSY);
+		}
+	}
+
+	/*
 	 * If device handle has already been invalidated, just
 	 * fail the command. In theory, command from scsi_vhci
 	 * client is impossible send down command with invalid
@@ -4695,7 +4750,7 @@
 	pMPI2DefaultReply_t		reply;
 	mptsas_fw_diagnostic_buffer_t	*pBuffer;
 	uint32_t			reply_addr;
-	uint16_t			SMID, iocstatus, action;
+	uint16_t			SMID, iocstatus;
 	mptsas_slots_t			*slots = mpt->m_active;
 	mptsas_cmd_t			*cmd = NULL;
 	uint8_t				function, buffer_type;
@@ -4737,22 +4792,6 @@
 	if ((function != MPI2_FUNCTION_EVENT_NOTIFICATION) &&
 	    (function != MPI2_FUNCTION_DIAG_BUFFER_POST)) {
 		/*
-		 * If this is a raid action reply for system shutdown just exit
-		 * because the reply doesn't matter.  Signal that we got the
-		 * reply even though it's not really necessary since we're
-		 * shutting down.
-		 */
-		if (function == MPI2_FUNCTION_RAID_ACTION) {
-			action = ddi_get16(mpt->m_acc_reply_frame_hdl,
-			    &reply->FunctionDependent1);
-			if (action ==
-			    MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED) {
-				cv_broadcast(&mpt->m_fw_diag_cv);
-				return;
-			}
-		}
-
-		/*
 		 * This could be a TM reply, which use the last allocated SMID,
 		 * so allow for that.
 		 */
@@ -4797,6 +4836,7 @@
 		mptsas_check_scsi_io_error(mpt, (pMpi2SCSIIOReply_t)reply, cmd);
 		break;
 	case MPI2_FUNCTION_SCSI_TASK_MGMT:
+		cmd->cmd_rfm = reply_addr;
 		mptsas_check_task_mgt(mpt, (pMpi2SCSIManagementReply_t)reply,
 		    cmd);
 		break;
@@ -5940,9 +5980,12 @@
 		}
 		ASSERT(ptgt->m_devhdl == devhdl);
 
-		if (topo_node->flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) {
-			/*
-			 * Get latest RAID info, if RAID volume status change
+		if ((topo_node->flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) ||
+		    (topo_node->flags ==
+		    MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED)) {
+			/*
+			 * Get latest RAID info if RAID volume status changes
+			 * or Phys Disk status changes
 			 */
 			(void) mptsas_get_raid_info(mpt);
 		}
@@ -7101,8 +7144,8 @@
 		 * just exit the event.
 		 */
 		(void) mptsas_get_raid_info(mpt);
-		for (config = 0; config < slots->m_num_raid_configs;
-		    config++) {
+		for (config = 0; (config < slots->m_num_raid_configs) &&
+		    (!found); config++) {
 			for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
 				if (slots->m_raidconfig[config].m_raidvol[vol].
 				    m_raidhandle == devhandle) {
@@ -8187,7 +8230,7 @@
 	}
 
 	rval = mptsas_ioc_task_management(mpt,
-	    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, devhdl, 0);
+	    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, devhdl, 0, NULL, 0, 0);
 
 	mptsas_doneq_empty(mpt);
 	return (rval);
@@ -8283,9 +8326,9 @@
 		switch (tasktype) {
 		case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
 			if (Tgt(cmd) == target) {
-				mptsas_log(mpt, CE_NOTE, "mptsas_flush_target "
-				    "discovered non-NULL cmd in slot %d, "
-				    "tasktype 0x%x", slot, tasktype);
+				NDBG25(("mptsas_flush_target discovered non-"
+				    "NULL cmd in slot %d, tasktype 0x%x", slot,
+				    tasktype));
 				mptsas_dump_cmd(mpt, cmd);
 				mptsas_remove_cmd(mpt, cmd);
 				mptsas_set_pkt_reason(mpt, cmd, reason, stat);
@@ -8299,9 +8342,9 @@
 		case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
 			if ((Tgt(cmd) == target) && (Lun(cmd) == lun)) {
 
-				mptsas_log(mpt, CE_NOTE, "mptsas_flush_target "
-				    "discovered non-NULL cmd in slot %d, "
-				    "tasktype 0x%x", slot, tasktype);
+				NDBG25(("mptsas_flush_target discovered non-"
+				    "NULL cmd in slot %d, tasktype 0x%x", slot,
+				    tasktype));
 				mptsas_dump_cmd(mpt, cmd);
 				mptsas_remove_cmd(mpt, cmd);
 				mptsas_set_pkt_reason(mpt, cmd, reason,
@@ -8433,8 +8476,8 @@
 			continue;
 		}
 
-		mptsas_log(mpt, CE_NOTE, "mptsas_flush_hba discovered non-NULL "
-		    "cmd in slot %d", slot);
+		NDBG25(("mptsas_flush_hba discovered non-NULL cmd in slot %d",
+		    slot));
 		mptsas_dump_cmd(mpt, cmd);
 
 		mptsas_remove_cmd(mpt, cmd);
@@ -8688,7 +8731,7 @@
 		if (slots->m_slot[sp->cmd_slot] != NULL) {
 			rval = mptsas_ioc_task_management(mpt,
 			    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, target,
-			    lun);
+			    lun, NULL, 0, 0);
 
 			/*
 			 * The transport layer expects only TRUE and FALSE.
@@ -8705,7 +8748,7 @@
 	 * If pkt is NULL then abort task set
 	 */
 	rval = mptsas_ioc_task_management(mpt,
-	    MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, target, lun);
+	    MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, target, lun, NULL, 0, 0);
 
 	/*
 	 * The transport layer expects only TRUE and FALSE.
@@ -9314,6 +9357,7 @@
 	mutex_exit(&mpt->m_mutex);
 }
 
+/*ARGSUSED*/
 static void
 mptsas_dump_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd)
 {
@@ -9322,20 +9366,19 @@
 	char	buf[128];
 
 	buf[0] = '\0';
-	mptsas_log(mpt, CE_NOTE, "?Cmd (0x%p) dump for Target %d Lun %d:\n",
-	    (void *)cmd, Tgt(cmd), Lun(cmd));
+	NDBG25(("?Cmd (0x%p) dump for Target %d Lun %d:\n", (void *)cmd,
+	    Tgt(cmd), Lun(cmd)));
 	(void) sprintf(&buf[0], "\tcdb=[");
 	for (i = 0; i < (int)cmd->cmd_cdblen; i++) {
 		(void) sprintf(&buf[strlen(buf)], " 0x%x", *cp++);
 	}
 	(void) sprintf(&buf[strlen(buf)], " ]");
-	mptsas_log(mpt, CE_NOTE, "?%s\n", buf);
-	mptsas_log(mpt, CE_NOTE,
-	    "?pkt_flags=0x%x pkt_statistics=0x%x pkt_state=0x%x\n",
+	NDBG25(("?%s\n", buf));
+	NDBG25(("?pkt_flags=0x%x pkt_statistics=0x%x pkt_state=0x%x\n",
 	    cmd->cmd_pkt->pkt_flags, cmd->cmd_pkt->pkt_statistics,
-	    cmd->cmd_pkt->pkt_state);
-	mptsas_log(mpt, CE_NOTE, "?pkt_scbp=0x%x cmd_flags=0x%x\n",
-	    *(cmd->cmd_pkt->pkt_scbp), cmd->cmd_flags);
+	    cmd->cmd_pkt->pkt_state));
+	NDBG25(("?pkt_scbp=0x%x cmd_flags=0x%x\n", *(cmd->cmd_pkt->pkt_scbp),
+	    cmd->cmd_flags));
 }
 
 static void
@@ -9453,9 +9496,13 @@
 		    offsetof(MPI2_SCSI_IO_REQUEST, SGL) / 4);
 
 		/*
-		 * Setup descriptor info
-		 */
-		desc_type = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+		 * Setup descriptor info.  RAID passthrough must use the
+		 * default request descriptor which is already set, so if this
+		 * is a SCSI IO request, change the descriptor to SCSI IO.
+		 */
+		if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) {
+			desc_type = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
+		}
 		request_desc_high = (ddi_get16(acc_hdl,
 		    &scsi_io_req->DevHandle) << 16);
 	}
@@ -9523,7 +9570,8 @@
 		task = (pMpi2SCSITaskManagementRequest_t)request_msg;
 		mptsas_setup_bus_reset_delay(mpt);
 		rv = mptsas_ioc_task_management(mpt, task->TaskType,
-		    task->DevHandle, (int)task->LUN[1]);
+		    task->DevHandle, (int)task->LUN[1], reply, reply_size,
+		    mode);
 
 		if (rv != TRUE) {
 			status = EIO;
@@ -10867,13 +10915,13 @@
 		 * Bits 16 - 23 8-bit Bus number
 		 * Bits 24 - 25 2-bit Address Space type identifier
 		 *
-		 * Store the device number in PCIDeviceHwId.
-		 * Store the function number in MpiPortNumber.
-		 * PciInformation stores bus, device, and function together
-		 */
-		adapter_data->PCIDeviceHwId = (reg_data[0] & 0x0000F800) >> 11;
-		adapter_data->MpiPortNumber = (reg_data[0] & 0x00000700) >> 8;
-		adapter_data->PciInformation = (reg_data[0] & 0x00FFFF00) >> 8;
+		 */
+		adapter_data->PciInformation.u.bits.BusNumber =
+		    (reg_data[0] & 0x00FF0000) >> 16;
+		adapter_data->PciInformation.u.bits.DeviceNumber =
+		    (reg_data[0] & 0x0000F800) >> 11;
+		adapter_data->PciInformation.u.bits.FunctionNumber =
+		    (reg_data[0] & 0x00000700) >> 8;
 		ddi_prop_free((void *)reg_data);
 	} else {
 		/*
@@ -10882,7 +10930,7 @@
 		 */
 		adapter_data->PCIDeviceHwId = 0xFFFFFFFF;
 		adapter_data->MpiPortNumber = 0xFFFFFFFF;
-		adapter_data->PciInformation = 0xFFFFFFFF;
+		adapter_data->PciInformation.u.AsDWORD = 0xFFFFFFFF;
 	}
 
 	/*
@@ -11240,6 +11288,15 @@
 	ASSERT(mutex_owned(&mpt->m_mutex));
 
 	/*
+	 * Set a flag telling I/O path that we're processing a reset.  This is
+	 * needed because after the reset is complete, the hash table still
+	 * needs to be rebuilt.  If I/Os are started before the hash table is
+	 * rebuilt, I/O errors will occur.  This flag allows I/Os to be marked
+	 * so that they can be retried.
+	 */
+	mpt->m_in_reset = TRUE;
+
+	/*
 	 * Set all throttles to HOLD
 	 */
 	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
@@ -11300,6 +11357,12 @@
 		mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
 		ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
 	}
+
+	/*
+	 * Clear the reset flag so that I/Os can continue.
+	 */
+	mpt->m_in_reset = FALSE;
+
 	return (rval);
 }
 
@@ -13221,7 +13284,8 @@
 	 * scsi_vhci, so no need to try page83
 	 */
 	if (sd_inq && (sd_inq->inq_dtype == DTYPE_RODIRECT ||
-	    sd_inq->inq_dtype == DTYPE_OPTICAL))
+	    sd_inq->inq_dtype == DTYPE_OPTICAL ||
+	    sd_inq->inq_dtype == DTYPE_ESI))
 		goto create_lun;
 
 	/*
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c	Sun Mar 14 17:27:54 2010 -0700
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c	Mon Mar 15 08:36:17 2010 +0800
@@ -20,12 +20,12 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
+ * Copyright (c) 2000 to 2010, LSI Corporation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms of all code within
@@ -357,10 +357,20 @@
 	}
 
 	/*
-	 * Wait for the command to complete or timeout.
+	 * If this is a request for a RAID info page, or any page called during
+	 * the RAID info page request, poll because these config page requests
+	 * are nested.  Poll to avoid data corruption due to one page's data
+	 * overwriting the outer page request's data.  This can happen when
+	 * the mutex is released in cv_wait.
 	 */
-	while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
-		cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
+	if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
+	    (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
+	    (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
+		(void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
+	} else {
+		while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
+			cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
+		}
 	}
 
 	/*
@@ -507,10 +517,20 @@
 	mptsas_start_config_page_access(mpt, cmd);
 
 	/*
-	 * Wait for the command to complete or timeout.
+	 * If this is a request for a RAID info page, or any page called during
+	 * the RAID info page request, poll because these config page requests
+	 * are nested.  Poll to avoid data corruption due to one page's data
+	 * overwriting the outer page request's data.  This can happen when
+	 * the mutex is released in cv_wait.
 	 */
-	while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
-		cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
+	if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
+	    (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
+	    (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
+		(void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
+	} else {
+		while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
+			cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
+		}
 	}
 
 	/*
@@ -1068,7 +1088,7 @@
  */
 int
 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
-	int lun)
+	int lun, uint8_t *reply, uint32_t reply_size, int mode)
 {
 	/*
 	 * In order to avoid allocating variables on the stack,
@@ -1082,7 +1102,8 @@
 	mptsas_cmd_t				*cmd;
 	struct scsi_pkt				*pkt;
 	mptsas_slots_t				*slots = mpt->m_active;
-	uint32_t				request_desc_low;
+	uint32_t				request_desc_low, i;
+	pMPI2DefaultReply_t			reply_msg;
 
 	/*
 	 * Can't start another task management routine.
@@ -1146,6 +1167,32 @@
 		rval = FALSE;
 
 	/*
+	 * If a reply frame was used and there is a reply buffer to copy the
+	 * reply data into, copy it.  If this fails, log a message, but don't
+	 * fail the TM request.
+	 */
+	if (cmd->cmd_rfm && reply) {
+		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+		reply_msg = (pMPI2DefaultReply_t)
+		    (mpt->m_reply_frame + (cmd->cmd_rfm -
+		    mpt->m_reply_frame_dma_addr));
+		if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
+			reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
+		}
+		mutex_exit(&mpt->m_mutex);
+		for (i = 0; i < reply_size; i++) {
+			if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
+			    mode)) {
+				mptsas_log(mpt, CE_WARN, "failed to copy out "
+				    "reply data for TM request");
+				break;
+			}
+		}
+		mutex_enter(&mpt->m_mutex);
+	}
+
+	/*
 	 * clear the TM slot before returning
 	 */
 	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c	Sun Mar 14 17:27:54 2010 -0700
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_raid.c	Mon Mar 15 08:36:17 2010 +0800
@@ -20,12 +20,12 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
+ * Copyright (c) 2000 to 2010, LSI Corporation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms of all code within
@@ -173,7 +173,7 @@
 	element = (pMpi2RaidConfig0ConfigElement_t)
 	    &raidconfig_page0->ConfigElement;
 
-	for (i = 0; i < numelements; i++, element++) {
+	for (i = 0; ((i < numelements) && native); i++, element++) {
 		/*
 		 * Get the element type.  Could be Volume,
 		 * PhysDisk, Hot Spare, or Online Capacity
@@ -560,31 +560,34 @@
 }
 
 /*
- * The only RAID Action needed throughout the driver is for System Shutdown.
- * Since this is the only RAID Action and because this Action does not require
- * waiting for a reply, make this a non-generic function.  If it turns out that
- * other RAID Actions are required later, a generic function should be used.
+ * RAID Action for System Shutdown. This request uses the dedicated TM slot to
+ * avoid a call to mptsas_save_cmd.  Since Solaris requires that the mutex is
+ * not held during the mptsas_quiesce function, this RAID action must not use
+ * the normal code path of requests and replies.
  */
 void
 mptsas_raid_action_system_shutdown(mptsas_t *mpt)
 {
 	pMpi2RaidActionRequest_t	action;
-	uint8_t				ir_active = FALSE;
+	uint8_t				ir_active = FALSE, reply_type;
+	uint8_t				function, found_reply = FALSE;
+	uint16_t			SMID, action_type;
 	mptsas_slots_t			*slots = mpt->m_active;
-	int				config, vol, action_flags = 0;
+	int				config, vol;
 	mptsas_cmd_t			*cmd;
-	struct scsi_pkt			*pkt;
-	uint32_t			request_desc_low;
-
-	ASSERT(mutex_owned(&mpt->m_mutex));
+	uint32_t			request_desc_low, reply_addr;
+	int				cnt;
+	pMpi2ReplyDescriptorsUnion_t	reply_desc_union;
+	pMPI2DefaultReply_t		reply;
+	pMpi2AddressReplyDescriptor_t	address_reply;
 
 	/*
 	 * Before doing the system shutdown RAID Action, make sure that the IOC
 	 * supports IR and make sure there is a valid volume for the request.
 	 */
 	if (mpt->m_ir_capable) {
-		for (config = 0; config < slots->m_num_raid_configs;
-		    config++) {
+		for (config = 0; (config < slots->m_num_raid_configs) &&
+		    (!ir_active); config++) {
 			for (vol = 0; vol < MPTSAS_MAX_RAIDVOLS; vol++) {
 				if (slots->m_raidconfig[config].m_raidvol[vol].
 				    m_israid) {
@@ -599,81 +602,166 @@
 	}
 
 	/*
-	 * Get a command from the pool.
-	 */
-	if (mptsas_request_from_pool(mpt, &cmd, &pkt) == -1) {
-		mptsas_log(mpt, CE_NOTE, "command pool is full for RAID "
-		    "action request");
-		return;
-	}
-	action_flags |= MPTSAS_REQUEST_POOL_CMD;
-
-	bzero((caddr_t)cmd, sizeof (*cmd));
-	bzero((caddr_t)pkt, scsi_pkt_size());
-
-	pkt->pkt_cdbp		= (opaque_t)&cmd->cmd_cdb[0];
-	pkt->pkt_scbp		= (opaque_t)&cmd->cmd_scb;
-	pkt->pkt_ha_private	= (opaque_t)cmd;
-	pkt->pkt_flags		= (FLAG_NOINTR | FLAG_HEAD);
-	pkt->pkt_time		= 5;
-	cmd->cmd_pkt		= pkt;
-	cmd->cmd_flags		= CFLAG_CMDIOC;
-
-	/*
-	 * Send RAID Action.  We don't care what the reply is so just exit
-	 * after sending the request.  This is just sent to the controller to
-	 * keep the volume from having to resync the next time it starts.  If
-	 * the request doesn't work for whatever reason, we're not going to
-	 * bother wondering why.
+	 * If TM slot is already being used (highly unlikely), show message and
+	 * don't issue the RAID action.
 	 */
-	if (mptsas_save_cmd(mpt, cmd) == TRUE) {
-		cmd->cmd_flags |= CFLAG_PREPARED;
-		/*
-		 * Form message for raid action
-		 */
-		action = (pMpi2RaidActionRequest_t)(mpt->m_req_frame +
-		    (mpt->m_req_frame_size * cmd->cmd_slot));
-		bzero(action, mpt->m_req_frame_size);
-		action->Function = MPI2_FUNCTION_RAID_ACTION;
-		action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
-
-		/*
-		 * Send request
-		 */
-		(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
-		    DDI_DMA_SYNC_FORDEV);
-		request_desc_low = (cmd->cmd_slot << 16) +
-		    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-		MPTSAS_START_CMD(mpt, request_desc_low, 0);
-
-		/*
-		 * Even though reply does not matter, wait no more than 5
-		 * seconds here to get the reply just because we don't want to
-		 * leave it hanging if it's coming.  Use the FW diag cv.
-		 */
-		(void) cv_reltimedwait(&mpt->m_fw_diag_cv, &mpt->m_mutex,
-		    drv_usectohz(5 * MICROSEC), TR_CLOCK_TICK);
+	if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
+		mptsas_log(mpt, CE_WARN, "RAID Action slot in use.  Cancelling"
+		    " System Shutdown RAID Action.\n");
+		return;
 	}
 
 	/*
-	 * Be sure to deallocate cmd before leaving.
+	 * Create the cmd and put it in the dedicated TM slot.
+	 */
+	cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
+	bzero((caddr_t)cmd, sizeof (*cmd));
+	cmd->cmd_pkt = NULL;
+	cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
+	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
+
+	/*
+	 * Form message for raid action.
+	 */
+	action = (pMpi2RaidActionRequest_t)(mpt->m_req_frame +
+	    (mpt->m_req_frame_size * cmd->cmd_slot));
+	bzero(action, mpt->m_req_frame_size);
+	action->Function = MPI2_FUNCTION_RAID_ACTION;
+	action->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
+
+	/*
+	 * Send RAID Action.
+	 */
+	(void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+	request_desc_low = (cmd->cmd_slot << 16) +
+	    MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+	MPTSAS_START_CMD(mpt, request_desc_low, 0);
+
+	/*
+	 * Even though reply does not matter because the system is shutting
+	 * down, wait no more than 5 seconds here to get the reply just because
+	 * we don't want to leave it hanging if it's coming.  Poll because
+	 * interrupts are disabled when this function is called.
 	 */
-	if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
-		mptsas_remove_cmd(mpt, cmd);
-		action_flags &= (~MPTSAS_REQUEST_POOL_CMD);
+	for (cnt = 0; cnt < 5000; cnt++) {
+		/*
+		 * Check for a reply.
+		 */
+		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+
+		reply_desc_union = (pMpi2ReplyDescriptorsUnion_t)
+		    MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index);
+
+		if (ddi_get32(mpt->m_acc_post_queue_hdl,
+		    &reply_desc_union->Words.Low) == 0xFFFFFFFF ||
+		    ddi_get32(mpt->m_acc_post_queue_hdl,
+		    &reply_desc_union->Words.High) == 0xFFFFFFFF) {
+			drv_usecwait(1000);
+			continue;
+		}
+
+		/*
+		 * There is a reply.  If it's not an address reply, ignore it.
+		 */
+		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_ADDRESS_REPLY) {
+			goto clear_and_continue;
+		}
+
+		/*
+		 * SMID must be the TM slot since that's what we're using for
+		 * this RAID action.  If not, ignore this reply.
+		 */
+		address_reply =
+		    (pMpi2AddressReplyDescriptor_t)reply_desc_union;
+		SMID = ddi_get16(mpt->m_acc_post_queue_hdl,
+		    &address_reply->SMID);
+		if (SMID != MPTSAS_TM_SLOT(mpt)) {
+			goto clear_and_continue;
+		}
+
+		/*
+		 * If reply frame is not in the proper range ignore it.
+		 */
+		reply_addr = ddi_get32(mpt->m_acc_post_queue_hdl,
+		    &address_reply->ReplyFrameAddress);
+		if ((reply_addr < mpt->m_reply_frame_dma_addr) ||
+		    (reply_addr >= (mpt->m_reply_frame_dma_addr +
+		    (mpt->m_reply_frame_size * mpt->m_free_queue_depth))) ||
+		    ((reply_addr - mpt->m_reply_frame_dma_addr) %
+		    mpt->m_reply_frame_size != 0)) {
+			goto clear_and_continue;
+		}
+
+		/*
+		 * If not a RAID action reply ignore it.
+		 */
+		(void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+		reply = (pMPI2DefaultReply_t)(mpt->m_reply_frame +
+		    (reply_addr - mpt->m_reply_frame_dma_addr));
+		function = ddi_get8(mpt->m_acc_reply_frame_hdl,
+		    &reply->Function);
+		if (function != MPI2_FUNCTION_RAID_ACTION) {
+			goto clear_and_continue;
+		}
+
+		/*
+		 * Finally, make sure this is the System Shutdown RAID action.
+		 * If not, ignore reply.
+		 */
+		action_type = ddi_get16(mpt->m_acc_reply_frame_hdl,
+		    &reply->FunctionDependent1);
+		if (action_type !=
+		    MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED) {
+			goto clear_and_continue;
+		}
+		found_reply = TRUE;
+
+clear_and_continue:
+		/*
+		 * Clear the reply descriptor for re-use and increment index.
+		 */
+		ddi_put64(mpt->m_acc_post_queue_hdl,
+		    &((uint64_t *)(void *)mpt->m_post_queue)[mpt->m_post_index],
+		    0xFFFFFFFFFFFFFFFF);
+		(void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0,
+		    DDI_DMA_SYNC_FORDEV);
+
+		/*
+		 * Update the global reply index and keep looking for the
+		 * reply if not found yet.
+		 */
+		if (++mpt->m_post_index == mpt->m_post_queue_depth) {
+			mpt->m_post_index = 0;
+		}
+		ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyPostHostIndex,
+		    mpt->m_post_index);
+		if (!found_reply) {
+			continue;
+		}
+
+		break;
 	}
-	if (action_flags & MPTSAS_REQUEST_POOL_CMD)
-		mptsas_return_to_pool(mpt, cmd);
 
+	/*
+	 * clear the used slot as the last step.
+	 */
+	slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
 }
 
 int
 mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
 {
-	int		config, i, vol = (-1);
+	int		config, i = 0, vol = (-1);
 	mptsas_slots_t	*slots = mpt->m_active;
 
-	for (config = 0; config < slots->m_num_raid_configs; config++) {
+	for (config = 0; (config < slots->m_num_raid_configs) && (vol != i);
+	    config++) {
 		for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
 			if (slots->m_raidconfig[config].m_raidvol[i].
 			    m_raidhandle == volid) {
--- a/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h	Sun Mar 14 17:27:54 2010 -0700
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_ioctl.h	Mon Mar 15 08:36:17 2010 +0800
@@ -20,12 +20,12 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
+ * Copyright (c) 2000 to 2010, LSI Corporation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms of all code within
@@ -80,6 +80,18 @@
 #define	MPTIOCTL_STATUS_GOOD		0
 #define	MPTIOCTL_STATUS_LEN_TOO_SHORT	1
 
+typedef struct mptsas_pci_bits
+{
+	union {
+		struct {
+			uint32_t	DeviceNumber	:5;
+			uint32_t	FunctionNumber	:3;
+			uint32_t	BusNumber	:24;
+		} bits;
+		uint32_t	AsDWORD;
+	} u;
+	uint32_t	PciSegmentId;
+} mptsas_pci_bits_t;
 /*
  *  The following is the MPTIOCTL_GET_ADAPTER_DATA data structure.  This data
  *  structure is setup so that we hopefully are properly aligned for both
@@ -95,22 +107,21 @@
 #define	MPTIOCTL_ADAPTER_TYPE_SAS2	4
 typedef struct mptsas_adapter_data
 {
-	uint32_t	StructureLength;
-	uint32_t	AdapterType;
-	uint32_t	MpiPortNumber;
-	uint32_t	PCIDeviceHwId;
-	uint32_t	PCIDeviceHwRev;
-	uint32_t	SubSystemId;
-	uint32_t	SubsystemVendorId;
-	uint32_t	Reserved1;
-	uint32_t	MpiFirmwareVersion;
-	uint32_t	BiosVersion;
-	uint8_t		DriverVersion[32];
-	uint8_t		Reserved2;
-	uint8_t		ScsiId;
-	uint16_t	Reserved3;
-	uint32_t	PciInformation;
-	uint32_t	PciSegmentId;
+	uint32_t		StructureLength;
+	uint32_t		AdapterType;
+	uint32_t		MpiPortNumber;
+	uint32_t		PCIDeviceHwId;
+	uint32_t		PCIDeviceHwRev;
+	uint32_t		SubSystemId;
+	uint32_t		SubsystemVendorId;
+	uint32_t		Reserved1;
+	uint32_t		MpiFirmwareVersion;
+	uint32_t		BiosVersion;
+	uint8_t			DriverVersion[32];
+	uint8_t			Reserved2;
+	uint8_t			ScsiId;
+	uint16_t		Reserved3;
+	mptsas_pci_bits_t	PciInformation;
 } mptsas_adapter_data_t;
 
 
--- a/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Sun Mar 14 17:27:54 2010 -0700
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Mon Mar 15 08:36:17 2010 +0800
@@ -20,12 +20,12 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
- * Copyright (c) 2000 to 2009, LSI Corporation.
+ * Copyright (c) 2000 to 2010, LSI Corporation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms of all code within
@@ -847,6 +847,11 @@
 	uint8_t			m_ir_capable;
 
 	/*
+	 * Is HBA processing a diag reset?
+	 */
+	uint8_t			m_in_reset;
+
+	/*
 	 * per instance cmd data structures for task management cmds
 	 */
 	m_event_struct_t	m_event_task_mgmt;	/* must be last */
@@ -1244,7 +1249,8 @@
     caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...);
 
 int mptsas_ioc_task_management(mptsas_t *mpt, int task_type,
-    uint16_t dev_handle, int lun);
+    uint16_t dev_handle, int lun, uint8_t *reply, uint32_t reply_size,
+    int mode);
 int mptsas_send_event_ack(mptsas_t *mpt, uint32_t event, uint32_t eventcntx);
 void mptsas_send_pending_event_ack(mptsas_t *mpt);
 void mptsas_set_throttle(struct mptsas *mpt, mptsas_target_t *ptgt, int what);