diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
index 32f513b1b78a..eb8efdcefe48 100644
--- a/drivers/scsi/aic94xx/aic94xx.h
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -102,6 +102,7 @@ int  asd_abort_task_set(struct domain_device *, u8 *lun);
 int  asd_clear_aca(struct domain_device *, u8 *lun);
 int  asd_clear_task_set(struct domain_device *, u8 *lun);
 int  asd_lu_reset(struct domain_device *, u8 *lun);
+int  asd_I_T_nexus_reset(struct domain_device *dev);
 int  asd_query_task(struct sas_task *);
 
 /* ---------- Adapter and Port management ---------- */
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 5d761eb67442..88d1e731b65e 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -1003,7 +1003,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
 	.lldd_abort_task_set	= asd_abort_task_set,
 	.lldd_clear_aca		= asd_clear_aca,
 	.lldd_clear_task_set	= asd_clear_task_set,
-	.lldd_I_T_nexus_reset	= NULL,
+	.lldd_I_T_nexus_reset	= asd_I_T_nexus_reset,
 	.lldd_lu_reset		= asd_lu_reset,
 	.lldd_query_task	= asd_query_task,
 
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index 144f5ad20453..d684c7432e63 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -140,8 +140,14 @@ int asd_clear_nexus_port(struct asd_sas_port *port)
 	CLEAR_NEXUS_POST;
 }
 
-#if 0
-static int asd_clear_nexus_I_T(struct domain_device *dev)
+enum clear_nexus_phase {
+	NEXUS_PHASE_PRE,
+	NEXUS_PHASE_POST,
+	NEXUS_PHASE_RESUME,
+};
+
+static int asd_clear_nexus_I_T(struct domain_device *dev,
+			       enum clear_nexus_phase phase)
 {
 	struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
 	struct asd_ascb *ascb;
@@ -150,12 +156,56 @@ static int asd_clear_nexus_I_T(struct domain_device *dev)
 
 	CLEAR_NEXUS_PRE;
 	scb->clear_nexus.nexus = NEXUS_I_T;
-	scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
+	switch (phase) {
+	case NEXUS_PHASE_PRE:
+		scb->clear_nexus.flags = EXEC_Q | SUSPEND_TX;
+		break;
+	case NEXUS_PHASE_POST:
+		scb->clear_nexus.flags = SEND_Q | NOTINQ;
+		break;
+	case NEXUS_PHASE_RESUME:
+		scb->clear_nexus.flags = RESUME_TX;
+	}
 	scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
 						   dev->lldd_dev);
 	CLEAR_NEXUS_POST;
 }
-#endif
+
+int asd_I_T_nexus_reset(struct domain_device *dev)
+{
+	int res, tmp_res, i;
+	struct sas_phy *phy = sas_find_local_phy(dev);
+	/* Standard mandates link reset for ATA  (type 0) and
+	 * hard reset for SSP (type 1) */
+	int reset_type = (dev->dev_type == SATA_DEV ||
+			  (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
+
+	asd_clear_nexus_I_T(dev, NEXUS_PHASE_PRE);
+	/* send a hard reset */
+	ASD_DPRINTK("sending %s reset to %s\n",
+		    reset_type ? "hard" : "soft", phy->dev.bus_id);
+	res = sas_phy_reset(phy, reset_type);
+	if (res == TMF_RESP_FUNC_COMPLETE) {
+		/* wait for the maximum settle time */
+		msleep(500);
+		/* clear all outstanding commands (keep nexus suspended) */
+		asd_clear_nexus_I_T(dev, NEXUS_PHASE_POST);
+	}
+	for (i = 0 ; i < 3; i++) {
+		tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
+		if (tmp_res == TC_RESUME)
+			return res;
+		msleep(500);
+	}
+
+	/* This is a bit of a problem:  the sequencer is still suspended
+	 * and is refusing to resume.  Hope it will resume on a bigger hammer
+	 * or the disk is lost */
+	dev_printk(KERN_ERR, &phy->dev,
+		   "Failed to resume nexus after reset 0x%x\n", tmp_res);
+
+	return TMF_RESP_FUNC_FAILED;
+}
 
 static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
 {