--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Sun Jan 29 11:45:53 2017
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Sun Jan 29 11:45:53 2017
@@ -556,7 +556,7 @@
 };
 
 
-#define	MPTSAS_MOD_STRING "MPTSAS HBA Driver 00.00.00.24"
+#define	MPTSAS_MOD_STRING "MPTSAS HBA Driver 00.00.00.24X"
 
 static struct modldrv modldrv = {
 	&mod_driverops,	/* Type of module. This one is a driver */
@@ -1335,6 +1335,12 @@
 		goto fail;
 	intr_added++;
 
+	/*
+	 * The mutex to protect task management during reset
+	 */
+	mutex_init(&mpt->m_taskmgmt_mutex, NULL, MUTEX_SPIN,
+	    DDI_INTR_PRI(mpt->m_intr_pri));
+
 	/* Initialize mutex used in interrupt handler */
 	mutex_init(&mpt->m_mutex, NULL, MUTEX_DRIVER,
 	    DDI_INTR_PRI(mpt->m_intr_pri));
@@ -1629,6 +1635,7 @@
 			mutex_destroy(&mpt->m_tx_waitq_mutex);
 			mutex_destroy(&mpt->m_passthru_mutex);
 			mutex_destroy(&mpt->m_mutex);
+			mutex_destroy(&mpt->m_taskmgmt_mutex);
 			for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
 				mutex_destroy(
 				    &mpt->m_phy_info[i].smhba_info.phy_mutex);
@@ -2048,6 +2055,7 @@
 	mutex_destroy(&mpt->m_tx_waitq_mutex);
 	mutex_destroy(&mpt->m_passthru_mutex);
 	mutex_destroy(&mpt->m_mutex);
+	mutex_destroy(&mpt->m_taskmgmt_mutex);
 	for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
 		mutex_destroy(&mpt->m_phy_info[i].smhba_info.phy_mutex);
 	}
@@ -2409,7 +2417,7 @@
 		if ((ioc_status & MPI2_IOC_STATE_MASK) !=
 		    MPI2_IOC_STATE_OPERATIONAL) {
 			mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
-			if (mptsas_restart_ioc(mpt) == DDI_FAILURE) {
+			if (mptsas_reset_handler(mpt) == DDI_FAILURE) {
 				mptsas_log(mpt, CE_WARN,
 				    "mptsas_power: hard reset failed");
 				mutex_exit(&mpt->m_mutex);
@@ -3426,16 +3434,20 @@
 	 * re-initialized.  If this is the case, return BUSY so the I/O can be
 	 * retried later.
 	 */
+	mutex_enter(&mpt->m_taskmgmt_mutex);
 	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);
+			mutex_exit(&mpt->m_taskmgmt_mutex);
 			return (rval);
 		} else {
+			mutex_exit(&mpt->m_taskmgmt_mutex);
 			return (TRAN_BUSY);
 		}
 	}
+	mutex_exit(&mpt->m_taskmgmt_mutex);
 
 	/*
 	 * If device handle has already been invalidated, just
@@ -3691,7 +3703,9 @@
 			 * allocated packet and bail out.
 			 */
 			mutex_enter(&mpt->m_mutex);
-			if (mpt->m_in_reset) {
+			mutex_enter(&mpt->m_taskmgmt_mutex);
+			if (mpt->m_in_reset == TRUE) {
+				mutex_exit(&mpt->m_taskmgmt_mutex);
 				mutex_exit(&mpt->m_mutex);
 
 				cmd->cmd_flags = CFLAG_FREE;
@@ -3698,6 +3712,7 @@
 				kmem_cache_free(mpt->m_kmem_cache, cmd);
 				return (NULL);
 			}
+			mutex_exit(&mpt->m_taskmgmt_mutex);
 			mpt->m_extreq_sense_refcount++;
 			ASSERT(mpt->m_extreq_sense_refcount > 0);
 			mutex_exit(&mpt->m_mutex);
@@ -5372,10 +5387,13 @@
 			NDBG20(("send mptsas_handle_event_sync success"));
 		}
 
-		if (mpt->m_in_reset) {
+		mutex_enter(&mpt->m_taskmgmt_mutex);
+		if (mpt->m_in_reset == TRUE) {
 			NDBG20(("dropping event received during reset"));
+			mutex_exit(&mpt->m_taskmgmt_mutex);
 			return;
 		}
+		mutex_exit(&mpt->m_taskmgmt_mutex);
 
 		if ((ddi_taskq_dispatch(mpt->m_event_taskq, mptsas_handle_event,
 		    (void *)args, DDI_NOSLEEP)) != DDI_SUCCESS) {
@@ -6342,10 +6360,12 @@
 		 * If HBA is being reset, don't perform operations depending
 		 * on the IOC. We must free the topo list, however.
 		 */
-		if (!mpt->m_in_reset)
+
+		mutex_enter(&mpt->m_taskmgmt_mutex);
+		if (mpt->m_in_reset == FALSE)
 			mptsas_handle_topo_change(topo_node, parent);
-		else
-			NDBG20(("skipping topo change received during reset"));
+		mutex_exit(&mpt->m_taskmgmt_mutex);
+
 		save_node = topo_node;
 		topo_node = topo_node->next;
 		ASSERT(save_node);
@@ -7614,11 +7634,14 @@
 	/*
 	 * If HBA is being reset, drop incoming event.
 	 */
-	if (mpt->m_in_reset) {
+	mutex_enter(&mpt->m_taskmgmt_mutex);
+	if (mpt->m_in_reset == TRUE) {
 		NDBG20(("dropping event received prior to reset"));
+		mutex_exit(&mpt->m_taskmgmt_mutex);
 		mutex_exit(&mpt->m_mutex);
 		return;
 	}
+	mutex_exit(&mpt->m_taskmgmt_mutex);
 
 	eventreply = (pMpi2EventNotificationReply_t)
 	    (mpt->m_reply_frame + (rfm -
@@ -9922,7 +9945,7 @@
 			mptsas_log(mpt, CE_WARN, "MPT Firmware Fault, "
 			    "code: %04x", doorbell);
 			mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
-			if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
+			if ((mptsas_reset_handler(mpt)) == DDI_FAILURE) {
 				mptsas_log(mpt, CE_WARN, "Reset failed"
 				    "after fault was detected");
 			}
@@ -11179,8 +11202,8 @@
 		mptsas_dma_free(&dataout_dma_state);
 	}
 	if (pt_flags & MPTSAS_CMD_TIMEOUT) {
-		if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
-			mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
+		if ((mptsas_reset_handler(mpt)) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_reset_handler failed");
 		}
 	}
 	if (request_msg)
@@ -12685,7 +12708,7 @@
 			 * firmware.  Reset if failed also.
 			 */
 			mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
-			if (mptsas_restart_ioc(mpt) == DDI_FAILURE) {
+			if (mptsas_reset_handler(mpt) == DDI_FAILURE) {
 				status = EFAULT;
 			}
 			mutex_exit(&mpt->m_mutex);
@@ -12757,7 +12780,7 @@
 		case MPTIOCTL_RESET_ADAPTER:
 			mutex_enter(&mpt->m_mutex);
 			mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
-			if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
+			if ((mptsas_reset_handler(mpt)) == DDI_FAILURE) {
 				mptsas_log(mpt, CE_WARN, "reset adapter IOCTL "
 				    "failed");
 				status = EFAULT;
@@ -12824,7 +12847,7 @@
 }
 
 int
-mptsas_restart_ioc(mptsas_t *mpt)
+mptsas_reset_handler(mptsas_t *mpt)
 {
 	int		rval = DDI_SUCCESS;
 	mptsas_target_t	*ptgt = NULL;
@@ -12832,13 +12855,19 @@
 	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
+	 * Set a flag telling task management we are 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.
 	 */
+	mutex_enter(&mpt->m_taskmgmt_mutex);
+	if (mpt->m_in_reset == TRUE) {
+		mutex_exit(&mpt->m_taskmgmt_mutex);
+		return (DDI_FAILURE);
+	}
 	mpt->m_in_reset = TRUE;
+	mutex_exit(&mpt->m_taskmgmt_mutex);
 
 	/*
 	 * Wait until all the allocated sense data buffers for DMA are freed.
@@ -12903,7 +12932,9 @@
 	/*
 	 * Clear the reset flag so that I/Os can continue.
 	 */
+	mutex_enter(&mpt->m_taskmgmt_mutex);
 	mpt->m_in_reset = FALSE;
+	mutex_exit(&mpt->m_taskmgmt_mutex);
 
 	return (rval);
 }
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c	Sun Jan 29 11:45:55 2017
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c	Sun Jan 29 11:45:55 2017
@@ -602,8 +602,8 @@
 
 	if (config_flags & MPTSAS_CMD_TIMEOUT) {
 		mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
-		if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
-			mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
+		if ((mptsas_reset_handler(mpt)) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_reset_handler failed");
 		}
 	}
 
@@ -1203,8 +1203,8 @@
 		mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
 		    "try to reset ioc to recovery!");
 		mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
-		if (mptsas_restart_ioc(mpt)) {
-			mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
+		if (mptsas_reset_handler(mpt)) {
+			mptsas_log(mpt, CE_WARN, "mptsas_reset_handler failed");
 			rval = FAILED;
 		}
 	}
@@ -1406,8 +1406,8 @@
 	    drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
 	if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
 		mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
-		if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
-			mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
+		if ((mptsas_reset_handler(mpt)) == DDI_FAILURE) {
+			mptsas_log(mpt, CE_WARN, "mptsas_reset_handler failed");
 		}
 		rvalue = -1;
 	}
--- old/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Sun Jan 29 11:45:56 2017
+++ new/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h	Sun Jan 29 11:45:56 2017
@@ -937,6 +937,11 @@
 	uint8_t			m_in_reset;
 
 	/*
+	 * Task management protection
+	 */
+	kmutex_t		m_taskmgmt_mutex;
+
+	/*
 	 * per instance cmd data structures for task management cmds
 	 */
 	m_event_struct_t	m_event_task_mgmt;	/* must be last */
@@ -1332,7 +1337,7 @@
 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);
-int mptsas_restart_ioc(mptsas_t *mpt);
+int mptsas_reset_handler(mptsas_t *mpt);
 void mptsas_update_driver_data(struct mptsas *mpt);
 uint64_t mptsas_get_sata_guid(mptsas_t *mpt, mptsas_target_t *ptgt, int lun);
 
