changeset 13118:98bb3694e858

6965278 nv_sata: harden driver against inconsistent hardware behavior 6965266 nv_sata: synchronous path incorrectly uses cv_wait 6948165 user-initiated sata reset does not recover
author Martin Faltesek <Martin.Faltesek@Sun.COM>
date Fri, 13 Aug 2010 15:06:10 -0700
parents f8c2d8257841
children 0e16e468e300
files usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c usr/src/uts/common/io/sata/impl/sata.c usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h
diffstat 3 files changed, 1004 insertions(+), 1058 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c	Fri Aug 13 14:49:55 2010 -0700
+++ b/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c	Fri Aug 13 15:06:10 2010 -0700
@@ -123,7 +123,7 @@
 static void mcp5x_reg_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle);
 static void ck804_reg_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle);
 static void nv_uninit_port(nv_port_t *nvp);
-static int nv_init_port(nv_port_t *nvp);
+static void nv_init_port(nv_port_t *nvp);
 static int nv_init_ctl(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle);
 static int mcp5x_packet_complete_intr(nv_ctl_t *nvc, nv_port_t *nvp);
 #ifdef NCQ
@@ -146,10 +146,10 @@
 static void nv_suspend(nv_port_t *nvp);
 static int nv_start_sync(nv_port_t *nvp, sata_pkt_t *spkt);
 static int nv_abort_active(nv_port_t *nvp, sata_pkt_t *spkt, int abort_reason,
-    int flag);
+    boolean_t reset);
 static void nv_copy_registers(nv_port_t *nvp, sata_device_t *sd,
     sata_pkt_t *spkt);
-static void nv_report_add_remove(nv_port_t *nvp, int flags);
+static void nv_link_event(nv_port_t *nvp, int flags);
 static int nv_start_async(nv_port_t *nvp, sata_pkt_t *spkt);
 static int nv_wait3(nv_port_t *nvp, uchar_t onbits1, uchar_t offbits1,
     uchar_t failure_onbits2, uchar_t failure_offbits2,
@@ -158,9 +158,8 @@
 static int nv_wait(nv_port_t *nvp, uchar_t onbits, uchar_t offbits,
     uint_t timeout_usec, int type_wait);
 static int nv_start_rqsense_pio(nv_port_t *nvp, nv_slot_t *nv_slotp);
-static void nv_init_port_link_processing(nv_ctl_t *nvc);
-static void nv_setup_timeout(nv_port_t *nvp, int time);
-static void nv_monitor_reset(nv_port_t *nvp);
+static void nv_setup_timeout(nv_port_t *nvp, clock_t microseconds);
+static clock_t nv_monitor_reset(nv_port_t *nvp);
 static int nv_bm_status_clear(nv_port_t *nvp);
 static void nv_log(nv_ctl_t *nvc, nv_port_t *nvp, const char *fmt, ...);
 
@@ -323,93 +322,59 @@
 	NULL
 };
 
-
-/*
- * Wait for a signature.
- * If this variable is non-zero, the driver will wait for a device signature
- * before reporting a device reset to the sata module.
- * Some (most?) drives will not process commands sent to them before D2H FIS
- * is sent to a host.
- */
-int nv_wait_for_signature = 1;
-
-/*
- * Check for a signature availability.
- * If this variable is non-zero, the driver will check task file error register
- * for indication of a signature availability before reading a signature.
- * Task file error register bit 0 set to 1 indicates that the drive
- * is ready and it has sent the D2H FIS with a signature.
- * This behavior of the error register is not reliable in the mcp5x controller.
- */
-int nv_check_tfr_error = 0;
-
-/*
- * Max signature acquisition time, in milliseconds.
- * The driver will try to acquire a device signature within specified time and
- * quit acquisition operation if signature was not acquired.
- */
-long nv_sig_acquisition_time = NV_SIG_ACQUISITION_TIME;
-
-/*
- * If this variable is non-zero, the driver will wait for a signature in the
- * nv_monitor_reset function without any time limit.
- * Used for debugging and drive evaluation.
- */
-int nv_wait_here_forever = 0;
-
-/*
- * Reset after hotplug.
- * If this variable is non-zero, driver will reset device after hotplug
- * (device attached) interrupt.
- * If the variable is zero, driver will not reset the new device nor will it
- * try to read device signature.
- * Chipset is generating a hotplug (device attached) interrupt with a delay, so
- * the device should have already sent the D2H FIS with the signature.
- */
-int nv_reset_after_hotplug = 1;
-
-/*
- * Delay after device hotplug.
- * It specifies the time between detecting a hotplugged device and sending
- * a notification to the SATA module.
- * It is used when device is not reset after hotpugging and acquiring signature
- * may be unreliable. The delay should be long enough for a device to become
- * ready to accept commands.
- */
-int nv_hotplug_delay = NV_HOTPLUG_DELAY;
-
-
 /*
  * Maximum number of consecutive interrupts processed in the loop in the
  * single invocation of the port interrupt routine.
  */
 int nv_max_intr_loops = NV_MAX_INTR_PER_DEV;
 
-
-
 /*
  * wait between checks of reg status
  */
 int nv_usec_delay = NV_WAIT_REG_CHECK;
 
 /*
- * The following is needed for nv_vcmn_err()
+ * The following used for nv_vcmn_err() and nv_log()
+ */
+
+/*
+ * temp buffer to save from wasting limited stack space
  */
-static kmutex_t nv_log_mutex; /* protects nv_log_buf */
 static char nv_log_buf[NV_LOGBUF_LEN];
+
+/*
+ * protects nv_log_buf
+ */
+static kmutex_t nv_log_mutex;
+
+/*
+ * these on-by-default flags were chosen so that the driver
+ * logs as much non-usual run-time information as possible
+ * without overflowing the ring with useless information or
+ * causing any significant performance penalty.
+ */
 int nv_debug_flags =
     NVDBG_HOT|NVDBG_RESET|NVDBG_ALWAYS|NVDBG_TIMEOUT|NVDBG_EVENT;
+
+/*
+ * normally debug information is not logged to the console
+ * but this allows it to be enabled.
+ */
 int nv_log_to_console = B_FALSE;
 
-int nv_prom_print = B_FALSE;
-
 /*
- * for debugging
+ * normally debug information is not logged to cmn_err but
+ * in some cases it may be desired.
  */
-#ifdef DEBUG
-int ncq_commands = 0;
-int non_ncq_commands = 0;
-#endif
+int nv_log_to_cmn_err = B_FALSE;
+
+/*
+ * using prom print avoids using cmn_err/syslog and goes right
+ * to the console which may be desirable in some situations, but
+ * it may be synchronous, which would change timings and
+ * impact performance.  Use with caution.
+ */
+int nv_prom_print = B_FALSE;
 
 /*
  * Opaque state pointer to be initialized by ddi_soft_state_init()
@@ -444,7 +409,9 @@
 static struct nv_sgp_cbp2cmn nv_sgp_cbp2cmn[NV_MAX_CBPS];
 #endif
 
-/* We still have problems in 40-bit DMA support, so disable it by default */
+/*
+ * control whether 40bit DMA is used or not
+ */
 int nv_sata_40bit_dma = B_TRUE;
 
 static sata_tran_hotplug_ops_t nv_hotplug_ops = {
@@ -600,7 +567,7 @@
 static int
 nv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 {
-	int status, attach_state, intr_types, bar, i, command;
+	int status, attach_state, intr_types, bar, i, j, command;
 	int inst = ddi_get_instance(dip);
 	ddi_acc_handle_t pci_conf_handle;
 	nv_ctl_t *nvc;
@@ -788,9 +755,34 @@
 #endif	/* SGPIO_SUPPORT */
 
 		/*
-		 * Initiate link processing and device identification
+		 * Do initial reset so that signature can be gathered
 		 */
-		nv_init_port_link_processing(nvc);
+		for (j = 0; j < NV_NUM_PORTS; j++) {
+			ddi_acc_handle_t bar5_hdl;
+			uint32_t sstatus;
+			nv_port_t *nvp;
+
+			nvp = &(nvc->nvc_port[j]);
+			bar5_hdl = nvp->nvp_ctlp->nvc_bar_hdl[5];
+			sstatus = ddi_get32(bar5_hdl, nvp->nvp_sstatus);
+
+			if (SSTATUS_GET_DET(sstatus) ==
+			    SSTATUS_DET_DEVPRE_PHYCOM) {
+
+				nvp->nvp_state |= NV_ATTACH;
+				nvp->nvp_type = SATA_DTYPE_UNKNOWN;
+				mutex_enter(&nvp->nvp_mutex);
+				nv_reset(nvp, "attach");
+
+				while (nvp->nvp_state & NV_RESET) {
+					cv_wait(&nvp->nvp_reset_cv,
+					    &nvp->nvp_mutex);
+				}
+
+				mutex_exit(&nvp->nvp_mutex);
+			}
+		}
+
 		/*
 		 * attach to sata module
 		 */
@@ -1214,6 +1206,8 @@
 	uint8_t cport = sd->satadev_addr.cport;
 	uint8_t pmport = sd->satadev_addr.pmport;
 	uint8_t qual = sd->satadev_addr.qual;
+	uint8_t det;
+
 	nv_port_t *nvp;
 
 	if (cport >= NV_MAX_PORTS(nvc)) {
@@ -1237,7 +1231,7 @@
 	 * This check seems to be done in the SATA module.
 	 * It may not be required here
 	 */
-	if (nvp->nvp_state & NV_PORT_INACTIVE) {
+	if (nvp->nvp_state & NV_DEACTIVATED) {
 		nv_cmn_err(CE_WARN, nvc, nvp,
 		    "port inactive.  Use cfgadm to activate");
 		sd->satadev_type = SATA_DTYPE_UNKNOWN;
@@ -1247,10 +1241,10 @@
 		return (SATA_SUCCESS);
 	}
 
-	if (nvp->nvp_state & NV_PORT_FAILED) {
+	if (nvp->nvp_state & NV_FAILED) {
 		NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
 		    "probe: port failed", NULL);
-		sd->satadev_type = SATA_DTYPE_NONE;
+		sd->satadev_type = nvp->nvp_type;
 		sd->satadev_state = SATA_PSTATE_FAILED;
 		mutex_exit(&nvp->nvp_mutex);
 
@@ -1271,45 +1265,56 @@
 
 	nv_copy_registers(nvp, sd, NULL);
 
-	if (nvp->nvp_state & (NV_PORT_RESET | NV_PORT_RESET_RETRY)) {
+	if (nvp->nvp_state & (NV_RESET|NV_LINK_EVENT)) {
 		/*
-		 * We are waiting for reset to complete and to fetch
-		 * a signature.
-		 * Reset will cause the link to go down for a short period of
-		 * time.  If reset processing continues for less than
-		 * NV_LINK_DOWN_TIMEOUT, fake the status of the link so that
-		 * we will not report intermittent link down.
-		 * Maybe we should report previous link state?
+		 * during a reset or link event, fake the status
+		 * as it may be changing as a result of the reset
+		 * or link event.
 		 */
-		if (TICK_TO_MSEC(ddi_get_lbolt() - nvp->nvp_reset_time) <
-		    NV_LINK_DOWN_TIMEOUT) {
-			SSTATUS_SET_IPM(sd->satadev_scr.sstatus,
-			    SSTATUS_IPM_ACTIVE);
-			SSTATUS_SET_DET(sd->satadev_scr.sstatus,
-			    SSTATUS_DET_DEVPRE_PHYCOM);
-			sd->satadev_type = nvp->nvp_type;
-			mutex_exit(&nvp->nvp_mutex);
-
-			return (SATA_SUCCESS);
+		DTRACE_PROBE(state_reset_link_event_faking_status_p);
+		DTRACE_PROBE1(nvp_state_h, int, nvp->nvp_state);
+
+		SSTATUS_SET_IPM(sd->satadev_scr.sstatus,
+		    SSTATUS_IPM_ACTIVE);
+		SSTATUS_SET_DET(sd->satadev_scr.sstatus,
+		    SSTATUS_DET_DEVPRE_PHYCOM);
+		sd->satadev_type = nvp->nvp_type;
+		mutex_exit(&nvp->nvp_mutex);
+
+		return (SATA_SUCCESS);
+	}
+
+	det = SSTATUS_GET_DET(sd->satadev_scr.sstatus);
+
+	/*
+	 * determine link status
+	 */
+	if (det != SSTATUS_DET_DEVPRE_PHYCOM) {
+		switch (det) {
+
+		case SSTATUS_DET_NODEV:
+		case SSTATUS_DET_PHYOFFLINE:
+			sd->satadev_type = SATA_DTYPE_NONE;
+			break;
+
+		default:
+			sd->satadev_type = SATA_DTYPE_UNKNOWN;
+			break;
 		}
-	}
+
+		mutex_exit(&nvp->nvp_mutex);
+
+		return (SATA_SUCCESS);
+	}
+
 	/*
 	 * Just report the current port state
 	 */
 	sd->satadev_type = nvp->nvp_type;
-	sd->satadev_state = nvp->nvp_state | SATA_PSTATE_PWRON;
+	DTRACE_PROBE1(nvp_type_h, int, nvp->nvp_type);
+
 	mutex_exit(&nvp->nvp_mutex);
 
-#ifdef SGPIO_SUPPORT
-	if (nvp->nvp_type == SATA_DTYPE_ATADISK) {
-		nv_sgp_drive_connect(nvp->nvp_ctlp, SGP_CTLR_PORT_TO_DRV(
-		    nvp->nvp_ctlp->nvc_ctlr_num, nvp->nvp_port_num));
-	} else {
-		nv_sgp_drive_disconnect(nvp->nvp_ctlp, SGP_CTLR_PORT_TO_DRV(
-		    nvp->nvp_ctlp->nvc_ctlr_num, nvp->nvp_port_num));
-	}
-#endif
-
 	return (SATA_SUCCESS);
 }
 
@@ -1330,63 +1335,88 @@
 
 	mutex_enter(&nvp->nvp_mutex);
 
-	/*
-	 * record number of commands for debugging
-	 */
-	nvp->nvp_seq++;
-
-	if ((nvp->nvp_state & NV_PORT_INIT) == 0) {
+	if (nvp->nvp_state & NV_DEACTIVATED) {
+
+		NVLOG(NVDBG_ERRS, nvc, nvp,
+		    "nv_sata_start: NV_DEACTIVATED", NULL);
+		DTRACE_PROBE(nvp_state_inactive_p);
+
 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
-		NVLOG(NVDBG_ERRS, nvc, nvp,
-		    "nv_sata_start: port not yet initialized", NULL);
 		nv_copy_registers(nvp, &spkt->satapkt_device, NULL);
 		mutex_exit(&nvp->nvp_mutex);
 
 		return (SATA_TRAN_PORT_ERROR);
 	}
 
-	if (nvp->nvp_state & NV_PORT_INACTIVE) {
+	if (nvp->nvp_state & NV_FAILED) {
+
+		NVLOG(NVDBG_ERRS, nvc, nvp,
+		    "nv_sata_start: NV_FAILED state", NULL);
+		DTRACE_PROBE(nvp_state_failed_p);
+
 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
-		NVLOG(NVDBG_ERRS, nvc, nvp,
-		    "nv_sata_start: NV_PORT_INACTIVE", NULL);
 		nv_copy_registers(nvp, &spkt->satapkt_device, NULL);
 		mutex_exit(&nvp->nvp_mutex);
 
 		return (SATA_TRAN_PORT_ERROR);
 	}
 
-	if (nvp->nvp_state & NV_PORT_FAILED) {
-		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
-		NVLOG(NVDBG_ERRS, nvc, nvp,
-		    "nv_sata_start: NV_PORT_FAILED state", NULL);
-		nv_copy_registers(nvp, &spkt->satapkt_device, NULL);
-		mutex_exit(&nvp->nvp_mutex);
-
-		return (SATA_TRAN_PORT_ERROR);
-	}
-
-	if (nvp->nvp_state & NV_PORT_RESET) {
+	if (nvp->nvp_state & NV_RESET) {
+
 		NVLOG(NVDBG_ERRS, nvc, nvp,
 		    "still waiting for reset completion", NULL);
+		DTRACE_PROBE(nvp_state_reset_p);
+
 		spkt->satapkt_reason = SATA_PKT_BUSY;
-		mutex_exit(&nvp->nvp_mutex);
 
 		/*
-		 * If in panic, timeouts do not occur, so fake one
-		 * so that the signature can be acquired to complete
-		 * the reset handling.
+		 * If in panic, timeouts do not occur, so invoke
+		 * reset handling directly so that the signature
+		 * can be acquired to complete the reset handling.
 		 */
 		if (ddi_in_panic()) {
-			nv_timeout(nvp);
+			NVLOG(NVDBG_ERRS, nvc, nvp,
+			    "nv_sata_start: calling nv_monitor_reset "
+			    "synchronously", NULL);
+
+			(void) nv_monitor_reset(nvp);
 		}
 
+		mutex_exit(&nvp->nvp_mutex);
+
 		return (SATA_TRAN_BUSY);
 	}
 
-	if (nvp->nvp_type == SATA_DTYPE_NONE) {
+	if (nvp->nvp_state & NV_LINK_EVENT) {
+
+		NVLOG(NVDBG_ERRS, nvc, nvp,
+		    "nv_sata_start(): link event ret bsy", NULL);
+		DTRACE_PROBE(nvp_state_link_event_p);
+
+		spkt->satapkt_reason = SATA_PKT_BUSY;
+
+		if (ddi_in_panic()) {
+			NVLOG(NVDBG_ERRS, nvc, nvp,
+			    "nv_sata_start: calling nv_timeout "
+			    "synchronously", NULL);
+
+			nv_timeout(nvp);
+		}
+
+		mutex_exit(&nvp->nvp_mutex);
+
+		return (SATA_TRAN_BUSY);
+	}
+
+
+	if ((nvp->nvp_type == SATA_DTYPE_NONE) ||
+	    (nvp->nvp_type == SATA_DTYPE_UNKNOWN)) {
+
+		NVLOG(NVDBG_ERRS, nvc, nvp,
+		    "nv_sata_start: nvp_type 0x%x", nvp->nvp_type);
+		DTRACE_PROBE1(not_ready_nvp_type_h, int, nvp->nvp_type);
+
 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
-		NVLOG(NVDBG_ERRS, nvc, nvp,
-		    "nv_sata_start: SATA_DTYPE_NONE", NULL);
 		nv_copy_registers(nvp, &spkt->satapkt_device, NULL);
 		mutex_exit(&nvp->nvp_mutex);
 
@@ -1394,9 +1424,11 @@
 	}
 
 	if (spkt->satapkt_device.satadev_type == SATA_DTYPE_PMULT) {
-		ASSERT(nvp->nvp_type == SATA_DTYPE_PMULT);
+
 		nv_cmn_err(CE_WARN, nvc, nvp,
-		    "port multipliers not supported by controller");
+		    "port multiplier not supported by controller");
+
+		ASSERT(nvp->nvp_type == SATA_DTYPE_PMULT);
 		spkt->satapkt_reason = SATA_PKT_CMD_UNSUPPORTED;
 		mutex_exit(&nvp->nvp_mutex);
 
@@ -1410,41 +1442,62 @@
 	 * non-restore related commands should be processed.
 	 */
 	if (spkt->satapkt_cmd.satacmd_flags.sata_clear_dev_reset) {
-		nvp->nvp_state &= ~NV_PORT_RESTORE;
+
 		NVLOG(NVDBG_RESET, nvc, nvp,
-		    "nv_sata_start: clearing NV_PORT_RESTORE", NULL);
+		    "nv_sata_start: clearing NV_RESTORE", NULL);
+		DTRACE_PROBE(clearing_restore_p);
+		DTRACE_PROBE1(nvp_state_before_clear_h, int, nvp->nvp_state);
+
+		nvp->nvp_state &= ~NV_RESTORE;
 	}
 
 	/*
-	 * if the device was recently reset as indicated by NV_PORT_RESTORE,
+	 * if the device was recently reset as indicated by NV_RESTORE,
 	 * only allow commands which restore device state.  The sata module
-	 * marks such commands with with sata_ignore_dev_reset.
+	 * marks such commands with sata_ignore_dev_reset.
 	 *
-	 * during coredump, nv_reset is called and but then the restore
-	 * doesn't happen.  For now, workaround by ignoring the wait for
-	 * restore if the system is panicing.
+	 * during coredump, nv_reset is called but the restore isn't
+	 * processed, so ignore the wait for restore if the system
+	 * is panicing.
 	 */
-	if ((nvp->nvp_state & NV_PORT_RESTORE) &&
+	if ((nvp->nvp_state & NV_RESTORE) &&
 	    !(spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset) &&
 	    (ddi_in_panic() == 0)) {
-		spkt->satapkt_reason = SATA_PKT_BUSY;
+
 		NVLOG(NVDBG_RESET, nvc, nvp,
 		    "nv_sata_start: waiting for restore ", NULL);
+		DTRACE_PROBE1(restore_no_ignore_reset_nvp_state_h,
+		    int, nvp->nvp_state);
+
+		spkt->satapkt_reason = SATA_PKT_BUSY;
 		mutex_exit(&nvp->nvp_mutex);
 
 		return (SATA_TRAN_BUSY);
 	}
 
-	if (nvp->nvp_state & NV_PORT_ABORTING) {
+	if (nvp->nvp_state & NV_ABORTING) {
+
+		NVLOG(NVDBG_ERRS, nvc, nvp,
+		    "nv_sata_start: NV_ABORTING", NULL);
+		DTRACE_PROBE1(aborting_nvp_state_h, int, nvp->nvp_state);
+
 		spkt->satapkt_reason = SATA_PKT_BUSY;
-		NVLOG(NVDBG_ERRS, nvc, nvp,
-		    "nv_sata_start: NV_PORT_ABORTING", NULL);
 		mutex_exit(&nvp->nvp_mutex);
 
 		return (SATA_TRAN_BUSY);
 	}
 
-	/* Clear SError to be able to check errors after the command failure */
+	/*
+	 * record command sequence for debugging.
+	 */
+	nvp->nvp_seq++;
+
+	DTRACE_PROBE2(command_start, int *, nvp, int,
+	    spkt->satapkt_cmd.satacmd_cmd_reg);
+
+	/*
+	 * clear SError to be able to check errors after the command failure
+	 */
 	nv_put32(nvp->nvp_ctlp->nvc_bar_hdl[5], nvp->nvp_serror, 0xffffffff);
 
 	if (spkt->satapkt_op_mode &
@@ -1521,6 +1574,12 @@
 		(*(nvc->nvc_set_intr))(nvp, NV_INTR_DISABLE);
 	}
 
+	/*
+	 * overload the satapkt_reason with BUSY so code below
+	 * will know when it's done
+	 */
+	spkt->satapkt_reason = SATA_PKT_BUSY;
+
 	if ((ret = nv_start_common(nvp, spkt)) != SATA_TRAN_ACCEPTED) {
 		if (spkt->satapkt_op_mode & SATA_OPMODE_POLLING) {
 			(*(nvc->nvc_set_intr))(nvp, NV_INTR_ENABLE);
@@ -1544,14 +1603,12 @@
 
 	/*
 	 * non-polling synchronous mode handling.  The interrupt will signal
-	 * when the IO is completed.
+	 * when device IO is completed.
 	 */
-	cv_wait(&nvp->nvp_poll_cv, &nvp->nvp_mutex);
-
-	if (spkt->satapkt_reason != SATA_PKT_COMPLETED) {
-
-		spkt->satapkt_reason = SATA_PKT_TIMEOUT;
-	}
+	while (spkt->satapkt_reason == SATA_PKT_BUSY) {
+		cv_wait(&nvp->nvp_sync_cv, &nvp->nvp_mutex);
+	}
+
 
 	NVLOG(NVDBG_SYNC, nvp->nvp_ctlp, nvp, "nv_sata_satapkt_sync:"
 	    " done % reason %d", spkt->satapkt_reason);
@@ -1582,9 +1639,6 @@
 			mutex_enter(&nvp->nvp_mutex);
 			spkt->satapkt_reason = SATA_PKT_TIMEOUT;
 			nv_copy_registers(nvp, &spkt->satapkt_device, spkt);
-			nvp->nvp_state |= NV_PORT_RESET;
-			nvp->nvp_state &= ~(NV_PORT_RESTORE |
-			    NV_PORT_RESET_RETRY);
 			nv_reset(nvp, "poll_wait");
 			nv_complete_io(nvp, spkt, 0);
 			mutex_exit(&nvp->nvp_mutex);
@@ -1609,9 +1663,6 @@
 			    " unclaimed -- resetting", NULL);
 			mutex_enter(&nvp->nvp_mutex);
 			nv_copy_registers(nvp, &spkt->satapkt_device, spkt);
-			nvp->nvp_state |= NV_PORT_RESET;
-			nvp->nvp_state &= ~(NV_PORT_RESTORE |
-			    NV_PORT_RESET_RETRY);
 			nv_reset(nvp, "poll_wait intr not claimed");
 			spkt->satapkt_reason = SATA_PKT_TIMEOUT;
 			nv_complete_io(nvp, spkt, 0);
@@ -1650,7 +1701,7 @@
 
 	mutex_enter(&nvp->nvp_mutex);
 
-	if (nvp->nvp_state & NV_PORT_INACTIVE) {
+	if (nvp->nvp_state & NV_DEACTIVATED) {
 		mutex_exit(&nvp->nvp_mutex);
 		nv_cmn_err(CE_WARN, nvc, nvp,
 		    "abort request failed: port inactive");
@@ -1689,7 +1740,8 @@
  * held and returns with it held.  Not NCQ aware.
  */
 static int
-nv_abort_active(nv_port_t *nvp, sata_pkt_t *spkt, int abort_reason, int flag)
+nv_abort_active(nv_port_t *nvp, sata_pkt_t *spkt, int abort_reason,
+    boolean_t reset)
 {
 	int aborted = 0, i, reset_once = B_FALSE;
 	struct nv_slot *nv_slotp;
@@ -1697,19 +1749,9 @@
 
 	ASSERT(MUTEX_HELD(&nvp->nvp_mutex));
 
-	/*
-	 * return if the port is not configured
-	 */
-	if (nvp->nvp_slot == NULL) {
-		NVLOG(NVDBG_ENTRY, nvp->nvp_ctlp, nvp,
-		    "nv_abort_active: not configured so returning", NULL);
-
-		return (0);
-	}
-
 	NVLOG(NVDBG_ENTRY, nvp->nvp_ctlp, nvp, "nv_abort_active", NULL);
 
-	nvp->nvp_state |= NV_PORT_ABORTING;
+	nvp->nvp_state |= NV_ABORTING;
 
 	for (i = 0; i < nvp->nvp_queue_depth; i++) {
 
@@ -1744,13 +1786,10 @@
 			nv_put8(bmhdl, nvp->nvp_bmicx,  0);
 
 			/*
-			 * Reset only if explicitly specified by the arg flag
+			 * Reset only if explicitly specified by the arg reset
 			 */
-			if (flag == B_TRUE) {
+			if (reset == B_TRUE) {
 				reset_once = B_TRUE;
-				nvp->nvp_state |= NV_PORT_RESET;
-				nvp->nvp_state &= ~(NV_PORT_RESTORE |
-				    NV_PORT_RESET_RETRY);
 				nv_reset(nvp, "abort_active");
 			}
 		}
@@ -1760,7 +1799,7 @@
 		aborted++;
 	}
 
-	nvp->nvp_state &= ~NV_PORT_ABORTING;
+	nvp->nvp_state &= ~NV_ABORTING;
 
 	return (aborted);
 }
@@ -1775,7 +1814,7 @@
 	int cport = sd->satadev_addr.cport;
 	nv_ctl_t *nvc = ddi_get_soft_state(nv_statep, ddi_get_instance(dip));
 	nv_port_t *nvp = &(nvc->nvc_port[cport]);
-	int ret = SATA_SUCCESS;
+	int ret = SATA_FAILURE;
 
 	ASSERT(cport < NV_MAX_PORTS(nvc));
 
@@ -1788,15 +1827,78 @@
 	case SATA_ADDR_CPORT:
 		/*FALLTHROUGH*/
 	case SATA_ADDR_DCPORT:
-		nvp->nvp_state |= NV_PORT_RESET;
-		nvp->nvp_state &= ~NV_PORT_RESTORE;
+
+		ret = SATA_SUCCESS;
+
+		/*
+		 * If a reset is already in progress, don't disturb it
+		 */
+		if ((nvp->nvp_state & (NV_RESET|NV_RESTORE)) &&
+		    (ddi_in_panic() == 0)) {
+			NVLOG(NVDBG_RESET, nvc, nvp,
+			    "nv_sata_reset: reset already in progress", NULL);
+			DTRACE_PROBE(reset_already_in_progress_p);
+
+			break;
+		}
+
+		/*
+		 * log the pre-reset state of the driver because dumping the
+		 * blocks will disturb it.
+		 */
+		if (ddi_in_panic() == 1) {
+			NVLOG(NVDBG_RESET, nvc, nvp, "in_panic.  nvp_state: "
+			    "0x%x nvp_reset_time: %d nvp_last_cmd: 0x%x "
+			    "nvp_previous_cmd: 0x%x nvp_reset_count: %d "
+			    "nvp_first_reset_reason: %s "
+			    "nvp_reset_reason: %s nvp_seq: %d "
+			    "in_interrupt: %d", nvp->nvp_state,
+			    nvp->nvp_reset_time, nvp->nvp_last_cmd,
+			    nvp->nvp_previous_cmd, nvp->nvp_reset_count,
+			    nvp->nvp_first_reset_reason,
+			    nvp->nvp_reset_reason, nvp->nvp_seq,
+			    servicing_interrupt());
+		}
+
 		nv_reset(nvp, "sata_reset");
+
 		(void) nv_abort_active(nvp, NULL, SATA_PKT_RESET, B_FALSE);
 
+		/*
+		 * If the port is inactive, do a quiet reset and don't attempt
+		 * to wait for reset completion or do any post reset processing
+		 *
+		 */
+		if (nvp->nvp_state & NV_DEACTIVATED) {
+			nvp->nvp_state &= ~NV_RESET;
+			nvp->nvp_reset_time = 0;
+
+			break;
+		}
+
+		/*
+		 * clear the port failed flag.  It will get set again
+		 * if the port is still not functioning.
+		 */
+		nvp->nvp_state &= ~NV_FAILED;
+
+		/*
+		 * timeouts are not available while the system is
+		 * dropping core, so call nv_monitor_reset() directly
+		 */
+		if (ddi_in_panic() != 0) {
+			while (nvp->nvp_state & NV_RESET) {
+				drv_usecwait(1000);
+				(void) nv_monitor_reset(nvp);
+			}
+
+			break;
+		}
+
 		break;
 	case SATA_ADDR_CNTRL:
 		NVLOG(NVDBG_ENTRY, nvc, nvp,
-		    "nv_sata_reset: conroller reset not supported", NULL);
+		    "nv_sata_reset: controller reset not supported", NULL);
 
 		break;
 	case SATA_ADDR_PMPORT:
@@ -1808,26 +1910,9 @@
 		/*
 		 * unsupported case
 		 */
-		ret = SATA_FAILURE;
 		break;
 	}
 
-	if (ret == SATA_SUCCESS) {
-		/*
-		 * If the port is inactive, do a quiet reset and don't attempt
-		 * to wait for reset completion or do any post reset processing
-		 */
-		if (nvp->nvp_state & NV_PORT_INACTIVE) {
-			nvp->nvp_state &= ~NV_PORT_RESET;
-			nvp->nvp_reset_time = 0;
-		}
-
-		/*
-		 * clear the port failed flag
-		 */
-		nvp->nvp_state &= ~NV_PORT_FAILED;
-	}
-
 	mutex_exit(&nvp->nvp_mutex);
 
 	return (ret);
@@ -1843,6 +1928,8 @@
 	int cport = sd->satadev_addr.cport;
 	nv_ctl_t *nvc = ddi_get_soft_state(nv_statep, ddi_get_instance(dip));
 	nv_port_t *nvp = &(nvc->nvc_port[cport]);
+	ddi_acc_handle_t bar5_hdl = nvp->nvp_ctlp->nvc_bar_hdl[5];
+	uint32_t sstatus;
 
 	ASSERT(cport < NV_MAX_PORTS(nvc));
 	NVLOG(NVDBG_ENTRY, nvc, nvp, "nv_sata_activate", NULL);
@@ -1855,13 +1942,30 @@
 
 	(*(nvc->nvc_set_intr))(nvp, NV_INTR_ENABLE);
 
-	nvp->nvp_state &= ~NV_PORT_INACTIVE;
-	/* Initiate link probing and device signature acquisition */
+	/*
+	 * initiate link probing and device signature acquisition
+	 */
+
+	bar5_hdl = nvp->nvp_ctlp->nvc_bar_hdl[5];
+
+	sstatus = ddi_get32(bar5_hdl, nvp->nvp_sstatus);
+
 	nvp->nvp_type = SATA_DTYPE_NONE;
-	nvp->nvp_signature = 0;
-	nvp->nvp_state |= NV_PORT_RESET; /* | NV_PORT_PROBE; */
-	nvp->nvp_state &= ~(NV_PORT_RESTORE | NV_PORT_RESET_RETRY);
-	nv_reset(nvp, "sata_activate");
+	nvp->nvp_signature = NV_NO_SIG;
+	nvp->nvp_state &= ~NV_DEACTIVATED;
+
+	if (SSTATUS_GET_DET(sstatus) ==
+	    SSTATUS_DET_DEVPRE_PHYCOM) {
+
+		nvp->nvp_state |= NV_ATTACH;
+		nvp->nvp_type = SATA_DTYPE_UNKNOWN;
+		nv_reset(nvp, "sata_activate");
+
+		while (nvp->nvp_state & NV_RESET) {
+			cv_wait(&nvp->nvp_reset_cv, &nvp->nvp_mutex);
+		}
+
+	}
 
 	mutex_exit(&nvp->nvp_mutex);
 
@@ -1889,7 +1993,7 @@
 	/*
 	 * make the device inaccessible
 	 */
-	nvp->nvp_state |= NV_PORT_INACTIVE;
+	nvp->nvp_state |= NV_DEACTIVATED;
 
 	/*
 	 * disable the interrupts on port
@@ -2003,8 +2107,8 @@
 			nv_slotp->nvslot_v_addr =
 			    spkt->satapkt_cmd.satacmd_bp->b_un.b_addr;
 			/*
-			 * Freeing DMA resources allocated by the framework
-			 * now to avoid buffer overwrite (dma sync) problems
+			 * Freeing DMA resources allocated by the sata common
+			 * module to avoid buffer overwrite (dma sync) problems
 			 * when the buffer is released at command completion.
 			 * Primarily an issue on systems with more than
 			 * 4GB of memory.
@@ -2024,7 +2128,7 @@
 		nv_slotp->nvslot_v_addr =
 		    spkt->satapkt_cmd.satacmd_bp->b_un.b_addr;
 		/*
-		 * Freeing DMA resources allocated by the framework now to
+		 * Freeing DMA resources allocated by the sata common module to
 		 * avoid buffer overwrite (dma sync) problems when the buffer
 		 * is released at command completion.  This is not an issue
 		 * for write because write does not update the buffer.
@@ -2098,22 +2202,9 @@
 nv_read_signature(nv_port_t *nvp)
 {
 	ddi_acc_handle_t cmdhdl = nvp->nvp_cmd_hdl;
-	int retry_once = 0;
+	int retry_count = 0;
 
 	retry:
-	/*
-	 * Task file error register bit 0 set to 1 indicate that drive
-	 * is ready and have sent D2H FIS with a signature.
-	 */
-	if (nv_check_tfr_error != 0) {
-		uint8_t tfr_error = nv_get8(cmdhdl, nvp->nvp_error);
-		if (!(tfr_error & SATA_ERROR_ILI)) {
-			NVLOG(NVDBG_VERBOSE, nvp->nvp_ctlp, nvp,
-			    "nv_read_signature: signature not ready", NULL);
-
-			return;
-		}
-	}
 
 	nvp->nvp_signature = nv_get8(cmdhdl, nvp->nvp_count);
 	nvp->nvp_signature |= (nv_get8(cmdhdl, nvp->nvp_sect) << 8);
@@ -2125,72 +2216,71 @@
 
 	switch (nvp->nvp_signature) {
 
-	case NV_SIG_DISK:
+	case NV_DISK_SIG:
 		NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp, "drive is a disk", NULL);
+		DTRACE_PROBE(signature_is_disk_device_p)
 		nvp->nvp_type = SATA_DTYPE_ATADISK;
+
 		break;
-	case NV_SIG_ATAPI:
+	case NV_ATAPI_SIG:
 		NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
 		    "drive is an optical device", NULL);
+		DTRACE_PROBE(signature_is_optical_device_p)
 		nvp->nvp_type = SATA_DTYPE_ATAPICD;
 		break;
-	case NV_SIG_PM:
+	case NV_PM_SIG:
 		NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
 		    "device is a port multiplier", NULL);
+		DTRACE_PROBE(signature_is_port_multiplier_p)
 		nvp->nvp_type = SATA_DTYPE_PMULT;
 		break;
-	case NV_SIG_NOTREADY:
+	case NV_NO_SIG:
 		NVLOG(NVDBG_VERBOSE, nvp->nvp_ctlp, nvp,
-		    "signature not ready", NULL);
+		    "signature not available", NULL);
+		DTRACE_PROBE(sig_not_available_p);
 		nvp->nvp_type = SATA_DTYPE_UNKNOWN;
 		break;
 	default:
-		if (retry_once++ == 0) {
+		if (retry_count++ == 0) {
 			/*
 			 * this is a rare corner case where the controller
-			 * was in the middle of updating the registers as the
-			 * driver is reading them.  If this happens, wait a
-			 * bit and retry, but just once.
+			 * is updating the task file registers as the driver
+			 * is reading them.  If this happens, wait a bit and
+			 * retry once.
 			 */
 			NV_DELAY_NSEC(1000000);
+			NVLOG(NVDBG_VERBOSE, nvp->nvp_ctlp, nvp,
+			    "invalid signature 0x%x retry once",
+			    nvp->nvp_signature);
+			DTRACE_PROBE1(signature_invalid_retry_once_h,
+			    int, nvp->nvp_signature);
 
 			goto retry;
 		}
 
-		nv_cmn_err(CE_WARN, nvp->nvp_ctlp, nvp, "signature %X not"
-		    " recognized", nvp->nvp_signature);
+		nv_cmn_err(CE_WARN, nvp->nvp_ctlp, nvp,
+		    "invalid signature 0x%x", nvp->nvp_signature);
 		nvp->nvp_type = SATA_DTYPE_UNKNOWN;
+
 		break;
 	}
-
-	if (nvp->nvp_signature) {
-		nvp->nvp_state &= ~(NV_PORT_RESET_RETRY | NV_PORT_RESET);
-	}
-
-#ifdef SGPIO_SUPPORT
-	if (nvp->nvp_signature == NV_SIG_DISK) {
-		nv_sgp_drive_connect(nvp->nvp_ctlp, SGP_CTLR_PORT_TO_DRV(
-		    nvp->nvp_ctlp->nvc_ctlr_num, nvp->nvp_port_num));
-	} else {
-		nv_sgp_drive_disconnect(nvp->nvp_ctlp, SGP_CTLR_PORT_TO_DRV(
-		    nvp->nvp_ctlp->nvc_ctlr_num, nvp->nvp_port_num));
-	}
-#endif
 }
 
 
 /*
- * Set up a new timeout or complete a timeout.
- * Timeout value has to be specified in microseconds. If time is zero, no new
- * timeout is scheduled.
- * Must be called at the end of the timeout routine.
+ * Set up a new timeout or complete a timeout in microseconds.
+ * If microseconds is zero, no new timeout is scheduled.  Must be
+ * called at the end of the timeout routine.
  */
 static void
-nv_setup_timeout(nv_port_t *nvp, int time)
+nv_setup_timeout(nv_port_t *nvp, clock_t microseconds)
 {
 	clock_t old_duration = nvp->nvp_timeout_duration;
 
-	ASSERT(time != 0);
+	if (microseconds == 0) {
+
+		return;
+	}
 
 	if (nvp->nvp_timeout_id != 0 && nvp->nvp_timeout_duration == 0) {
 		/*
@@ -2200,14 +2290,19 @@
 		 * If nvp_timeout_duration is 0, then this function
 		 * was re-entered. Just exit.
 		 */
-	cmn_err(CE_WARN, "nv_setup_timeout re-entered");
+		cmn_err(CE_WARN, "nv_setup_timeout re-entered");
+
 		return;
 	}
+
 	nvp->nvp_timeout_duration = 0;
+
 	if (nvp->nvp_timeout_id == 0) {
-		/* Start new timer */
+		/*
+		 * start new timer
+		 */
 		nvp->nvp_timeout_id = timeout(nv_timeout, (void *)nvp,
-		    drv_usectohz(time));
+		    drv_usectohz(microseconds));
 	} else {
 		/*
 		 * If the currently running timeout is due later than the
@@ -2215,15 +2310,16 @@
 		 * Our timeouts do not need to be accurate - we would be just
 		 * checking that the specified time was exceeded.
 		 */
-		if (old_duration > time) {
+		if (old_duration > microseconds) {
 			mutex_exit(&nvp->nvp_mutex);
 			(void) untimeout(nvp->nvp_timeout_id);
 			mutex_enter(&nvp->nvp_mutex);
 			nvp->nvp_timeout_id = timeout(nv_timeout, (void *)nvp,
-			    drv_usectohz(time));
+			    drv_usectohz(microseconds));
 		}
 	}
-	nvp->nvp_timeout_duration = time;
+
+	nvp->nvp_timeout_duration = microseconds;
 }
 
 
@@ -2232,8 +2328,6 @@
 
 /*
  * Reset the port
- *
- * Entered with nvp mutex held
  */
 static void
 nv_reset(nv_port_t *nvp, char *reason)
@@ -2243,11 +2337,26 @@
 	nv_ctl_t *nvc = nvp->nvp_ctlp;
 	uint32_t sctrl, serr, sstatus;
 	uint8_t bmicx;
-	int i, j, reset = 0;
+	int i, j;
+	boolean_t reset_success = B_FALSE;
 
 	ASSERT(mutex_owned(&nvp->nvp_mutex));
 
+	/*
+	 * If the port is reset right after the controller receives
+	 * the DMA activate command (or possibly any other FIS),
+	 * controller operation freezes without any known recovery
+	 * procedure.  Until Nvidia advises on a recovery mechanism,
+	 * avoid the situation by waiting sufficiently long to
+	 * ensure the link is not actively transmitting any FIS.
+	 * 100ms was empirically determined to be large enough to
+	 * ensure no transaction was left in flight but not too long
+	 * as to cause any significant thread delay.
+	 */
+	drv_usecwait(100000);
+
 	serr = nv_get32(bar5_hdl, nvp->nvp_serror);
+	DTRACE_PROBE1(serror_h, int, serr);
 
 	/*
 	 * stop DMA engine.
@@ -2255,13 +2364,39 @@
 	bmicx = nv_get8(nvp->nvp_bm_hdl, nvp->nvp_bmicx);
 	nv_put8(nvp->nvp_bm_hdl, nvp->nvp_bmicx,  bmicx & ~BMICX_SSBM);
 
-	nvp->nvp_state |= NV_PORT_RESET;
+	/*
+	 * the current setting of the NV_RESET in nvp_state indicates whether
+	 * this is the first reset attempt or a retry.
+	 */
+	if (nvp->nvp_state & NV_RESET) {
+		nvp->nvp_reset_retry_count++;
+
+		NVLOG(NVDBG_RESET, nvc, nvp, "npv_reset_retry_count: %d",
+		    nvp->nvp_reset_retry_count);
+
+	} else {
+		nvp->nvp_reset_retry_count = 0;
+		nvp->nvp_reset_count++;
+		nvp->nvp_state |= NV_RESET;
+
+		NVLOG(NVDBG_RESET, nvc, nvp, "nvp_reset_count: %d reason: %s "
+		    "serror: 0x%x seq: %d run: %d cmd: 0x%x",
+		    nvp->nvp_reset_count, reason, serr, nvp->nvp_seq,
+		    nvp->nvp_non_ncq_run, nvp->nvp_last_cmd);
+	}
+
+	/*
+	 * a link event could have occurred slightly before excessive
+	 * interrupt processing invokes a reset.  Reset handling overrides
+	 * link event processing so it's safe to clear it here.
+	 */
+	nvp->nvp_state &= ~(NV_RESTORE|NV_LINK_EVENT);
+
 	nvp->nvp_reset_time = ddi_get_lbolt();
-	nvp->nvp_reset_count++;
-
-	if (strcmp(reason, "attach") != 0) {
-		nv_cmn_err(CE_NOTE, nvc, nvp, "nv_reset: reason: %s serr 0x%x",
-		    reason, serr);
+
+	if ((nvp->nvp_state & (NV_ATTACH|NV_HOTPLUG)) == 0) {
+		nv_cmn_err(CE_NOTE, nvc, nvp, "nv_reset: reason: %s serr 0x%x"
+		    " nvp_state: 0x%x", reason, serr, nvp->nvp_state);
 		/*
 		 * keep a record of why the first reset occurred, for debugging
 		 */
@@ -2272,9 +2407,6 @@
 		}
 	}
 
-	NVLOG(NVDBG_RESET, nvc, nvp, "nv_reset_count: %d",
-	    nvp->nvp_reset_count);
-
 	(void) strncpy(nvp->nvp_reset_reason, reason, NV_REASON_LEN);
 
 	/*
@@ -2285,31 +2417,36 @@
 	/*
 	 * Issue hardware reset; retry if necessary.
 	 */
-	for (i = 0; i < NV_RESET_ATTEMPTS; i++) {
+	for (i = 0; i < NV_COMRESET_ATTEMPTS; i++) {
+
 		/*
-		 * Clear signature registers
+		 * clear signature registers and the error register too
 		 */
 		nv_put8(cmdhdl, nvp->nvp_sect, 0);
 		nv_put8(cmdhdl, nvp->nvp_lcyl, 0);
 		nv_put8(cmdhdl, nvp->nvp_hcyl, 0);
 		nv_put8(cmdhdl, nvp->nvp_count, 0);
 
-		/* Clear task file error register */
 		nv_put8(nvp->nvp_cmd_hdl, nvp->nvp_error, 0);
 
 		/*
 		 * assert reset in PHY by writing a 1 to bit 0 scontrol
 		 */
 		sctrl = nv_get32(bar5_hdl, nvp->nvp_sctrl);
+
 		nv_put32(bar5_hdl, nvp->nvp_sctrl,
 		    sctrl | SCONTROL_DET_COMRESET);
 
 		/* Wait at least 1ms, as required by the spec */
 		drv_usecwait(nv_reset_length);
 
+		serr = nv_get32(bar5_hdl, nvp->nvp_serror);
+		DTRACE_PROBE1(aftercomreset_serror_h, int, serr);
+
 		/* Reset all accumulated error bits */
 		nv_put32(bar5_hdl, nvp->nvp_serror, 0xffffffff);
 
+
 		sstatus = nv_get32(bar5_hdl, nvp->nvp_sstatus);
 		sctrl = nv_get32(bar5_hdl, nvp->nvp_sctrl);
 		NVLOG(NVDBG_RESET, nvc, nvp, "nv_reset: applied (%d); "
@@ -2329,29 +2466,30 @@
 			if ((SSTATUS_GET_IPM(sstatus) == SSTATUS_IPM_ACTIVE) &&
 			    (SSTATUS_GET_DET(sstatus) ==
 			    SSTATUS_DET_DEVPRE_PHYCOM)) {
-				reset = 1;
+				reset_success = B_TRUE;
 				break;
 			}
 		}
-		if (reset == 1)
+
+		if (reset_success == B_TRUE)
 			break;
 	}
+
+
 	serr = nv_get32(bar5_hdl, nvp->nvp_serror);
-	if (reset == 0) {
+	DTRACE_PROBE1(last_serror_h, int, serr);
+
+	if (reset_success == B_FALSE) {
 		NVLOG(NVDBG_RESET, nvc, nvp, "nv_reset not succeeded "
-		    "(serr 0x%x) after %d attempts", serr, i);
+		    "after %d attempts. serr: 0x%x", i, serr);
 	} else {
-		NVLOG(NVDBG_RESET, nvc, nvp, "nv_reset succeeded (serr 0x%x)"
-		    "after %dms", serr, TICK_TO_MSEC(ddi_get_lbolt() -
-		    nvp->nvp_reset_time));
-	}
-	nvp->nvp_reset_time = ddi_get_lbolt();
-
-	if (servicing_interrupt()) {
-		nv_setup_timeout(nvp, NV_ONE_MSEC);
-	} else if (!(nvp->nvp_state & NV_PORT_RESET_RETRY)) {
-		nv_monitor_reset(nvp);
-	}
+		NVLOG(NVDBG_RESET, nvc, nvp, "nv_reset succeeded"
+		    " after %dms. serr: 0x%x", TICK_TO_MSEC(ddi_get_lbolt() -
+		    nvp->nvp_reset_time), serr);
+	}
+
+	nvp->nvp_wait_sig  = NV_WAIT_SIG;
+	nv_setup_timeout(nvp, nvp->nvp_wait_sig);
 }
 
 
@@ -2570,7 +2708,7 @@
 
 	stran.sata_tran_hba_rev = SATA_TRAN_HBA_REV;
 	stran.sata_tran_hba_dip = nvc->nvc_dip;
-	stran.sata_tran_hba_num_cports = NV_NUM_CPORTS;
+	stran.sata_tran_hba_num_cports = NV_NUM_PORTS;
 	stran.sata_tran_hba_features_support =
 	    SATA_CTLF_HOTPLUG | SATA_CTLF_ASN | SATA_CTLF_ATAPI;
 	stran.sata_tran_hba_qdepth = NV_QUEUE_SLOTS;
@@ -2602,7 +2740,8 @@
 		mutex_init(&nvp->nvp_mutex, NULL, MUTEX_DRIVER,
 		    DDI_INTR_PRI(nvc->nvc_intr_pri));
 
-		cv_init(&nvp->nvp_poll_cv, NULL, CV_DRIVER, NULL);
+		cv_init(&nvp->nvp_sync_cv, NULL, CV_DRIVER, NULL);
+		cv_init(&nvp->nvp_reset_cv, NULL, CV_DRIVER, NULL);
 
 		nvp->nvp_data	= cmd_addr + NV_DATA;
 		nvp->nvp_error	= cmd_addr + NV_ERROR;
@@ -2627,7 +2766,7 @@
 		 * Initialize dma handles, etc.
 		 * If it fails, the port is in inactive state.
 		 */
-		(void) nv_init_port(nvp);
+		nv_init_port(nvp);
 	}
 
 	/*
@@ -2657,7 +2796,7 @@
  * making error handling more messy.  The easy way is to just allocate
  * all 32 slots, which is what most drives support anyway.
  */
-static int
+static void
 nv_init_port(nv_port_t *nvp)
 {
 	nv_ctl_t *nvc = nvp->nvp_ctlp;
@@ -2673,15 +2812,6 @@
 	dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
 	dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
 
-	if (nvp->nvp_state & NV_PORT_INIT) {
-		NVLOG(NVDBG_INIT, nvc, nvp,
-		    "nv_init_port previously initialized", NULL);
-
-		return (NV_SUCCESS);
-	} else {
-		NVLOG(NVDBG_INIT, nvc, nvp, "nv_init_port initializing", NULL);
-	}
-
 	nvp->nvp_sg_dma_hdl = kmem_zalloc(sizeof (ddi_dma_handle_t) *
 	    NV_QUEUE_SLOTS, KM_SLEEP);
 
@@ -2705,7 +2835,7 @@
 		if (rc != DDI_SUCCESS) {
 			nv_uninit_port(nvp);
 
-			return (NV_FAILURE);
+			return;
 		}
 
 		rc = ddi_dma_mem_alloc(nvp->nvp_sg_dma_hdl[i], prd_size,
@@ -2716,7 +2846,7 @@
 		if (rc != DDI_SUCCESS) {
 			nv_uninit_port(nvp);
 
-			return (NV_FAILURE);
+			return;
 		}
 
 		rc = ddi_dma_addr_bind_handle(nvp->nvp_sg_dma_hdl[i], NULL,
@@ -2727,7 +2857,7 @@
 		if (rc != DDI_DMA_MAPPED) {
 			nv_uninit_port(nvp);
 
-			return (NV_FAILURE);
+			return;
 		}
 
 		ASSERT(count == 1);
@@ -2752,121 +2882,10 @@
 	 * after interrupts are initialized.
 	 */
 	nvp->nvp_type = SATA_DTYPE_NONE;
-	nvp->nvp_signature = 0;
-
-	nvp->nvp_state |= NV_PORT_INIT;
-
-	return (NV_SUCCESS);
 }
 
 
 /*
- * Establish initial link & device type
- * Called only from nv_attach
- * Loops up to approximately 210ms; can exit earlier.
- * The time includes wait for the link up and completion of the initial
- * signature gathering operation.
- */
-static void
-nv_init_port_link_processing(nv_ctl_t *nvc)
-{
-	ddi_acc_handle_t bar5_hdl;
-	nv_port_t *nvp;
-	volatile uint32_t sstatus;
-	int port, links_up, ready_ports, i;
-
-
-	for (port = 0; port < NV_MAX_PORTS(nvc); port++) {
-		nvp = &(nvc->nvc_port[port]);
-		if (nvp != NULL && (nvp->nvp_state & NV_PORT_INIT)) {
-			/*
-			 * Initiate device identification, if any is attached
-			 * and reset was not already applied by hot-plug
-			 * event processing.
-			 */
-			mutex_enter(&nvp->nvp_mutex);
-			if (!(nvp->nvp_state & NV_PORT_RESET)) {
-				nvp->nvp_state |= NV_PORT_RESET | NV_PORT_PROBE;
-				nv_reset(nvp, "attach");
-			}
-			mutex_exit(&nvp->nvp_mutex);
-		}
-	}
-	/*
-	 * Wait up to 10ms for links up.
-	 * Spec says that link should be up in 1ms.
-	 */
-	for (i = 0; i < 10; i++) {
-		drv_usecwait(NV_ONE_MSEC);
-		links_up = 0;
-		for (port = 0; port < NV_MAX_PORTS(nvc); port++) {
-			nvp = &(nvc->nvc_port[port]);
-			mutex_enter(&nvp->nvp_mutex);
-			bar5_hdl = nvp->nvp_ctlp->nvc_bar_hdl[5];
-			sstatus = nv_get32(bar5_hdl, nvp->nvp_sstatus);
-			if ((SSTATUS_GET_IPM(sstatus) == SSTATUS_IPM_ACTIVE) &&
-			    (SSTATUS_GET_DET(sstatus) ==
-			    SSTATUS_DET_DEVPRE_PHYCOM)) {
-				if ((nvp->nvp_state & NV_PORT_RESET) &&
-				    nvp->nvp_type == SATA_DTYPE_NONE) {
-					nvp->nvp_type = SATA_DTYPE_UNKNOWN;
-				}
-				NVLOG(NVDBG_INIT, nvc, nvp,
-				    "nv_init_port_link_processing()"
-				    "link up; time from reset %dms",
-				    TICK_TO_MSEC(ddi_get_lbolt() -
-				    nvp->nvp_reset_time));
-				links_up++;
-			}
-			mutex_exit(&nvp->nvp_mutex);
-		}
-		if (links_up == NV_MAX_PORTS(nvc)) {
-			break;
-		}
-	}
-	NVLOG(NVDBG_RESET, nvc, nvp, "nv_init_port_link_processing():"
-	    "%d links up", links_up);
-	/*
-	 * At this point, if any device is attached, the link is established.
-	 * Wait till devices are ready to be accessed, no more than 200ms.
-	 * 200ms is empirical time in which a signature should be available.
-	 */
-	for (i = 0; i < 200; i++) {
-		ready_ports = 0;
-		for (port = 0; port < NV_MAX_PORTS(nvc); port++) {
-			nvp = &(nvc->nvc_port[port]);
-			mutex_enter(&nvp->nvp_mutex);
-			bar5_hdl = nvp->nvp_ctlp->nvc_bar_hdl[5];
-			sstatus = nv_get32(bar5_hdl, nvp->nvp_sstatus);
-			if ((SSTATUS_GET_IPM(sstatus) == SSTATUS_IPM_ACTIVE) &&
-			    (SSTATUS_GET_DET(sstatus) ==
-			    SSTATUS_DET_DEVPRE_PHYCOM) &&
-			    !(nvp->nvp_state & (NV_PORT_RESET |
-			    NV_PORT_RESET_RETRY))) {
-				/*
-				 * Reset already processed
-				 */
-				NVLOG(NVDBG_RESET, nvc, nvp,
-				    "nv_init_port_link_processing()"
-				    "device ready; port state %x; "
-				    "time from reset %dms", nvp->nvp_state,
-				    TICK_TO_MSEC(ddi_get_lbolt() -
-				    nvp->nvp_reset_time));
-
-				ready_ports++;
-			}
-			mutex_exit(&nvp->nvp_mutex);
-		}
-		if (ready_ports == links_up) {
-			break;
-		}
-		drv_usecwait(NV_ONE_MSEC);
-	}
-	NVLOG(NVDBG_RESET, nvc, nvp, "nv_init_port_link_processing():"
-	    "%d devices ready", ready_ports);
-}
-
-/*
  * Free dynamically allocated structures for port.
  */
 static void
@@ -2874,19 +2893,6 @@
 {
 	int i;
 
-	/*
-	 * It is possible to reach here before a port has been initialized or
-	 * after it has already been uninitialized.  Just return in that case.
-	 */
-	if (nvp->nvp_slot == NULL) {
-
-		return;
-	}
-	/*
-	 * Mark port unusable now.
-	 */
-	nvp->nvp_state &= ~NV_PORT_INIT;
-
 	NVLOG(NVDBG_INIT, nvp->nvp_ctlp, nvp,
 	    "nv_uninit_port uninitializing", NULL);
 
@@ -2991,7 +2997,8 @@
 		nv_uninit_port(nvp);
 		mutex_exit(&nvp->nvp_mutex);
 		mutex_destroy(&nvp->nvp_mutex);
-		cv_destroy(&nvp->nvp_poll_cv);
+		cv_destroy(&nvp->nvp_sync_cv);
+		cv_destroy(&nvp->nvp_reset_cv);
 	}
 
 	kmem_free(nvc->nvc_port, NV_MAX_PORTS(nvc) * sizeof (nv_port_t));
@@ -3029,7 +3036,7 @@
 
 /*
  * Main interrupt handler for ck804.  handles normal device
- * interrupts as well as port hot plug and remove interrupts.
+ * interrupts and hot plug and remove interrupts.
  *
  */
 static void
@@ -3065,6 +3072,7 @@
 		int port_mask[] = {CK804_INT_PDEV_INT, CK804_INT_SDEV_INT};
 
 		if ((port_mask[port] & intr_status) == 0) {
+
 			continue;
 		}
 
@@ -3076,18 +3084,10 @@
 		mutex_enter(&nvp->nvp_mutex);
 
 		/*
-		 * there was a corner case found where an interrupt
-		 * arrived before nvp_slot was set.  Should
-		 * probably should track down why that happens and try
-		 * to eliminate that source and then get rid of this
-		 * check.
+		 * this case might be encountered when the other port
+		 * is active
 		 */
-		if (nvp->nvp_slot == NULL) {
-			status = nv_get8(nvp->nvp_ctl_hdl, nvp->nvp_status);
-			NVLOG(NVDBG_ALWAYS, nvc, nvp, "spurious interrupt "
-			    "received before initialization "
-			    "completed status=%x", status);
-			mutex_exit(&nvp->nvp_mutex);
+		if (nvp->nvp_state & NV_DEACTIVATED) {
 
 			/*
 			 * clear interrupt bits
@@ -3095,9 +3095,12 @@
 			nv_put8(bar5_hdl, nvc->nvc_ck804_int_status,
 			    port_mask[port]);
 
+			mutex_exit(&nvp->nvp_mutex);
+
 			continue;
 		}
 
+
 		if ((&(nvp->nvp_slot[0]))->nvslot_spkt == NULL)  {
 			status = nv_get8(nvp->nvp_ctl_hdl, nvp->nvp_status);
 			NVLOG(NVDBG_ALWAYS, nvc, nvp, "spurious interrupt "
@@ -3195,9 +3198,9 @@
 
 		if ((sstatus & SSTATUS_DET_DEVPRE_PHYCOM) ==
 		    SSTATUS_DET_DEVPRE_PHYCOM) {
-			nv_report_add_remove(nvp, 0);
+			nv_link_event(nvp, NV_REM_DEV);
 		} else {
-			nv_report_add_remove(nvp, NV_PORT_HOTREMOVED);
+			nv_link_event(nvp, NV_ADD_DEV);
 		}
 	clear:
 		/*
@@ -3235,7 +3238,7 @@
 			(*(nvc->nvc_set_intr))(nvp, NV_INTR_DISABLE);
 			nv_port_state_change(nvp, SATA_EVNT_PORT_FAILED,
 			    SATA_ADDR_CPORT, SATA_PSTATE_FAILED);
-			nvp->nvp_state |= NV_PORT_FAILED;
+			nvp->nvp_state |= NV_FAILED;
 			(void) nv_abort_active(nvp, NULL, SATA_PKT_DEV_ERROR,
 			    B_TRUE);
 			nv_cmn_err(CE_WARN, nvc, nvp, "unable to clear "
@@ -3251,7 +3254,6 @@
 /*
  * Interrupt handler for mcp5x.  It is invoked by the wrapper for each port
  * on the controller, to handle completion and hot plug and remove events.
- *
  */
 static uint_t
 mcp5x_intr_port(nv_port_t *nvp)
@@ -3274,8 +3276,22 @@
 		 */
 		int_status = nv_get16(bar5_hdl, nvp->nvp_mcp5x_int_status);
 
+		/*
+		 * if the port is deactivated, just clear the interrupt and
+		 * return.  can get here even if interrupts were disabled
+		 * on this port but enabled on the other.
+		 */
+		if (nvp->nvp_state & NV_DEACTIVATED) {
+			nv_put16(bar5_hdl, nvp->nvp_mcp5x_int_status,
+			    int_status);
+
+			return (DDI_INTR_CLAIMED);
+		}
+
 		NVLOG(NVDBG_INTR, nvc, nvp, "int_status = %x", int_status);
 
+		DTRACE_PROBE1(int_status_before_h, int, int_status);
+
 		/*
 		 * MCP5X_INT_IGNORE interrupts will show up in the status,
 		 * but are masked out from causing an interrupt to be generated
@@ -3283,6 +3299,8 @@
 		 */
 		int_status &= ~(MCP5X_INT_IGNORE);
 
+		DTRACE_PROBE1(int_status_after_h, int, int_status);
+
 		/*
 		 * exit the loop when no more interrupts to process
 		 */
@@ -3299,7 +3317,8 @@
 			 * from the DDI's perspective even though the packet
 			 * completion may not have succeeded.  If it fails,
 			 * need to manually clear the interrupt, otherwise
-			 * clearing is implicit.
+			 * clearing is implicit as a result of reading the
+			 * task file status register.
 			 */
 			ret = DDI_INTR_CLAIMED;
 			if (mcp5x_packet_complete_intr(nvc, nvp) ==
@@ -3330,7 +3349,7 @@
 			ret = DDI_INTR_CLAIMED;
 
 			mutex_enter(&nvp->nvp_mutex);
-			nv_report_add_remove(nvp, NV_PORT_HOTREMOVED);
+			nv_link_event(nvp, NV_REM_DEV);
 			mutex_exit(&nvp->nvp_mutex);
 
 		} else if (int_status & MCP5X_INT_ADD) {
@@ -3338,23 +3357,30 @@
 			ret = DDI_INTR_CLAIMED;
 
 			mutex_enter(&nvp->nvp_mutex);
-			nv_report_add_remove(nvp, 0);
+			nv_link_event(nvp, NV_ADD_DEV);
 			mutex_exit(&nvp->nvp_mutex);
 		}
 		if (clear) {
 			nv_put16(bar5_hdl, nvp->nvp_mcp5x_int_status, clear);
 			clear = 0;
 		}
-		/* Protect against a stuck interrupt */
+
+		/*
+		 * protect against a stuck interrupt
+		 */
 		if (intr_cycles++ == NV_MAX_INTR_LOOP) {
-			nv_cmn_err(CE_WARN, nvc, nvp, "excessive interrupt "
-			    "processing.  Disabling port int_status=%X"
+
+			NVLOG(NVDBG_INTR, nvc, nvp, "excessive interrupt "
+			    "processing.  Disabling interrupts int_status=%X"
 			    " clear=%X", int_status, clear);
+			DTRACE_PROBE(excessive_interrupts_f);
+
 			mutex_enter(&nvp->nvp_mutex);
 			(*(nvc->nvc_set_intr))(nvp, NV_INTR_DISABLE);
-			nv_port_state_change(nvp, SATA_EVNT_PORT_FAILED,
-			    SATA_ADDR_CPORT, SATA_PSTATE_FAILED);
-			nvp->nvp_state |= NV_PORT_FAILED;
+			/*
+			 * reset the device.  If it remains inaccessible
+			 * after a reset it will be failed then.
+			 */
 			(void) nv_abort_active(nvp, NULL, SATA_PKT_DEV_ERROR,
 			    B_TRUE);
 			mutex_exit(&nvp->nvp_mutex);
@@ -3496,7 +3522,9 @@
 	bmstatus = nv_get8(bmhdl, nvp->nvp_bmisx);
 
 	if (!(bmstatus & (BMISX_IDEINTS | BMISX_IDERR))) {
-		NVLOG(NVDBG_INTR, nvc, nvp, "BMISX_IDEINTS not set", NULL);
+		DTRACE_PROBE1(bmstatus_h, int, bmstatus);
+		NVLOG(NVDBG_INTR, nvc, nvp, "BMISX_IDEINTS not set %x",
+		    bmstatus);
 		mutex_exit(&nvp->nvp_mutex);
 
 		return (NV_FAILURE);
@@ -3506,7 +3534,7 @@
 	 * Commands may have been processed by abort or timeout before
 	 * interrupt processing acquired the mutex. So we may be processing
 	 * an interrupt for packets that were already removed.
-	 * For functionning NCQ processing all slots may be checked, but
+	 * For functioning NCQ processing all slots may be checked, but
 	 * with NCQ disabled (current code), relying on *_run flags is OK.
 	 */
 	if (nvp->nvp_non_ncq_run) {
@@ -3518,6 +3546,7 @@
 		if (status & SATA_STATUS_BSY) {
 			nv_cmn_err(CE_WARN, nvc, nvp,
 			    "unexpected SATA_STATUS_BSY set");
+			DTRACE_PROBE(unexpected_status_bsy_p);
 			mutex_exit(&nvp->nvp_mutex);
 			/*
 			 * calling function will clear interrupt.  then
@@ -3646,7 +3675,7 @@
 		 * to signal the sleeping thread that the cmd is complete.
 		 */
 		if ((spkt->satapkt_op_mode & SATA_OPMODE_POLLING) == 0) {
-			cv_signal(&nvp->nvp_poll_cv);
+			cv_signal(&nvp->nvp_sync_cv);
 		}
 
 		return;
@@ -4025,14 +4054,15 @@
  * number if possible
  */
 static void
-nv_vcmn_err(int ce, nv_ctl_t *nvc, nv_port_t *nvp, char *fmt, va_list ap)
+nv_vcmn_err(int ce, nv_ctl_t *nvc, nv_port_t *nvp, const char *fmt, va_list ap,
+	boolean_t log_to_sata_ring)
 {
 	char port[NV_STR_LEN];
 	char inst[NV_STR_LEN];
 	dev_info_t *dip;
 
 	if (nvc) {
-		(void) snprintf(inst, NV_STR_LEN, "inst %d",
+		(void) snprintf(inst, NV_STR_LEN, "inst%d ",
 		    ddi_get_instance(nvc->nvc_dip));
 		dip = nvc->nvc_dip;
 	} else {
@@ -4040,7 +4070,8 @@
 	}
 
 	if (nvp) {
-		(void) sprintf(port, "port%d", nvp->nvp_port_num);
+		(void) snprintf(port, NV_STR_LEN, "port%d",
+		    nvp->nvp_port_num);
 		dip = nvp->nvp_ctlp->nvc_dip;
 	} else {
 		port[0] = '\0';
@@ -4048,7 +4079,7 @@
 
 	mutex_enter(&nv_log_mutex);
 
-	(void) sprintf(nv_log_buf, "nv_sata %s %s%s", inst, port,
+	(void) sprintf(nv_log_buf, "%s%s%s", inst, port,
 	    (inst[0]|port[0] ? ": " :""));
 
 	(void) vsnprintf(&nv_log_buf[strlen(nv_log_buf)],
@@ -4062,22 +4093,20 @@
 		if (nv_prom_print) {
 			prom_printf("%s\n", nv_log_buf);
 		} else {
-			cmn_err(ce, "%s", nv_log_buf);
+			cmn_err(ce, "%s\n", nv_log_buf);
 		}
-
-
 	} else {
 		cmn_err(ce, "!%s", nv_log_buf);
 	}
 
-
-	(void) sprintf(nv_log_buf, "%s%s", port, (port[0] ? ": " :""));
-
-	(void) vsnprintf(&nv_log_buf[strlen(nv_log_buf)],
-	    NV_LOGBUF_LEN - strlen(nv_log_buf), fmt, ap);
-
-	sata_trace_debug(dip, nv_log_buf);
-
+	if (log_to_sata_ring == B_TRUE) {
+		(void) sprintf(nv_log_buf, "%s%s", port, (port[0] ? ": " :""));
+
+		(void) vsnprintf(&nv_log_buf[strlen(nv_log_buf)],
+		    NV_LOGBUF_LEN - strlen(nv_log_buf), fmt, ap);
+
+		sata_trace_debug(dip, nv_log_buf);
+	}
 
 	mutex_exit(&nv_log_mutex);
 }
@@ -4092,7 +4121,7 @@
 	va_list ap;
 
 	va_start(ap, fmt);
-	nv_vcmn_err(ce, nvc, nvp, fmt, ap);
+	nv_vcmn_err(ce, nvc, nvp, fmt, ap, B_TRUE);
 	va_end(ap);
 }
 
@@ -4102,6 +4131,13 @@
 {
 	va_list ap;
 
+	if (nv_log_to_cmn_err == B_TRUE) {
+		va_start(ap, fmt);
+		nv_vcmn_err(CE_CONT, nvc, nvp, fmt, ap, B_FALSE);
+		va_end(ap);
+
+	}
+
 	va_start(ap, fmt);
 
 	if (nvp == NULL && nvc == NULL) {
@@ -4120,7 +4156,8 @@
 
 	/*
 	 * nvp is not NULL, but nvc might be.  Reference nvp for both
-	 * port and dip.
+	 * port and dip, to get the port number prefixed on the
+	 * message.
 	 */
 	mutex_enter(&nv_log_mutex);
 
@@ -4185,6 +4222,7 @@
 		nv_put8(cmdhdl, nvp->nvp_feature,
 		    satacmd->satacmd_features_reg);
 
+
 		break;
 
 	case ATA_ADDR_LBA28:
@@ -4221,6 +4259,7 @@
 			nv_put8(cmdhdl, nvp->nvp_count,
 			    satacmd->satacmd_sec_count_lsb);
 		}
+
 		nv_put8(cmdhdl, nvp->nvp_feature,
 		    satacmd->satacmd_features_reg_ext);
 		nv_put8(cmdhdl, nvp->nvp_feature,
@@ -4232,6 +4271,7 @@
 		nv_put8(cmdhdl, nvp->nvp_hcyl, satacmd->satacmd_lba_high_msb);
 		nv_put8(cmdhdl, nvp->nvp_lcyl, satacmd->satacmd_lba_mid_msb);
 		nv_put8(cmdhdl, nvp->nvp_sect, satacmd->satacmd_lba_low_msb);
+
 		/*
 		 * Send the low-order half
 		 */
@@ -4540,8 +4580,6 @@
 	 */
 	nv_copy_registers(nvp, &spkt->satapkt_device, spkt);
 	nv_complete_io(nvp, spkt, 0);
-	nvp->nvp_state |= NV_PORT_RESET;
-	nvp->nvp_state &= ~(NV_PORT_RESTORE | NV_PORT_RESET_RETRY);
 	nv_reset(nvp, "pio_out");
 
 	return (SATA_TRAN_PORT_ERROR);
@@ -4581,12 +4619,12 @@
 
 	/*
 	 * The command is always sent via PIO, despite whatever the SATA
-	 * framework sets in the command.  Overwrite the DMA bit to do this.
+	 * common module sets in the command.  Overwrite the DMA bit to do this.
 	 * Also, overwrite the overlay bit to be safe (it shouldn't be set).
 	 */
 	nv_put8(cmdhdl, nvp->nvp_feature, 0);	/* deassert DMA and OVL */
 
-	/* set appropriately by the sata framework */
+	/* set appropriately by the sata common module */
 	nv_put8(cmdhdl, nvp->nvp_hcyl, satacmd->satacmd_lba_high_lsb);
 	nv_put8(cmdhdl, nvp->nvp_lcyl, satacmd->satacmd_lba_mid_lsb);
 	nv_put8(cmdhdl, nvp->nvp_sect, satacmd->satacmd_lba_low_lsb);
@@ -4630,8 +4668,6 @@
 
 		nv_copy_registers(nvp, &spkt->satapkt_device, spkt);
 		nv_complete_io(nvp, spkt, 0);
-		nvp->nvp_state |= NV_PORT_RESET;
-		nvp->nvp_state &= ~(NV_PORT_RESTORE | NV_PORT_RESET_RETRY);
 		nv_reset(nvp, "start_pkt_pio");
 
 		return (SATA_TRAN_PORT_ERROR);
@@ -4711,8 +4747,6 @@
 		sata_cmdp->satacmd_status_reg = nv_get8(ctlhdl,
 		    nvp->nvp_altstatus);
 		sata_cmdp->satacmd_error_reg = nv_get8(cmdhdl, nvp->nvp_error);
-		nvp->nvp_state |= NV_PORT_RESET;
-		nvp->nvp_state &= ~(NV_PORT_RESTORE | NV_PORT_RESET_RETRY);
 		nv_reset(nvp, "intr_pio_in");
 
 		return;
@@ -4886,9 +4920,6 @@
 		} else {
 			nv_slotp->nvslot_flags = NVSLOT_COMPLETE;
 			spkt->satapkt_reason = SATA_PKT_TIMEOUT;
-			nvp->nvp_state |= NV_PORT_RESET;
-			nvp->nvp_state &= ~(NV_PORT_RESTORE |
-			    NV_PORT_RESET_RETRY);
 			nv_reset(nvp, "intr_pkt_pio");
 		}
 
@@ -5009,7 +5040,7 @@
 
 			/*
 			 * In order to avoid clobbering the rqsense data
-			 * set by the SATA framework, the sense data read
+			 * set by the SATA common module, the sense data read
 			 * from the device is put in a separate buffer and
 			 * copied into the packet after the request sense
 			 * command successfully completes.
@@ -5071,7 +5102,7 @@
 			ctlr_count -= count;
 
 			if (ctlr_count > 0) {
-				/* consume remainding bytes */
+				/* consume remaining bytes */
 
 				for (; ctlr_count > 0;
 				    ctlr_count -= 2)
@@ -5104,6 +5135,7 @@
 	}
 }
 
+
 /*
  * ATA command, DMA data in/out
  */
@@ -5148,13 +5180,12 @@
 	/*
 	 * check for bus master errors
 	 */
+
 	if (bm_status & BMISX_IDERR) {
 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
 		sata_cmdp->satacmd_status_reg = nv_get8(ctlhdl,
 		    nvp->nvp_altstatus);
 		sata_cmdp->satacmd_error_reg = nv_get8(cmdhdl, nvp->nvp_error);
-		nvp->nvp_state |= NV_PORT_RESET;
-		nvp->nvp_state &= ~(NV_PORT_RESTORE | NV_PORT_RESET_RETRY);
 		nv_reset(nvp, "intr_dma");
 
 		return;
@@ -5341,7 +5372,12 @@
 
 	NVLOG(NVDBG_EVENT, nvp->nvp_ctlp, nvp,
 	    "nv_port_state_change: event 0x%x type 0x%x state 0x%x "
-	    "time %ld (ticks)", event, addr_type, state, ddi_get_lbolt());
+	    "lbolt %ld (ticks)", event, addr_type, state, ddi_get_lbolt());
+
+	if (ddi_in_panic() != 0) {
+
+		return;
+	}
 
 	bzero((void *)&sd, sizeof (sata_device_t));
 	sd.satadev_rev = SATA_DEVICE_REV;
@@ -5359,292 +5395,221 @@
 }
 
 
-
 /*
  * Monitor reset progress and signature gathering.
- * This function may loop, so it should not be called from interrupt
- * context.
- *
- * Entered with nvp mutex held.
  */
-static void
+static clock_t
 nv_monitor_reset(nv_port_t *nvp)
 {
 	ddi_acc_handle_t bar5_hdl = nvp->nvp_ctlp->nvc_bar_hdl[5];
 	uint32_t sstatus;
-	int send_notification = B_FALSE;
-	uint8_t dev_type;
+
+	ASSERT(MUTEX_HELD(&nvp->nvp_mutex));
 
 	sstatus = nv_get32(bar5_hdl, nvp->nvp_sstatus);
 
 	/*
-	 * We do not know here the reason for port reset.
 	 * Check the link status. The link needs to be active before
-	 * we can check the link's status.
+	 * checking the link's status.
 	 */
 	if ((SSTATUS_GET_IPM(sstatus) != SSTATUS_IPM_ACTIVE) ||
 	    (SSTATUS_GET_DET(sstatus) != SSTATUS_DET_DEVPRE_PHYCOM)) {
 		/*
 		 * Either link is not active or there is no device
-		 * If the link remains down for more than NV_LINK_DOWN_TIMEOUT
+		 * If the link remains down for more than NV_LINK_EVENT_DOWN
 		 * (milliseconds), abort signature acquisition and complete
-		 * reset processing.
-		 * The link will go down when COMRESET is sent by nv_reset(),
-		 * so it is practically nvp_reset_time milliseconds.
+		 * reset processing.  The link will go down when COMRESET is
+		 * sent by nv_reset().
 		 */
 
 		if (TICK_TO_MSEC(ddi_get_lbolt() - nvp->nvp_reset_time) >=
-		    NV_LINK_DOWN_TIMEOUT) {
-			NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
+		    NV_LINK_EVENT_DOWN) {
+
+			nv_cmn_err(CE_NOTE, nvp->nvp_ctlp, nvp,
 			    "nv_monitor_reset: no link - ending signature "
 			    "acquisition; time after reset %ldms",
 			    TICK_TO_MSEC(ddi_get_lbolt() -
 			    nvp->nvp_reset_time));
+
+			DTRACE_PROBE(no_link_reset_giving_up_f);
+
+			/*
+			 * If the drive was previously present and configured
+			 * and then subsequently removed, then send a removal
+			 * event to sata common module.
+			 */
+			if (nvp->nvp_type != SATA_DTYPE_NONE) {
+				nv_port_state_change(nvp,
+				    SATA_EVNT_DEVICE_DETACHED,
+				    SATA_ADDR_CPORT, 0);
+			}
+
+			nvp->nvp_type = SATA_DTYPE_NONE;
+			nvp->nvp_signature = NV_NO_SIG;
+			nvp->nvp_state &= ~(NV_DEACTIVATED);
+
+#ifdef SGPIO_SUPPORT
+			nv_sgp_drive_disconnect(nvp->nvp_ctlp,
+			    SGP_CTLR_PORT_TO_DRV(
+			    nvp->nvp_ctlp->nvc_ctlr_num,
+			    nvp->nvp_port_num));
+#endif
+
+			cv_signal(&nvp->nvp_reset_cv);
+
+			return (0);
 		}
-		nvp->nvp_state &= ~(NV_PORT_RESET | NV_PORT_RESET_RETRY |
-		    NV_PORT_PROBE | NV_PORT_HOTPLUG_DELAY);
-		/*
-		 * Else, if the link was lost (i.e. was present before)
-		 * the controller should generate a 'remove' interrupt
-		 * that will cause the appropriate event notification.
-		 */
-		return;
+
+		DTRACE_PROBE(link_lost_reset_keep_trying_p);
+
+		return (nvp->nvp_wait_sig);
 	}
 
 	NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
-	    "nv_monitor_reset: link up after reset; time %ldms",
+	    "nv_monitor_reset: link up.  time since reset %ldms",
 	    TICK_TO_MSEC(ddi_get_lbolt() - nvp->nvp_reset_time));
 
-sig_read:
-	if (nvp->nvp_signature != 0) {
+	nv_read_signature(nvp);
+
+
+	if (nvp->nvp_signature != NV_NO_SIG) {
 		/*
-		 * The link is up. The signature was acquired before (device
-		 * was present).
-		 * But we may need to wait for the signature (D2H FIS) before
-		 * accessing the drive.
+		 * signature has been acquired, send the appropriate
+		 * event to the sata common module.
 		 */
-		if (nv_wait_for_signature != 0) {
-			uint32_t old_signature;
-			uint8_t old_type;
-
-			old_signature = nvp->nvp_signature;
-			old_type = nvp->nvp_type;
-			nvp->nvp_signature = 0;
-			nv_read_signature(nvp);
-			if (nvp->nvp_signature == 0) {
-				nvp->nvp_signature = old_signature;
-				nvp->nvp_type = old_type;
-
-#ifdef NV_DEBUG
-				/* FOR DEBUGGING */
-				if (nv_wait_here_forever) {
-					drv_usecwait(1000);
-					goto sig_read;
-				}
+		if (nvp->nvp_state & (NV_ATTACH|NV_HOTPLUG)) {
+			char *source;
+
+			if (nvp->nvp_state & NV_HOTPLUG) {
+
+				source = "hotplugged";
+				nv_port_state_change(nvp,
+				    SATA_EVNT_DEVICE_ATTACHED,
+				    SATA_ADDR_CPORT, SATA_DSTATE_PWR_ACTIVE);
+				DTRACE_PROBE1(got_sig_for_hotplugged_device_h,
+				    int, nvp->nvp_state);
+
+			} else {
+				source = "activated or attached";
+				DTRACE_PROBE1(got_sig_for_existing_device_h,
+				    int, nvp->nvp_state);
+			}
+
+			NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
+			    "signature acquired for %s device. sig:"
+			    " 0x%x state: 0x%x nvp_type: 0x%x", source,
+			    nvp->nvp_signature, nvp->nvp_state, nvp->nvp_type);
+
+
+			nvp->nvp_state &= ~(NV_RESET|NV_ATTACH|NV_HOTPLUG);
+
+#ifdef SGPIO_SUPPORT
+			if (nvp->nvp_type == SATA_DTYPE_ATADISK) {
+				nv_sgp_drive_connect(nvp->nvp_ctlp,
+				    SGP_CTLR_PORT_TO_DRV(
+				    nvp->nvp_ctlp->nvc_ctlr_num,
+				    nvp->nvp_port_num));
+			} else {
+				nv_sgp_drive_disconnect(nvp->nvp_ctlp,
+				    SGP_CTLR_PORT_TO_DRV(
+				    nvp->nvp_ctlp->nvc_ctlr_num,
+				    nvp->nvp_port_num));
+			}
 #endif
-				/*
-				 * Wait, but not endlessly.
-				 */
-				if (TICK_TO_MSEC(ddi_get_lbolt() -
-				    nvp->nvp_reset_time) <
-				    nv_sig_acquisition_time) {
-					drv_usecwait(1000);
-					goto sig_read;
-				} else if (!(nvp->nvp_state &
-				    NV_PORT_RESET_RETRY)) {
-					/*
-					 * Retry reset.
-					 */
-					NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
-					    "nv_monitor_reset: retrying reset "
-					    "time after first reset: %ldms",
-					    TICK_TO_MSEC(ddi_get_lbolt() -
-					    nvp->nvp_reset_time));
-					nvp->nvp_state |= NV_PORT_RESET_RETRY;
-					nv_reset(nvp, "monitor_reset 1");
-					goto sig_read;
-				}
-
-				NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
-				    "nv_monitor_reset: terminating signature "
-				    "acquisition (1); time after reset: %ldms",
-				    TICK_TO_MSEC(ddi_get_lbolt() -
-				    nvp->nvp_reset_time));
-			} else {
-				NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
-				    "nv_monitor_reset: signature acquired; "
-				    "time after reset: %ldms",
-				    TICK_TO_MSEC(ddi_get_lbolt() -
-				    nvp->nvp_reset_time));
-			}
+
+			cv_signal(&nvp->nvp_reset_cv);
+
+			return (0);
 		}
-		/*
-		 * Clear reset state, set device reset recovery state
-		 */
-		nvp->nvp_state &= ~(NV_PORT_RESET | NV_PORT_RESET_RETRY |
-		    NV_PORT_PROBE);
-		nvp->nvp_state |= NV_PORT_RESTORE;
 
 		/*
-		 * Need to send reset event notification
-		 */
-		send_notification = B_TRUE;
-	} else {
-		/*
-		 * The link is up. The signature was not acquired before.
-		 * We can try to fetch a device signature.
+		 * Since this was not an attach, it was a reset of an
+		 * existing device
 		 */
-		dev_type = nvp->nvp_type;
-
-acquire_signature:
-		nv_read_signature(nvp);
-		if (nvp->nvp_signature != 0) {
-			/*
-			 * Got device signature.
-			 */
-			NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
-			    "nv_monitor_reset: signature acquired; "
-			    "time after reset: %ldms",
-			    TICK_TO_MSEC(ddi_get_lbolt() -
-			    nvp->nvp_reset_time));
-
-			/* Clear internal reset state */
-			nvp->nvp_state &=
-			    ~(NV_PORT_RESET | NV_PORT_RESET_RETRY);
-
-			if (dev_type != SATA_DTYPE_NONE) {
-				/*
-				 * We acquired the signature for a
-				 * pre-existing device that was not identified
-				 * before and and was reset.
-				 * Need to enter the device reset recovery
-				 * state and to send the reset notification.
-				 */
-				nvp->nvp_state |= NV_PORT_RESTORE;
-				send_notification = B_TRUE;
-			} else {
-				/*
-				 * Else, We acquired the signature because a new
-				 * device was attached (the driver attach or
-				 * a hot-plugged device). There is no need to
-				 * enter the device reset recovery state or to
-				 * send the reset notification, but we may need
-				 * to send a device attached notification.
-				 */
-				if (nvp->nvp_state & NV_PORT_PROBE) {
-					nv_port_state_change(nvp,
-					    SATA_EVNT_DEVICE_ATTACHED,
-					    SATA_ADDR_CPORT, 0);
-					nvp->nvp_state &= ~NV_PORT_PROBE;
-				}
-			}
-		} else {
-			if (TICK_TO_MSEC(ddi_get_lbolt() -
-			    nvp->nvp_reset_time) < nv_sig_acquisition_time) {
-				drv_usecwait(1000);
-				goto acquire_signature;
-			} else if (!(nvp->nvp_state & NV_PORT_RESET_RETRY)) {
-				/*
-				 * Some drives may require additional
-				 * reset(s) to get a valid signature
-				 * (indicating that the drive is ready).
-				 * If a drive was not just powered
-				 * up, the signature should be available
-				 * within few hundred milliseconds
-				 * after reset.  Therefore, if more than
-				 * NV_SIG_ACQUISITION_TIME has elapsed
-				 * while waiting for a signature, reset
-				 * device again.
-				 */
-				NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
-				    "nv_monitor_reset: retrying reset "
-				    "time after first reset: %ldms",
-				    TICK_TO_MSEC(ddi_get_lbolt() -
-				    nvp->nvp_reset_time));
-				nvp->nvp_state |= NV_PORT_RESET_RETRY;
-				nv_reset(nvp, "monitor_reset 2");
-				drv_usecwait(1000);
-				goto acquire_signature;
-			}
-			/*
-			 * Terminating signature acquisition.
-			 * Hopefully, the drive is ready.
-			 * The SATA module can deal with this as long as it
-			 * knows that some device is attached and a device
-			 * responds to commands.
-			 */
-			if (!(nvp->nvp_state & NV_PORT_PROBE)) {
-				send_notification = B_TRUE;
-			}
-			nvp->nvp_state &= ~(NV_PORT_RESET |
-			    NV_PORT_RESET_RETRY);
-			nvp->nvp_type = SATA_DTYPE_UNKNOWN;
-			if (nvp->nvp_state & NV_PORT_PROBE) {
-				nv_port_state_change(nvp,
-				    SATA_EVNT_DEVICE_ATTACHED,
-				    SATA_ADDR_CPORT, 0);
-				nvp->nvp_state &= ~NV_PORT_PROBE;
-			}
-			nvp->nvp_type = dev_type;
-			NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
-			    "nv_monitor_reset: terminating signature "
-			    "acquisition (2); time after reset: %ldms",
-			    TICK_TO_MSEC(ddi_get_lbolt() -
-			    nvp->nvp_reset_time));
-		}
-	}
-
-	if (send_notification) {
+		nvp->nvp_state &= ~NV_RESET;
+		nvp->nvp_state |= NV_RESTORE;
+
+
+
+		DTRACE_PROBE(got_signature_reset_complete_p);
+		DTRACE_PROBE1(nvp_signature_h, int, nvp->nvp_signature);
+		DTRACE_PROBE1(nvp_state_h, int, nvp->nvp_state);
+
+		NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
+		    "signature acquired reset complete. sig: 0x%x"
+		    " state: 0x%x", nvp->nvp_signature, nvp->nvp_state);
+
+		/*
+		 * interrupts may have been disabled so just make sure
+		 * they are cleared and re-enabled.
+		 */
+
+		(*(nvp->nvp_ctlp->nvc_set_intr))(nvp,
+		    NV_INTR_CLEAR_ALL|NV_INTR_ENABLE);
+
 		nv_port_state_change(nvp, SATA_EVNT_DEVICE_RESET,
 		    SATA_ADDR_DCPORT,
 		    SATA_DSTATE_RESET | SATA_DSTATE_PWR_ACTIVE);
-	}
-
-#ifdef SGPIO_SUPPORT
-	if (nvp->nvp_type == SATA_DTYPE_ATADISK) {
-		nv_sgp_drive_connect(nvp->nvp_ctlp, SGP_CTLR_PORT_TO_DRV(
-		    nvp->nvp_ctlp->nvc_ctlr_num, nvp->nvp_port_num));
-	} else {
-		nv_sgp_drive_disconnect(nvp->nvp_ctlp, SGP_CTLR_PORT_TO_DRV(
-		    nvp->nvp_ctlp->nvc_ctlr_num, nvp->nvp_port_num));
-	}
-#endif
+
+		return (0);
+	}
+
+
+	if (TICK_TO_MSEC(ddi_get_lbolt() - nvp->nvp_reset_time) >
+	    NV_RETRY_RESET_SIG) {
+
+
+		if (nvp->nvp_reset_retry_count >= NV_MAX_RESET_RETRY) {
+
+			nvp->nvp_state |= NV_FAILED;
+			nvp->nvp_state &= ~(NV_RESET|NV_ATTACH|NV_HOTPLUG);
+
+			DTRACE_PROBE(reset_exceeded_waiting_for_sig_p);
+			DTRACE_PROBE(reset_exceeded_waiting_for_sig_f);
+			DTRACE_PROBE1(nvp_state_h, int, nvp->nvp_state);
+			NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
+			    "reset time exceeded waiting for sig nvp_state %x",
+			    nvp->nvp_state);
+
+			nv_port_state_change(nvp, SATA_EVNT_PORT_FAILED,
+			    SATA_ADDR_CPORT, 0);
+
+			cv_signal(&nvp->nvp_reset_cv);
+
+			return (0);
+		}
+
+		nv_reset(nvp, "retry");
+
+		return (nvp->nvp_wait_sig);
+	}
+
+	/*
+	 * signature not received, keep trying
+	 */
+	DTRACE_PROBE(no_sig_keep_waiting_p);
+
+	/*
+	 * double the wait time for sig since the last try but cap it off at
+	 * 1 second.
+	 */
+	nvp->nvp_wait_sig = nvp->nvp_wait_sig * 2;
+
+	return (nvp->nvp_wait_sig > NV_ONE_SEC ? NV_ONE_SEC :
+	    nvp->nvp_wait_sig);
 }
 
 
 /*
- * Send a hotplug (add device) notification at the appropriate time after
- * hotplug detection.
- * Relies on nvp_reset_time set at a hotplug detection time.
- * Called only from nv_timeout when NV_PORT_HOTPLUG_DELAY flag is set in
- * the nvp_state.
- */
-static void
-nv_delay_hotplug_notification(nv_port_t *nvp)
-{
-
-	if (TICK_TO_MSEC(ddi_get_lbolt() - nvp->nvp_reset_time) >=
-	    nv_hotplug_delay) {
-		NVLOG(NVDBG_RESET, nvp->nvp_ctlp, nvp,
-		    "nv_delay_hotplug_notification: notifying framework after "
-		    "%dms delay", TICK_TO_MSEC(ddi_get_lbolt() -
-		    nvp->nvp_reset_time));
-		nvp->nvp_state &= ~NV_PORT_HOTPLUG_DELAY;
-		nv_port_state_change(nvp, SATA_EVNT_DEVICE_ATTACHED,
-		    SATA_ADDR_CPORT, 0);
-	}
-}
-
-/*
  * timeout processing:
  *
  * Check if any packets have crossed a timeout threshold.  If so,
  * abort the packet.  This function is not NCQ-aware.
  *
- * If reset was invoked, call reset monitoring function.
+ * If reset is in progress, call reset monitoring function.
  *
- * Timeout frequency may be lower for checking packet timeout (1s)
- * and higher for reset monitoring (1ms)
+ * Timeout frequency may be lower for checking packet timeout
+ * and higher for reset monitoring.
  *
  */
 static void
@@ -5652,37 +5617,150 @@
 {
 	nv_port_t *nvp = arg;
 	nv_slot_t *nv_slotp;
-	int next_timeout = NV_ONE_SEC;	/* Default */
+	clock_t next_timeout_us = NV_ONE_SEC;
 	uint16_t int_status;
 	uint8_t status, bmstatus;
 	static int intr_warn_once = 0;
+	uint32_t serror;
+
 
 	ASSERT(nvp != NULL);
 
 	mutex_enter(&nvp->nvp_mutex);
 	nvp->nvp_timeout_id = 0;
 
-	/*
-	 * If the port is not in the init state, ignore it.
-	 */
-	if ((nvp->nvp_state & NV_PORT_INIT) == 0) {
-		NVLOG(NVDBG_TIMEOUT, nvp->nvp_ctlp, nvp,
-		    "nv_timeout: port uninitialized", NULL);
-		next_timeout = 0;
+	if (nvp->nvp_state & (NV_DEACTIVATED|NV_FAILED)) {
+		next_timeout_us = 0;
+
+		goto finished;
+	}
+
+	if (nvp->nvp_state & NV_RESET) {
+		next_timeout_us = nv_monitor_reset(nvp);
 
 		goto finished;
 	}
 
-	if (nvp->nvp_state & (NV_PORT_RESET | NV_PORT_RESET_RETRY)) {
-		nv_monitor_reset(nvp);
-		next_timeout = NV_ONE_MSEC;	/* at least 1ms */
-
-		goto finished;
-	}
-
-	if ((nvp->nvp_state & NV_PORT_HOTPLUG_DELAY) != 0) {
-		nv_delay_hotplug_notification(nvp);
-		next_timeout = NV_ONE_MSEC;	/* at least 1ms */
+	if (nvp->nvp_state & NV_LINK_EVENT) {
+		boolean_t device_present = B_FALSE;
+		uint32_t sstatus;
+		ddi_acc_handle_t bar5_hdl = nvp->nvp_ctlp->nvc_bar_hdl[5];
+
+		if (TICK_TO_USEC(ddi_get_lbolt() -
+		    nvp->nvp_link_event_time) < NV_LINK_EVENT_SETTLE) {
+
+			next_timeout_us = 10 * NV_ONE_MSEC;
+
+			DTRACE_PROBE(link_event_set_no_timeout_keep_waiting_p);
+
+			goto finished;
+		}
+
+		DTRACE_PROBE(link_event_settled_now_process_p);
+
+		nvp->nvp_state &= ~NV_LINK_EVENT;
+
+		/*
+		 * ck804 routinely reports the wrong hotplug/unplug event,
+		 * and it's been seen on mcp55 when there are signal integrity
+		 * issues.  Therefore need to infer the event from the
+		 * current link status.
+		 */
+
+		sstatus = nv_get32(bar5_hdl, nvp->nvp_sstatus);
+
+		if ((SSTATUS_GET_IPM(sstatus) == SSTATUS_IPM_ACTIVE) &&
+		    (SSTATUS_GET_DET(sstatus) ==
+		    SSTATUS_DET_DEVPRE_PHYCOM)) {
+			device_present = B_TRUE;
+		}
+
+		if ((nvp->nvp_signature != NV_NO_SIG) &&
+		    (device_present == B_FALSE)) {
+
+			NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
+			    "nv_timeout: device detached", NULL);
+
+			DTRACE_PROBE(device_detached_p);
+
+			(void) nv_abort_active(nvp, NULL, SATA_PKT_PORT_ERROR,
+			    B_FALSE);
+
+			nv_port_state_change(nvp, SATA_EVNT_DEVICE_DETACHED,
+			    SATA_ADDR_CPORT, 0);
+
+			nvp->nvp_signature = NV_NO_SIG;
+			nvp->nvp_rem_time = ddi_get_lbolt();
+			nvp->nvp_type = SATA_DTYPE_NONE;
+			next_timeout_us = 0;
+
+#ifdef SGPIO_SUPPORT
+			nv_sgp_drive_disconnect(nvp->nvp_ctlp,
+			    SGP_CTLR_PORT_TO_DRV(nvp->nvp_ctlp->nvc_ctlr_num,
+			    nvp->nvp_port_num));
+#endif
+
+			goto finished;
+		}
+
+		/*
+		 * if the device was already present, and it's still present,
+		 * then abort any outstanding command and issue a reset.
+		 * This may result from transient link errors.
+		 */
+
+		if ((nvp->nvp_signature != NV_NO_SIG) &&
+		    (device_present == B_TRUE)) {
+
+			NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
+			    "nv_timeout: spurious link event", NULL);
+			DTRACE_PROBE(spurious_link_event_p);
+
+			(void) nv_abort_active(nvp, NULL, SATA_PKT_PORT_ERROR,
+			    B_FALSE);
+
+			nvp->nvp_signature = NV_NO_SIG;
+			nvp->nvp_trans_link_time = ddi_get_lbolt();
+			nvp->nvp_trans_link_count++;
+			next_timeout_us = 0;
+
+			nv_reset(nvp, "transient link event");
+
+			goto finished;
+		}
+
+
+		/*
+		 * a new device has been inserted
+		 */
+		if ((nvp->nvp_signature == NV_NO_SIG) &&
+		    (device_present == B_TRUE)) {
+			NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
+			    "nv_timeout: device attached", NULL);
+
+			DTRACE_PROBE(device_attached_p);
+			nvp->nvp_add_time = ddi_get_lbolt();
+			next_timeout_us = 0;
+			nvp->nvp_reset_count = 0;
+			nvp->nvp_state = NV_HOTPLUG;
+			nvp->nvp_type = SATA_DTYPE_UNKNOWN;
+			nv_reset(nvp, "hotplug");
+
+			goto finished;
+		}
+
+		/*
+		 * no link, and no prior device.  Nothing to do, but
+		 * log this.
+		 */
+		NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
+		    "nv_timeout: delayed hot processing no link no prior"
+		    " device", NULL);
+		DTRACE_PROBE(delayed_hotplug_no_link_no_prior_device_p);
+
+		nvp->nvp_trans_link_time = ddi_get_lbolt();
+		nvp->nvp_trans_link_count++;
+		next_timeout_us = 0;
 
 		goto finished;
 	}
@@ -5716,7 +5794,7 @@
 		 * timeout not needed if there is a polling thread
 		 */
 		if (spkt->satapkt_op_mode & SATA_OPMODE_POLLING) {
-			next_timeout = 0;
+			next_timeout_us = 0;
 
 			goto finished;
 		}
@@ -5724,63 +5802,71 @@
 		if (TICK_TO_SEC(ddi_get_lbolt() - nv_slotp->nvslot_stime) >
 		    spkt->satapkt_time) {
 
-			uint32_t serr = nv_get32(nvp->nvp_ctlp->nvc_bar_hdl[5],
+			serror = nv_get32(nvp->nvp_ctlp->nvc_bar_hdl[5],
 			    nvp->nvp_serror);
+			status = nv_get8(nvp->nvp_ctl_hdl,
+			    nvp->nvp_altstatus);
+			bmstatus = nv_get8(nvp->nvp_bm_hdl,
+			    nvp->nvp_bmisx);
 
 			nv_cmn_err(CE_NOTE, nvp->nvp_ctlp, nvp,
 			    "nv_timeout: aborting: "
-			    "nvslot_stime: %ld max ticks till timeout: "
-			    "%ld cur_time: %ld cmd=%x lba=%d seq=%d",
+			    "nvslot_stime: %ld max ticks till timeout: %ld "
+			    "cur_time: %ld cmd = 0x%x lba = %d seq = %d",
 			    nv_slotp->nvslot_stime,
 			    drv_usectohz(MICROSEC *
 			    spkt->satapkt_time), ddi_get_lbolt(),
 			    cmd, lba, nvp->nvp_seq);
 
 			NVLOG(NVDBG_TIMEOUT, nvp->nvp_ctlp, nvp,
-			    "nv_timeout: SError at timeout: 0x%x", serr);
-
-			NVLOG(NVDBG_TIMEOUT, nvp->nvp_ctlp, nvp,
-			    "nv_timeout: previous cmd=%x",
+			    "nv_timeout: altstatus = 0x%x  bmicx = 0x%x "
+			    "serror = 0x%x previous_cmd = "
+			    "0x%x", status, bmstatus, serror,
 			    nvp->nvp_previous_cmd);
 
+
+			DTRACE_PROBE1(nv_timeout_packet_p, int, nvp);
+
 			if (nvp->nvp_mcp5x_int_status != NULL) {
-				status = nv_get8(nvp->nvp_ctl_hdl,
-				    nvp->nvp_altstatus);
-				bmstatus = nv_get8(nvp->nvp_bm_hdl,
-				    nvp->nvp_bmisx);
+
 				int_status = nv_get16(
 				    nvp->nvp_ctlp->nvc_bar_hdl[5],
 				    nvp->nvp_mcp5x_int_status);
 				NVLOG(NVDBG_TIMEOUT, nvp->nvp_ctlp, nvp,
-				    "nv_timeout: altstatus %x, bmicx %x, "
-				    "int_status %X", status, bmstatus,
-				    int_status);
+				    "int_status = 0x%x", int_status);
 
 				if (int_status & MCP5X_INT_COMPLETE) {
 					/*
-					 * Completion interrupt was missed!
-					 * Issue warning message once
+					 * Completion interrupt was missed.
+					 * Issue warning message once.
 					 */
 					if (!intr_warn_once) {
+
 						nv_cmn_err(CE_WARN,
 						    nvp->nvp_ctlp,
 						    nvp,
 						    "nv_sata: missing command "
-						    "completion interrupt(s)!");
+						    "completion interrupt");
 						intr_warn_once = 1;
+
 					}
+
 					NVLOG(NVDBG_TIMEOUT, nvp->nvp_ctlp,
 					    nvp, "timeout detected with "
 					    "interrupt ready - calling "
 					    "int directly", NULL);
+
 					mutex_exit(&nvp->nvp_mutex);
 					(void) mcp5x_intr_port(nvp);
 					mutex_enter(&nvp->nvp_mutex);
+
 				} else {
 					/*
 					 * True timeout and not a missing
 					 * interrupt.
 					 */
+					DTRACE_PROBE1(timeout_abort_active_p,
+					    int *, nvp);
 					(void) nv_abort_active(nvp, spkt,
 					    SATA_PKT_TIMEOUT, B_TRUE);
 				}
@@ -5795,22 +5881,22 @@
 			    " still in use so restarting timeout",
 			    NULL);
 
-			next_timeout = NV_ONE_SEC;
+			next_timeout_us = NV_ONE_SEC;
 		}
 	} else {
 		/*
 		 * there was no active packet, so do not re-enable timeout
 		 */
-		next_timeout = 0;
+		next_timeout_us = 0;
 		NVLOG(NVDBG_VERBOSE, nvp->nvp_ctlp, nvp,
 		    "nv_timeout: no active packet so not re-arming "
 		    "timeout", NULL);
 	}
 
 finished:
-	if (next_timeout != 0) {
-		nv_setup_timeout(nvp, next_timeout);
-	}
+
+	nv_setup_timeout(nvp, next_timeout_us);
+
 	mutex_exit(&nvp->nvp_mutex);
 }
 
@@ -5945,7 +6031,7 @@
 
 	mutex_enter(&nvp->nvp_mutex);
 
-	if (nvp->nvp_state & NV_PORT_INACTIVE) {
+	if (nvp->nvp_state & NV_DEACTIVATED) {
 		mutex_exit(&nvp->nvp_mutex);
 
 		return;
@@ -5960,8 +6046,6 @@
 	 * Force a reset which will cause a probe and re-establish
 	 * any state needed on the drive.
 	 */
-	nvp->nvp_state |= NV_PORT_RESET;
-	nvp->nvp_state &= ~(NV_PORT_RESTORE | NV_PORT_RESET_RETRY);
 	nv_reset(nvp, "resume");
 
 	mutex_exit(&nvp->nvp_mutex);
@@ -5982,7 +6066,7 @@
 	}
 #endif
 
-	if (nvp->nvp_state & NV_PORT_INACTIVE) {
+	if (nvp->nvp_state & NV_DEACTIVATED) {
 		mutex_exit(&nvp->nvp_mutex);
 
 		return;
@@ -6118,226 +6202,85 @@
 
 
 /*
- * Hot plug and remove interrupts can occur when the device is reset.  Just
- * masking the interrupt doesn't always work well because if a
+ * hot plug and remove interrupts can occur when the device is reset.
+ * Masking the interrupt doesn't always work well because if a
  * different interrupt arrives on the other port, the driver can still
  * end up checking the state of the other port and discover the hot
- * interrupt flag is set even though it was masked.  Checking for recent
- * reset activity and then ignoring turns out to be the easiest way.
- *
- * Entered with nvp mutex held.
+ * interrupt flag is set even though it was masked.  Also, when there are
+ * errors on the link there can be transient link events which need to be
+ * masked and eliminated as well.
  */
 static void
-nv_report_add_remove(nv_port_t *nvp, int flags)
+nv_link_event(nv_port_t *nvp, int flag)
 {
-	ddi_acc_handle_t bar5_hdl = nvp->nvp_ctlp->nvc_bar_hdl[5];
-	uint32_t sstatus;
-	int i;
-	clock_t nv_lbolt = ddi_get_lbolt();
-
-
-	NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp, "nv_report_add_remove() - "
-	    "time (ticks) %d flags %x", nv_lbolt, flags);
+
+	NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp, "nv_link_event: flag: %s",
+	    flag ? "add" : "remove");
+
+	ASSERT(MUTEX_HELD(&nvp->nvp_mutex));
+
+	nvp->nvp_link_event_time = ddi_get_lbolt();
+
+	/*
+	 * if a port has been deactivated, ignore all link events
+	 */
+	if (nvp->nvp_state & NV_DEACTIVATED) {
+		NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp, "ignoring link event"
+		    " port deactivated", NULL);
+		DTRACE_PROBE(ignoring_link_port_deactivated_p);
+
+		return;
+	}
 
 	/*
-	 * wait up to 1ms for sstatus to settle and reflect the true
-	 * status of the port.  Failure to do so can create confusion
-	 * in probe, where the incorrect sstatus value can still
-	 * persist.
+	 * if the drive has been reset, ignore any transient events.  If it's
+	 * a real removal event, nv_monitor_reset() will handle it.
 	 */
-	for (i = 0; i < 1000; i++) {
-		sstatus = nv_get32(bar5_hdl, nvp->nvp_sstatus);
-
-		if ((flags == NV_PORT_HOTREMOVED) &&
-		    ((sstatus & SSTATUS_DET_DEVPRE_PHYCOM) !=
-		    SSTATUS_DET_DEVPRE_PHYCOM)) {
-			break;
-		}
-
-		if ((flags != NV_PORT_HOTREMOVED) &&
-		    ((sstatus & SSTATUS_DET_DEVPRE_PHYCOM) ==
-		    SSTATUS_DET_DEVPRE_PHYCOM)) {
-			break;
-		}
-		drv_usecwait(1);
-	}
-
-	NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
-	    "sstatus took %d us for DEVPRE_PHYCOM to settle", i);
-
-	if (flags == NV_PORT_HOTREMOVED) {
-
-		(void) nv_abort_active(nvp, NULL, SATA_PKT_PORT_ERROR,
-		    B_FALSE);
-
-		/*
-		 * No device, no point of bothering with device reset
-		 */
-		nvp->nvp_type = SATA_DTYPE_NONE;
-		nvp->nvp_signature = 0;
-		nvp->nvp_state &= ~(NV_PORT_RESET | NV_PORT_RESET_RETRY |
-		    NV_PORT_RESTORE);
+	if (nvp->nvp_state & NV_RESET) {
+		NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp, "ignoring link event"
+		    " during reset", NULL);
+		DTRACE_PROBE(ignoring_link_event_during_reset_p);
+
+		return;
+	}
+
+	/*
+	 * if link event processing is already enabled, nothing to
+	 * do.
+	 */
+	if (nvp->nvp_state & NV_LINK_EVENT) {
+
 		NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
-		    "nv_report_add_remove() hot removed", NULL);
-		nv_port_state_change(nvp,
-		    SATA_EVNT_DEVICE_DETACHED,
-		    SATA_ADDR_CPORT, 0);
-
-#ifdef SGPIO_SUPPORT
-		nv_sgp_drive_disconnect(nvp->nvp_ctlp, SGP_CTLR_PORT_TO_DRV(
-		    nvp->nvp_ctlp->nvc_ctlr_num, nvp->nvp_port_num));
-#endif
-	} else {
-		/*
-		 * This is a hot plug or link up indication
-		 * Now, re-check the link state - no link, no device
-		 */
-		if ((SSTATUS_GET_IPM(sstatus) == SSTATUS_IPM_ACTIVE) &&
-		    (SSTATUS_GET_DET(sstatus) == SSTATUS_DET_DEVPRE_PHYCOM)) {
-
-			if (nvp->nvp_type == SATA_DTYPE_NONE) {
-				/*
-				 * Real device attach - there was no device
-				 * attached to this port before this report
-				 */
-				NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
-				    "nv_report_add_remove() new device hot"
-				    "plugged", NULL);
-				nvp->nvp_reset_time = ddi_get_lbolt();
-				if (!(nvp->nvp_state &
-				    (NV_PORT_RESET_RETRY | NV_PORT_RESET))) {
-
-					nvp->nvp_signature = 0;
-					if (nv_reset_after_hotplug != 0) {
-
-						/*
-						 * Send reset to obtain a device
-						 * signature
-						 */
-						nvp->nvp_state |=
-						    NV_PORT_RESET |
-						    NV_PORT_PROBE;
-						nv_reset(nvp,
-						    "report_add_remove");
-					} else {
-						nvp->nvp_type =
-						    SATA_DTYPE_UNKNOWN;
-					}
-				}
-
-				if (!(nvp->nvp_state & NV_PORT_PROBE)) {
-					if (nv_reset_after_hotplug == 0) {
-						/*
-						 * In case a hotplug interrupt
-						 * is generated right after a
-						 * link is up, delay reporting
-						 * a hotplug event to let the
-						 * drive to initialize and to
-						 * send a D2H FIS with a
-						 * signature.
-						 * The timeout will issue an
-						 * event notification after
-						 * the NV_HOTPLUG_DELAY
-						 * milliseconds delay.
-						 */
-						nvp->nvp_state |=
-						    NV_PORT_HOTPLUG_DELAY;
-						nvp->nvp_type =
-						    SATA_DTYPE_UNKNOWN;
-						/*
-						 * Make sure timer is running.
-						 */
-						nv_setup_timeout(nvp,
-						    NV_ONE_MSEC);
-					} else {
-						nv_port_state_change(nvp,
-						    SATA_EVNT_DEVICE_ATTACHED,
-						    SATA_ADDR_CPORT, 0);
-					}
-				}
-				return;
-			}
-			/*
-			 * Otherwise it is a bogus attach, indicating recovered
-			 * link loss. No real need to report it after-the-fact.
-			 * But we may keep some statistics, or notify the
-			 * sata module by reporting LINK_LOST/LINK_ESTABLISHED
-			 * events to keep track of such occurrences.
-			 * Anyhow, we may want to terminate signature
-			 * acquisition.
-			 */
-			NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
-			    "nv_report_add_remove() ignoring plug interrupt "
-			    "- recovered link?", NULL);
-
-			if (nvp->nvp_state &
-			    (NV_PORT_RESET_RETRY | NV_PORT_RESET)) {
-				NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp,
-				    "nv_report_add_remove() - "
-				    "time since last reset %dms",
-				    TICK_TO_MSEC(ddi_get_lbolt() -
-				    nvp->nvp_reset_time));
-				/*
-				 * If the driver does not have to wait for
-				 * a signature, then terminate reset processing
-				 * now.
-				 */
-				if (nv_wait_for_signature == 0) {
-					NVLOG(NVDBG_RESET, nvp->nvp_ctlp,
-					    nvp, "nv_report_add_remove() - ",
-					    "terminating signature acquisition",
-					    ", time after reset: %dms",
-					    TICK_TO_MSEC(ddi_get_lbolt() -
-					    nvp->nvp_reset_time));
-
-					nvp->nvp_state &= ~(NV_PORT_RESET |
-					    NV_PORT_RESET_RETRY);
-
-					if (!(nvp->nvp_state & NV_PORT_PROBE)) {
-						nvp->nvp_state |=
-						    NV_PORT_RESTORE;
-						nvp->nvp_state &=
-						    ~NV_PORT_PROBE;
-
-						/*
-						 * It is not the initial device
-						 * probing, so notify sata
-						 * module that device was
-						 * reset
-						 */
-						nv_port_state_change(nvp,
-						    SATA_EVNT_DEVICE_RESET,
-						    SATA_ADDR_DCPORT,
-						    SATA_DSTATE_RESET |
-						    SATA_DSTATE_PWR_ACTIVE);
-					}
-
-				}
-			}
-			return;
-		}
-		NVLOG(NVDBG_HOT, nvp->nvp_ctlp, nvp, "nv_report_add_remove()"
-		    "ignoring add dev interrupt - "
-		    "link is down or no device!", NULL);
-	}
-
+		    "received link event while processing already in "
+		    "progress", NULL);
+		DTRACE_PROBE(nv_link_event_already_set_p);
+
+		return;
+	}
+
+	DTRACE_PROBE1(link_event_p, int, nvp);
+
+	nvp->nvp_state |= NV_LINK_EVENT;
+
+	nv_setup_timeout(nvp, NV_LINK_EVENT_SETTLE);
 }
 
+
 /*
  * Get request sense data and stuff it the command's sense buffer.
  * Start a request sense command in order to get sense data to insert
  * in the sata packet's rqsense buffer.  The command completion
  * processing is in nv_intr_pkt_pio.
  *
- * The sata framework provides a function to allocate and set-up a
+ * The sata common module provides a function to allocate and set-up a
  * request sense packet command. The reasons it is not being used here is:
  * a) it cannot be called in an interrupt context and this function is
  *    called in an interrupt context.
  * b) it allocates DMA resources that are not used here because this is
  *    implemented using PIO.
  *
- * If, in the future, this is changed to use DMA, the sata framework should
- * be used to allocate and set-up the error retrieval (request sense)
+ * If, in the future, this is changed to use DMA, the sata common module
+ * should be used to allocate and set-up the error retrieval (request sense)
  * command.
  */
 static int
@@ -6391,10 +6334,12 @@
 	    4000000, 0) == B_FALSE) {
 		if (nv_get8(cmdhdl, nvp->nvp_status) &
 		    (SATA_STATUS_ERR | SATA_STATUS_DF)) {
+			spkt->satapkt_reason = SATA_PKT_DEV_ERROR;
 			NVLOG(NVDBG_ATAPI, nvp->nvp_ctlp, nvp,
 			    "nv_start_rqsense_pio: rqsense dev error (HP0)",
 			    NULL);
 		} else {
+			spkt->satapkt_reason = SATA_PKT_TIMEOUT;
 			NVLOG(NVDBG_ATAPI, nvp->nvp_ctlp, nvp,
 			    "nv_start_rqsense_pio: rqsense timeout (HP0)",
 			    NULL);
@@ -6402,8 +6347,6 @@
 
 		nv_copy_registers(nvp, &spkt->satapkt_device, spkt);
 		nv_complete_io(nvp, spkt, 0);
-		nvp->nvp_state |= NV_PORT_RESET;
-		nvp->nvp_state &= ~(NV_PORT_RESTORE | NV_PORT_RESET_RETRY);
 		nv_reset(nvp, "rqsense_pio");
 
 		return (NV_FAILURE);
@@ -6462,9 +6405,9 @@
 		nv_put8(cmdhdl, nvp->nvp_hcyl, 0);
 		nv_put8(cmdhdl, nvp->nvp_count, 0);
 
-		nvp->nvp_signature = 0;
-		nvp->nvp_type = 0;
-		nvp->nvp_state |= NV_PORT_RESET;
+		nvp->nvp_signature = NV_NO_SIG;
+		nvp->nvp_type = SATA_DTYPE_NONE;
+		nvp->nvp_state |= NV_RESET;
 		nvp->nvp_reset_time = ddi_get_lbolt();
 
 		/*
--- a/usr/src/uts/common/io/sata/impl/sata.c	Fri Aug 13 14:49:55 2010 -0700
+++ b/usr/src/uts/common/io/sata/impl/sata.c	Fri Aug 13 15:06:10 2010 -0700
@@ -44,6 +44,7 @@
 #include <sys/sysevent/dr.h>
 #include <sys/taskq.h>
 #include <sys/disp.h>
+#include <sys/sdt.h>
 
 #include <sys/sata/impl/sata.h>
 #include <sys/sata/sata_hba.h>
@@ -15520,16 +15521,7 @@
 		    cport_mutex);
 		rv = EIO;
 	}
-	/*
-	 * Beacuse the port was reset, it should be probed and
-	 * attached device reinitialized. At this point the
-	 * port state is unknown - it's state is HBA-specific.
-	 * Re-probe port to get its state.
-	 */
-	if (sata_reprobe_port(sata_hba_inst, sata_device,
-	    SATA_DEV_IDENTIFY_RETRY) != SATA_SUCCESS) {
-		rv = EIO;
-	}
+
 	return (rv);
 }
 
@@ -15624,7 +15616,6 @@
 	sata_device_t sata_device;
 	int rv = 0;
 	int tcport;
-	int tpmport = 0;
 
 	sata_device.satadev_rev = SATA_DEVICE_REV;
 
@@ -15682,27 +15673,6 @@
 			    "sata_hba_ioctl: reset controller failed"));
 			return (EIO);
 		}
-		/*
-		 * Because ports were reset, port states are unknown.
-		 * They should be re-probed to get their state and
-		 * attached devices should be reinitialized.
-		 */
-		for (tcport = 0; tcport < SATA_NUM_CPORTS(sata_hba_inst);
-		    tcport++) {
-			sata_device.satadev_addr.cport = tcport;
-			sata_device.satadev_addr.pmport = tpmport;
-			sata_device.satadev_addr.qual = SATA_ADDR_CPORT;
-
-			/*
-			 * The sata_reprobe_port() will mark a
-			 * SATA_EVNT_DEVICE_RESET event on the port
-			 * multiplier, all its sub-ports will be probed by
-			 * sata daemon afterwards.
-			 */
-			if (sata_reprobe_port(sata_hba_inst, &sata_device,
-			    SATA_DEV_IDENTIFY_RETRY) != SATA_SUCCESS)
-				rv = EIO;
-		}
 	}
 	/*
 	 * Unlock all ports
@@ -18624,6 +18594,8 @@
 			sata_log(sata_hba_inst, CE_WARN,
 			    "SATA device at port %d - device failed",
 			    saddr->cport);
+
+			DTRACE_PROBE(port_failed_f);
 		}
 		/*
 		 * No point of retrying - device failed or some other event
--- a/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h	Fri Aug 13 14:49:55 2010 -0700
+++ b/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h	Fri Aug 13 15:06:10 2010 -0700
@@ -53,6 +53,7 @@
 #define	NV_LOGBUF_LEN	512
 #define	NV_REASON_LEN	30
 
+
 typedef struct nv_ctl {
 	/*
 	 * Each of these are specific to the chipset in use.
@@ -159,7 +160,8 @@
 	uint32_t	*nvp_sactive;
 
 	kmutex_t	nvp_mutex;	/* main per port mutex */
-	kcondvar_t	nvp_poll_cv;	/* handshake cv between poll & isr */
+	kcondvar_t	nvp_sync_cv;	/* handshake btwn ISR and start thrd */
+	kcondvar_t	nvp_reset_cv;	/* when reset is synchronous */
 
 	/*
 	 * nvp_slot is a pointer to an array of nv_slot
@@ -178,7 +180,10 @@
 
 	timeout_id_t	nvp_timeout_id;
 
-	clock_t		nvp_reset_time;	/* time of last reset */
+	clock_t		nvp_reset_time;		/* time of last reset */
+	clock_t		nvp_link_event_time;	/* time of last plug event */
+	int		nvp_reset_retry_count;
+	clock_t		nvp_wait_sig; /* wait before rechecking sig */
 
 	int		nvp_state; /* state of port. flags defined below */
 
@@ -188,7 +193,16 @@
 #ifdef SGPIO_SUPPORT
 	uint8_t		nvp_sgp_ioctl_mod; /* LEDs modified by ioctl */
 #endif
-	int		nvp_timeout_duration;
+	clock_t		nvp_timeout_duration;
+
+
+	/*
+	 * debug and statistical information
+	 */
+	clock_t		nvp_rem_time;
+	clock_t		nvp_add_time;
+	clock_t		nvp_trans_link_time;
+	int		nvp_trans_link_count;
 
 	uint8_t		nvp_last_cmd;
 	uint8_t		nvp_previous_cmd;
@@ -305,6 +319,7 @@
 #define	NV_SLEEP	1
 #define	NV_NOSLEEP	2
 
+
 /*
  * port offsets from base address ioaddr1
  */
@@ -386,21 +401,21 @@
 #define	MCP_SATA_AE_CTL_PRI_SWNCQ	(1 << 1) /* software NCQ chan 0 */
 #define	MCP_SATA_AE_CTL_SEC_SWNCQ	(1 << 2) /* software NCQ chan 1 */
 
-#define	NV_DELAY_NSEC(wait_ns) \
-{ \
-	hrtime_t start, end; \
-	start = end =  gethrtime(); \
-	while ((end - start) < wait_ns) \
-		end = gethrtime(); \
+#define	NV_DELAY_NSEC(wait_ns)		\
+{					\
+	hrtime_t start, end;		\
+	start = end =  gethrtime();	\
+	while ((end - start) < wait_ns)	\
+		end = gethrtime();	\
 }
 
 /*
- * signatures in task file registers after device reset
+ * signature in task file registers after device reset
  */
-#define	NV_SIG_DISK	0x00000101
-#define	NV_SIG_ATAPI	0xeb140101
-#define	NV_SIG_PM	0x96690101
-#define	NV_SIG_NOTREADY	0x00000000
+#define	NV_DISK_SIG	0x00000101
+#define	NV_ATAPI_SIG	0xeb140101
+#define	NV_PM_SIG	0x96690101
+#define	NV_NO_SIG	0x00000000
 
 /*
  * These bar5 offsets are common to mcp51/mcp55/ck804 and thus
@@ -574,12 +589,12 @@
 
 #define	PRDE_EOT	((uint_t)0x80000000)
 
-#define	NV_DMA_NSEGS	256  /* XXX DEBUG TEST change back to 257 */
+#define	NV_DMA_NSEGS	257 /* at least 1MB (4KB/pg * 256) + 1 if misaligned */
 
 /*
  * ck804 and mcp55 both have 2 ports per controller
  */
-#define	NV_NUM_CPORTS	2
+#define	NV_NUM_PORTS	2
 
 /*
  * Number of slots to allocate in data nv_sata structures to handle
@@ -610,50 +625,66 @@
 #define	NV_ONE_MSEC		1000
 
 /*
+ * initial wait before checking for signature, in microseconds
+ */
+#define	NV_WAIT_SIG	2500
+
+
+/*
  * Length of port reset (microseconds) - SControl bit 0 set to 1
  */
 #define	NV_RESET_LENGTH		1000
 
-#define	NV_RESET_ATTEMPTS	3
+/*
+ * the maximum number of comresets to issue while
+ * performing link reset in nv_reset()
+ */
+#define	NV_COMRESET_ATTEMPTS	3
 
 /*
- * The maximum amount of time (milliseconds) a link can be down during
- * reset without assuming that there is no device attached.
+ * amount of time to wait for a signature in reset, in ms, before
+ * issuing another reset
  */
-#define	NV_LINK_DOWN_TIMEOUT	10
+#define	NV_RETRY_RESET_SIG	5000
 
 /*
- * The maximum amount of time (milliseconds) the signature acquisition can
- * drag on before it is terminated.
- * Some disks have very long acquisition times after hotplug, related to
- * to spinning-up and reading some data from a media.
- * The value below is empirical (20s)
- *
+ * the maximum number of resets to issue to gather signature
+ * before giving up
  */
-#define	NV_SIG_ACQUISITION_TIME	20000
+#define	NV_MAX_RESET_RETRY	8
 
 /*
- * Minimum amount of time (milliseconds) to delay reporting hotplug
- * (device added) event.
- * It is the time allowed for a drive to initialize and to send a D2H FIS with
- * a device signature.
- * It varies between drives from a few milliseconds up to 20s.
+ * amount of time (us) to wait after receiving a link event
+ * before acting on it.  This is because of flakey hardware
+ * sometimes issues the wrong, multiple, or out of order link
+ * events.
  */
-#define	NV_HOTPLUG_DELAY	20000
+#define	NV_LINK_EVENT_SETTLE	500000
+
+/*
+ * The amount of time (ms) a link can be missing
+ * before declaring it removed.
+ */
+#define	NV_LINK_EVENT_DOWN	200
 
 /*
  * nvp_state flags
  */
-#define	NV_PORT_INACTIVE	0x001
-#define	NV_PORT_ABORTING	0x002
-#define	NV_PORT_HOTREMOVED	0x004
-#define	NV_PORT_INIT		0x008
-#define	NV_PORT_FAILED		0x010
-#define	NV_PORT_RESET		0x020
-#define	NV_PORT_RESET_RETRY	0x040
-#define	NV_PORT_RESTORE		0x080
-#define	NV_PORT_PROBE		0x100
-#define	NV_PORT_HOTPLUG_DELAY	0x200
+#define	NV_DEACTIVATED	0x001
+#define	NV_ABORTING	0x002
+#define	NV_FAILED	0x004
+#define	NV_RESET	0x008
+#define	NV_RESTORE	0x010
+#define	NV_LINK_EVENT	0x020
+#define	NV_ATTACH	0x040
+#define	NV_HOTPLUG	0x080
+
+
+/*
+ * flags for nv_report_link_event()
+ */
+#define	NV_ADD_DEV 0
+#define	NV_REM_DEV 1
 
 /*
  * nvc_state flags